-/* 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()
{
}
chdirec(ipp)
-register struct inode **ipp;
+ register struct inode **ipp;
{
register struct inode *ip;
struct a {
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.
*/
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);
}
/*
}
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);
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);
}
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);
}
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(".")
}
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);
/*
* 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;
}
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;
{
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
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);
}
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);
}
{
struct stat ds;
- IUPDAT(ip, &time, &time, 0);
+ IUPDAT(ip, time, time, 0);
/*
* Copy from inode table
*/
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;
}
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;
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;
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
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);
}
* Set IUPD and IACC times on file.
* Can't set ICHG.
*/
-utime()
+outime()
{
register struct a {
char *fname;
} *uap;
register struct inode *ip;
time_t tv[2];
+ struct timeval tv0, tv1;
uap = (struct a *)u.u_ap;
if ((ip = owner(1)) == NULL)
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);
}
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);
+}