int vfs_mkdir(struct thread *t, const char *path, mode_t mode) { int ret; struct resp_lookup res; struct mount_entry *mount_pt; uid_t uid; gid_t gid; /* Kernel request */ if (!t) { uid = 0; gid = 0; } else { uid = t->uid; gid = t->gid; } ret = vfs_lookup(t, path, &res, &mount_pt); if (ret < 0) return ret; if (!mount_pt->fi->parent->fs_ops->mkdir) return -ENOSYS; if ((size_t)ret == strlen(path)) return -EEXIST; return mount_pt->fi->parent->fs_ops->mkdir(mount_pt, path + ret, res.inode.inode, uid, gid, mode); }
int sc_chmod(thread_t *t, syscall_result_t *r, chmod_args_t *args) { int res=0; proc_t *p = t->thr_proc; vnode_t *node; char pname[PATH_MAX]; if((res = copyinstr(pname, args->fname, PATH_MAX))) return res; res = vfs_lookup(p->p_curdir, &node, pname, t, LKP_NORMAL); if(res) return res; vattr_t va; va.va_mask=VATTR_ALL; if((res = VOP_GETATTR(node, &va))) goto err; res = -EPERM; if(p->p_cred->p_euid != 0 && p->p_cred->p_euid != va.va_uid) goto err; mode_t mode = args->mode & 07777; if(ISSET(mode, S_ISGID) && p->p_cred->p_euid!=0 && va.va_gid!=p->p_cred->p_egid) UNSET(mode, S_ISGID); //mamy prawo kasować bit suid/sgid? va.va_mask = VATTR_MODE; va.va_mode = mode; if((res = VOP_SETATTR(node, &va))) goto err; vrele(node); return 0; err: vrele(node); return res; }
int char_dev_register(const char *name, const struct kfile_operations *ops) { struct path node; struct nas *dev_nas; if (vfs_lookup("/dev", &node)) { return -1; } if (node.node == NULL) { return -ENODEV; } vfs_create_child(&node, name, S_IFCHR | S_IRALL | S_IWALL, &node); if (!(node.node)) { return -1; } dev_nas = node.node->nas; dev_nas->fs = filesystem_create("empty"); if (dev_nas->fs == NULL) { return -ENOMEM; } dev_nas->fs->file_op = ops; return 0; }
/* Does most of the work for link(). */ int vfs_link(char *oldpath, char *newpath) { struct vnode *oldfile; struct vnode *newdir; char newname[NAME_MAX+1]; int result; result = vfs_lookup(oldpath, &oldfile); if (result) { return result; } result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname)); if (result) { VOP_DECREF(oldfile); return result; } if (oldfile->vn_fs==NULL || newdir->vn_fs==NULL || oldfile->vn_fs != newdir->vn_fs) { VOP_DECREF(newdir); VOP_DECREF(oldfile); return EXDEV; } result = VOP_LINK(newdir, newname, oldfile); VOP_DECREF(newdir); VOP_DECREF(oldfile); return result; }
int ext2_mount(const char *dir, int flags, void *_args) { printk("ext2_mount(dir=%s, flags=%x, args=%p)\n", dir, flags, _args); struct { char *dev; char *opt; } *args = _args; struct vnode vnode; struct inode *dev; int err; struct uio uio = {0}; /* FIXME */ if ((err = vfs_lookup(args->dev, &uio, &vnode, NULL))) goto error; if ((err = vfs_vget(&vnode, &dev))) goto error; struct inode *fs; if ((err = ext2fs.load(dev, &fs))) goto error; return vfs_bind(dir, fs); error: return err; }
int binfmt_load(struct proc *proc, const char *path, struct proc **ref) { struct vnode vnode; struct inode *inode = NULL; int err = 0; struct uio uio; memset(&uio, 0, sizeof(struct uio)); if (proc) { uio = PROC_UIO(proc); } if ((err = vfs_lookup(path, &uio, &vnode, NULL))) return err; if ((err = vfs_vget(&vnode, &inode))) return err; for (size_t i = 0; i < NR_BINFMT; ++i) { if (!binfmt_list[i].check(inode)) { binfmt_fmt_load(proc, path, inode, &binfmt_list[i], ref); vfs_close(inode); return 0; } } vfs_close(inode); return -ENOEXEC; }
static int vfs_walk(struct vfs_walk_data *data) { if (!strcmp(data->next, "")) return -ENOENT; if (!strcmp(data->next, ".")) { data->tail = vfs_path_next_entry(data->next, data->tail); return 0; } if (!strcmp(data->next, "..")) { struct fs_entry *parent = vfs_entry_get(data->entry->parent); vfs_entry_put(data->entry); data->entry = parent; data->tail = vfs_path_next_entry(data->next, data->tail); return 0; } struct fs_entry *entry; int rc; mutex_lock(&data->entry->node->mux); entry = vfs_lookup(data->entry, data->next, false, &rc); mutex_unlock(&data->entry->node->mux); if (!entry) return rc; vfs_entry_put(data->entry); data->entry = entry; data->tail = vfs_path_next_entry(data->next, data->tail); return 0; }
/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Funtion :lstat64 Input :const char *path < file path to get its status > struct stat64_i386 *buf < stat structure > Output :struct stat64_i386 *buf < stat structure > Return :int < result > Description :get file status _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ SYSCALL int lstat64(const char *path, struct stat64_i386 *buf) { struct file_name *fname; struct vnode *vnode; int err; //printf("lstat64:path[%s] ", path); if (UNLIKELY(!path)) { return(-EFAULT); } err = vm_check_access((void*)buf, sizeof(struct stat64_i386), PROT_WRITE); if (UNLIKELY(err)) { return(-EFAULT); } err = vfs_lookup(path, &fname, LOOKUP_ENTRY); if (err) { //printf("err:%d\n", -err); return(err); } vnode = fname->dentry->d_vnode; put_file_name(fname); err = vfs_stat64(vnode, buf); return(err); }
void vfs_get_leaf_path(struct path *path) { char *leaf_name; if ((NULL == (leaf_name = getenv("PWD"))) || (0 != vfs_lookup(leaf_name, path))) { vfs_get_root_path(path); } }
int vfs_open(char *path, uint32_t open_flags, struct inode **node_store) { bool can_write = 0; switch (open_flags & O_ACCMODE) { case O_RDONLY: break; case O_WRONLY: case O_RDWR: can_write = 1; break; default: return -E_INVAL; } if (open_flags & O_TRUNC) { if (!can_write) { return -E_INVAL; } } int ret; struct inode *dir, *node; if (open_flags & O_CREAT) { char *name; bool excl = (open_flags & O_EXCL) != 0; if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) { return ret; } ret = vop_create(dir, name, excl, &node); vop_ref_dec(dir); } else { ret = vfs_lookup(path, &node); } if (ret != 0) { return ret; } assert(node != NULL); if ((ret = vop_open(node, open_flags)) != 0) { vop_ref_dec(node); return ret; } vop_open_inc(node); if (open_flags & O_TRUNC) { if ((ret = vop_truncate(node, 0)) != 0) { vop_open_dec(node); vop_ref_dec(node); return ret; } } *node_store = node; return 0; }
/* * vfs_chdir - Set current directory, as a pathname. Use vfs_lookup to translate * it to a inode. */ int vfs_chdir(char *path) { // 改变当前的路径- int ret; struct inode *node; if ((ret = vfs_lookup(path, &node)) == 0) { ret = vfs_set_curdir(node); // 设置当前的目录 vop_ref_dec(node); } return ret; }
int vfs_readlink(char *path, struct iobuf *iob) { int ret; struct inode *node; if ((ret = vfs_lookup(path, &node)) != 0) { return ret; } ret = vop_readlink(node, iob); vop_ref_dec(node); return ret; }
int vfs_link(const char *oldname, const char *newname) { int rc; struct fs_entry *oldentry = vfs_resolve_path(oldname, &rc); if (!oldentry) return rc; struct vfs_walk_data wd; vfs_walk_start(&wd, newname); rc = vfs_walk_parent(&wd); if (rc) { vfs_walk_stop(&wd); vfs_entry_put(oldentry); return rc; } struct fs_entry *dir = wd.entry; struct fs_node *node = dir->node; if (!node->ops->lookup || !node->ops->link) { vfs_walk_stop(&wd); vfs_entry_put(oldentry); return -ENOTSUP; } mutex_lock(&node->mux); struct fs_entry *newentry = vfs_lookup(dir, wd.next, true, &rc); if (!newentry) { mutex_unlock(&node->mux); vfs_walk_stop(&wd); vfs_entry_put(oldentry); return rc; } if (newentry->node) { mutex_unlock(&node->mux); vfs_walk_stop(&wd); vfs_entry_put(oldentry); vfs_entry_put(newentry); return -EEXIST; } rc = node->ops->link(oldentry, node, newentry); mutex_unlock(&node->mux); vfs_walk_stop(&wd); vfs_entry_put(oldentry); vfs_entry_put(newentry); return rc; }
/* * Set current directory, as a pathname. Use vfs_lookup to translate * it to a vnode. */ int vfs_chdir(char *path) { struct vnode *vn; int result; result = vfs_lookup(path, &vn); if (result) { return result; } result = vfs_setcurdir(vn); VOP_DECREF(vn); return result; }
/* file_open() - open a file */ s32 file_open(ks8 * const path, u32 flags, file_info_t *fp) { vfs_dirent_t *ent; s32 ret; ent = (vfs_dirent_t *) kmalloc(sizeof(vfs_dirent_t)); if(!ent) return ENOMEM; /* Check that the file exists */ ret = vfs_lookup(path, ent); if(ret == SUCCESS) { /* File exists. Was exclusive creation requested? */ if(flags & O_EXCL) { kfree(ent); return EEXIST; } /* Check perms */ fp->dirent = ent; fp->flags = flags; fp->offset = (flags & O_APPEND) ? ent->size : 0; return SUCCESS; } else if(ret == ENOENT) { /* File does not exist. Was creation requested? */ if(flags & O_CREATE) { /* Check perms; create file; set offset = 0 */ /* TODO */ return ENOSYS; } else { kfree(ent); return ENOENT; /* File does not exist */ } } else { kfree(ent); return ret; /* Something went wrong in vfs_lookup() */ } }
static int vfs_file_open(const char *name, struct fs_file *file, bool create) { struct vfs_walk_data wd; int rc; vfs_walk_start(&wd, name); rc = vfs_walk_parent(&wd); if (rc) { vfs_walk_stop(&wd); return rc; } struct fs_node *dir = wd.entry->node; struct fs_entry *entry; if (!dir->ops || !dir->ops->lookup) { vfs_walk_stop(&wd); return -ENOTSUP; } mutex_lock(&dir->mux); entry = vfs_lookup(wd.entry, wd.next, create, &rc); if (create && entry && !entry->node) { if (!dir->ops->create) rc = -ENOTSUP; else rc = dir->ops->create(dir, entry); } mutex_unlock(&dir->mux); vfs_walk_stop(&wd); if (rc) { vfs_entry_put(entry); return rc; } file->entry = entry; file->node = entry->node; file->ops = entry->node->fops; file->offset = 0; if (file->ops && file->ops->open) { rc = file->ops->open(file); if (rc) vfs_file_cleanup(file); } return rc; }
int sc_access(thread_t *t, syscall_result_t *r, access_args_t *args) { int error = 0; vnode_t *node; proc_t *proc = t->thr_proc; char fname[PATH_MAX]; if((error = copyinstr(fname, args->fname, PATH_MAX))) return error; if((error = vfs_lookup(proc->p_curdir, &node, fname, t, LKP_ACCESS_REAL_ID))) return error; int res = VOP_ACCESS(node, args->mode, proc->p_cred); vrele(node); return res; }
/* * Does most of the work for readlink(). * * Note, however, if you're implementing symlinks, that various * other parts of the VFS layer are missing crucial elements of * support for symlinks. */ int vfs_readlink(char *path, struct uio *uio) { struct vnode *vn; int result; result = vfs_lookup(path, &vn); if (result) { return result; } result = VOP_READLINK(vn, uio); VOP_DECREF(vn); return result; }
int vfs_mkdir(const char *name) { struct vfs_walk_data wd; int rc; vfs_walk_start(&wd, name); rc = vfs_walk_parent(&wd); if (rc) { vfs_walk_stop(&wd); return rc; } struct fs_entry *dir = wd.entry; struct fs_node *node = dir->node; if (!node->ops->lookup || !node->ops->mkdir) { vfs_walk_stop(&wd); return -ENOTSUP; } mutex_lock(&node->mux); struct fs_entry *entry = vfs_lookup(dir, wd.next, true, &rc); if (!entry) { mutex_unlock(&node->mux); vfs_walk_stop(&wd); return rc; } if (entry->node) { mutex_unlock(&node->mux); vfs_walk_stop(&wd); vfs_entry_put(entry); return -EEXIST; } rc = node->ops->mkdir(node, entry); mutex_unlock(&node->mux); vfs_walk_stop(&wd); vfs_entry_put(entry); return rc; }
errno_t sc_stat(thread_t *t, syscall_result_t *r, stat_args *args) { int res=0; proc_t *p = t->thr_proc; vnode_t *node; char pname[PATH_MAX]; if((res = copyinstr(pname, args->pathname, PATH_MAX))) return res; if((res = vm_is_avail((vm_addr_t)args->buf, sizeof(struct stat)))) return res; res = vfs_lookup(p->p_curdir, &node, pname, t, (args->mode == STAT_LINK)?LKP_NO_FOLLOW:LKP_NORMAL); if(res) return res; res = vnode_stat(node, args->buf); vrele(node); if(res) return res; return 0; }
static int sys_open(uint32_t syscall, void *stack) { UNUSED_ARGUMENT(syscall); char const *path = PEEK_STACK(stack, char const *); stack = NEXT_STACK_ITEM(stack); /* flags and mode isn't used at the moment */ ps_t *ps = scheduler_get_current_process(); vnode_t *vnode = kmalloc(sizeof(vnode_t)); if(vfs_lookup(path, vnode)) { log_info("sys_open", "process %u tried to open non existing file %s.\n", ps->id, path); return -1; } int fd = get_next_fd(ps->file_descriptors, PROCESS_MAX_NUM_FD); if (fd == -1) { log_info("sys_open", "File descriptor table for ps %u is full.\n", ps->id); kfree(vnode); return -1; } if (vnode->v_op->vn_open(vnode)) { log_error("sys_open", "Can't open the vnode for path %s for ps %u\n", path, ps->id); kfree(vnode); return -1; } ps->file_descriptors[fd].vnode = vnode; return fd; }
static mount_tty(struct tty* tty, const struct kfile_operations *file_ops) { struct path node; /* register char device */ node = vfs_lookup("/dev"); if (!node) { return -1; } mode = S_IFCHR | S_IRALL | S_IWALL; node = vfs_create_child(node, name, mode); if (!node) { return -1; } nas = node->nas; if (NULL == (nas->fs = filesystem_create("empty"))) { return -1; } nas->fs->file_op = file_ops; nas->fi = dev; }
int vfs_link(char *old_path, char *new_path) { int ret; char *new_name; struct inode *old_node, *new_dir; if ((ret = vfs_lookup(old_path, &old_node)) != 0) { return ret; } if ((ret = vfs_lookup_parent(new_path, &new_dir, &new_name)) != 0) { vop_ref_dec(old_node); return ret; } if (old_node->in_fs == NULL || old_node->in_fs != new_dir->in_fs) { ret = -E_XDEV; } else { ret = vop_link(new_dir, new_name, old_node); } vop_ref_dec(old_node); vop_ref_dec(new_dir); return ret; }
int _create(vnode_t *vn, vnode_t **vpp, const char *name, vattr_t *attr) { int error; *vpp = NULL; if(!vn || !name || !attr || vn->v_type != VNODE_TYPE_DIR) return -EINVAL; ///@todo check for invalid name //check vnode_t *tmp; ///@todo w całym VFS i fs-ach trzeba przemyśleć strategię blokowania... error = vfs_lookup(vn, &tmp, name, NULL, LKP_NORMAL); if(error != -ENOENT) { if(!error) vrele(tmp); return -EEXIST; // a może raczej powinniśmy zmodyfikować ist. plik? } //plik nie istnieje -> tworzymy devfs_node_t *pn = vn->v_private; devfs_node_t *n = kmem_zalloc(sizeof(devfs_node_t), KM_SLEEP); if(!n) return -ENOMEM; str_cpy(n->i_name, name); n->i_type = (attr->va_type == VNODE_TYPE_DEV)? _INODE_TYPE_DEV:_INODE_TYPE_DIR; n->i_attr = attr->va_mode; n->i_uid = attr->va_uid; n->i_gid = attr->va_gid; n->i_dirvnode = NULL; n->i_dev = attr->va_dev; n->i_parent = pn; n->i_child = NULL; n->i_next = pn->i_child; pn->i_child = n; return _get_vnode(n, vpp, vn->v_vfs); }
int sc_chown(thread_t *t, syscall_result_t *r, chown_args_t *args) { int res=0; proc_t *p = t->thr_proc; vnode_t *node; char pname[PATH_MAX]; if((res = copyinstr(pname, args->fname, PATH_MAX))) return res; res = vfs_lookup(p->p_curdir, &node, pname, t, LKP_NORMAL); if(res) return res; vattr_t va; va.va_mask=VATTR_ALL; if((res = VOP_GETATTR(node, &va))) goto err; res = -EPERM; if(p->p_cred->p_euid != 0 && p->p_cred->p_euid != va.va_uid) goto err; if(p->p_cred->p_euid != 0) //tak... póki co nie ma zmian dla nie roota goto err; va.va_mask = VATTR_UID | VATTR_GID | VATTR_MODE; if(args->uid!=-1) va.va_uid = args->uid; if(args->gid!=-1) va.va_gid = args->gid; if(p->p_cred->p_euid!=0) //tymczasowo niemożliwe UNSET(va.va_mode, S_ISUID | S_ISGID); if((res = VOP_SETATTR(node, &va))) goto err; vrele(node); return 0; err: vrele(node); return res; }
void dev_init(void) { init_device(null); init_device(stdin); init_device(stdout); init_device(disk0); /* for Nand flash */ init_device(disk1); init_device(tty); //init_device(ashmem); // link such as stdout int ret; char *new_name; struct inode *old_node, *new_dir; if ((ret = vfs_lookup("stdout:", &old_node)) != 0) { kprintf("erho"); return;// ret; } if ((ret = vfs_lookup_parent("/dev", &new_dir, &new_name)) != 0) { vop_ref_dec(old_node); return;// ret; } // if (old_node->in_fs == NULL || old_node->in_fs != new_dir->in_fs) { // ret = -E_XDEV; // } // else { ret = vop_link(new_dir, new_name, old_node); kprintf("odife%d\n", ret); // } vop_ref_dec(old_node); vop_ref_dec(new_dir); }
static int tmpfs_init(void * par) { struct path dir_path, dev_path, root; struct node *dev_node; int res; struct ramdisk *ramdisk; if (!par) { return 0; } /*TODO */ if (0 != vfs_lookup(TMPFS_DIR, &dir_path)) { return -ENOENT; } ramdisk = ramdisk_create(tmpfs_dev, FILESYSTEM_SIZE * PAGE_SIZE()); if (0 != (res = err(ramdisk))) { return res; } dev_node = ramdisk->bdev->dev_vfs_info; if (!dev_node) { return -1; } /* format filesystem */ if (0 != (res = tmpfs_format((void *) dev_node))) { return res; } /* mount filesystem */ dev_path.node = dev_node; dev_path.mnt_desc = root.mnt_desc; return tmpfs_mount(dev_path.node, dir_path.node); }
/* * Convert a pathname into a pointer to a vnode. * * The FOLLOW flag is set when symbolic links are to be followed * when they occur at the end of the name translation process. * Symbolic links are always followed for all other pathname * components other than the last. * * If the LOCKLEAF flag is set, a locked vnode is returned. * * The segflg defines whether the name is to be copied from user * space or kernel space. * * Overall outline of namei: * * copy in name * get starting directory * while (!done && !error) { * call lookup to search path. * if symbolic link, massage name in buffer and continue * } */ int namei(struct nameidata *ndp) { struct filedesc *fdp; /* pointer to file descriptor state */ char *cp; /* pointer into pathname argument */ struct vnode *dp; /* the directory we are searching */ struct iovec aiov; /* uio for reading symbolic links */ struct uio auio; int error, linklen; struct componentname *cnp = &ndp->ni_cnd; struct proc *p = cnp->cn_proc; ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; #ifdef DIAGNOSTIC if (!cnp->cn_cred || !cnp->cn_proc) panic ("namei: bad cred/proc"); if (cnp->cn_nameiop & (~OPMASK)) panic ("namei: nameiop contaminated with flags"); if (cnp->cn_flags & OPMASK) panic ("namei: flags contaminated with nameiops"); #endif fdp = cnp->cn_proc->p_fd; /* * Get a buffer for the name to be translated, and copy the * name into the buffer. */ if ((cnp->cn_flags & HASBUF) == 0) cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK); if (ndp->ni_segflg == UIO_SYSSPACE) error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN, &ndp->ni_pathlen); else error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN, &ndp->ni_pathlen); /* * Fail on null pathnames */ if (error == 0 && ndp->ni_pathlen == 1) error = ENOENT; if (error) { fail: pool_put(&namei_pool, cnp->cn_pnbuf); ndp->ni_vp = NULL; return (error); } #ifdef KTRACE if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) ktrnamei(cnp->cn_proc, cnp->cn_pnbuf); #endif #if NSYSTRACE > 0 if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE)) systrace_namei(ndp); #endif /* * Strip trailing slashes, as requested */ if (cnp->cn_flags & STRIPSLASHES) { char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2; cp = end; while (cp >= cnp->cn_pnbuf && (*cp == '/')) cp--; /* Still some remaining characters in the buffer */ if (cp >= cnp->cn_pnbuf) { ndp->ni_pathlen -= (end - cp); *(cp + 1) = '\0'; } } ndp->ni_loopcnt = 0; /* * Get starting point for the translation. */ if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) ndp->ni_rootdir = rootvnode; if ((p->p_p->ps_flags & PS_TAMED)) { error = tame_namei(p, cnp->cn_pnbuf); if (error) goto fail; } /* * Check if starting from root directory or current directory. */ if (cnp->cn_pnbuf[0] == '/') { dp = ndp->ni_rootdir; vref(dp); } else if (ndp->ni_dirfd == AT_FDCWD) { dp = fdp->fd_cdir; vref(dp); } else { struct file *fp = fd_getfile(fdp, ndp->ni_dirfd); if (fp == NULL) { pool_put(&namei_pool, cnp->cn_pnbuf); return (EBADF); } dp = (struct vnode *)fp->f_data; if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) { pool_put(&namei_pool, cnp->cn_pnbuf); return (ENOTDIR); } vref(dp); } for (;;) { if (!dp->v_mount) { /* Give up if the directory is no longer mounted */ pool_put(&namei_pool, cnp->cn_pnbuf); return (ENOENT); } cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_startdir = dp; if ((error = vfs_lookup(ndp)) != 0) { pool_put(&namei_pool, cnp->cn_pnbuf); return (error); } /* * If not a symbolic link, return search result. */ if ((cnp->cn_flags & ISSYMLINK) == 0) { if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) pool_put(&namei_pool, cnp->cn_pnbuf); else cnp->cn_flags |= HASBUF; return (0); } if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN)) VOP_UNLOCK(ndp->ni_dvp, 0, p); if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) { error = ELOOP; break; } if (ndp->ni_pathlen > 1) cp = pool_get(&namei_pool, PR_WAITOK); else cp = cnp->cn_pnbuf; aiov.iov_base = cp; aiov.iov_len = MAXPATHLEN; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; auio.uio_procp = cnp->cn_proc; auio.uio_resid = MAXPATHLEN; error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); if (error) { badlink: if (ndp->ni_pathlen > 1) pool_put(&namei_pool, cp); break; } linklen = MAXPATHLEN - auio.uio_resid; if (linklen == 0) { error = ENOENT; goto badlink; } if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { error = ENAMETOOLONG; goto badlink; } if (ndp->ni_pathlen > 1) { memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); pool_put(&namei_pool, cnp->cn_pnbuf); cnp->cn_pnbuf = cp; } else cnp->cn_pnbuf[linklen] = '\0'; ndp->ni_pathlen += linklen; vput(ndp->ni_vp); dp = ndp->ni_dvp; /* * Check if root directory should replace current directory. */ if (cnp->cn_pnbuf[0] == '/') { vrele(dp); dp = ndp->ni_rootdir; vref(dp); } } pool_put(&namei_pool, cnp->cn_pnbuf); vrele(ndp->ni_dvp); vput(ndp->ni_vp); ndp->ni_vp = NULL; return (error); }
/* Does most of the work for open(). */ int vfs_open(char *path, int openflags, struct vnode **ret) { int how; int result; int canwrite; struct vnode *vn = NULL; how = openflags & O_ACCMODE; switch (how) { case O_RDONLY: canwrite=0; break; case O_WRONLY: case O_RDWR: canwrite=1; break; default: return EINVAL; } if (openflags & O_CREAT) { char name[NAME_MAX+1]; struct vnode *dir; int excl = (openflags & O_EXCL)!=0; result = vfs_lookparent(path, &dir, name, sizeof(name)); if (result) { return result; } result = VOP_CREAT(dir, name, excl, &vn); VOP_DECREF(dir); } else { result = vfs_lookup(path, &vn); } if (result) { return result; } assert(vn != NULL); result = VOP_OPEN(vn, openflags); if (result) { VOP_DECREF(vn); return result; } VOP_INCOPEN(vn); if (openflags & O_TRUNC) { if (canwrite==0) { result = EINVAL; } else { result = VOP_TRUNCATE(vn, 0); } if (result) { VOP_DECOPEN(vn); VOP_DECREF(vn); return result; } } *ret = vn; return 0; }
errno_t sc_open(thread_t *p, syscall_result_t *r, sc_open_args *arg) { int fd; int flags = arg->flags; int error = 0; vnode_t *node; proc_t *proc = p->thr_proc; char fname[PATH_MAX+1]; if((error = copyinstr(fname, arg->fname, PATH_MAX))) return error; KASSERT(proc->p_rootdir!=NULL); error = vfs_lookup(proc->p_curdir, &node, fname, p, LKP_NORMAL); if(error) { if(!(flags & O_CREAT)) return error; vnode_t *parent; error = vfs_lookup_parent(proc->p_curdir, &parent, fname, p); if(error) return error; if((error = VOP_ACCESS(parent, W_OK, proc->p_cred))) { vrele(parent); return error; } vattr_t attr; attr.va_mode = arg->mode & ~(proc->p_umask) & 0777; attr.va_type = VNODE_TYPE_REG; attr.va_uid = proc->p_cred->p_uid; attr.va_gid = proc->p_cred->p_gid; attr.va_size = 0; attr.va_dev = NULL; error = VOP_CREATE(parent, &node, _get_last_cmpt(fname), &attr); VOP_UNLOCK(parent); if(error) return error; VOP_LOCK(node); } else { //plik istnieje if((flags & O_CREAT) && (flags & O_EXCL)) { vrele(node); return -EEXIST; } if((node->v_type == VNODE_TYPE_DIR) && (flags & (O_RDWR | O_WRONLY))) { vrele(node); return -EISDIR; } } int wmode = (flags & O_RDWR) ? (W_OK | R_OK) : (flags & O_RDONLY) ? (R_OK) : (W_OK); if((error = VOP_ACCESS(node, wmode, proc->p_cred))) { vrele(node); return error; } if((error = VOP_OPEN(node, flags, arg->mode))) { vrele(node); return error; } if(ISSET(flags, O_RDWR | O_WRONLY) && ISSET(flags, O_TRUNC) && node->v_type == VNODE_TYPE_REG) VOP_TRUNCATE(node, 0); if((error = f_alloc(proc, node, flags, &fd))) { vrele(node); // <- powinno to tutaj być, dopisałem bo nie było. return error; } VOP_UNLOCK(node); r->result = fd; return 0; }