From 698c4147fcdf22eb4279b4da9bf55f096e48b55b Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Thu, 12 Mar 2020 14:42:08 -0400 Subject: [PATCH] fix getdent name length calculation --- Makefile | 2 +- libfuse/Makefile | 2 +- libfuse/include/fuse_dirents.h | 14 ++++--- libfuse/include/linux_dirent64.h | 12 ++++++ libfuse/lib/fuse_dirents.c | 72 +++++++++----------------------- src/fuse_readdir_linux.icpp | 16 +++---- src/fuse_readdir_plus_linux.icpp | 16 +++---- src/fuse_readdir_plus_posix.icpp | 27 +++++++++++- src/fuse_readdir_posix.icpp | 27 +++++++++++- 9 files changed, 101 insertions(+), 87 deletions(-) create mode 100644 libfuse/include/linux_dirent64.h diff --git a/Makefile b/Makefile index 5673aebe..ad577f1a 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ USE_XATTR = 1 UGID_USE_RWLOCK = 0 ifeq ($(DEBUG),1) -DEBUG_FLAGS := -g +DEBUG_FLAGS := -O0 -g else DEBUG_FLAGS := endif diff --git a/libfuse/Makefile b/libfuse/Makefile index 01c7e7a4..5157ef17 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -1,7 +1,7 @@ VERSION = 2.9.7-mergerfs_2.29.0 ifeq ($(DEBUG),1) -DEBUG_FLAGS := -g +DEBUG_FLAGS := -O0 -g else DEBUG_FLAGS := endif diff --git a/libfuse/include/fuse_dirents.h b/libfuse/include/fuse_dirents.h index 963960a3..4c0e06d8 100644 --- a/libfuse/include/fuse_dirents.h +++ b/libfuse/include/fuse_dirents.h @@ -25,6 +25,7 @@ extern "C" { #include "fuse_dirent.h" #include "fuse_direntplus.h" #include "fuse_entry.h" +#include "linux_dirent64.h" #include #include @@ -55,20 +56,21 @@ void fuse_dirents_free(fuse_dirents_t *d); void fuse_dirents_reset(fuse_dirents_t *d); int fuse_dirents_add(fuse_dirents_t *d, - const struct dirent *de); + const struct dirent *de, + const uint64_t namelen); int fuse_dirents_add_plus(fuse_dirents_t *d, const struct dirent *de, + const uint64_t namelen, const fuse_entry_t *entry, const struct stat *st); -#ifdef __linux__ -struct linux_dirent64; -int fuse_dirents_add_linux(fuse_dirents_t *d, - const struct linux_dirent64 *de); +int fuse_dirents_add_linux(fuse_dirents_t *d, + const struct linux_dirent64 *de, + const uint64_t namelen); int fuse_dirents_add_linux_plus(fuse_dirents_t *d, const struct linux_dirent64 *de, + const uint64_t namelen, const fuse_entry_t *entry, const struct stat *st); -#endif void *fuse_dirents_find(fuse_dirents_t *d, const uint64_t ino); diff --git a/libfuse/include/linux_dirent64.h b/libfuse/include/linux_dirent64.h new file mode 100644 index 00000000..5ba8e328 --- /dev/null +++ b/libfuse/include/linux_dirent64.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct linux_dirent64 +{ + uint64_t d_ino; + int64_t d_off; + uint16_t d_reclen; + uint8_t d_type; + char d_name[]; +}; diff --git a/libfuse/lib/fuse_dirents.c b/libfuse/lib/fuse_dirents.c index 18b3a4d1..8c8c6157 100644 --- a/libfuse/lib/fuse_dirents.c +++ b/libfuse/lib/fuse_dirents.c @@ -5,6 +5,7 @@ #include "fuse_direntplus.h" #include "fuse_dirents.h" #include "fuse_entry.h" +#include "linux_dirent64.h" #include "stat_utils.h" #include @@ -17,26 +18,6 @@ #define DEFAULT_SIZE (1024 * 16) -static -uint64_t -dirent_exact_namelen(const struct dirent *d_) -{ -#ifdef _D_EXACT_NAMELEN - return _D_EXACT_NAMELEN(d_); -#elif defined _DIRENT_HAVE_D_NAMLEN - return d_->d_namlen; -#else - return strlen(d_->d_name); -#endif -} - -static -uint64_t -dirent_alloc_namelen(const struct dirent *d_) -{ - return (dirent_exact_namelen(d_) + 1); -} - static uint64_t align_uint64_t(uint64_t v_) @@ -254,10 +235,10 @@ fuse_dirents_convert_plus2normal(fuse_dirents_t *d_) int fuse_dirents_add(fuse_dirents_t *d_, - const struct dirent *dirent_) + const struct dirent *dirent_, + const uint64_t namelen_) { uint64_t size; - uint64_t namelen; fuse_dirent_t *d; switch(d_->type) @@ -271,8 +252,7 @@ fuse_dirents_add(fuse_dirents_t *d_, return -EINVAL; } - namelen = dirent_alloc_namelen(dirent_); - size = fuse_dirent_size(namelen); + size = fuse_dirent_size(namelen_); d = fuse_dirents_alloc(d_,size); if(d == NULL) @@ -280,9 +260,9 @@ fuse_dirents_add(fuse_dirents_t *d_, d->ino = dirent_->d_ino; d->off = d_->data_len; - d->namelen = namelen; + d->namelen = namelen_; d->type = dirent_->d_type; - memcpy(d->name,dirent_->d_name,namelen); + memcpy(d->name,dirent_->d_name,namelen_); return 0; } @@ -290,11 +270,11 @@ fuse_dirents_add(fuse_dirents_t *d_, int fuse_dirents_add_plus(fuse_dirents_t *d_, const struct dirent *dirent_, + const uint64_t namelen_, const fuse_entry_t *entry_, const struct stat *st_) { uint64_t size; - uint64_t namelen; fuse_direntplus_t *d; switch(d_->type) @@ -308,8 +288,7 @@ fuse_dirents_add_plus(fuse_dirents_t *d_, break; } - namelen = dirent_alloc_namelen(dirent_); - size = fuse_direntplus_size(namelen); + size = fuse_direntplus_size(namelen_); d = fuse_dirents_alloc(d_,size); if(d == NULL) @@ -317,9 +296,9 @@ fuse_dirents_add_plus(fuse_dirents_t *d_, d->dirent.ino = dirent_->d_ino; d->dirent.off = d_->data_len; - d->dirent.namelen = namelen; + d->dirent.namelen = namelen_; d->dirent.type = dirent_->d_type; - memcpy(d->dirent.name,dirent_->d_name,namelen); + memcpy(d->dirent.name,dirent_->d_name,namelen_); d->entry = *entry_; @@ -328,22 +307,12 @@ fuse_dirents_add_plus(fuse_dirents_t *d_, return 0; } -#ifdef __linux__ -struct linux_dirent64 -{ - uint64_t d_ino; - int64_t d_off; - uint16_t d_reclen; - uint8_t d_type; - char d_name[]; -}; - int fuse_dirents_add_linux(fuse_dirents_t *d_, - const struct linux_dirent64 *dirent_) + const struct linux_dirent64 *dirent_, + const uint64_t namelen_) { uint64_t size; - uint64_t namelen; fuse_dirent_t *d; switch(d_->type) @@ -357,8 +326,7 @@ fuse_dirents_add_linux(fuse_dirents_t *d_, return -EINVAL; } - namelen = (dirent_->d_reclen - offsetof(struct linux_dirent64,d_name)); - size = fuse_dirent_size(namelen); + size = fuse_dirent_size(namelen_); d = fuse_dirents_alloc(d_,size); if(d == NULL) @@ -366,9 +334,9 @@ fuse_dirents_add_linux(fuse_dirents_t *d_, d->ino = dirent_->d_ino; d->off = d_->data_len; - d->namelen = namelen; + d->namelen = namelen_; d->type = dirent_->d_type; - memcpy(d->name,dirent_->d_name,namelen); + memcpy(d->name,dirent_->d_name,namelen_); return 0; } @@ -376,11 +344,11 @@ fuse_dirents_add_linux(fuse_dirents_t *d_, int fuse_dirents_add_linux_plus(fuse_dirents_t *d_, const struct linux_dirent64 *dirent_, + const uint64_t namelen_, const fuse_entry_t *entry_, const struct stat *st_) { uint64_t size; - uint64_t namelen; fuse_direntplus_t *d; switch(d_->type) @@ -394,8 +362,7 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_, break; } - namelen = (dirent_->d_reclen - offsetof(struct linux_dirent64,d_name)); - size = fuse_direntplus_size(namelen); + size = fuse_direntplus_size(namelen_); d = fuse_dirents_alloc(d_,size); if(d == NULL) @@ -403,9 +370,9 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_, d->dirent.ino = dirent_->d_ino; d->dirent.off = d_->data_len; - d->dirent.namelen = namelen; + d->dirent.namelen = namelen_; d->dirent.type = dirent_->d_type; - memcpy(d->dirent.name,dirent_->d_name,namelen); + memcpy(d->dirent.name,dirent_->d_name,namelen_); d->entry = *entry_; @@ -413,7 +380,6 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_, return 0; } -#endif void fuse_dirents_reset(fuse_dirents_t *d_) diff --git a/src/fuse_readdir_linux.icpp b/src/fuse_readdir_linux.icpp index cee408a4..dd950b45 100644 --- a/src/fuse_readdir_linux.icpp +++ b/src/fuse_readdir_linux.icpp @@ -26,6 +26,7 @@ #include "fs_inode.hpp" #include "fs_path.hpp" #include "hashset.hpp" +#include "linux_dirent64.h" #include "mempools.hpp" #include "rwlock.hpp" #include "ugid.hpp" @@ -42,15 +43,6 @@ using std::string; using std::vector; -struct linux_dirent64 -{ - uint64_t d_ino; - int64_t d_off; - uint16_t d_reclen; - uint8_t d_type; - char d_name[]; -}; - namespace l { static @@ -84,6 +76,7 @@ namespace l char *buf; HashSet names; string basepath; + uint64_t namelen; struct linux_dirent64 *d; buf = (char*)g_DENTS_BUF_POOL.alloc(); @@ -116,14 +109,15 @@ namespace l for(int64_t pos = 0; pos < nread; pos += d->d_reclen) { d = (struct linux_dirent64*)(buf + pos); + namelen = (strlen(d->d_name) + 1); - rv = names.put(d->d_name); + rv = names.put(d->d_name,namelen); if(rv == 0) continue; d->d_ino = fs::inode::recompute(d->d_ino,dev); - rv = fuse_dirents_add_linux(buf_,d); + rv = fuse_dirents_add_linux(buf_,d,namelen); if(rv) return close_free_ret_enomem(dirfd,buf); } diff --git a/src/fuse_readdir_plus_linux.icpp b/src/fuse_readdir_plus_linux.icpp index 5d6d3bec..14f50e6d 100644 --- a/src/fuse_readdir_plus_linux.icpp +++ b/src/fuse_readdir_plus_linux.icpp @@ -27,6 +27,7 @@ #include "fs_inode.hpp" #include "fs_path.hpp" #include "hashset.hpp" +#include "linux_dirent64.h" #include "mempools.hpp" #include "rwlock.hpp" #include "ugid.hpp" @@ -43,15 +44,6 @@ using std::string; using std::vector; -struct linux_dirent64 -{ - uint64_t d_ino; - int64_t d_off; - uint16_t d_reclen; - uint8_t d_type; - char d_name[]; -}; - namespace l { static @@ -84,6 +76,7 @@ namespace l char *buf; HashSet names; string basepath; + uint64_t namelen; struct stat st; fuse_entry_t entry; struct linux_dirent64 *d; @@ -122,8 +115,9 @@ namespace l for(int64_t pos = 0; pos < nread; pos += d->d_reclen) { d = (struct linux_dirent64*)(buf + pos); + namelen = (strlen(d->d_name) + 1); - rv = names.put(d->d_name); + rv = names.put(d->d_name,namelen); if(rv == 0) continue; @@ -134,7 +128,7 @@ namespace l d->d_ino = fs::inode::recompute(d->d_ino,dev); st.st_ino = d->d_ino; - rv = fuse_dirents_add_linux_plus(buf_,d,&entry,&st); + rv = fuse_dirents_add_linux_plus(buf_,d,namelen,&entry,&st); if(rv) return close_free_ret_enomem(dirfd,buf); } diff --git a/src/fuse_readdir_plus_posix.icpp b/src/fuse_readdir_plus_posix.icpp index cd1afc5a..57e72f09 100644 --- a/src/fuse_readdir_plus_posix.icpp +++ b/src/fuse_readdir_plus_posix.icpp @@ -45,6 +45,26 @@ using std::vector; namespace l { + static + uint64_t + dirent_exact_namelen(const struct dirent *d_) + { +#ifdef _D_EXACT_NAMLEN + return _D_EXACT_NAMLEN(d_); +#elif defined _DIRENT_HAVE_D_NAMLEN + return d_->d_namlen; +#else + return strlen(d_->d_name); +#endif + } + + static + uint64_t + dirent_alloc_namelen(const struct dirent *d_) + { + return (dirent_exact_namelen(d_) + 1); + } + static int readdir_plus(const Branches &branches_, @@ -55,6 +75,7 @@ namespace l HashSet names; string basepath; struct stat st; + uint64_t namelen; fuse_entry_t entry; entry.nodeid = 0; @@ -83,7 +104,9 @@ namespace l rv = 0; for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh)) { - rv = names.put(de->d_name); + namelen = l::dirent_alloc_namelen(de); + + rv = names.put(de->d_name,namelen); if(rv == 0) continue; @@ -94,7 +117,7 @@ namespace l de->d_ino = fs::inode::recompute(de->d_ino,dev); st.st_ino = de->d_ino; - rv = fuse_dirents_add_plus(buf_,de,&entry,&st); + rv = fuse_dirents_add_plus(buf_,de,namelen,&entry,&st); if(rv) return (fs::closedir(dh),-ENOMEM); } diff --git a/src/fuse_readdir_posix.icpp b/src/fuse_readdir_posix.icpp index a0c4f465..06dae26e 100644 --- a/src/fuse_readdir_posix.icpp +++ b/src/fuse_readdir_posix.icpp @@ -44,6 +44,26 @@ using std::vector; namespace l { + static + uint64_t + dirent_exact_namelen(const struct dirent *d_) + { +#ifdef _D_EXACT_NAMLEN + return _D_EXACT_NAMLEN(d_); +#elif defined _DIRENT_HAVE_D_NAMLEN + return d_->d_namlen; +#else + return strlen(d_->d_name); +#endif + } + + static + uint64_t + dirent_alloc_namelen(const struct dirent *d_) + { + return (dirent_exact_namelen(d_) + 1); + } + static int readdir(const Branches &branches_, @@ -53,6 +73,7 @@ namespace l dev_t dev; HashSet names; string basepath; + uint64_t namelen; for(size_t i = 0, ei = branches_.size(); i != ei; i++) { @@ -74,13 +95,15 @@ namespace l rv = 0; for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh)) { - rv = names.put(de->d_name); + namelen = l::dirent_alloc_namelen(de); + + rv = names.put(de->d_name,namelen); if(rv == 0) continue; de->d_ino = fs::inode::recompute(de->d_ino,dev); - rv = fuse_dirents_add(buf_,de); + rv = fuse_dirents_add(buf_,de,namelen); if(rv) return (fs::closedir(dh),-ENOMEM); }