-/* lfs_vnops.c 4.21 82/03/18 */
+/* lfs_vnops.c 4.30 82/07/24 */
#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/stat.h"
#include "../h/inode.h"
-#include "../h/ino.h"
-#include "../h/pte.h"
-#include "../h/vm.h"
+#include "../h/fs.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"
+#ifdef EFS
+#include "../net/in.h"
+#include "../h/efs.h"
+#endif
+#include "../h/quota.h"
+#include "../h/descrip.h"
chdir()
{
}
if(access(ip, IEXEC))
goto bad;
- irele(ip);
- if (*ipp) {
- ilock(*ipp);
- iput(*ipp);
- }
+ iunlock(ip);
+ if (*ipp)
+ irele(*ipp);
*ipp = ip;
return;
/*
* Creat system call.
*/
-creat()
+ocreat()
{
register struct inode *ip;
register struct a {
u.u_error = EISDIR;
}
}
- if (u.u_error)
- goto out;
+ if (u.u_error) {
+ iput(ip);
+ return;
+ }
if (trf == 1)
itrunc(ip);
- irele(ip);
+ iunlock(ip);
if ((fp = falloc()) == NULL)
goto out;
fp->f_flag = mode&(FREAD|FWRITE);
+ 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)
return;
u.u_ofile[i] = NULL;
fp->f_count--;
out:
- if (ip != NULL)
- iput(ip);
+ irele(ip);
}
/*
* 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_rdev = uap->dev;
ip->i_flag |= IACC|IUPD|ICHG;
}
ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
if (ip == NULL)
return;
- if ((ip->i_mode&IFMT)==IFDIR && !suser())
- goto out1;
+ if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
+ iput(ip);
+ return;
+ }
ip->i_nlink++;
ip->i_flag |= ICHG;
iupdat(ip, &time, &time, 1);
- irele(ip);
+ iunlock(ip);
u.u_dirp = (caddr_t)uap->linkname;
xp = namei(uchar, 1, 0);
if (xp != NULL) {
ip->i_flag |= ICHG;
}
out1:
- iput(ip);
+ irele(ip);
}
/*
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)
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(".")
* to avoid hanging on the iget
if (pp->i_number == u.u_dent.d_ino) {
ip = pp;
ip->i_count++;
+ unlinkingdot++;
} else
- ip = iget(pp->i_dev, u.u_dent.d_ino);
+ ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
if(ip == NULL)
goto out1;
if((ip->i_mode&IFMT)==IFDIR && !suser())
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);
+ 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;
+ }
ip->i_nlink--;
ip->i_flag |= ICHG;
out:
- iput(ip);
+ if (unlinkingdot)
+ irele(ip);
+ else
+ iput(ip);
out1:
iput(pp);
}
fp = getf(uap->fdes);
if (fp == NULL)
return;
- if (fp->f_flag&FSOCKET) {
+ if (fp->f_type == DTYPE_SOCKET) {
u.u_error = ESPIPE;
return;
}
if (uap->sbase == 1)
uap->off += fp->f_offset;
- else if (uap->sbase == 2)
+ else if (uap->sbase == 2) {
+#ifdef EFS
+ struct inode *ip = fp->f_inode;
+ uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size;
+#else
uap->off += fp->f_inode->i_size;
+#endif
+ }
fp->f_offset = uap->off;
u.u_r.r_off = uap->off;
}
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);
fp = getf(uap->fdes);
if (fp == NULL)
return;
- if (fp->f_flag & FSOCKET)
+#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
stat1(fp->f_inode, uap->sb);
}
/*
- * Stat system call. This version does not follow links.
+ * Stat system call. This version follows links.
*/
stat()
{
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 0);
+ 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);
}
/*
- * Lstat system call. This version does follow links.
+ * Lstat system call. This version does not follow links.
*/
lstat()
{
} *uap;
uap = (struct a *)u.u_ap;
- ip = namei(uchar, 0, 1);
+ 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);
}
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
+ * Copy from inode table
*/
ds.st_dev = ip->i_dev;
ds.st_ino = ip->i_number;
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_rdev = (dev_t)ip->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);
+ 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;
if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
u.u_error = EFAULT;
}
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;
if ((ip = owner(1)) == NULL)
return;
+#ifdef EFS
+ if (efsinode(ip)) {
+ dev_t ndev = ip->i_rdev;
+
+ 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);
+ }
+#endif
ip->i_mode &= ~07777;
- if (u.u_uid)
+ 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
+ if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
+ (ip->i_mode & IFMT) != IFCHR)
+ uap->fmode &= ~u.u_cmask;
+#endif
+ }
ip->i_mode |= uap->fmode&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);
}
int uid;
int gid;
} *uap;
+#if QUOTA
+ register long change;
+#endif
uap = (struct a *)u.u_ap;
if (!suser() || (ip = owner(0)) == NULL)
return;
- ip->i_uid = uap->uid;
- ip->i_gid = uap->gid;
+#ifdef EFS
+ if (efsinode(ip)) {
+ dev_t ndev = ip->i_rdev;
+
+ 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);
+ }
+#endif
+#if QUOTA
+ /*
+ * 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)
+ change = 0;
+ else {
+ register struct fs *fs = ip->i_fs;
+
+ if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
+ register off_t size;
+
+ size = blkroundup(fs, ip->i_size) - change;
+ change += size;
+ change += fs->fs_bsize;
+ /* This assumes NIADDR <= 2 */
+ if (size > NINDIR(fs) * fs->fs_bsize)
+ change += fs->fs_bsize;
+ } else
+ change = fragroundup(fs, ip->i_size);
+ change /= DEV_BSIZE;
+ }
+ chkdq(ip, -change, 1);
+ chkiq(ip->i_dev, ip, ip->i_uid, 1);
+ dqrele(ip->i_dquot);
+#endif
+ /*
+ * 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;
ip->i_flag |= ICHG;
if (u.u_ruid != 0)
ip->i_mode &= ~(ISUID|ISGID);
+#if QUOTA
+ ip->i_dquot = inoquota(ip);
+ chkdq(ip, change, 1);
+ chkiq(ip->i_dev, NULL, uap->uid, 1);
+#endif
iput(ip);
}
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);
}