X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/4147b3f690ea42bd015c9077ae49137621134f19..b32450f463002a07ee0e7581a231c6916a24a5d7:/usr/src/sys/ufs/lfs/lfs_vnops.c diff --git a/usr/src/sys/ufs/lfs/lfs_vnops.c b/usr/src/sys/ufs/lfs/lfs_vnops.c index 62113452d1..de458ac382 100644 --- a/usr/src/sys/ufs/lfs/lfs_vnops.c +++ b/usr/src/sys/ufs/lfs/lfs_vnops.c @@ -1,22 +1,21 @@ -/* lfs_vnops.c 4.30 82/07/24 */ +/* lfs_vnops.c 4.40 82/10/17 */ #include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" +#include "../h/kernel.h" #include "../h/file.h" #include "../h/stat.h" #include "../h/inode.h" #include "../h/fs.h" #include "../h/buf.h" #include "../h/proc.h" -#include "../h/inline.h" -#ifdef EFS -#include "../net/in.h" -#include "../h/efs.h" -#endif #include "../h/quota.h" #include "../h/descrip.h" +#include "../h/uio.h" +#include "../h/socket.h" +#include "../h/socketvar.h" chdir() { @@ -32,7 +31,7 @@ chroot() } chdirec(ipp) -register struct inode **ipp; + register struct inode **ipp; { register struct inode *ip; struct a { @@ -66,16 +65,29 @@ open() register struct inode *ip; register struct a { char *fname; - int rwmode; + int flags; + int mode; } *uap; + int checkpermissions = 1; uap = (struct a *)u.u_ap; - ip = namei(uchar, 0, 1); + if (uap->flags&FCREATE) { + ip = namei(uchar, 1, 1); + if (ip == NULL) { + if (u.u_error) + return; + ip = maknode(uap->mode&07777&(~ISVTX)); + checkpermissions = 0; + uap->flags &= ~FTRUNCATE; + } + } else + ip = namei(uchar, 0, 1); if (ip == NULL) return; - open1(ip, ++uap->rwmode, 0); + open1(ip, ++uap->flags, checkpermissions); } +#ifndef NOCOMPAT /* * Creat system call. */ @@ -93,58 +105,74 @@ ocreat() if (u.u_error) return; ip = maknode(uap->fmode&07777&(~ISVTX)); - if (ip==NULL) + if (ip == NULL) return; - open1(ip, FWRITE, 2); + open1(ip, FWRITE, 0); } else - open1(ip, FWRITE, 1); + open1(ip, FWRITE|FTRUNCATE, 0); } +#endif /* * Common code for open and creat. - * Check permissions, allocate an open file structure, - * and call the device open routine if any. + * Check permissions (if we haven't done so already), + * allocate an open file structure, and call + * the device open routine, if any. */ -open1(ip, mode, trf) +open1(ip, mode, checkpermissions) register struct inode *ip; register mode; { register struct file *fp; - int i; + int i, flags; - if (trf != 2) { + if (checkpermissions) { if (mode&FREAD) - (void) access(ip, IREAD); + if (access(ip, IREAD)) + goto bad; if (mode&FWRITE) { - (void) access(ip, IWRITE); - if ((ip->i_mode&IFMT) == IFDIR) + if (access(ip, IWRITE)) + goto bad; + if ((ip->i_mode&IFMT) == IFDIR) { u.u_error = EISDIR; + goto bad; + } } } - if (u.u_error) { - iput(ip); - return; + + /* + * Check locking on inode. Release "inode lock" + * while doing so in case we block inside flocki. + */ + flags = 0; + if (mode&(FRDLOCK|FWRLOCK)) { + iunlock(ip); + flags = flocki(ip, 0, mode); + ilock(ip); + if (u.u_error) + goto bad; } - if (trf == 1) - itrunc(ip); + if (mode&FTRUNCATE) + itrunc(ip, 0); iunlock(ip); if ((fp = falloc()) == NULL) goto out; - fp->f_flag = mode&(FREAD|FWRITE); + fp->f_flag = mode & FMODES; fp->f_type = DTYPE_FILE; i = u.u_r.r_val1; fp->f_inode = ip; -#ifdef EFS - openi(ip, mode&(FREAD|FWRITE), trf); -#else - openi(ip, mode&(FREAD|FWRITE)); -#endif - if (u.u_error == 0) + u.u_error = openi(ip, mode); + if (u.u_error == 0) { + u.u_pofile[i] = flags; return; + } u.u_ofile[i] = NULL; fp->f_count--; out: irele(ip); + return; +bad: + iput(ip); } /* @@ -206,7 +234,7 @@ link() } ip->i_nlink++; ip->i_flag |= ICHG; - iupdat(ip, &time, &time, 1); + iupdat(ip, time, time, 1); iunlock(ip); u.u_dirp = (caddr_t)uap->linkname; xp = namei(uchar, 1, 0); @@ -222,13 +250,12 @@ link() u.u_error = EXDEV; goto out; } - wdir(ip); + direnter(ip); out: if (u.u_error) { ip->i_nlink--; ip->i_flag |= ICHG; } -out1: irele(ip); } @@ -268,11 +295,7 @@ symlink() 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); + u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); iput(ip); } @@ -287,33 +310,11 @@ unlink() struct a { char *fname; }; - struct fs *fs; - struct buf *bp; - int lbn, bn, base; int unlinkingdot = 0; pp = namei(uchar, 2, 0); - if(pp == NULL) + if (pp == NULL) return; -#ifdef EFS - /* divert to extended file system if off machine. */ - if (efsinode(pp)) { - dev_t ndev = pp->i_rdev; - - iput(pp); /* avoid recursive hang on inode */ - efsunlink(ndev); - if (u.u_error != EEXIST) - return; - - /* - * If a null pathname remainder, then do - * the unlink locally after restoring state. - */ - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - pp = namei(uchar, 2, 0); - } -#endif /* * Check for unlink(".") @@ -338,45 +339,10 @@ unlink() } 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; - } -*/ - if (u.u_count == 0) { - /* - * first entry in block, so set d_ino to zero. - */ -/*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n" -/*ZZ*/,pp->i_fs->fs_fsmnt,pp->i_number,u.u_offset,u.u_dent.d_name); - u.u_base = (caddr_t)&u.u_dent; - u.u_count = DIRSIZ(&u.u_dent); - u.u_dent.d_ino = 0; - writei(pp); - } else { - /* - * updating preceeding entry to skip over current entry. - */ - fs = pp->i_fs; - lbn = lblkno(fs, u.u_offset); - base = blkoff(fs, u.u_offset); - bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count)); - bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn)); - if (bp->b_flags & B_ERROR) { - brelse(bp); - goto out; - } - ((struct direct *)(bp->b_un.b_addr + base))->d_reclen += - u.u_dent.d_reclen; -/*ZZ*/if(((int)(bp->b_un.b_addr + base)&0x1ff)+u.u_dent.d_reclen>512) -/*ZZ*/ panic("unlink: reclen"); - bwrite(bp); - pp->i_flag |= IUPD|ICHG; + if (dirremove()) { + ip->i_nlink--; + ip->i_flag |= ICHG; } - ip->i_nlink--; - ip->i_flag |= ICHG; - out: if (unlinkingdot) irele(ip); @@ -389,33 +355,27 @@ out1: /* * Seek system call */ -seek() +lseek() { register struct file *fp; register struct a { - int fdes; + int fd; off_t off; int sbase; } *uap; uap = (struct a *)u.u_ap; - fp = getf(uap->fdes); + fp = getf(uap->fd); if (fp == NULL) return; if (fp->f_type == DTYPE_SOCKET) { u.u_error = ESPIPE; return; } - if (uap->sbase == 1) + if (uap->sbase == FSEEK_RELATIVE) uap->off += fp->f_offset; - else if (uap->sbase == 2) { -#ifdef EFS - struct inode *ip = fp->f_inode; - uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size; -#else + else if (uap->sbase == FSEEK_EOF) uap->off += fp->f_inode->i_size; -#endif - } fp->f_offset = uap->off; u.u_r.r_off = uap->off; } @@ -438,26 +398,14 @@ saccess() u.u_uid = u.u_ruid; u.u_gid = u.u_rgid; ip = namei(uchar, 0, 1); -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; - - iput(ip); - efssaccess(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = namei(uchar, 0, 1); - } -#endif 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); + if (uap->fmode&FACCESS_READ && access(ip, IREAD)) + goto done; + if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE)) + goto done; + if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC)) + goto done; +done: iput(ip); } u.u_uid = svuid; @@ -471,20 +419,14 @@ fstat() { register struct file *fp; register struct a { - int fdes; + int fd; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; - fp = getf(uap->fdes); + fp = getf(uap->fd); if (fp == NULL) return; -#ifdef EFS - if (efsinode(fp->f_inode)) { - efsfstat(fp->f_inode->i_rdev, fp); - return; - } -#endif if (fp->f_type == DTYPE_SOCKET) u.u_error = sostat(fp->f_socket, uap->sb); else @@ -506,19 +448,6 @@ stat() ip = namei(uchar, 0, 1); if (ip == NULL) return; -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; - - iput(ip); - efsstat(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = namei(uchar, 0, 1); - } -#endif stat1(ip, uap->sb); iput(ip); } @@ -538,19 +467,6 @@ lstat() ip = namei(uchar, 0, 0); if (ip == NULL) return; -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; - - iput(ip); - efslstat(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = namei(uchar, 0, 0); - } -#endif stat1(ip, uap->sb); iput(ip); } @@ -565,7 +481,7 @@ stat1(ip, ub) { struct stat ds; - IUPDAT(ip, &time, &time, 0); + IUPDAT(ip, time, time, 0); /* * Copy from inode table */ @@ -580,7 +496,13 @@ stat1(ip, ub) ds.st_atime = ip->i_atime; ds.st_mtime = ip->i_mtime; ds.st_ctime = ip->i_ctime; - ds.st_blksize = ip->i_fs->fs_bsize; + /* this doesn't belong here */ + if ((ip->i_mode&IFMT) == IFBLK) + ds.st_blksize = BLKDEV_IOSIZE; + else if ((ip->i_mode&IFMT) == IFCHR) + ds.st_blksize = MAXBSIZE; + else + ds.st_blksize = ip->i_fs->fs_bsize; if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) u.u_error = EFAULT; } @@ -595,44 +517,26 @@ readlink() char *name; char *buf; int count; - } *uap; + } *uap = (struct a *)u.u_ap; + int resid; ip = namei(uchar, 0, 0); if (ip == NULL) return; -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; - - iput(ip); - efsreadlink(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = namei(uchar, 0, 0); - return (0); - } -#endif 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); + u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); out: iput(ip); - u.u_r.r_val1 = uap->count - u.u_count; + u.u_r.r_val1 = uap->count - resid; } chmod() { - register struct inode *ip; - register struct a { + struct inode *ip; + struct a { char *fname; int fmode; } *uap; @@ -640,83 +544,123 @@ chmod() uap = (struct a *)u.u_ap; if ((ip = owner(1)) == NULL) return; -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; + chmod1(ip, uap->fmode); +} - iput(ip); - efschmod(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = owner(1); +fchmod() +{ + struct a { + int fd; + int fmode; + } *uap; + register struct inode *ip; + register struct file *fp; + + uap = (struct a *)u.u_ap; + fp = getf(uap->fd); + if (fp == NULL) + return; + if (fp->f_type == DTYPE_SOCKET) { + u.u_error = EINVAL; + return; } -#endif + ip = fp->f_inode; + ilock(ip); + if (u.u_uid != ip->i_uid && !suser()) { + iunlock(ip); + return; + } + chmod1(ip, uap->fmode); +} + +chmod1(ip, mode) + register struct inode *ip; + register int mode; +{ + register int *gp; + ip->i_mode &= ~07777; if (u.u_uid) { - uap->fmode &= ~ISVTX; - if (ip->i_gid >= NGRPS || - (u.u_grps[ip->i_gid/(sizeof(int)*8)] & - (1 << ip->i_gid%(sizeof(int)*8))) == 0) - uap->fmode &= ~ISGID; -#if MUSH + mode &= ~ISVTX; + for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++) + if (*gp == ip->i_gid) + goto ok; + mode &= ~ISGID; +ok: + ; +#ifdef MUSH if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 && (ip->i_mode & IFMT) != IFCHR) - uap->fmode &= ~u.u_cmask; + mode &= ~u.u_cmask; #endif } - ip->i_mode |= uap->fmode&07777; + ip->i_mode |= mode&07777; ip->i_flag |= ICHG; if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) xrele(ip); -#ifdef MELB - if ((ip->i_mode & ISUID) && ip->i_uid == 0) - printf("%s: ino %d (%s) setuid root\n" - , getfs(ip->i_dev)->s_fsmnt - , ip->i_number - , u.u_dent.d_name - ); -#endif iput(ip); } chown() { - register struct inode *ip; - register struct a { + struct inode *ip; + struct a { char *fname; int uid; int gid; } *uap; -#if QUOTA - register long change; -#endif uap = (struct a *)u.u_ap; if (!suser() || (ip = owner(0)) == NULL) return; -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; + chown1(ip, uap->uid, uap->gid); +} - iput(ip); - efschown(ndev); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = owner(0); +fchown() +{ + struct a { + int fd; + int uid; + int gid; + } *uap; + register struct inode *ip; + register struct file *fp; + + uap = (struct a *)u.u_ap; + fp = getf(uap->fd); + if (fp == NULL) + return; + if (fp->f_type == DTYPE_SOCKET) { + u.u_error = EINVAL; + return; } -#endif -#if QUOTA + ip = fp->f_inode; + ilock(ip); + if (!suser()) { + iunlock(ip); + return; + } + chown1(ip, uap->uid, uap->gid); +} + +/* + * Perform chown operation on inode ip; + * inode must be locked prior to call. + */ +chown1(ip, uid, gid) + register struct inode *ip; + int uid, gid; +{ +#ifdef QUOTA + register long change; + /* * This doesn't allow for holes in files (which hopefully don't * happen often in files that we chown), and is not accurate anyway * (eg: it totally ignores 3 level indir blk files - but hopefully * noone who can make a file that big will have a quota) */ - if (ip->i_uid == uap->uid) + if (ip->i_uid == uid) change = 0; else { register struct fs *fs = ip->i_fs; @@ -727,7 +671,7 @@ chown() size = blkroundup(fs, ip->i_size) - change; change += size; change += fs->fs_bsize; - /* This assumes NIADDR <= 2 */ + /* this assumes NIADDR <= 2 */ if (size > NINDIR(fs) * fs->fs_bsize) change += fs->fs_bsize; } else @@ -739,20 +683,20 @@ chown() dqrele(ip->i_dquot); #endif /* - * keep uid/gid's in sane range - no err, so chown(file, uid, -1) - * will do something useful + * keep uid/gid's in sane range -- no err, + * so chown(file, uid, -1) will do something useful */ - if (uap->uid >= 0 && uap->uid <= 32767) /* should have a const */ - ip->i_uid = uap->uid; - if (uap->gid >= 0 && uap->gid <= 32767) /* same here */ - ip->i_gid = uap->gid; + if (uid >= 0 && uid <= 32767) /* should have a constant */ + ip->i_uid = uid; + if (gid >= 0 && gid <= 32767) /* same here */ + ip->i_gid = gid; ip->i_flag |= ICHG; if (u.u_ruid != 0) ip->i_mode &= ~(ISUID|ISGID); -#if QUOTA +#ifdef QUOTA ip->i_dquot = inoquota(ip); chkdq(ip, change, 1); - chkiq(ip->i_dev, NULL, uap->uid, 1); + chkiq(ip->i_dev, NULL, uid, 1); #endif iput(ip); } @@ -761,7 +705,7 @@ chown() * Set IUPD and IACC times on file. * Can't set ICHG. */ -utime() +outime() { register struct a { char *fname; @@ -769,6 +713,7 @@ utime() } *uap; register struct inode *ip; time_t tv[2]; + struct timeval tv0, tv1; uap = (struct a *)u.u_ap; if ((ip = owner(1)) == NULL) @@ -776,21 +721,10 @@ utime() if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { u.u_error = EFAULT; } else { -#ifdef EFS - if (efsinode(ip)) { - dev_t ndev = ip->i_rdev; - - iput(ip); - efsutime(ndev, uap->fname, tv); - if (u.u_error != EEXIST) - return; - u.u_error = 0; - u.u_dirp = (caddr_t)u.u_arg[0]; - ip = owner(1); - } -#endif ip->i_flag |= IACC|IUPD|ICHG; - iupdat(ip, &tv[0], &tv[1], 0); + tv0.tv_sec = tv[0]; tv0.tv_usec = 0; + tv1.tv_sec = tv[1]; tv1.tv_usec = 0; + iupdat(ip, &tv0, &tv1, 0); } iput(ip); } @@ -800,3 +734,152 @@ sync() update(0); } + +flock() +{ + struct a { + int fd; + int how; + } *uap; + register struct file *fp; + register int cmd, flags; + + uap = (struct a *)u.u_ap; + fp = getf(uap->fd); + if (fp == NULL) + return; + if (fp->f_type == DTYPE_SOCKET) { /* XXX */ + u.u_error = EINVAL; + return; + } + cmd = uap->how; + flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK); + if (cmd&FUNLOCK) { + if (flags == 0) { + u.u_error = EINVAL; + return; + } + funlocki(fp->f_inode, flags); + u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK); + return; + } + /* + * No reason to write lock a file we've already + * write locked, similarly with a read lock. + */ + if ((flags&WRLOCK) && (cmd&FWRLOCK) || + (flags&RDLOCK) && (cmd&FRDLOCK)) + return; + u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd); +} + +truncate() +{ + struct a { + char *fname; + int length; + } *uap = (struct a *)u.u_ap; + struct inode *ip; + + ip = namei(uchar, 0, 1); + if (ip == NULL) + return; + if (access(ip, IWRITE)) + goto bad; + if ((ip->i_mode&IFMT) == IFDIR) { + u.u_error = EISDIR; + goto bad; + } + itrunc(ip, uap->length); + return; +bad: + iput(ip); +} + +ftruncate() +{ + struct a { + int fd; + int length; + } *uap = (struct a *)u.u_ap; + struct inode *ip; + struct file *fp; + + fp = getf(uap->fd); + if (fp == NULL) + return; + if (fp->f_type == DTYPE_SOCKET) { + u.u_error = EINVAL; + return; + } + if ((fp->f_flag&FWRITE) == 0) { + u.u_error = EINVAL; + return; + } + ip = fp->f_inode; + ilock(ip); + itrunc(ip, uap->length); +} + +rename() +{ +#ifdef notdef + struct a { + char *from; + char *to; + } *uap; +#endif + +} + +/* + * Make a new file. + */ +struct inode * +maknode(mode) + int mode; +{ + register struct inode *ip; + ino_t ipref; + + if ((mode & IFMT) == IFDIR) + ipref = dirpref(u.u_pdir->i_fs); + else + ipref = u.u_pdir->i_number; + ip = ialloc(u.u_pdir, ipref, mode); + if (ip == NULL) { + iput(u.u_pdir); + return (NULL); + } +#ifdef QUOTA + if (ip->i_dquot != NODQUOT) + panic("maknode: dquot"); +#endif + ip->i_flag |= IACC|IUPD|ICHG; + if ((mode & IFMT) == 0) + mode |= IFREG; + ip->i_mode = mode & ~u.u_cmask; + ip->i_nlink = 1; + ip->i_uid = u.u_uid; + ip->i_gid = u.u_pdir->i_gid; +#ifdef QUOTA + ip->i_dquot = inoquota(ip); +#endif + + /* + * Make sure inode goes to disk before directory entry. + */ + iupdat(ip, time, time, 1); + direnter(ip); + if (u.u_error) { + /* + * write error occurred trying to update directory + * so must deallocate the inode + */ + ip->i_nlink = 0; + ip->i_flag |= ICHG; + iput(ip); + return (NULL); + } + return (ip); +}