Skip to content

Commit

Permalink
hfsfuse: add directory entries to lookup cache when listing
Browse files Browse the repository at this point in the history
Pre-emptively adds records found when listing directories to hfsfuse's
cache for future lookups. Previously only paths explicitly requested
by open, getattr, etc were included in the cache.

Since getattr is often called on the results of readdir immediately
after, this is in practice multiple times faster for directory listing
or traversing directories with things like `find`.
  • Loading branch information
0x09 committed May 11, 2024
1 parent 16981f9 commit 4217985
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
4 changes: 4 additions & 0 deletions lib/libhfsuser/hfsuser.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ char* hfs_get_path(hfs_volume* vol, hfs_cnid_t cnid) {
return out;
}

void hfs_cache_path(hfs_volume* vol, const char* path, size_t len, hfs_catalog_keyed_record_t* record) {
hfs_record_cache_add(((struct hfs_device*)vol->cbdata)->cache, path, len, record);
}

static inline void* hfs_memdup(const void* ptr, size_t size) {
char* p = malloc(size);
if(!p)
Expand Down
1 change: 1 addition & 0 deletions lib/libhfsuser/hfsuser.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ ssize_t hfs_pathname_to_unix(const hfs_unistr255_t* u16, char* u8);
int hfs_pathname_from_unix(const char* u8, hfs_unistr255_t* u16);

char* hfs_get_path(hfs_volume* vol, hfs_cnid_t cnid);
void hfs_cache_path(hfs_volume*, const char* path, size_t len, hfs_catalog_keyed_record_t*);
int hfs_lookup(hfs_volume* vol, const char* path, hfs_catalog_keyed_record_t* record, hfs_catalog_key_t* key, uint8_t* fork);
void hfs_stat(hfs_volume* vol, hfs_catalog_keyed_record_t* key, struct stat* st, uint8_t fork, struct hfs_decmpfs_header*);
void hfs_serialize_finderinfo(hfs_catalog_keyed_record_t*, char[32]);
Expand Down
31 changes: 27 additions & 4 deletions src/hfsfuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ struct hf_dir {
hfs_catalog_keyed_record_t* records;
hfs_unistr255_t* names;
uint32_t nentries;
char* path;
size_t pathlen;
};

static int hfsfuse_opendir(const char* path, struct fuse_file_info* info) {
Expand All @@ -182,6 +184,17 @@ static int hfsfuse_opendir(const char* path, struct fuse_file_info* info) {
goto end;
d->parent_cnid = key.parent_cnid;

d->pathlen = strlen(path);
if(d->pathlen > 1)
d->pathlen++;
if(!(d->path = malloc(d->pathlen))) {
ret = -ENOMEM;
goto end;
}
if(d->pathlen > 1)
memcpy(d->path,path,d->pathlen-1);
d->path[d->pathlen-1] = '/';

if(hfslib_get_directory_contents(vol,d->dir_record.folder.cnid,&d->records,&d->names,&d->nentries,NULL)) {
ret = -1;
goto end;
Expand Down Expand Up @@ -209,6 +222,7 @@ static int hfsfuse_releasedir(const char* path, struct fuse_file_info* info) {
struct hf_dir* d = (struct hf_dir*)info->fh;
free(d->names);
free(d->records);
free(d->path);
free(d);
return 0;
}
Expand All @@ -235,19 +249,28 @@ static int hfsfuse_readdir(const char* path, void* buf, fuse_fill_dir_t filler,
if(filler(buf, "..", stp, 2))
return 0;
}
char pelem[HFS_NAME_MAX+1];

char* fullpath = malloc(d->pathlen+HFS_NAME_MAX+1);
if(!fullpath)
return -ENOMEM;

memcpy(fullpath,d->path,d->pathlen);
char* pelem = fullpath + d->pathlen;
int ret = 0;
for(off_t i = max(0,offset-2); i < d->nentries; i++) {
int err;
if((err = hfs_pathname_to_unix(d->names+i,pelem)) < 0) {
ret = err;
ssize_t len;
if((len = hfs_pathname_to_unix(d->names+i,pelem)) < 0) {
ret = len;
continue;
}
hfs_cache_path(vol,fullpath,d->pathlen+len,d->records+i);

struct stat st = {0};
hfs_stat(vol,d->records+i,&st,0,NULL);
if(filler(buf,pelem,&st,i+3))
break;
}
free(fullpath);
return min(ret,0);
}

Expand Down

0 comments on commit 4217985

Please sign in to comment.