📄 gfs_syscalls.c
字号:
/* * Change current working directory (``.''). */chdir(){ chdirec(&u.u_cdir);}/* * Change notion of root (``/'') directory. */chroot(){ if (suser()) chdirec(&u.u_rdir);}/* * Common routine for chroot and chdir. */chdirec(gpp) register struct gnode **gpp;{ register struct gnode *gp; register struct a { char *fname; } *uap = (struct a *)u.u_ap; register struct nameidata *ndp = &u.u_nd; register int ret; ndp->ni_nameiop = LOOKUP | FOLLOW; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->fname, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out; } gp = gfs_namei(ndp); if (gp == NULL || u.u_error) goto out; if ((gp->g_mode&GFMT) != GFDIR) { u.u_error = ENOTDIR; goto bad; } if (access(gp, GEXEC)) goto bad; gfs_unlock(gp); if (*gpp) grele(*gpp); *gpp = gp; goto out;bad: gput(gp);out: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Open system call. */open(){ register struct a { char *fname; int mode; int crtmode; } *uap = (struct a *) u.u_ap; copen(uap->mode-FOPEN, uap->crtmode, uap->fname);}/* * Creat system call. */creat(){ register struct a { char *fname; int fmode; } *uap = (struct a *)u.u_ap; copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);}/* * Common code for open and creat. * Check permissions, allocate an open file structure, * and call the device open routine if any. */copen(mode, arg, fname) register int mode; int arg; caddr_t fname;{ register struct gnode *gp; register struct file *fp; register struct nameidata *ndp = &u.u_nd; register int i; caddr_t value; int ret; if ((mode&(FREAD|FWRITE)) == 0) { u.u_error = EINVAL; return; } KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(fname, ndp->ni_dirp, MAXPATHLEN, (u_int *)0)) { goto out; } if (mode&FCREAT) { if (mode & FEXCL) ndp->ni_nameiop = CREATE; else ndp->ni_nameiop = CREATE | FOLLOW; gp = gfs_namei(ndp); if (gp == NULL) { if (u.u_error) { goto out; } /* * Don't let a non super user create a regular file * with the sticky bit set. */ if (u.u_uid) arg &= ~GSVTX; if ((gp = GMAKNODE((arg & 07777) | GFREG, (dev_t) 0, ndp)) == (struct gnode *) GNOFUNC) { u.u_error = EOPNOTSUPP; goto out; } if (gp == NULL) { goto out; } mode &= ~FTRUNC; } else { if (mode&FEXCL) { u.u_error = EEXIST; gput(gp); goto out; } mode &= ~FCREAT; } } else { ndp->ni_nameiop = LOOKUP | FOLLOW; gp = gfs_namei(ndp); if (gp == NULL) { goto out; } } if ((gp->g_mode & GFMT) == GFSOCK) { u.u_error = EOPNOTSUPP; goto free_gp; } if ((mode&FCREAT) == 0) { if (mode&FREAD) if (access(gp, GREAD)) goto free_gp; if (mode&(FWRITE|FTRUNC)) { if (access(gp, GWRITE)) goto free_gp; if ((gp->g_mode&GFMT) == GFDIR) { u.u_error = EISDIR; goto free_gp; } } }waitinuse: while ((mode & FBLKINUSE) && (gp->g_flag & GINUSE)) { /*002*/ if (mode & FNDELAY) { u.u_error = EWOULDBLOCK; goto free_gp; } sleep_unlock((caddr_t)&gp->g_flag, PLOCK, &gp->g_lk); gfs_lock(gp); } if ((gp->g_mode & GFMT) == GFPORT) mode &= ~FTRUNC; if (mode&FTRUNC) { if (GTRUNC(gp, (u_long)0, u.u_cred) == GNOFUNC) u.u_error = EOPNOTSUPP; if (u.u_error) goto free_gp; } /* * This should be done first to verify this resource exists. */ fp = falloc(); if (fp == NULL) goto free_gp; gfs_unlock(gp); fp->f_flag = mode&FMASK; if ((gp->g_mode & GFMT) == GFPORT) { /* * For named-pipes, the FNDELAY flag must propagate to * the rdwr layer. Also, FAPPEND must always be set so * that fp->f_offset is correctly maintained. */ fp->f_offset = 0; fp->f_flag |= FAPPEND | (mode & FNDELAY); fp->f_type = DTYPE_PORT; } else fp->f_type = DTYPE_INODE; fp->f_ops = &gnodeops; fp->f_data = (caddr_t)gp; i = u.u_r.r_val1; if (setjmp(&u.u_qsave)) { if (u.u_error == 0) u.u_error = EINTR; goto free_fp; } u.u_error = GOPEN(gp, mode); if (u.u_error == 0) { if ((mode&FBLKANDSET)==FBLKANDSET) { /*002*/ gp->g_flag |= GINUSE; U_POFILE_SET(i, U_POFILE(i) | UF_INUSE); (*fp->f_ops->fo_ioctl)(fp, FIOSINUSE, value, u.u_cred); u.u_r.r_val1 = i; } goto out; } /* * The call to the sfs open routine failed or was interrupted. Clean * up the u-area and deallocated the file table entry so it can be * used by someone else. */free_fp: U_OFILE_SET(i,NULL); U_POFILE_SET(i,0); crfree(fp->f_cred); smp_lock(&lk_file, LK_RETRY); fp->f_data = (caddr_t)0; fp->f_count = 0; smp_unlock(&lk_file); fp = NULL; if (u.u_error==EALREADY && (gp->g_flag&GINUSE)) { /* gnode was grabbed while we were */ u.u_error = 0; /* blocked. wait to free up again.*/ gfs_lock(gp); /* need to lock again */ goto waitinuse; }free_gp: if (!smp_owner(&gp->g_lk)) grele(gp); else gput(gp);out: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Mknod system call */mknod(){ register struct gnode *gp; register struct a { char *fname; int fmode; int dev; } *uap; register struct nameidata *ndp = &u.u_nd; register int ret; uap = (struct a *)u.u_ap; if (!suser() && ((uap->fmode & GFMT) != GFPORT)) return; /* if a non-privileged user is making */ /* a port node then negate the error */ /* posted by SUSER. */ u.u_error = 0; ndp->ni_nameiop = CREATE; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->fname, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out2; } gp = gfs_namei(ndp); if (gp != NULL) { u.u_error = EEXIST; goto out; } if (u.u_error) { goto out2; } if ((gp = GMAKNODE(uap->fmode, uap->dev, ndp)) == (struct gnode *) GNOFUNC) { u.u_error = EOPNOTSUPP; goto out2; } if (gp == NULL) { goto out2; } out: gput(gp);out2: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Synch an open file. */fsync(){ register struct a { int fd; } *uap = (struct a *)u.u_ap; register struct gnode *gp; register struct file *fp; fp = getgnode(uap->fd); if (fp == NULL) return; if ((gp = (struct gnode *)fp->f_data) == 0) { u.u_error = EBADF; return; } gfs_lock(gp); if (GSYNCG(gp, fp->f_cred) == GNOFUNC) u.u_error = EOPNOTSUPP; gfs_unlock(gp);}/* * Change mode of a file given path name. */chmod(){ register struct gnode *gp; register struct a { char *fname; int fmode; } *uap = (struct a *)u.u_ap; /* where should owner be? */ if ((gp = owner(uap->fname, FOLLOW)) == NULL) return; u.u_error = chmod1(gp, uap->fmode, u.u_cred); gput(gp);}/* * Change mode of a file given a file descriptor. */fchmod(){ register struct a { int fd; int fmode; } *uap; register struct gnode *gp; register struct file *fp; uap = (struct a *)u.u_ap; fp = getgnode(uap->fd); if (fp == NULL) return; if ((gp = (struct gnode *)fp->f_data) == 0) { u.u_error = EBADF; return; } if (u.u_uid != gp->g_uid && !suser()) return; gfs_lock(gp); u.u_error = chmod1(gp, uap->fmode, fp->f_cred); gfs_unlock(gp);}/* * Change the mode on a file. * Gnode must be locked before calling. */chmod1(gp, mode, cred) register struct gnode *gp; register int mode; struct ucred *cred;{ register int sticky = gp->g_mode & GSVTX; register int ret; if (ISREADONLY(gp->g_mp)) return(EROFS); if (u.u_uid) { if ((gp->g_mode & GFMT) != GFDIR) mode &= ~GSVTX; if (!groupmember(gp->g_gid)) mode &= ~GSGID; } /* for the new text table sticky changes blow away unref-ed text */ if ((gp->g_flag>EXT) && (mode&GSVTX) && sticky == 0) { xrele(gp); } gp->g_mode &= ~07777; gp->g_mode |= mode&07777; gp->g_flag |= (GCHG | GCMODE); if (!ISLOCAL(gp->g_mp)) { if (ret = GUPDATE(gp, 0, 0, 0, cred)) { return(ret); } } if (gp->g_flag>EXT && (gp->g_mode&GSVTX) == 0 && sticky) xrele(gp); return(0);}/* * Set ownership given a path name. */chown(){ register struct gnode *gp; register struct a { char *fname; int uid; int gid; } *uap; uap = (struct a *)u.u_ap; /* * owner() is not going to perform additional access checks * over chown1(). Leave it for now, but this should change * eventually. */ if ((gp = owner(uap->fname, NOFOLLOW)) == NULL) return; u.u_error = chown1(gp, uap->uid, uap->gid, u.u_cred); gput(gp);}/* * Set ownership given a file descriptor. */fchown(){ register struct a { int fd; int uid; int gid; } *uap; register struct gnode *gp; register struct file *fp; uap = (struct a *)u.u_ap; fp = getgnode(uap->fd); if (fp == NULL) return; if ((gp = (struct gnode *)fp->f_data) == 0) { u.u_error = EBADF; return; } if (!suser()) return; gfs_lock(gp); u.u_error = chown1(gp, uap->uid, uap->gid, fp->f_cred); gfs_unlock(gp);}/* * Perform chown operation on gnode gp; * gnode must be locked prior to call. */chown1(gp, uid, gid, cred) register struct gnode *gp; struct ucred *cred; register int uid, gid;{ register int ret = 0;#ifdef QUOTA register long change;#endif if (ISREADONLY(gp->g_mp)) return(EROFS); if (uid == -1) uid = gp->g_uid; if (gid == -1) gid = gp->g_gid; if (uid != gp->g_uid && !suser()) return(u.u_error); if (gid != gp->g_gid && !groupmember(gid) && !suser()) return(u.u_error);#ifdef QUOTA if (gp->g_uid == uid) /* this just speeds things a little */ change = 0; else change = gp->g_blocks; (void) chkdq(gp, -change, 1); (void) chkiq(gp->g_dev, gp, gp->g_uid, 1); dquot_lock(gp->g_dquot); dqrele(gp->g_dquot); dquot_unlock(gp->g_dquot);#endif gp->g_uid = uid; gp->g_gid = gid; gp->g_flag |= (GCHG | GCID); if (u.u_ruid != 0) gp->g_mode &= ~(GSUID|GSGID); if (!ISLOCAL(gp->g_mp)) { if (ret = GUPDATE(gp, 0, 0, 0, cred)) { return(ret); } } #ifdef QUOTA gp->g_dquot = inoquota(gp); (void) chkdq(gp, change, 1); (void) chkiq(gp->g_dev, (struct gnode *)NULL, uid, 1); return (u.u_error); #else return (ret);#endif}utimes(){ register struct a { char *fname; struct timeval *tptr; } *uap = (struct a *)u.u_ap; register struct gnode *gp; struct timeval tv[2]; register struct nameidata *ndp = &u.u_nd; register int ret; ndp->ni_nameiop = LOOKUP | FOLLOW; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->fname, ndp->ni_dirp, MAXPATHLEN, (u_int *)0)) { KM_FREE(ndp->ni_dirp, KM_NAMEI); return; } gp = GNAMEI(ndp); KM_FREE(ndp->ni_dirp, KM_NAMEI); if (gp == NULL) { return; } if (ISREADONLY(gp->g_mp)) { u.u_error = EROFS; gput(gp); return; } ret = GGETVAL(gp); if (uap->tptr != NULL) { u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); } else { tv[0].tv_sec = tv[1].tv_sec = timepick->tv_sec; tv[0].tv_usec = tv[1].tv_usec = timepick->tv_usec; } /* If not the owner or su and tptr is NULL, check for write access. */ /* If tptr is not NULL then EPERM error condition. */ if ((u.u_error == 0) && (u.u_uid != gp->g_uid) && u.u_uid != 0) { if (uap->tptr != NULL) u.u_error = EPERM; else access(gp,GWRITE); } if (u.u_error == 0) { if (tv[0].tv_sec < 0 || tv[0].tv_usec < 0 || tv[1].tv_sec < 0 || tv[1].tv_usec < 0 || tv[0].tv_usec >= 1000000 || tv[1].tv_usec >= 1000000) u.u_error = EINVAL; else { gp->g_flag |= GMOD|GACC|GUPD|GCHG; if (GUPDATE(gp, &tv[0], &tv[1], 0, u.u_cred) == GNOFUNC) u.u_error = EOPNOTSUPP; } } gput(gp);}/* * Flush any pending I/O. */sync(){ update(); gfs_gupdat(NODEV);}/* * Truncate a file given its path name. */truncate(){ register struct a { char *fname; u_long length; } *uap = (struct a *)u.u_ap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -