From: Xavi Hernandez Date: Tue, 9 Apr 2024 08:26:59 +0000 (+0200) Subject: client: fix d_reclen for readdir X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=15774e5d41b55d8cbbc447dc5e2056d849a07d69;p=ceph.git 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 (cherry picked from commit 5ac01659cf8f33457c78546731d694d1e99fcc91) --- diff --git a/src/client/Client.cc b/src/client/Client.cc index a84e69f38f2..bcc6cd20140 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -14,6 +14,7 @@ // unix-ey fs stuff +#include #include #include #include @@ -9226,14 +9227,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;