Skip to content

Commit 2060e18

Browse files
authored
Merge pull request ceph#59936 from anoopcs9/client-chown-statx-fixes
client: Handle empty pathnames for `ceph_chownat()` and `ceph_statxat()`
2 parents 744eb5c + edd7fe7 commit 2060e18

File tree

5 files changed

+72
-11
lines changed

5 files changed

+72
-11
lines changed

src/client/Client.cc

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8907,7 +8907,6 @@ int Client::chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid
89078907
tout(cct) << new_gid << std::endl;
89088908
tout(cct) << flags << std::endl;
89098909

8910-
filepath path(relpath);
89118910
InodeRef in;
89128911
InodeRef dirinode;
89138912

@@ -8917,10 +8916,24 @@ int Client::chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid
89178916
return r;
89188917
}
89198918

8920-
r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
8921-
if (r < 0) {
8922-
return r;
8919+
if (!strcmp(relpath, "")) {
8920+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
8921+
if (flags & AT_EMPTY_PATH) {
8922+
in = dirinode;
8923+
goto out;
8924+
}
8925+
#endif
8926+
return -CEPHFS_ENOENT;
8927+
} else {
8928+
filepath path(relpath);
8929+
r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
8930+
if (r < 0) {
8931+
return r;
8932+
}
89238933
}
8934+
8935+
out:
8936+
89248937
struct stat attr;
89258938
attr.st_uid = new_uid;
89268939
attr.st_gid = new_gid;
@@ -12230,19 +12243,32 @@ int Client::statxat(int dirfd, const char *relpath,
1223012243

1223112244
unsigned mask = statx_to_mask(flags, want);
1223212245

12246+
InodeRef in;
1223312247
InodeRef dirinode;
1223412248
std::scoped_lock lock(client_lock);
1223512249
int r = get_fd_inode(dirfd, &dirinode);
1223612250
if (r < 0) {
1223712251
return r;
1223812252
}
1223912253

12240-
InodeRef in;
12241-
filepath path(relpath);
12242-
r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), mask, dirinode);
12243-
if (r < 0) {
12244-
return r;
12254+
if (!strcmp(relpath, "")) {
12255+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
12256+
if (flags & AT_EMPTY_PATH) {
12257+
in = dirinode;
12258+
goto out;
12259+
}
12260+
#endif
12261+
return -CEPHFS_ENOENT;
12262+
} else {
12263+
filepath path(relpath);
12264+
r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), mask, dirinode);
12265+
if (r < 0) {
12266+
return r;
12267+
}
1224512268
}
12269+
12270+
out:
12271+
1224612272
r = _getattr(in, mask, perms);
1224712273
if (r < 0) {
1224812274
ldout(cct, 3) << __func__ << " exit on error!" << dendl;

src/include/cephfs/ceph_ll_client.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ struct ceph_statx {
110110
* others in the future, we disallow setting any that aren't recognized.
111111
*/
112112
#define CEPH_REQ_FLAG_MASK (AT_SYMLINK_NOFOLLOW|AT_STATX_DONT_SYNC)
113+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
114+
#define CEPH_AT_EMPTY_PATH (CEPH_REQ_FLAG_MASK|AT_EMPTY_PATH)
115+
#endif
113116

114117
/* fallocate mode flags */
115118
#ifndef FALLOC_FL_KEEP_SIZE

src/include/cephfs/libcephfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
937937
* @param relpath to the file/directory to get statistics of
938938
* @param stx the ceph_statx struct that will be filled in with the file's statistics.
939939
* @param want bitfield of CEPH_STATX_* flags showing designed attributes
940-
* @param flags bitfield that can be used to set AT_* modifier flags (AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC, AT_STATX_DONT_SYNC and AT_SYMLINK_NOFOLLOW)
940+
* @param flags bitfield that can be used to set AT_* modifier flags (AT_STATX_DONT_SYNC, AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH)
941941
* @returns 0 on success or negative error code on failure.
942942
*/
943943
int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
@@ -1104,7 +1104,7 @@ int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int g
11041104
* @param relpath the relpath of the file/directory to change the ownership of.
11051105
* @param uid the user id to set on the file/directory.
11061106
* @param gid the group id to set on the file/directory.
1107-
* @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW)
1107+
* @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH)
11081108
* @returns 0 on success or negative error code on failure.
11091109
*/
11101110
int ceph_chownat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,

src/libcephfs.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,11 @@ extern "C" int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const cha
982982
{
983983
if (!cmount->is_mounted())
984984
return -CEPHFS_ENOTCONN;
985+
#ifdef CEPH_AT_EMPTY_PATH
986+
if (flags & ~CEPH_AT_EMPTY_PATH)
987+
#else
985988
if (flags & ~CEPH_REQ_FLAG_MASK)
989+
#endif
986990
return -CEPHFS_EINVAL;
987991
return cmount->get_client()->statxat(dirfd, relpath, stx, cmount->default_perms,
988992
want, flags);

src/test/libcephfs/test.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,13 +2706,34 @@ TEST(LibCephFS, Statxat) {
27062706
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
27072707
ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_2, &stx, 0, 0), 0);
27082708
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2709+
// test relative to root with empty relpath
2710+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
2711+
int dir_fd = ceph_openat(cmount, fd, dir_name, O_DIRECTORY | O_RDONLY, 0);
2712+
ASSERT_LE(0, dir_fd);
2713+
ASSERT_EQ(ceph_statxat(cmount, dir_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
2714+
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
2715+
ASSERT_EQ(0, ceph_close(cmount, dir_fd));
2716+
int file_fd = ceph_openat(cmount, fd, rel_file_name_2, O_RDONLY, 0);
2717+
ASSERT_LE(0, file_fd);
2718+
ASSERT_EQ(ceph_statxat(cmount, file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
2719+
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2720+
ASSERT_EQ(0, ceph_close(cmount, file_fd));
2721+
#endif
27092722
ASSERT_EQ(0, ceph_close(cmount, fd));
27102723

27112724
// test relative to dir
27122725
fd = ceph_open(cmount, dir_path, O_DIRECTORY | O_RDONLY, 0);
27132726
ASSERT_LE(0, fd);
27142727
ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_1, &stx, 0, 0), 0);
27152728
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2729+
// test relative to dir with empty relpath
2730+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
2731+
int rel_file_fd = ceph_openat(cmount, fd, rel_file_name_1, O_RDONLY, 0);
2732+
ASSERT_LE(0, rel_file_fd);
2733+
ASSERT_EQ(ceph_statxat(cmount, rel_file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
2734+
ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
2735+
ASSERT_EQ(0, ceph_close(cmount, rel_file_fd));
2736+
#endif
27162737

27172738
// delete the dirtree, recreate and verify
27182739
ASSERT_EQ(0, ceph_unlink(cmount, file_path));
@@ -3265,6 +3286,13 @@ TEST(LibCephFS, Chownat) {
32653286
// change ownership to nobody -- we assume nobody exists and id is always 65534
32663287
ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
32673288
ASSERT_EQ(ceph_chownat(cmount, fd, rel_file_path, 65534, 65534, 0), 0);
3289+
// change relative fd ownership with AT_EMPTY_PATH
3290+
#if defined(__linux__) && defined(AT_EMPTY_PATH)
3291+
int file_fd = ceph_openat(cmount, fd, rel_file_path, O_RDONLY, 0);
3292+
ASSERT_LE(0, file_fd);
3293+
ASSERT_EQ(ceph_chownat(cmount, file_fd, "", 65534, 65534, AT_EMPTY_PATH), 0);
3294+
ceph_close(cmount, file_fd);
3295+
#endif
32683296
ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
32693297
ceph_close(cmount, fd);
32703298

0 commit comments

Comments
 (0)