/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* High-level VFS operations on pathnames.31*/3233#include <types.h>34#include <kern/errno.h>35#include <kern/fcntl.h>36#include <limits.h>37#include <lib.h>38#include <vfs.h>39#include <vnode.h>404142/* Does most of the work for open(). */43int44vfs_open(char *path, int openflags, mode_t mode, struct vnode **ret)45{46int how;47int result;48int canwrite;49struct vnode *vn = NULL;5051how = openflags & O_ACCMODE;5253switch (how) {54case O_RDONLY:55canwrite=0;56break;57case O_WRONLY:58case O_RDWR:59canwrite=1;60break;61default:62return EINVAL;63}6465if (openflags & O_CREAT) {66char name[NAME_MAX+1];67struct vnode *dir;68int excl = (openflags & O_EXCL)!=0;6970result = vfs_lookparent(path, &dir, name, sizeof(name));71if (result) {72return result;73}7475result = VOP_CREAT(dir, name, excl, mode, &vn);7677VOP_DECREF(dir);78}79else {80result = vfs_lookup(path, &vn);81}8283if (result) {84return result;85}8687KASSERT(vn != NULL);8889result = VOP_OPEN(vn, openflags);90if (result) {91VOP_DECREF(vn);92return result;93}9495VOP_INCOPEN(vn);9697if (openflags & O_TRUNC) {98if (canwrite==0) {99result = EINVAL;100}101else {102result = VOP_TRUNCATE(vn, 0);103}104if (result) {105VOP_DECOPEN(vn);106VOP_DECREF(vn);107return result;108}109}110111*ret = vn;112113return 0;114}115116/* Does most of the work for close(). */117void118vfs_close(struct vnode *vn)119{120/*121* VOP_DECOPEN and VOP_DECREF don't return errors.122*123* We assume that the file system makes every reasonable124* effort to not fail. If it does fail - such as on a hard I/O125* error or something - vnode.c prints a warning. The reason126* we don't report errors up to or above this level is that127* (1) most application software does not check for close128* failing, and more importantly129* (2) we're often called from places like process exit130* where reporting the error is impossible and131* meaningful recovery is entirely impractical.132*/133134VOP_DECOPEN(vn);135VOP_DECREF(vn);136}137138/* Does most of the work for remove(). */139int140vfs_remove(char *path)141{142struct vnode *dir;143char name[NAME_MAX+1];144int result;145146result = vfs_lookparent(path, &dir, name, sizeof(name));147if (result) {148return result;149}150151result = VOP_REMOVE(dir, name);152VOP_DECREF(dir);153154return result;155}156157/* Does most of the work for rename(). */158int159vfs_rename(char *oldpath, char *newpath)160{161struct vnode *olddir;162char oldname[NAME_MAX+1];163struct vnode *newdir;164char newname[NAME_MAX+1];165int result;166167result = vfs_lookparent(oldpath, &olddir, oldname, sizeof(oldname));168if (result) {169return result;170}171result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname));172if (result) {173VOP_DECREF(olddir);174return result;175}176177if (olddir->vn_fs==NULL || newdir->vn_fs==NULL ||178olddir->vn_fs != newdir->vn_fs) {179VOP_DECREF(newdir);180VOP_DECREF(olddir);181return EXDEV;182}183184result = VOP_RENAME(olddir, oldname, newdir, newname);185186VOP_DECREF(newdir);187VOP_DECREF(olddir);188189return result;190}191192/* Does most of the work for link(). */193int194vfs_link(char *oldpath, char *newpath)195{196struct vnode *oldfile;197struct vnode *newdir;198char newname[NAME_MAX+1];199int result;200201result = vfs_lookup(oldpath, &oldfile);202if (result) {203return result;204}205result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname));206if (result) {207VOP_DECREF(oldfile);208return result;209}210211if (oldfile->vn_fs==NULL || newdir->vn_fs==NULL ||212oldfile->vn_fs != newdir->vn_fs) {213VOP_DECREF(newdir);214VOP_DECREF(oldfile);215return EXDEV;216}217218result = VOP_LINK(newdir, newname, oldfile);219220VOP_DECREF(newdir);221VOP_DECREF(oldfile);222223return result;224}225226/*227* Does most of the work for symlink().228*229* Note, however, if you're implementing symlinks, that various230* other parts of the VFS layer are missing crucial elements of231* support for symlinks.232*/233int234vfs_symlink(const char *contents, char *path)235{236struct vnode *newdir;237char newname[NAME_MAX+1];238int result;239240result = vfs_lookparent(path, &newdir, newname, sizeof(newname));241if (result) {242return result;243}244245result = VOP_SYMLINK(newdir, newname, contents);246VOP_DECREF(newdir);247248return result;249}250251/*252* Does most of the work for readlink().253*254* Note, however, if you're implementing symlinks, that various255* other parts of the VFS layer are missing crucial elements of256* support for symlinks.257*/258int259vfs_readlink(char *path, struct uio *uio)260{261struct vnode *vn;262int result;263264result = vfs_lookup(path, &vn);265if (result) {266return result;267}268269result = VOP_READLINK(vn, uio);270271VOP_DECREF(vn);272273return result;274}275276/*277* Does most of the work for mkdir.278*/279int280vfs_mkdir(char *path, mode_t mode)281{282struct vnode *parent;283char name[NAME_MAX+1];284int result;285286result = vfs_lookparent(path, &parent, name, sizeof(name));287if (result) {288return result;289}290291result = VOP_MKDIR(parent, name, mode);292293VOP_DECREF(parent);294295return result;296}297298/*299* Does most of the work for rmdir.300*/301int302vfs_rmdir(char *path)303{304struct vnode *parent;305char name[NAME_MAX+1];306int result;307308result = vfs_lookparent(path, &parent, name, sizeof(name));309if (result) {310return result;311}312313result = VOP_RMDIR(parent, name);314315VOP_DECREF(parent);316317return result;318}319320321322