static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); do { struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } char *subpath; next: subpath = sfs_lookup_subpath(path); if (strcmp(path, ".") == 0) { if ((path = subpath) != NULL) { goto next; } break; } int ret; struct inode *subnode; if (strcmp(path, "..") == 0) { ret = sfs_load_parent(sfs, sin, &subnode); } else { if (strlen(path) > SFS_MAX_FNAME_LEN) { vop_ref_dec(node); return -E_TOO_BIG; } ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); } vop_ref_dec(node); if (ret != 0) { return ret; } node = subnode, path = subpath; } while (path != NULL); *node_store = node; return 0; }
/* * sfs_lookup - Parse path relative to the passed directory * DIR, and hand back the inode for the file it * refers to. */ static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } struct inode *subnode; int ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); vop_ref_dec(node); if (ret != 0) { return ret; } *node_store = subnode; return 0; }
/* *sfs_namefile -Compute pathname relative to filesystem root of the file and copy to the specified io buffer. * */ static int sfs_namefile(struct inode *node, struct iobuf *iob) { struct sfs_disk_entry *entry; if (iob->io_resid <= 2 || (entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) { return -E_NO_MEM; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret; char *ptr = iob->io_base + iob->io_resid; size_t alen, resid = iob->io_resid - 2; vop_ref_inc(node); while (1) { struct inode *parent; if ((ret = sfs_lookup_once(sfs, sin, "..", &parent, NULL)) != 0) { goto failed; } uint32_t ino = sin->ino; vop_ref_dec(node); if (node == parent) { vop_ref_dec(node); break; } node = parent, sin = vop_info(node, sfs_inode); assert(ino != sin->ino && sin->din->type == SFS_TYPE_DIR); lock_sin(sin); { ret = sfs_dirent_findino_nolock(sfs, sin, ino, entry); } unlock_sin(sin); if (ret != 0) { goto failed; } if ((alen = strlen(entry->name) + 1) > resid) { goto failed_nomem; } resid -= alen, ptr -= alen; memcpy(ptr, entry->name, alen - 1); ptr[alen - 1] = '/'; } alen = iob->io_resid - resid - 2; ptr = memmove(iob->io_base + 1, ptr, alen); ptr[-1] = '/', ptr[alen] = '\0'; iobuf_skip(iob, alen); kfree(entry); return 0; failed_nomem: ret = -E_NO_MEM; failed: vop_ref_dec(node); kfree(entry); return ret; }