/* * 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; }
/* * Create a link in a directory to the specified inode by number, with * the specified name, and optionally hand back the slot. */ static int sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot) { int emptyslot = -1; int result; struct sfs_dir sd; /* Look up the name. We want to make sure it *doesn't* exist. */ result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot); if (result!=0 && result!=ENOENT) { return result; } if (result==0) { return EEXIST; } if (strlen(name)+1 > sizeof(sd.sfd_name)) { return ENAMETOOLONG; } /* If we didn't get an empty slot, add the entry at the end. */ if (emptyslot < 0) { emptyslot = sfs_dir_nentries(sv); } /* Set up the entry. */ bzero(&sd, sizeof(sd)); sd.sfd_ino = ino; strcpy(sd.sfd_name, name); /* Hand back the slot, if so requested. */ if (slot) { *slot = emptyslot; } /* Write the entry. */ return sfs_writedir(sv, &sd, emptyslot); }
static int sfs_mkdir(struct vnode *vv, const char *name){ struct sfs_fs *sfs = vv->vn_fs->fs_data; struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *newguy; u_int32_t ino; int result, result2, slot1, slot2; /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { return result; } if (result==0) { /* Directory or file of same name already exists */ return EINVAL; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_DIR, &newguy); if (result) { return result; } /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, &slot1); if (result) { VOP_DECREF(&newguy->sv_v); return result; } /* Increment linkcount of the new directory and mark it dirty */ newguy->sv_i.sfi_linkcount++; newguy->sv_dirty = 1; /* Link . and .. into our directory */ result = sfs_dir_link(newguy, ".", newguy->sv_ino, &slot2); if (result) { result2 = sfs_dir_unlink(sv, slot1); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return result; } newguy->sv_i.sfi_linkcount++; newguy->sv_dirty = 1; result = sfs_dir_link(newguy, "..", sv->sv_ino, NULL); if (result) { result2 = sfs_dir_unlink(newguy, slot2); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; result2 = sfs_dir_unlink(sv, slot1); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return result; } sv->sv_i.sfi_linkcount++; sv->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return 0; }
static int sfs_mkdir(struct vnode *v, const char *name, mode_t mode) { struct sfs_fs *sfs = v->vn_fs->fs_data; struct sfs_vnode *sv = v->vn_data; int result; uint32_t ino; struct sfs_dinode *dir_inodeptr; struct sfs_dinode *new_inodeptr; struct sfs_vnode *newguy; (void)mode; lock_acquire(sv->sv_lock); reserve_buffers(SFS_BLOCKSIZE); result = sfs_dinode_load(sv); if (result) { goto die_early; } dir_inodeptr = sfs_dinode_map(sv); if (dir_inodeptr->sfi_linkcount == 0) { result = ENOENT; goto die_simple; } /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { goto die_simple; } /* If it exists, fail */ if (result==0) { result = EEXIST; goto die_simple; } /* * If we're trying to create . or .. and we get this far * (meaning the entry in question is missing), the fs is * corrupted. Let's not make it worse. Best at this point to * bail out and run fsck. */ if (!strcmp(name, ".") || !strcmp(name, "..")) { panic("sfs: %s: No %s entry in dir %u; please fsck\n", sfs->sfs_sb.sb_volname, name, sv->sv_ino); } result = sfs_makeobj(sfs, SFS_TYPE_DIR, &newguy); if (result) { goto die_simple; } new_inodeptr = sfs_dinode_map(newguy); result = sfs_dir_link(newguy, ".", newguy->sv_ino, NULL); if (result) { goto die_uncreate; } result = sfs_dir_link(newguy, "..", sv->sv_ino, NULL); if (result) { goto die_uncreate; } result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); if (result) { goto die_uncreate; } /* * Increment link counts (Note: not until after the names are * added - that way if one fails, the link count will be zero, * and reclaim will dispose of the new directory. * * Note also that the name in the parent directory gets added * last, so there's no case in which we have to go back and * remove it. */ new_inodeptr->sfi_linkcount += 2; dir_inodeptr->sfi_linkcount++; sfs_dinode_mark_dirty(newguy); sfs_dinode_mark_dirty(sv); sfs_dinode_unload(newguy); sfs_dinode_unload(sv); lock_release(newguy->sv_lock); lock_release(sv->sv_lock); VOP_DECREF(&newguy->sv_absvn); unreserve_buffers(SFS_BLOCKSIZE); KASSERT(result==0); return result; die_uncreate: sfs_dinode_unload(newguy); lock_release(newguy->sv_lock); VOP_DECREF(&newguy->sv_absvn); die_simple: sfs_dinode_unload(sv); die_early: unreserve_buffers(SFS_BLOCKSIZE); lock_release(sv->sv_lock); return result; }
/* * 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; }