/* * Look for a name in a directory and hand back a vnode for the * file, if there is one. */ static int sfs_lookonce(struct sfs_vnode *sv, const char *name, struct sfs_vnode **ret, int *slot) { struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data; u_int32_t ino; int result; result = sfs_dir_findname(sv, name, &ino, slot, NULL); if (result) { return result; } result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret); if (result) { return result; } if ((*ret)->sv_i.sfi_linkcount == 0) { panic("sfs: Link count of file %u found in dir %u is 0\n", (*ret)->sv_ino, sv->sv_ino); } return 0; }
/* * Create a file. If EXCL is set, insist that the filename not already * exist; otherwise, if it already exists, just open it. */ static int sfs_creat(struct vnode *v, const char *name, int excl, struct vnode **ret) { struct sfs_fs *sfs = v->vn_fs->fs_data; struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *newguy; u_int32_t ino; int result; /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { return result; } /* If it exists and we didn't want it to, fail */ if (result==0 && excl) { return EEXIST; } if (result==0) { /* We got a file; load its vnode and return */ result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy); if (result) { return result; } *ret = &newguy->sv_v; return 0; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy); if (result) { return result; } /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); if (result) { VOP_DECREF(&newguy->sv_v); return result; } /* Update the linkcount of the new file */ newguy->sv_i.sfi_linkcount++; /* and consequently mark it dirty. */ newguy->sv_dirty = 1; *ret = &newguy->sv_v; return 0; }
/* * Get vnode for the root of the filesystem. * The root vnode is always found in block 1 (SFS_ROOT_LOCATION). */ struct vnode * sfs_getroot(struct fs *fs) { struct sfs_fs *sfs = fs->fs_data; struct sfs_vnode *sv; int result; result = sfs_loadvnode(sfs, SFS_ROOT_LOCATION, SFS_TYPE_INVAL, &sv); if (result) { panic("sfs: getroot: Cannot load root vnode\n"); } return &sv->sv_v; }
/* * Create a new filesystem object and hand back its vnode. */ static int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret) { u_int32_t ino; int result; /* * First, get an inode. (Each inode is a block, and the inode * number is the block number, so just get a block.) */ result = sfs_balloc(sfs, &ino); if (result) { return result; } /* * Now load a vnode for it. */ return sfs_loadvnode(sfs, ino, type, ret); }
/* * Get the full pathname for a file. This only needs to work on directories. * Since we don't support subdirectories, assume it's the root directory * and hand back the empty string. (The VFS layer takes care of the * device name, leading slash, etc.) */ static int sfs_namefile(struct vnode *vv, struct uio *uio) { /* * 1. All you really have is inode number of directory passed in. * 2. Get inode number of parent by reading directory slot 0 (..) * 3. loadvnode of parent * 4. Get our name by reading through parent directory for our inode * number * 5. Add this name to string * 6. Repeat 2 through 5 until we hit root * 7. uiomove * Deal with reference counters as you need to, as loadvnode * increments refcount on vnode that we load. */ struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *child_dir, *parent_dir; struct sfs_dir tsd; int err, nentries, slot; char to_add[SFS_NAMELEN + 1], pathname[(SFS_NAMELEN + 1) * SFS_DIR_DEPTH]; /* If we're root, do nothing */ if(sv->sv_ino == SFS_ROOT_LOCATION) return 0; child_dir = sv; VOP_INCREF(&child_dir->sv_v); while(1){ err = sfs_readdir(child_dir, &tsd, 1); if(err) return err; assert(!strcmp(tsd.sfd_name, "..")); err = sfs_loadvnode(child_dir->sv_v.vn_fs->fs_data, tsd.sfd_ino, SFS_TYPE_INVAL, &parent_dir); if(err) return err; nentries = sfs_dir_nentries(parent_dir); slot = 2; while (slot < nentries){ err = sfs_readdir(parent_dir, &tsd, slot); if(err) return err; if(tsd.sfd_ino == child_dir->sv_ino) break; slot++; } /* * Doesn't make sense if we don't find our directory listed in our * parent directory.. */ assert(slot < nentries); strcpy(to_add, tsd.sfd_name); strcat(to_add, "/"); strcat(to_add, pathname); strcpy(pathname, to_add); VOP_DECREF(&child_dir->sv_v); if(parent_dir->sv_ino == SFS_ROOT_LOCATION){ VOP_DECREF(&parent_dir->sv_v); break; } else child_dir = parent_dir; } err = uiomove(pathname, strlen(pathname) + 1, uio); if(err) return err; return 0; }
/* * Create a file. If EXCL is set, insist that the filename not already * exist; otherwise, if it already exists, just open it. * * Locking: Gets/releases the vnode lock for v. Does not lock the new vnode, * as nobody else can get to it except by searching the directory it's in, * which is locked. * * Requires up to 4 buffers as VOP_DECREF invocations may take 3. */ static int sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode, struct vnode **ret) { struct sfs_fs *sfs = v->vn_fs->fs_data; struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *newguy; struct sfs_dinode *sv_dino; struct sfs_dinode *new_dino; uint32_t ino; int result; lock_acquire(sv->sv_lock); reserve_buffers(SFS_BLOCKSIZE); result = sfs_dinode_load(sv); if (result) { unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return result; } sv_dino = sfs_dinode_map(sv); if (sv_dino->sfi_linkcount == 0) { sfs_dinode_unload(sv); unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return ENOENT; } sfs_dinode_unload(sv); /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return result; } /* If it exists and we didn't want it to, fail */ if (result==0 && excl) { unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return EEXIST; } if (result==0) { /* We got something; load its vnode and return */ result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy); if (result) { unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return result; } *ret = &newguy->sv_absvn; unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return 0; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy); if (result) { unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return result; } /* sfs_makeobj loads the inode for us */ new_dino = sfs_dinode_map(newguy); /* We don't currently support file permissions; ignore MODE */ (void)mode; /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); if (result) { sfs_dinode_unload(newguy); lock_release(newguy->sv_lock); VOP_DECREF(&newguy->sv_absvn); lock_release(sv->sv_lock); unreserve_buffers(SFS_BLOCKSIZE); return result; } /* Update the linkcount of the new file */ new_dino->sfi_linkcount++; /* and consequently mark it dirty. */ sfs_dinode_mark_dirty(newguy); *ret = &newguy->sv_absvn; sfs_dinode_unload(newguy); unreserve_buffers(SFS_BLOCKSIZE); lock_release(newguy->sv_lock); lock_release(sv->sv_lock); return 0; }
/* * Create a file. If EXCL is set, insist that the filename not already * exist; otherwise, if it already exists, just open it. */ static int sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode, struct vnode **ret) { struct sfs_fs *sfs = v->vn_fs->fs_data; struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *newguy; uint32_t ino; int result; vfs_biglock_acquire(); /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { vfs_biglock_release(); return result; } /* If it exists and we didn't want it to, fail */ if (result==0 && excl) { vfs_biglock_release(); return EEXIST; } if (result==0) { /* We got a file; load its vnode and return */ result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy); if (result) { vfs_biglock_release(); return result; } *ret = &newguy->sv_v; vfs_biglock_release(); return 0; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy); if (result) { vfs_biglock_release(); return result; } /* We don't currently support file permissions; ignore MODE */ (void)mode; /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); if (result) { VOP_DECREF(&newguy->sv_v); vfs_biglock_release(); return result; } /* Update the linkcount of the new file */ newguy->sv_i.sfi_linkcount++; /* and consequently mark it dirty. */ newguy->sv_dirty = true; *ret = &newguy->sv_v; vfs_biglock_release(); return 0; }