📄 syscalls.c
字号:
/* * Copyright (c) 2005-2007, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * syscalls.c - Virtual File System System Call */#include <prex/prex.h>#include <sys/stat.h>#include <sys/vnode.h>#include <sys/file.h>#include <sys/mount.h>#include <sys/dirent.h>#include <sys/list.h>#include <sys/buf.h>#include <limits.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include "vfs.h"int sys_open(char *path, int flags, mode_t mode, file_t *file){ vnode_t vp, dvp; file_t fp; char *filename; int err; dprintf("sys_open: path=%s flags=%x mode=%x\n", path, flags, mode); if (flags & O_CREAT) { err = namei(path, &vp); if (err == ENOENT) { /* Create new file. */ if ((err = lookup(path, &dvp, &filename)) != 0) return err; if (dvp->v_mount->m_flags & MNT_RDONLY) { vput(dvp); return EROFS; } mode &= ~S_IFMT; mode |= S_IFREG; err = VOP_CREATE(dvp, filename, mode); vput(dvp); if (err) return err; if ((err = namei(path, &vp)) != 0) return err; flags &= ~O_TRUNC; } else if (err) { return err; } else { /* File already exits */ if (flags & O_EXCL) { vput(vp); return EEXIST; } flags &= ~O_CREAT; } } else { /* Open */ if ((err = namei(path, &vp)) != 0) return err; } if ((flags & O_CREAT) == 0) { if ((flags & O_ACCMODE) != O_RDONLY || flags & O_TRUNC) { if (vp->v_mount->m_flags & MNT_RDONLY) { vput(vp); return EROFS; } if (vp->v_type == VDIR) { /* Openning directory with writable. */ vput(vp); return EISDIR; } } } /* Setup file structure */ if (!(fp = malloc(sizeof(struct file)))) { vput(vp); return ENOMEM; } /* Request to file system */ if ((err = VOP_OPEN(vp, mode)) != 0) { free(fp); vput(vp); return err; } memset(fp, 0, sizeof(struct file)); fp->f_vnode = vp; fp->f_flags = flags; fp->f_offset = 0; fp->f_count = 1; *file = fp; vn_unlock(vp); return 0;}int sys_close(file_t fp){ vnode_t vp; int err; dprintf("sys_close: fp=%x\n", (u_int)fp); vp = fp->f_vnode; if (--fp->f_count > 0) { vrele(vp); return 0; } vn_lock(vp); if ((err = VOP_CLOSE(vp, fp)) != 0) { vn_unlock(vp); return err; } vput(vp); free(fp); return 0;}int sys_read(file_t fp, void *buf, size_t size, size_t *count){ vnode_t vp; int err; dprintf("sys_read: fp=%x buf=%x size=%d\n", (u_int)fp, (u_int)buf, size); if ((fp->f_flags & O_ACCMODE) == O_WRONLY) return EPERM; if (size == 0) { *count = 0; return 0; } vp = fp->f_vnode; vn_lock(vp); err = VOP_READ(vp, fp, buf, size, count); vn_unlock(vp); return err;}int sys_write(file_t fp, void *buf, size_t size, size_t *count){ vnode_t vp; int err; dprintf("sys_write: fp=%x buf=%x size=%d\n", (u_int)fp, (u_int)buf, size); if (size == 0) { *count = 0; return 0; } vp = fp->f_vnode; vn_lock(vp); err = VOP_WRITE(vp, fp, buf, size, count); vn_unlock(vp); return err;}int sys_lseek(file_t fp, off_t off, int type, off_t *origin){ vnode_t vp; dprintf("sys_seek: fp=%x off=%d type=%d\n", (u_int)fp, (u_int)off, type); vp = fp->f_vnode; vn_lock(vp); switch (type) { case SEEK_SET: if (off < 0) off = 0; if (off > vp->v_size) off = vp->v_size; break; case SEEK_CUR: if (fp->f_offset + off > vp->v_size) off = vp->v_size; else if (fp->f_offset + off < 0) off = 0; else off = fp->f_offset + off; break; case SEEK_END: if (off > 0) off = vp->v_size; else if (vp->v_size + off < 0) off = 0; else off = vp->v_size + off; break; default: vn_unlock(vp); return EINVAL; } /* Request to check the file offset */ if (VOP_SEEK(vp, fp, fp->f_offset, off) != 0) { vn_unlock(vp); return EINVAL; } *origin = off; fp->f_offset = off; vn_unlock(vp); return 0;}int sys_ioctl(file_t fp, u_int cmd, u_long arg){ vnode_t vp; int err; dprintf("sys_ioctl: fp=%x cmd=%d arg=%d\n", fp, cmd, arg); vp = fp->f_vnode; vn_lock(vp); err = VOP_IOCTL(vp, fp, cmd, arg); vn_unlock(vp); return err;}int sys_fsync(file_t fp){ vnode_t vp; int err; dprintf("sys_fsync: fp=%x\n", fp); if ((fp->f_flags & O_ACCMODE) == O_RDONLY) return EBADF; vp = fp->f_vnode; vn_lock(vp); err = VOP_FSYNC(vp, fp); vn_unlock(vp); return err; }int sys_fstat(file_t fp, struct stat *st){ vnode_t vp; dprintf("sys_fstat: fp=%x\n", fp); memset(st, 0, sizeof(struct stat)); vp = fp->f_vnode; vn_lock(vp); st->st_ino = (ino_t)&vp; st->st_size = vp->v_size; st->st_mode = vp->v_mode; vn_unlock(vp); return 0;}/* * Return 0 if directory is empty */static int check_dir_empty(char *path){ int err; file_t fp; struct dirent dir; if ((err = sys_opendir(path, &fp)) != 0) return err; do { err = sys_readdir(fp, &dir); if (err) break; } while (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, "..")); sys_closedir(fp); if (err == ENOENT) return 0; else if (err == 0) return EEXIST; return err;}int sys_opendir(char *path, file_t *file){ vnode_t dvp; file_t fp; int err; dprintf("sys_opendir: path=%s\n", path); if ((err = sys_open(path, O_RDONLY, 0, &fp)) != 0) return err; dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); sys_close(fp); return ENOTDIR; } vn_unlock(dvp); *file = fp; return 0;}int sys_closedir(file_t fp){ vnode_t dvp; int err; dprintf("sys_closedir: fp=%x\n", fp); dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); return EBADF; } vn_unlock(dvp); err = sys_close(fp); return err;}int sys_readdir(file_t fp, struct dirent *dir){ vnode_t dvp; int err; dprintf("sys_readdir: fp=%x\n", fp); dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); return ENOTDIR; } err = VOP_READDIR(dvp, fp, dir); vn_unlock(dvp); return err;}int sys_rewinddir(file_t fp){ vnode_t dvp; dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); return EINVAL; } fp->f_offset = 0; vn_unlock(dvp); return 0;}int sys_seekdir(file_t fp, long loc){ vnode_t dvp; dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); return EINVAL; } fp->f_offset = (off_t)loc; vn_unlock(dvp); return 0;}int sys_telldir(file_t fp, long *loc){ vnode_t dvp; dvp = fp->f_vnode; vn_lock(dvp); if (dvp->v_type != VDIR) { vn_unlock(dvp); return EINVAL; } *loc = (long)fp->f_offset; vn_unlock(dvp); return 0;}int sys_mkdir(char *path, mode_t mode){ char *name; vnode_t vp, dvp; int err; dprintf("sys_mkdir: path=%s mode=%d\n", path, mode); if ((err = namei(path, &vp)) == 0) { /* File already exists */ vput(vp); return EEXIST; } if ((err = lookup(path, &dvp, &name)) != 0) { /* Directory already exists */ vput(vp); return err; } if (dvp->v_mount->m_flags & MNT_RDONLY) { err = EROFS; goto out; } mode &= ~S_IFMT; mode |= S_IFDIR; err = VOP_MKDIR(dvp, name, mode); out: vput(dvp); return err;}int sys_rmdir(char *path){ vnode_t vp, dvp; int err; char *name; dprintf("sys_rmdir: path=%s\n", path); if ((err = check_dir_empty(path)) != 0) return err; if ((err = namei(path, &vp)) != 0) return err; if (vp->v_mount->m_flags & MNT_RDONLY) { err = EROFS; goto out; } if (vp->v_type != VDIR) { err = ENOTDIR; goto out; } if (vp->v_flags & VROOT || vcount(vp) >= 2) { err = EBUSY; goto out; } if ((err = lookup(path, &dvp, &name)) != 0) goto out; err = VOP_RMDIR(dvp, vp, name); vn_unlock(vp); vgone(vp); vput(dvp); return err; out: vput(vp); return err;}int sys_mknod(char *path, mode_t mode){ char *name; vnode_t vp, dvp; int err; dprintf("sys_mknod: path=%s mode=%d\n", path, mode); if ((err = namei(path, &vp)) == 0) { vput(vp); return EEXIST; } if ((err = lookup(path, &dvp, &name)) != 0) return err; if (S_ISDIR(mode)) err = VOP_MKDIR(dvp, name, mode); else err = VOP_CREATE(dvp, name, mode); vput(dvp); return err;}int sys_rename(char *src, char *dest){ vnode_t vp1, vp2 = 0, dvp1, dvp2; char *sname, *dname; int err; size_t len; char root[] = "/"; dprintf("sys_rename: src=%s dest=%s\n", src, dest); if ((err = namei(src, &vp1)) != 0) return err; if (vp1->v_mount->m_flags & MNT_RDONLY) { err = EROFS; goto err1; } /* If source and dest are the same, do nothing */ if (!strncmp(src, dest, PATH_MAX)) goto err1; /* Check if target is directory of source */ len = strlen(dest); if (!strncmp(src, dest, len)) { err = EINVAL; goto err1; } /* Is the source busy ? */ if (vcount(vp1) >= 2) { err = EBUSY; goto err1; } /* Check type of source & target */ err = namei(dest, &vp2); if (err == 0) { /* target exists */ if (vp1->v_type == VDIR && vp2->v_type != VDIR) { err = ENOTDIR; goto err2; } else if (vp1->v_type != VDIR && vp2->v_type == VDIR) { err = EISDIR; goto err2; } if (vp2->v_type == VDIR && check_dir_empty(dest)) { err = EEXIST; goto err2; } if (vcount(vp2) >= 2) { err = EBUSY; goto err2; } } dname = strrchr(dest, '/'); if (dname == NULL) { err = ENOTDIR; goto err2; } if (dname == dest) dest = root; *dname = 0; dname++; if ((err = lookup(src, &dvp1, &sname)) != 0) goto err2; if ((err = namei(dest, &dvp2)) != 0) goto err3; /* The source and dest must be same file system */ if (dvp1->v_mount != dvp2->v_mount) { err = EXDEV; goto err4; } err = VOP_RENAME(dvp1, vp1, sname, dvp2, vp2, dname); err4: vput(dvp2); err3: vput(dvp1); err2: if (vp2) vput(vp2); err1: vput(vp1); return err;}int sys_unlink(char *path){ char *name; vnode_t vp, dvp; int err; dprintf("sys_unlink: path=%s\n", path); if ((err = namei(path, &vp)) != 0) return err; if (vp->v_mount->m_flags & MNT_RDONLY) { err = EROFS; goto out; } if (vp->v_type == VDIR) { err = EPERM; goto out; } if (vp->v_flags & VROOT || vcount(vp) >= 2) { err = EBUSY; goto out; } if ((err = lookup(path, &dvp, &name)) != 0) goto out; err = VOP_REMOVE(dvp, vp, name); vn_unlock(vp); vgone(vp); vput(dvp); return 0; out: vput(vp); return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -