int fdir_creat (fbuf *dir, const char *name, AFSFid fid) { int ret; int i; unsigned npages; DirPage0 *page0; DirPage1 *page; int ind = 0; unsigned hash_value, next; assert (dir->len != 0); page0 = (DirPage0 *)fbuf_buf(dir); assert (page0); npages = ntohs(page0->header.pg_pgcount); if (npages < fbuf_len(dir) / AFSDIR_PAGESIZE) npages = fbuf_len(dir) / AFSDIR_PAGESIZE; if (find_entry (page0, name)) return EEXIST; hash_value = hashentry (name); next = page0->dheader.hash[hash_value]; for (i = 0; i < npages; ++i) { page = getpage (page0, i); ind = add_to_page (page0, page, i, name, fid, next); if (ind >= 0) break; } if (i == npages) { ret = create_new_page (&page, dir); if (ret) return ret; page0 = (DirPage0 *)fbuf_buf(dir); page0->header.pg_pgcount = htons(npages + 1); if (i < MAXPAGES) page0->dheader.map[i] = ENTRIESPERPAGE - 1; ind = add_to_page (page0, page, i, name, fid, next); assert (ind >= 0); } ind += i * ENTRIESPERPAGE; page0->dheader.hash[hash_value] = htons(ind + 1); return 0; }
int mdir_changefid(struct mnode *dir, const char *name, AFSFid fid) { fbuf the_fbuf; VenusFid vfid; int ret, saved_ret; int32_t len; assert (dir->flags.sbp); assert (dir->flags.fdp); vfid.Cell = 0; vfid.fid = fid; ret = fbuf_create (&the_fbuf, dir->fd, dir->sb.st_size, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) return ret; saved_ret = fdir_changefid (&the_fbuf, name, &vfid); if (ret == 0) { len = fbuf_len (&the_fbuf); mnode_update_size (dir, &len); } ret = fbuf_end (&the_fbuf); if (ret) return ret; return saved_ret; }
int mdir_mkdir (struct mnode *node, AFSFid dot, AFSFid dot_dot) { fbuf the_fbuf; int ret, saved_ret; int32_t len; assert (node->flags.sbp); assert (node->flags.fdp); ret = fbuf_create (&the_fbuf, node->fd, node->sb.st_size, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) return ret; saved_ret = fdir_mkdir (&the_fbuf, dot, dot_dot); if (ret == 0) { len = fbuf_len (&the_fbuf); mnode_update_size (node, &len); } ret = fbuf_end (&the_fbuf); if (ret) return ret; return saved_ret; }
int mdir_remove (struct mnode *node, const char *name) { fbuf the_fbuf; int ret, saved_ret; int32_t len; assert (node->flags.sbp); assert (node->flags.fdp); ret = fbuf_create (&the_fbuf, node->fd, node->sb.st_size, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) return ret; saved_ret = fdir_remove (&the_fbuf, name, NULL); if (ret == 0) { len = fbuf_len (&the_fbuf); mnode_update_size (node, &len); } ret = fbuf_end (&the_fbuf); if (ret) return ret; return saved_ret; }
static int create_new_page (DirPage1 **ret_page, fbuf *the_fbuf) { int ret; DirPage1 *page1; size_t len = fbuf_len(the_fbuf); ret = fbuf_truncate (the_fbuf, len + AFSDIR_PAGESIZE); if (ret) return ret; page1 = (DirPage1 *)((char *)fbuf_buf(the_fbuf) + len); page1->header.pg_pgcount = htons(0); page1->header.pg_tag = htons(AFSDIRMAGIC); page1->header.pg_freecount = ENTRIESPERPAGE - 1; memset (page1->header.pg_bitmap, 0, sizeof(page1->header.pg_bitmap)); set_used (page1, 0); *ret_page = page1; return 0; }
int mdir_rename(struct mnode *dir1, const char *name1, int32_t *len1, struct mnode *dir2, const char *name2, int32_t *len2) { fbuf origfbuf; fbuf newfbuf; fbuf *newfbufP = &newfbuf; VenusFid child, origVFid; int ret, dirp; int same_dir = FALSE; origVFid.Cell = 0; origVFid.fid = dir1->fid; ret = fbuf_create (&origfbuf, dir1->fd, dir1->sb.st_size, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) return ret; ret = fdir_lookup(&origfbuf, &origVFid, name1, &child); if (ret) { fbuf_end (&origfbuf); return ret; } dirp = afs_dir_p (child.fid.Vnode); if (dir1 == dir2) { newfbufP = &origfbuf; same_dir = TRUE; } else { ret = fbuf_create (&newfbuf, dir2->fd, dir2->sb.st_size, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) { fbuf_end (&origfbuf); return ret; } } { VenusFid sentenced_file; VenusFid dir; dir.fid = dir2->fid; dir.Cell = 0; if (fdir_lookup(newfbufP, &dir, name2, &sentenced_file) == ENOENT) { ret = fdir_creat (newfbufP, name2, child.fid); if (ret) goto out1; } else { if (afs_dir_p (sentenced_file.fid.Vnode) != dirp) { /* XXX check properly */ ret = EISDIR; goto out1; } if (dirp && fdir_emptyp(newfbufP) != TRUE) { ret = ENOTEMPTY; goto out1; } ret = fdir_changefid(newfbufP, name2, &child); if (ret) goto out1; } } ret = fdir_remove (&origfbuf, name1, NULL); if (ret == 0) { *len1 = fbuf_len (&origfbuf); if (!same_dir) *len2 = fbuf_len (newfbufP); } out1: fbuf_end (&origfbuf); if (!same_dir) { fbuf_end (&newfbuf); } return ret; }
int fdir_readdir (fbuf *the_fbuf, fdir_readdir_func func, void *arg, VenusFid dir, uint32_t *offset) { DirPage0 *page0; unsigned i, j; VenusFid fid; unsigned len = fbuf_len(the_fbuf); unsigned npages; unsigned first_slot; int ret; page0 = (DirPage0 *)fbuf_buf(the_fbuf); assert (page0); npages = ntohs(page0->header.pg_pgcount); if (npages < len / AFSDIR_PAGESIZE) npages = len / AFSDIR_PAGESIZE; if (offset && *offset) { i = *offset / ENTRIESPERPAGE; first_slot = *offset % ENTRIESPERPAGE; assert(i > 0 || first_slot >= 12); } else { i = 0; first_slot = 12; } for (; i < npages; ++i) { DirPage1 *page = getpage (page0, i); for (j = first_slot; j < ENTRIESPERPAGE - 1; ++j) { if (first_slotp (page, j)) { DirEntry *entry = &page->entry[j]; if (entry->flag != AFSDIR_FIRST) continue; fid.Cell = dir.Cell; fid.fid.Volume = dir.fid.Volume; fid.fid.Vnode = ntohl (entry->fid.Vnode); fid.fid.Unique = ntohl (entry->fid.Unique); ret = (*func)(&fid, entry->name, arg); if (ret) { if (ret > 0) j++; /* look at next entry next time */ goto done; } j += additional_entries (entry->name); } } first_slot = 0; } done: if (offset) *offset = i * ENTRIESPERPAGE + j; return 0; }