From 4217985fb4bb439692fc83fecd7bfb9d23280f39 Mon Sep 17 00:00:00 2001 From: tab Date: Sat, 11 May 2024 17:41:36 -0400 Subject: [PATCH] hfsfuse: add directory entries to lookup cache when listing 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`. --- lib/libhfsuser/hfsuser.c | 4 ++++ lib/libhfsuser/hfsuser.h | 1 + src/hfsfuse.c | 31 +++++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/libhfsuser/hfsuser.c b/lib/libhfsuser/hfsuser.c index 8f3a63c..c36ae90 100644 --- a/lib/libhfsuser/hfsuser.c +++ b/lib/libhfsuser/hfsuser.c @@ -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) diff --git a/lib/libhfsuser/hfsuser.h b/lib/libhfsuser/hfsuser.h index 448df94..e54dedb 100644 --- a/lib/libhfsuser/hfsuser.h +++ b/lib/libhfsuser/hfsuser.h @@ -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]); diff --git a/src/hfsfuse.c b/src/hfsfuse.c index 9a62cc7..41aeb7c 100644 --- a/src/hfsfuse.c +++ b/src/hfsfuse.c @@ -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) { @@ -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; @@ -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; } @@ -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); }