📄 gfs_syscalls.c
字号:
register struct gnode *gp; register struct nameidata *ndp = &u.u_nd; 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 bad2; } gp = gfs_namei(ndp); if (gp == NULL) goto bad2; if (access(gp, GWRITE)) goto bad; if ((gp->g_mode&GFMT) == GFDIR) { u.u_error = EISDIR; goto bad; } if (GTRUNC(gp, uap->length, u.u_cred) == GNOFUNC) u.u_error = EOPNOTSUPP;bad: gput(gp);bad2: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Truncate a file given a file descriptor. */ftruncate(){ register struct a { int fd; u_long length; } *uap = (struct a *)u.u_ap; register struct gnode *gp; register struct file *fp; fp = getgnode(uap->fd); if (fp == NULL) return; if ((fp->f_flag&FWRITE) == 0) { u.u_error = EINVAL; return; } if ((gp = (struct gnode *)fp->f_data) == 0) { u.u_error = EBADF; return; } if (ISREADONLY(gp->g_mp)) { u.u_error = EROFS; return; } gfs_lock(gp); if (GTRUNC(gp, uap->length, fp->f_cred) == GNOFUNC) u.u_error = EOPNOTSUPP; gfs_unlock(gp); return;}/* * symlink -- make a symbolic link */symlink(){ register struct a { char *target; char *linkname; } *uap; register struct gnode *gp; register struct nameidata *ndp = &u.u_nd; register char *target_cp; register char *source_cp; uap = (struct a *)u.u_ap; /* get us the target name */ KM_ALLOC(target_cp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (target_cp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->target, target_cp, MAXPATHLEN, (u_int *) 0)) { goto out1; } /* get us the source name */ KM_ALLOC(source_cp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (source_cp == NULL) { u.u_error = EIO; goto out1; } if (u.u_error = copyinstr(uap->linkname, source_cp, MAXPATHLEN, (u_int *) 0)) { goto out2; } /* we may not create a symlink when the source exists */ ndp->ni_nameiop = CREATE; ndp->ni_dirp = source_cp; gp = gfs_namei(ndp); if (gp) { gput(gp); u.u_error = EEXIST; goto out2; } if (u.u_error) { goto out2; } /* create the special file type for a symlink */ if (GSYMLINK(ndp, target_cp) == GNOFUNC) u.u_error = EOPNOTSUPP;out2: KM_FREE(source_cp, KM_NAMEI);out1: KM_FREE(target_cp, KM_NAMEI);}/* * Seek system call */lseek(){ register struct file *fp; register struct a { int fd; off_t off; int sbase; } *uap; register struct gnode *gp; register long where; register int ret = 0; uap = (struct a *)u.u_ap; GETF(fp, uap->fd); if (fp->f_type != DTYPE_INODE) { u.u_error = ESPIPE; return; } if (fp->f_data == (caddr_t)0) { u.u_error = EBADF; return; } /* should seeks just arbitrarily be done?, should we check * with the correct sfs to see if the operation can be done? */ gp = (struct gnode *)fp->f_data; switch (uap->sbase) { case L_INCR: where = fp->f_offset + uap->off; break; case L_XTND: where = uap->off + ((struct gnode *)fp->f_data)->g_size; break; case L_SET: where = uap->off; break; default: u.u_error = EINVAL; return; } /* * if gnode type is a regular file, and resulting offset * would be negative, return an error. */ if ((where < 0) && ((gp->g_mode & GFMT) == GFREG)) { u.u_error = EINVAL; return; } /* * Call sfs's seek routine */ ret = GSEEK(gp, where); /* * there needs to be a documentation change here, if * the seek is not successful (which is not possible for * ufs), fp->offset does not change */ if (u.u_error) { u.u_error = EINVAL; where = -1; } else { if (ret) { u.u_error = EOPNOTSUPP; return; } smp_lock(&fp->f_lk, LK_RETRY); fp->f_offset = where; smp_unlock(&fp->f_lk); } u.u_r.r_off = where;}/* * Access system call */saccess(){ register int svuid, svgid; register struct gnode *gp; register struct a { char *fname; int fmode; } *uap; register struct nameidata *ndp = &u.u_nd; register long mode_mask = ~(X_OK | R_OK | W_OK); uap = (struct a *)u.u_ap; if (uap->fmode & mode_mask) { 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(uap->fname, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { KM_FREE(ndp->ni_dirp, KM_NAMEI); return; } svuid = u.u_uid; svgid = u.u_gid; u.u_uid = u.u_ruid; u.u_gid = u.u_rgid; ndp->ni_nameiop = LOOKUP | FOLLOW; gp = gfs_namei(ndp); if (gp != NULL) { /* * make checks for M_NODEV, M_NOSUID, and M_NOEXEC * flags */ if ((uap->fmode&R_OK) && access(gp, GREAD)) goto done; if ((uap->fmode&W_OK) && access(gp, GWRITE)) goto done; /* * convoluted as it seems, the following test * needs to be checked: * if a regular file is being checked for exec * and the filesystem is NOSUID * and the file is SUID or SGID * and we are not the super user * or if a regular file is being checked for exec * and the filesystem is NOEXEC * and we are not the super user * we may not permit access to the file */ if (uap->fmode&X_OK) { if ((gp->g_mp->m_flags & M_NOSUID) && (gp->g_mode & (GSUID | GSGID)) && (gp->g_mode & GFREG) && u.u_uid) { u.u_error = EROFS; goto done; } if ((gp->g_mp->m_flags & M_NOEXEC) && (gp->g_mode & GEXEC) && (gp->g_mode & GFREG) && u.u_uid) { u.u_error = EROFS; goto done; } if (access(gp, GEXEC)) goto done; }done: gput(gp); } u.u_uid = svuid; u.u_gid = svgid; KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Stat system call. This version follows links. */stat(){ stat1(FOLLOW);}/* * Lstat system call. This version does not follow links. */lstat(){ stat1(NOFOLLOW);}stat1(follow) register int follow;{ register struct gnode *gp; register struct a { char *fname; struct stat *ub; } *uap; struct stat sb; register struct nameidata *ndp = &u.u_nd; uap = (struct a *)u.u_ap; 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) goto out; gfs_unlock(gp); (void) GSTAT(gp, &sb); grele(gp); if (!u.u_error) u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));out: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Return target name of a symbolic link */readlink(){ register struct gnode *gp; register struct a { char *name; char *buf; int count; } *uap = (struct a *)u.u_ap; register struct nameidata *ndp = &u.u_nd; struct uio _auio; register struct uio *auio = &_auio; struct iovec _aiov; register struct iovec *aiov = &_aiov; ndp->ni_nameiop = LOOKUP; 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->name, ndp->ni_dirp, MAXPATHLEN, (u_int *)0)) { goto out1; } gp = gfs_namei(ndp); if (gp == NULL) goto out1; /* if the sfs doesn't allow links everything is cool */ if ((gp->g_mode&GFMT) != GFLNK) { u.u_error = EINVAL; goto out; } auio->uio_iov = aiov; auio->uio_iovcnt = 1; aiov->iov_base = uap->buf; aiov->iov_len = auio->uio_resid = uap->count; auio->uio_segflg = auio->uio_offset = 0; if (GREADLINK(gp, auio) == GNOFUNC) u.u_error = EOPNOTSUPP;out: gput(gp); if (u.u_error == NULL) u.u_r.r_val1 = uap->count - auio->uio_resid;out1: KM_FREE(ndp->ni_dirp, KM_NAMEI);}struct file *getgnode(fdes) register int fdes;{ register struct file *fp; if ((unsigned)fdes > u.u_omax || (fp = U_OFILE(fdes)) == NULL) { u.u_error = EBADF; return ((struct file *)0); } if (fp->f_type != DTYPE_INODE && fp->f_type != DTYPE_PORT) { u.u_error = EINVAL; return ((struct file *)0); } return (fp);}getmnt(){ register struct a { u_int *cookie; struct fs_data *buf; u_int nbytes; int mode; char *path; } *uap = (struct a *) u.u_ap; register u_int number; register struct mount *mp; int cookie, i; register struct fs_data *fs_data; register int count; register struct gnode *gp; register struct nameidata *ndp = &u.u_nd; register struct gnode *rgp; switch(uap->mode) { case STAT_ONE: case NOSTAT_ONE: 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->path, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out; } ndp->ni_nameiop = LOOKUP | FOLLOW; gp = gfs_namei(ndp); if (gp == NULL) goto out; gfs_unlock(gp); mp = gp->g_mp; if (uap->mode == STAT_ONE) { gref(mp->m_rootgp); fs_data = GGETFSDATA(mp); grele(mp->m_rootgp); } else fs_data = mp->m_fs_data; if (! u.u_error) u.u_error = copyout((caddr_t) fs_data, (caddr_t) uap->buf, sizeof(struct fs_data)); u.u_r.r_val1 = 1; grele(gp);out: KM_FREE(ndp->ni_dirp, KM_NAMEI); break; case STAT_MANY: case NOSTAT_MANY: /* insure we can get all the stuff out. */ if ((count = number = uap->nbytes / sizeof(struct fs_data)) < 1) { u.u_error = EINVAL; break; } if (u.u_error = copyin(uap->cookie, &cookie, sizeof(cookie))) break; if (cookie < 0 || cookie > NMOUNT) { u.u_error = EINVAL; break; } i = cookie; /* save in case none found */ for (mp = &mount[cookie]; mp < &mount[NMOUNT] && number; mp++, cookie++) { /* * Check if mp is mounted on and if so get a * ref on its file system. */ if (rgp = fref(mp, (dev_t)0)) { number--; if (uap->mode == STAT_MANY) { gref(mp->m_rootgp); fs_data = GGETFSDATA(mp); grele(mp->m_rootgp); if (u.u_error == EINTR) { grele(rgp); break; } } else fs_data = mp->m_fs_data; if (!u.u_error) if (u.u_error = copyout((caddr_t)fs_data, (caddr_t) uap->buf, sizeof(struct fs_data))) { grele(rgp); break; } /* * Release ref on file system. */ grele(rgp); /* save slot # of last one found */ /* we wouldn't have to do this, if this was */ /* a linked list */ i = cookie; uap->buf++; } } ( ((u.u_r.r_val1 = count - number) > 0) ? (cookie = ++i) : (cookie = i) ); copyout(&cookie, uap->cookie, sizeof(cookie)); break; default: u.u_error = EINVAL; break; }}getdirentries(){ register struct a { int fd; struct gen_dir *buf; u_int nbytes; u_int *cookie; } *uap = (struct a *) u.u_ap; register struct file *fp; register struct gnode *gp; struct uio _auio; register struct uio *auio = &_auio; struct iovec _aiov; register struct iovec *aiov = &_aiov; register int ret; if ((fp = getgnode(uap->fd)) == NULL) { /* bad file descriptor */ /* * getgnode returns EINVAL if not an INODE or PORT * we just interpret that to mean it isn't a directory * either */ if (u.u_error == EINVAL) u.u_error = ENOTDIR; return; } if (fp->f_type != DTYPE_INODE) { /* this must be a gnode */ u.u_error = EOPNOTSUPP; return; } gp = (struct gnode *) fp->f_data; if ((gp->g_mode & GFMT) != GFDIR) { /* this must be a directory */ u.u_error = ENOTDIR; return; } /* check for valid buffer */ if (uap->nbytes < DIRBLKSIZ || (uap->nbytes & (DIRBLKSIZ-1)) || !useracc(uap->buf,uap->nbytes,B_WRITE)) { u.u_error = EINVAL; return; } aiov->iov_base = (caddr_t) uap->buf; aiov->iov_len = uap->nbytes; auio->uio_iov = aiov; auio->uio_iovcnt = 1; auio->uio_segflg = UIO_USERSPACE; auio->uio_offset = fp->f_offset; auio->uio_resid = uap->nbytes; ret = GGETDIRENTS(gp, auio, fp->f_cred); if (u.u_error) return; /* POSIX says update access time */ if (u.u_procp->p_progenv == A_POSIX) gp->g_flag |= GACC; u.u_error = copyout((caddr_t)&fp->f_offset, (caddr_t)uap->cookie,sizeof(long)); u.u_r.r_val1 = uap->nbytes - auio->uio_resid; smp_lock(&fp->f_lk, LK_RETRY); fp->f_offset = auio->uio_offset; /* for lseek and next read */ smp_unlock(&fp->f_lk);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -