/* * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 * The President and Fellows of Harvard College. * * 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 University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY 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. */ /* * SFS filesystem * * Directory I/O */ #include #include #include #include #include #include "sfsprivate.h" /* * Read the directory entry out of slot SLOT of a directory vnode. * The "slot" is the index of the directory entry, starting at 0. */ static int sfs_readdir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd) { off_t actualpos; /* Compute the actual position in the directory to read. */ actualpos = slot * sizeof(struct sfs_direntry); return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_READ); } /* * Write (overwrite) the directory entry in slot SLOT of a directory * vnode. */ static int sfs_writedir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd) { off_t actualpos; /* Compute the actual position in the directory. */ KASSERT(slot>=0); actualpos = slot * sizeof(struct sfs_direntry); return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_WRITE); } /* * Compute the number of entries in a directory. * This actually computes the number of existing slots, and does not * account for empty slots. */ static int sfs_dir_nentries(struct sfs_vnode *sv) { off_t size; KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR); size = sv->sv_i.sfi_size; if (size % sizeof(struct sfs_direntry) != 0) { panic("sfs: directory %u: Invalid size %llu\n", sv->sv_ino, size); } return size / sizeof(struct sfs_direntry); } /* * Search a directory for a particular filename in a directory, and * return its inode number, its slot, and/or the slot number of an * empty directory slot if one is found. */ int sfs_dir_findname(struct sfs_vnode *sv, const char *name, uint32_t *ino, int *slot, int *emptyslot) { struct sfs_direntry tsd; int found, nentries, i, result; nentries = sfs_dir_nentries(sv); /* For each slot... */ found = 0; for (i=0; i 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, emptyslot, &sd); } /* * Unlink a name in a directory, by slot number. */ int sfs_dir_unlink(struct sfs_vnode *sv, int slot) { struct sfs_direntry sd; /* Initialize a suitable directory entry... */ bzero(&sd, sizeof(sd)); sd.sfd_ino = SFS_NOINO; /* ... and write it */ return sfs_writedir(sv, slot, &sd); } /* * Look for a name in a directory and hand back a vnode for the * file, if there is one. */ int sfs_lookonce(struct sfs_vnode *sv, const char *name, struct sfs_vnode **ret, int *slot) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; uint32_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: name %s (inode %u) in dir %u has linkcount 0\n", name, (*ret)->sv_ino, sv->sv_ino); } return 0; }