From 439add6ff7db90ed0597611582354a7e938db5f4 Mon Sep 17 00:00:00 2001 From: Lucian Petrut Date: Fri, 26 Feb 2021 08:32:38 +0000 Subject: [PATCH] cephfs: add ceph_may_delete function We're adding a new libcephfs function: ceph_may_delete. It checks if the mount permissions allow deleting a file or directory, without actually deleting it. This will allow us to drop the redundant permission checks at ceph-dokan level, saving about 1500 LOC. Note that the "DeleteFile" Dokan callback expects us to say if a delete operation is allowed. The "Cleanup" callback is supposed to perform the actual file or directory deletion. Signed-off-by: Lucian Petrut --- src/client/Client.cc | 25 +++++++++++++++++++++++++ src/client/Client.h | 1 + src/include/cephfs/libcephfs.h | 10 ++++++++++ src/libcephfs.cc | 7 +++++++ 4 files changed, 43 insertions(+) diff --git a/src/client/Client.cc b/src/client/Client.cc index 4b5aec4b3efb7..b7e5fca981c9f 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -5771,6 +5771,31 @@ out: return r; } +int Client::may_delete(const char *relpath, const UserPerm& perms) { + ldout(cct, 20) << __func__ << " " << relpath << "; " << perms << dendl; + + RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); + if (!mref_reader.is_state_satisfied()) + return -ENOTCONN; + + filepath path(relpath); + string name = path.last_dentry(); + path.pop_dentry(); + InodeRef dir; + + std::scoped_lock lock(client_lock); + int r = path_walk(path, &dir, perms); + if (r < 0) + return r; + if (cct->_conf->client_permissions) { + int r = may_delete(dir.get(), name.c_str(), perms); + if (r < 0) + return r; + } + + return 0; +} + int Client::may_hardlink(Inode *in, const UserPerm& perms) { ldout(cct, 20) << __func__ << " " << *in << "; " << perms << dendl; diff --git a/src/client/Client.h b/src/client/Client.h index 401d2fefaadd7..40ab802899bea 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -369,6 +369,7 @@ public: loff_t telldir(dir_result_t *dirp); void seekdir(dir_result_t *dirp, loff_t offset); + int may_delete(const char *relpath, const UserPerm& perms); int link(const char *existing, const char *newname, const UserPerm& perm, std::string alternate_name=""); int unlink(const char *path, const UserPerm& perm); int rename(const char *from, const char *to, const UserPerm& perm, std::string alternate_name=""); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index d3dbb2f84297d..6466da6177f92 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -746,6 +746,16 @@ int ceph_symlink(struct ceph_mount_info *cmount, const char *existing, const cha * @{ */ + +/** + * Checks if deleting a file, link or directory is allowed. + * + * @param cmount the ceph mount handle to use. + * @param path the path of the file, link or directory. + * @returns 0 on success or negative error code on failure. + */ +int ceph_may_delete(struct ceph_mount_info *cmount, const char *path); + /** * Removes a file, link, or symbolic link. If the file/link has multiple links to it, the * file will not disappear from the namespace until all references to it are removed. diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 806ad7a0a994e..948d80442f8f5 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -706,6 +706,13 @@ extern "C" void ceph_seekdir(struct ceph_mount_info *cmount, struct ceph_dir_res cmount->get_client()->seekdir(reinterpret_cast(dirp), offset); } +extern "C" int ceph_may_delete(struct ceph_mount_info *cmount, const char *path) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->may_delete(path, cmount->default_perms); +} + extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing, const char *newname) { -- 2.39.5