From 5ac01659cf8f33457c78546731d694d1e99fcc91 Mon Sep 17 00:00:00 2001 From: Xavi Hernandez Date: Tue, 9 Apr 2024 10:26:59 +0200 Subject: [PATCH] client: fix d_reclen for readdir Based on the man page of readdir(3), the d_reclen field should contain the total size of the record, which varies depending on the length of the returned name. However, the previous implementation was returning a hardcoded '1' in all cases. This patch computes the right size of the record and returns it. Fixes: https://tracker.ceph.com/issues/65389 Signed-off-by: Xavi Hernandez --- src/client/Client.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 8af860634a6..e208cf76675 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -14,6 +14,7 @@ // unix-ey fs stuff +#include #include #include #include @@ -9275,14 +9276,19 @@ void Client::seekdir(dir_result_t *dirp, loff_t offset) //}; void Client::fill_dirent(struct dirent *de, const char *name, int type, uint64_t ino, loff_t next_off) { - strncpy(de->d_name, name, 255); - de->d_name[255] = '\0'; + size_t len = strlen(name); + len = std::min(len, (size_t)255); + memcpy(de->d_name, name, len); + de->d_name[len] = '\0'; #if !defined(__CYGWIN__) && !(defined(_WIN32)) de->d_ino = ino; #if !defined(__APPLE__) && !defined(__FreeBSD__) de->d_off = next_off; #endif - de->d_reclen = 1; + // Calculate the real used size of the record + len = (uintptr_t)&de->d_name[len] - (uintptr_t)de + 1; + // The record size must be a multiple of the alignment of 'struct dirent' + de->d_reclen = (len + alignof(struct dirent) - 1) & ~(alignof(struct dirent) - 1); de->d_type = IFTODT(type); ldout(cct, 10) << __func__ << " '" << de->d_name << "' -> " << inodeno_t(de->d_ino) << " type " << (int)de->d_type << " w/ next_off " << hex << next_off << dec << dendl; -- 2.39.5