/* vfs_syscalls.c 4.21 82/03/18 */ #include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/reg.h" #include "../h/file.h" #include "../h/inode.h" #include "../h/ino.h" #include "../h/pte.h" #include "../h/vm.h" #include "../h/buf.h" #include "../h/mtpr.h" #include "../h/proc.h" #include "../h/inline.h" #include "../h/conf.h" #include "../h/socket.h" #include "../h/socketvar.h" #include "../h/stat.h" chdir() { chdirec(&u.u_cdir); } chroot() { if (suser()) chdirec(&u.u_rdir); } chdirec(ipp) register struct inode **ipp; { register struct inode *ip; struct a { char *fname; }; ip = namei(uchar, 0, 1); if(ip == NULL) return; if((ip->i_mode&IFMT) != IFDIR) { u.u_error = ENOTDIR; goto bad; } if(access(ip, IEXEC)) goto bad; irele(ip); if (*ipp) { ilock(*ipp); iput(*ipp); } *ipp = ip; return; bad: iput(ip); } /* * Open system call. */ open() { register struct inode *ip; register struct a { char *fname; int rwmode; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0, 1); if (ip == NULL) return; open1(ip, ++uap->rwmode, 0); } /* * Creat system call. */ creat() { register struct inode *ip; register struct a { char *fname; int fmode; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 1, 1); if (ip == NULL) { if (u.u_error) return; ip = maknode(uap->fmode&07777&(~ISVTX)); if (ip==NULL) return; open1(ip, FWRITE, 2); } else open1(ip, FWRITE, 1); } /* * Common code for open and creat. * Check permissions, allocate an open file structure, * and call the device open routine if any. */ open1(ip, mode, trf) register struct inode *ip; register mode; { register struct file *fp; int i; if (trf != 2) { if (mode&FREAD) (void) access(ip, IREAD); if (mode&FWRITE) { (void) access(ip, IWRITE); if ((ip->i_mode&IFMT) == IFDIR) u.u_error = EISDIR; } } if (u.u_error) goto out; if (trf == 1) itrunc(ip); irele(ip); if ((fp = falloc()) == NULL) goto out; fp->f_flag = mode&(FREAD|FWRITE); i = u.u_r.r_val1; fp->f_inode = ip; openi(ip, mode&(FREAD|FWRITE)); if (u.u_error == 0) return; u.u_ofile[i] = NULL; fp->f_count--; out: if (ip != NULL) iput(ip); } /* * Mknod system call */ mknod() { register struct inode *ip; register struct a { char *fname; int fmode; int dev; } *uap; uap = (struct a *)u.u_ap; if (suser()) { ip = namei(uchar, 1, 0); if (ip != NULL) { u.u_error = EEXIST; goto out; } } if (u.u_error) return; ip = maknode(uap->fmode); if (ip == NULL) return; if (uap->dev) { /* * Want to be able to use this to make badblock * inodes, so don't truncate the dev number. */ ip->i_un.i_rdev = uap->dev; ip->i_flag |= IACC|IUPD|ICHG; } out: iput(ip); } /* * link system call */ link() { register struct inode *ip, *xp; register struct a { char *target; char *linkname; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ if (ip == NULL) return; if ((ip->i_mode&IFMT)==IFDIR && !suser()) goto out1; ip->i_nlink++; ip->i_flag |= ICHG; iupdat(ip, &time, &time, 1); irele(ip); u.u_dirp = (caddr_t)uap->linkname; xp = namei(uchar, 1, 0); if (xp != NULL) { u.u_error = EEXIST; iput(xp); goto out; } if (u.u_error) goto out; if (u.u_pdir->i_dev != ip->i_dev) { iput(u.u_pdir); u.u_error = EXDEV; goto out; } wdir(ip); out: if (u.u_error) { ip->i_nlink--; ip->i_flag |= ICHG; } out1: iput(ip); } /* * symlink -- make a symbolic link */ symlink() { register struct a { char *target; char *linkname; } *uap; register struct inode *ip; register char *tp; register c, nc; uap = (struct a *)u.u_ap; tp = uap->target; nc = 0; while (c = fubyte(tp)) { if (c < 0) { u.u_error = EFAULT; return; } tp++; nc++; } u.u_dirp = uap->linkname; ip = namei(uchar, 1, 0); if (ip) { iput(ip); u.u_error = EEXIST; return; } if (u.u_error) return; ip = maknode(IFLNK | 0777); if (ip == NULL) return; u.u_base = uap->target; u.u_count = nc; u.u_offset = 0; u.u_segflg = 0; writei(ip); iput(ip); } /* * Unlink system call. * Hard to avoid races here, especially * in unlinking directories. */ unlink() { register struct inode *ip, *pp; struct a { char *fname; }; pp = namei(uchar, 2, 0); if(pp == NULL) return; /* * Check for unlink(".") * to avoid hanging on the iget */ if (pp->i_number == u.u_dent.d_ino) { ip = pp; ip->i_count++; } else ip = iget(pp->i_dev, u.u_dent.d_ino); if(ip == NULL) goto out1; if((ip->i_mode&IFMT)==IFDIR && !suser()) goto out; /* * Don't unlink a mounted file. */ if (ip->i_dev != pp->i_dev) { u.u_error = EBUSY; goto out; } if (ip->i_flag&ITEXT) xrele(ip); /* try once to free text */ /* if ((ip->i_flag&ITEXT) && ip->i_nlink==1) { u.u_error = ETXTBSY; goto out; } */ u.u_offset -= sizeof(struct direct); u.u_base = (caddr_t)&u.u_dent; u.u_count = sizeof(struct direct); u.u_dent.d_ino = 0; writei(pp); ip->i_nlink--; ip->i_flag |= ICHG; out: iput(ip); out1: iput(pp); } /* * Seek system call */ seek() { register struct file *fp; register struct a { int fdes; off_t off; int sbase; } *uap; uap = (struct a *)u.u_ap; fp = getf(uap->fdes); if (fp == NULL) return; if (fp->f_flag&FSOCKET) { u.u_error = ESPIPE; return; } if (uap->sbase == 1) uap->off += fp->f_offset; else if (uap->sbase == 2) uap->off += fp->f_inode->i_size; fp->f_offset = uap->off; u.u_r.r_off = uap->off; } /* * Access system call */ saccess() { register svuid, svgid; register struct inode *ip; register struct a { char *fname; int fmode; } *uap; uap = (struct a *)u.u_ap; svuid = u.u_uid; svgid = u.u_gid; u.u_uid = u.u_ruid; u.u_gid = u.u_rgid; ip = namei(uchar, 0, 1); if (ip != NULL) { if (uap->fmode&(IREAD>>6)) (void) access(ip, IREAD); if (uap->fmode&(IWRITE>>6)) (void) access(ip, IWRITE); if (uap->fmode&(IEXEC>>6)) (void) access(ip, IEXEC); iput(ip); } u.u_uid = svuid; u.u_gid = svgid; } /* * the fstat system call. */ fstat() { register struct file *fp; register struct a { int fdes; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; fp = getf(uap->fdes); if (fp == NULL) return; if (fp->f_flag & FSOCKET) u.u_error = sostat(fp->f_socket, uap->sb); else stat1(fp->f_inode, uap->sb); } /* * Stat system call. This version does not follow links. */ stat() { register struct inode *ip; register struct a { char *fname; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0, 0); if (ip == NULL) return; stat1(ip, uap->sb); iput(ip); } /* * Lstat system call. This version does follow links. */ lstat() { register struct inode *ip; register struct a { char *fname; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0, 1); if (ip == NULL) return; stat1(ip, uap->sb); iput(ip); } /* * The basic routine for fstat and stat: * get the inode and pass appropriate parts back. */ stat1(ip, ub) register struct inode *ip; struct stat *ub; { register struct dinode *dp; register struct buf *bp; struct stat ds; IUPDAT(ip, &time, &time, 0); /* * First copy from inode table */ ds.st_dev = ip->i_dev; ds.st_ino = ip->i_number; ds.st_mode = ip->i_mode; ds.st_nlink = ip->i_nlink; ds.st_uid = ip->i_uid; ds.st_gid = ip->i_gid; ds.st_rdev = (dev_t)ip->i_un.i_rdev; ds.st_size = ip->i_size; /* * next the dates in the disk */ bp = bread(ip->i_dev, itod(ip->i_number)); dp = bp->b_un.b_dino; dp += itoo(ip->i_number); ds.st_atime = dp->di_atime; ds.st_mtime = dp->di_mtime; ds.st_ctime = dp->di_ctime; brelse(bp); if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) u.u_error = EFAULT; } /* * Return target name of a symbolic link */ readlink() { register struct inode *ip; register struct a { char *name; char *buf; int count; } *uap; ip = namei(uchar, 0, 0); if (ip == NULL) return; if ((ip->i_mode&IFMT) != IFLNK) { u.u_error = ENXIO; goto out; } uap = (struct a *)u.u_ap; u.u_offset = 0; u.u_base = uap->buf; u.u_count = uap->count; u.u_segflg = 0; readi(ip); out: iput(ip); u.u_r.r_val1 = uap->count - u.u_count; } chmod() { register struct inode *ip; register struct a { char *fname; int fmode; } *uap; uap = (struct a *)u.u_ap; if ((ip = owner(1)) == NULL) return; ip->i_mode &= ~07777; if (u.u_uid) uap->fmode &= ~ISVTX; ip->i_mode |= uap->fmode&07777; ip->i_flag |= ICHG; if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) xrele(ip); iput(ip); } chown() { register struct inode *ip; register struct a { char *fname; int uid; int gid; } *uap; uap = (struct a *)u.u_ap; if (!suser() || (ip = owner(0)) == NULL) return; ip->i_uid = uap->uid; ip->i_gid = uap->gid; ip->i_flag |= ICHG; if (u.u_ruid != 0) ip->i_mode &= ~(ISUID|ISGID); iput(ip); } /* * Set IUPD and IACC times on file. * Can't set ICHG. */ utime() { register struct a { char *fname; time_t *tptr; } *uap; register struct inode *ip; time_t tv[2]; uap = (struct a *)u.u_ap; if ((ip = owner(1)) == NULL) return; if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { u.u_error = EFAULT; } else { ip->i_flag |= IACC|IUPD|ICHG; iupdat(ip, &tv[0], &tv[1], 0); } iput(ip); } sync() { update(0); }