From 190c7e355d3b4999c7f73016774a10eb16dab600 Mon Sep 17 00:00:00 2001 From: Radoslaw Zarzynski Date: Tue, 27 Jan 2015 23:25:33 +0100 Subject: [PATCH] client: implement support for O_PATH on Linux. Signed-off-by: Radoslaw Zarzynski --- src/client/Client.cc | 44 ++++++++++++++++++++++++++++++++++ src/test/libcephfs/test.cc | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/client/Client.cc b/src/client/Client.cc index 8d5e192ba7cab..adf87a0b9791f 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -5587,6 +5587,10 @@ int Client::fchmod(int fd, mode_t mode) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif struct stat attr; attr.st_mode = mode; return _setattr(f->inode, &attr, CEPH_SETATTR_MODE); @@ -5640,6 +5644,10 @@ int Client::fchown(int fd, int uid, int gid) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif struct stat attr; attr.st_uid = uid; attr.st_gid = gid; @@ -6375,6 +6383,14 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, Fh *fh = NULL; +#if defined(__linux__) + /* When the O_PATH is being specified, others flags than O_DIRECTORY + * and O_NOFOLLOW are ignored. Please refer do_entry_open() function + * in kernel (fs/open.c). */ + if (flags & O_PATH) + flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; +#endif + filepath path(relpath); Inode *in; bool created = false; @@ -6385,7 +6401,11 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; +#if defined(__linux__) + if (r == 0 && in->is_symlink() && (flags & O_NOFOLLOW) && !(flags & O_PATH)) +#else if (r == 0 && in->is_symlink() && (flags & O_NOFOLLOW)) +#endif return -ELOOP; if (r == -ENOENT && (flags & O_CREAT)) { @@ -6700,6 +6720,10 @@ loff_t Client::lseek(int fd, loff_t offset, int whence) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif return _lseek(f, offset, whence); } @@ -6819,6 +6843,10 @@ int Client::read(int fd, char *buf, loff_t size, loff_t offset) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif bufferlist bl; int r = _read(f, offset, size, &bl); ldout(cct, 3) << "read(" << fd << ", " << (void*)buf << ", " << size << ", " << offset << ") = " << r << dendl; @@ -7140,6 +7168,10 @@ int Client::write(int fd, const char *buf, loff_t size, loff_t offset) Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; +#if defined(__linux__) + if (fh->flags & O_PATH) + return -EBADF; +#endif int r = _write(fh, offset, size, buf); ldout(cct, 3) << "write(" << fd << ", \"...\", " << size << ", " << offset << ") = " << r << dendl; return r; @@ -7385,6 +7417,10 @@ int Client::ftruncate(int fd, loff_t length) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif struct stat attr; attr.st_size = length; return _setattr(f->inode, &attr, CEPH_SETATTR_SIZE); @@ -7400,6 +7436,10 @@ int Client::fsync(int fd, bool syncdataonly) Fh *f = get_filehandle(fd); if (!f) return -EBADF; +#if defined(__linux__) + if (f->flags & O_PATH) + return -EBADF; +#endif int r = _fsync(f, syncdataonly); ldout(cct, 3) << "fsync(" << fd << ", " << syncdataonly << ") = " << r << dendl; return r; @@ -9984,6 +10024,10 @@ int Client::fallocate(int fd, int mode, loff_t offset, loff_t length) Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; +#if defined(__linux__) + if (fh->flags & O_PATH) + return -EBADF; +#endif return _fallocate(fh, mode, offset, length); } diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index 00cd36c080e29..a607a1bd8270a 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -22,6 +22,10 @@ #include #include +#ifdef __linux__ +#include +#endif + TEST(LibCephFS, OpenEmptyComponent) { pid_t mypid = getpid(); @@ -650,8 +654,53 @@ TEST(LibCephFS, Fchown) { fd = ceph_open(cmount, test_file, O_RDWR, 0); ASSERT_EQ(fd, -EACCES); + + ceph_shutdown(cmount); +} + +#ifdef __linux__ +TEST(LibCephFS, FlagO_PATH) { + struct ceph_mount_info *cmount; + + ASSERT_EQ(0, ceph_create(&cmount, NULL)); + ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); + ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); + ASSERT_EQ(0, ceph_mount(cmount, NULL)); + + char test_file[PATH_MAX]; + sprintf(test_file, "test_oflag_%d", getpid()); + + int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666); + ASSERT_EQ(-ENOENT, fd); + + fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666); + ASSERT_GT(fd, 0); + ASSERT_EQ(0, ceph_close(cmount, fd)); + + // ok, the file has been created. perform real checks now + fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666); + ASSERT_GT(fd, 0); + + char buf[128]; + ASSERT_EQ(-EBADF, ceph_read(cmount, fd, buf, sizeof(buf), 0)); + ASSERT_EQ(-EBADF, ceph_write(cmount, fd, buf, sizeof(buf), 0)); + + // set perms to readable and writeable only by owner + ASSERT_EQ(-EBADF, ceph_fchmod(cmount, fd, 0600)); + + // change ownership to nobody -- we assume nobody exists and id is always 65534 + ASSERT_EQ(-EBADF, ceph_fchown(cmount, fd, 65534, 65534)); + + // try to sync + ASSERT_EQ(-EBADF, ceph_fsync(cmount, fd, false)); + + struct stat sb; + ASSERT_EQ(0, ceph_fstat(cmount, fd, &sb)); + + ASSERT_EQ(0, ceph_close(cmount, fd)); ceph_shutdown(cmount); } +#endif /* __linux */ TEST(LibCephFS, Symlinks) { struct ceph_mount_info *cmount; -- 2.39.5