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 fdir_emptyp (fbuf *dir) { DirPage0 *page0; unsigned npages; page0 = (DirPage0 *)fbuf_buf(dir); assert (page0); npages = ntohs(page0->header.pg_pgcount); return (npages == 1) && (page0->dheader.map[0] == 49); }
int fdir_lookup (fbuf *the_fbuf, const VenusFid *dir, const char *name, VenusFid *file) { DirPage0 *page0; unsigned ind; page0 = (DirPage0 *)fbuf_buf(the_fbuf); assert (page0); ind = find_by_name (page0, name, file, dir); if (ind == 0) return 0; else return ENOENT; }
int fdir_changefid (fbuf *the_fbuf, const char *name, const VenusFid *file) { DirPage0 *page0; int ret; page0 = (DirPage0 *)fbuf_buf(the_fbuf); assert (page0); ret = update_fid_by_name (page0, name, file); if (ret == 0) return 0; else return ENOENT; }
int fdir_mkdir (fbuf *the_fbuf, AFSFid dot, AFSFid dot_dot) { DirPage0 *page0; DirPage1 *page; int ind; int i; int tmp; int ret; ret = create_new_page (&page, the_fbuf); if (ret) return ret; page0 = (DirPage0 *)fbuf_buf(the_fbuf); memset (&page0->dheader, 0, sizeof(page0->dheader)); tmp = ENTRIESPERPAGE - (sizeof(PageHeader) + sizeof(DirHeader)) / sizeof(DirEntry); page0->header.pg_freecount = tmp; page0->dheader.map[0] = tmp; page0->header.pg_pgcount = htons(1); for (i = 0; i < 13; ++i) set_used (page, i); assert (page0->dheader.hash[hashentry(".")] == 0); ind = add_to_page (page0, page, 0, ".", dot, 0); assert (ind >= 0); page0->dheader.hash[hashentry(".")] = htons(ind + 1); assert (page0->dheader.hash[hashentry("..")] == 0); ind = add_to_page (page0, page, 0, "..", dot_dot, 0); assert (ind >= 0); page0->dheader.hash[hashentry("..")] = htons(ind + 1); return 0; }
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 dir_remove_name (FCacheEntry *e, const char *filename, fcache_cache_handle *cache_handle, char *cache_name, size_t cache_name_sz) { int ret; int fd; fbuf fb; struct stat sb; char *buf; char *p; size_t len; struct nnpfs_dirent *dp; struct nnpfs_dirent *last_dp; fcache_extra_file_name (e, cache_name, cache_name_sz); fd = open (cache_name, O_RDWR, 0); if (fd < 0) return errno; fcache_fhget (cache_name, cache_handle); if (fstat (fd, &sb) < 0) { ret = errno; close (fd); return ret; } len = sb.st_size; ret = fbuf_create (&fb, fd, len, FBUF_READ|FBUF_WRITE|FBUF_SHARED); if (ret) { close (fd); return ret; } last_dp = NULL; ret = ENOENT; for (p = buf = fbuf_buf (&fb); p < buf + len; p += dp->d_reclen) { dp = (struct nnpfs_dirent *)p; assert (dp->d_reclen > 0); if (strcmp (filename, dp->d_name) == 0) { if (last_dp != NULL) { size_t off1, off2; unsigned len; /* * d_reclen can be as largest (in worst case) * DIRBLKSIZ, and may not cause the entry to cross a * DIRBLKSIZ boundery. */ len = last_dp->d_reclen + dp->d_reclen; off1 = (char *)last_dp - buf; off2 = off1 + len; off1 /= DIRBLKSIZ; off2 /= DIRBLKSIZ; if (len < DIRBLKSIZ && off1 == off2) last_dp->d_reclen = len; } dp->d_fileno = 0; ret = 0; break; } last_dp = dp; } fbuf_end (&fb); close (fd); return ret; }
int fdir_remove (fbuf *dir, const char *name, AFSFid *fid) { int i; unsigned len = dir->len; DirPage0 *page0; DirPage1 *page; unsigned hash_value; DirEntry *entry = NULL; DirEntry *prev_entry; unsigned pageno; int found; unsigned npages; page0 = (DirPage0 *)fbuf_buf(dir); npages = ntohs(page0->header.pg_pgcount); if (npages < len / AFSDIR_PAGESIZE) npages = len / AFSDIR_PAGESIZE; hash_value = hashentry (name); i = ntohs(page0->dheader.hash[hash_value]); found = i == 0; prev_entry = NULL; while (!found) { entry = getentry (page0, i - 1); if (strcmp (entry->name, name) == 0) { found = TRUE; } else { i = ntohs(entry->next); if (i == 0) found = TRUE; prev_entry = entry; } } if (i == 0) return ENOENT; else { if (fid) { fid->Vnode = ntohl(entry->fid.Vnode); fid->Unique = ntohl(entry->fid.Unique); } if (prev_entry == NULL) page0->dheader.hash[hash_value] = entry->next; else prev_entry->next = entry->next; pageno = (i - 1) / ENTRIESPERPAGE; page = getpage (page0, pageno); remove_from_page (page0, page, pageno, (i - 1) % ENTRIESPERPAGE); if (pageno == npages - 1 && is_page_empty (page0, pageno)) { do { len -= AFSDIR_PAGESIZE; --pageno; --npages; } while(is_page_empty(page0, pageno)); page0->header.pg_pgcount = htons(npages); fbuf_truncate (dir, len); } return 0; } }
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; }