// -------------
+int Client::get_fd_inode(int fd, InodeRef *in) {
+ int r = 0;
+ if (fd == CEPHFS_AT_FDCWD) {
+ *in = cwd;
+ } else {
+ Fh *f = get_filehandle(fd);
+ if (!f) {
+ r = -CEPHFS_EBADF;
+ } else {
+ *in = f->inode;
+ }
+ }
+ return r;
+}
+
dir_result_t::dir_result_t(Inode *in, const UserPerm& perms)
: inode(in), offset(0), next_offset(2),
release_count(0), ordered_count(0), cache_index(0), start_shared_gen(0),
}
int Client::path_walk(const filepath& origpath, InodeRef *end,
- const UserPerm& perms, bool followsym, int mask)
+ const UserPerm& perms, bool followsym, int mask, InodeRef dirinode)
{
walk_dentry_result wdr;
- int rc = path_walk(origpath, &wdr, perms, followsym, mask);
+ int rc = path_walk(origpath, &wdr, perms, followsym, mask, dirinode);
*end = std::move(wdr.in);
return rc;
}
-int Client::path_walk(const filepath& origpath, walk_dentry_result* result, const UserPerm& perms, bool followsym, int mask)
+int Client::path_walk(const filepath& origpath, walk_dentry_result* result, const UserPerm& perms,
+ bool followsym, int mask, InodeRef dirinode)
{
filepath path = origpath;
InodeRef cur;
std::string alternate_name;
if (origpath.absolute())
cur = root;
- else
+ else if (!dirinode)
cur = cwd;
+ else {
+ cur = dirinode;
+ }
ceph_assert(cur);
+ ldout(cct, 20) << __func__ << " cur=" << *cur << dendl;
ldout(cct, 10) << __func__ << " " << path << dendl;
int symlinks = 0;
return _unlink(dir.get(), name.c_str(), perm);
}
+int Client::unlinkat(int dirfd, const char *relpath, int flags, const UserPerm& perm)
+{
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << flags << std::endl;
+
+ if (std::string(relpath) == "/") {
+ return flags & AT_REMOVEDIR ? -CEPHFS_EBUSY : -CEPHFS_EISDIR;
+ }
+
+ filepath path(relpath);
+ string name = path.last_dentry();
+ path.pop_dentry();
+ InodeRef dir;
+
+ std::scoped_lock lock(client_lock);
+
+ InodeRef dirinode;
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ r = path_walk(path, &dir, perm, true, 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ if (cct->_conf->client_permissions) {
+ r = may_delete(dir.get(), name.c_str(), perm);
+ if (r < 0) {
+ return r;
+ }
+ }
+ if (flags & AT_REMOVEDIR) {
+ r = _rmdir(dir.get(), name.c_str(), perm);
+ } else {
+ r = _unlink(dir.get(), name.c_str(), perm);
+ }
+ return r;
+}
+
int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm, std::string alternate_name)
{
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
return _mkdir(dir.get(), name.c_str(), mode, perm, 0, {}, std::move(alternate_name));
}
+int Client::mkdirat(int dirfd, const char *relpath, mode_t mode, const UserPerm& perm,
+ std::string alternate_name)
+{
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied())
+ return -CEPHFS_ENOTCONN;
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << mode << std::endl;
+ ldout(cct, 10) << __func__ << ": " << relpath << dendl;
+
+ if (std::string(relpath) == "/") {
+ return -CEPHFS_EEXIST;
+ }
+
+ filepath path(relpath);
+ string name = path.last_dentry();
+ path.pop_dentry();
+ InodeRef dir;
+
+ std::scoped_lock lock(client_lock);
+
+ InodeRef dirinode;
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ r = path_walk(path, &dir, perm, true, 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ if (cct->_conf->client_permissions) {
+ r = may_create(dir.get(), perm);
+ if (r < 0) {
+ return r;
+ }
+ }
+ return _mkdir(dir.get(), name.c_str(), mode, perm, 0, {}, std::move(alternate_name));
+}
+
int Client::mkdirs(const char *relpath, mode_t mode, const UserPerm& perms)
{
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
return _symlink(dir.get(), name.c_str(), target, perms, std::move(alternate_name));
}
+int Client::symlinkat(const char *target, int dirfd, const char *relpath, const UserPerm& perms,
+ std::string alternate_name)
+{
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << target << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+
+ if (std::string(relpath) == "/") {
+ return -CEPHFS_EEXIST;
+ }
+
+ filepath path(relpath);
+ string name = path.last_dentry();
+ path.pop_dentry();
+ InodeRef dir;
+
+ std::scoped_lock lock(client_lock);
+
+ InodeRef dirinode;
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+ r = path_walk(path, &dir, perms, true, 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ if (cct->_conf->client_permissions) {
+ int r = may_create(dir.get(), perms);
+ if (r < 0) {
+ return r;
+ }
+ }
+ return _symlink(dir.get(), name.c_str(), target, perms, std::move(alternate_name));
+}
+
int Client::readlink(const char *relpath, char *buf, loff_t size, const UserPerm& perms)
{
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
return _readlink(in.get(), buf, size);
}
+int Client::readlinkat(int dirfd, const char *relpath, char *buf, loff_t size, const UserPerm& perms) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+
+ InodeRef dirinode;
+ std::scoped_lock lock(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ InodeRef in;
+ filepath path(relpath);
+ r = path_walk(path, &in, perms, false, 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ return _readlink(in.get(), buf, size);
+}
+
int Client::_readlink(Inode *in, char *buf, size_t size)
{
if (!in->is_symlink())
return _setattr(f->inode, &attr, CEPH_SETATTR_MODE, perms);
}
+int Client::chmodat(int dirfd, const char *relpath, mode_t mode, int flags,
+ const UserPerm& perms) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << mode << std::endl;
+ tout(cct) << flags << std::endl;
+
+ filepath path(relpath);
+ InodeRef in;
+ InodeRef dirinode;
+
+ std::scoped_lock lock(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ struct stat attr;
+ attr.st_mode = mode;
+ return _setattr(in, &attr, CEPH_SETATTR_MODE, perms);
+}
+
int Client::lchmod(const char *relpath, mode_t mode, const UserPerm& perms)
{
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
return _setattr(in, &attr, mask, perms);
}
+int Client::chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid,
+ int flags, const UserPerm& perms) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << new_uid << std::endl;
+ tout(cct) << new_gid << std::endl;
+ tout(cct) << flags << std::endl;
+
+ filepath path(relpath);
+ InodeRef in;
+ InodeRef dirinode;
+
+ std::scoped_lock lock(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ struct stat attr;
+ attr.st_uid = new_uid;
+ attr.st_gid = new_gid;
+ return _setattr(in, &attr, CEPH_SETATTR_UID|CEPH_SETATTR_GID, perms);
+}
+
static void attr_set_atime_and_mtime(struct stat *attr,
const utime_t &atime,
const utime_t &mtime)
return _setattr(f->inode, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME, perms);
}
+int Client::utimensat(int dirfd, const char *relpath, struct timespec times[2], int flags,
+ const UserPerm& perms) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_nsec
+ << std::endl;
+ tout(cct) << "mtime: " << times[1].tv_sec << "." << times[1].tv_nsec
+ << std::endl;
+ tout(cct) << flags << std::endl;
+
+ filepath path(relpath);
+ InodeRef in;
+ InodeRef dirinode;
+
+ std::scoped_lock lock(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+#if defined(__linux__) && defined(O_PATH)
+ if (flags & O_PATH) {
+ return -CEPHFS_EBADF;
+ }
+#endif
+
+ r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), 0, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ struct stat attr;
+ utime_t atime(times[0]);
+ utime_t mtime(times[1]);
+
+ attr_set_atime_and_mtime(&attr, atime, mtime);
+ return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME, perms);
+}
+
int Client::flock(int fd, int operation, uint64_t owner)
{
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
return r;
}
+int Client::fdopendir(int dirfd, dir_result_t **dirpp, const UserPerm &perms) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << std::endl;
+ tout(cct) << dirfd << std::endl;
+
+ InodeRef dirinode;
+ std::scoped_lock locker(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ if (cct->_conf->client_permissions) {
+ r = may_open(dirinode.get(), O_RDONLY, perms);
+ if (r < 0) {
+ return r;
+ }
+ }
+ r = _opendir(dirinode.get(), dirpp, perms);
+ /* if ENOTDIR, dirpp will be an uninitialized point and it's very dangerous to access its value */
+ if (r != -CEPHFS_ENOTDIR) {
+ tout(cct) << (uintptr_t)*dirpp << std::endl;
+ }
+ return r;
+}
+
int Client::_opendir(Inode *in, dir_result_t **dirpp, const UserPerm& perms)
{
if (!in->is_dir())
/****** file i/o **********/
-int Client::open(const char *relpath, int flags, const UserPerm& perms,
- mode_t mode, int stripe_unit, int stripe_count,
- int object_size, const char *data_pool, std::string alternate_name)
-{
- RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
- if (!mref_reader.is_state_satisfied())
- return -CEPHFS_ENOTCONN;
+// common parts for open and openat. call with client_lock locked.
+int Client::create_and_open(std::optional<int> dirfd, const char *relpath, int flags,
+ const UserPerm& perms, mode_t mode, int stripe_unit,
+ int stripe_count, int object_size, const char *data_pool,
+ std::string alternate_name) {
+ ceph_assert(ceph_mutex_is_locked(client_lock));
int cflags = ceph_flags_sys2wire(flags);
-
- ldout(cct, 3) << "open enter(" << relpath << ", " << cflags << "," << mode << ")" << dendl;
- tout(cct) << "open" << std::endl;
- tout(cct) << relpath << std::endl;
tout(cct) << cflags << std::endl;
Fh *fh = NULL;
bool followsym = !((flags & O_NOFOLLOW) || ((flags & O_CREAT) && (flags & O_EXCL)));
int mask = ceph_caps_for_mode(ceph_flags_to_mode(cflags));
- std::scoped_lock lock(client_lock);
- int r = path_walk(path, &in, perms, followsym, mask);
+ InodeRef dirinode = nullptr;
+ if (dirfd) {
+ int r = get_fd_inode(*dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+ }
+ int r = path_walk(path, &in, perms, followsym, mask, dirinode);
if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL))
return -CEPHFS_EEXIST;
#if defined(__linux__) && defined(O_PATH)
if (r == 0 && in->is_symlink() && (flags & O_NOFOLLOW) && !(flags & O_PATH))
#else
- if (r == 0 && in->is_symlink() && (flags & O_NOFOLLOW))
+ if (r == 0 && in->is_symlink() && (flags & O_NOFOLLOW))
#endif
return -CEPHFS_ELOOP;
dirpath.pop_dentry();
InodeRef dir;
r = path_walk(dirpath, &dir, perms, true,
- cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0);
- if (r < 0)
+ cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0, dirinode);
+ if (r < 0) {
goto out;
+ }
if (cct->_conf->client_permissions) {
r = may_create(dir.get(), perms);
if (r < 0)
- goto out;
+ goto out;
}
r = _create(dir.get(), dname.c_str(), flags, mode, &in, &fh, stripe_unit,
stripe_count, object_size, data_pool, &created, perms,
if (cct->_conf->client_permissions) {
r = may_open(in.get(), flags, perms);
if (r < 0)
- goto out;
+ goto out;
}
}
}
out:
+ return r;
+}
+
+int Client::open(const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode, int stripe_unit, int stripe_count,
+ int object_size, const char *data_pool, std::string alternate_name)
+{
+ return openat(CEPHFS_AT_FDCWD, relpath, flags, perms, mode, stripe_unit,
+ stripe_count, object_size, data_pool, alternate_name);
+}
+
+int Client::_openat(int dirfd, const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode, std::string alternate_name) {
+ return create_and_open(dirfd, relpath, flags, perms, mode, 0, 0, 0, NULL, alternate_name);
+}
+
+int Client::openat(int dirfd, const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode, int stripe_unit, int stripe_count, int object_size,
+ const char *data_pool, std::string alternate_name) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ ldout(cct, 3) << "openat enter(" << relpath << ")" << dendl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+ tout(cct) << flags << std::endl;
+ tout(cct) << mode << std::endl;
+
+ std::scoped_lock locker(client_lock);
+ int r = create_and_open(dirfd, relpath, flags, perms, mode, stripe_unit, stripe_count,
+ object_size, data_pool, alternate_name);
+
tout(cct) << r << std::endl;
- ldout(cct, 3) << "open exit(" << path << ", " << cflags << ") = " << r << dendl;
+ ldout(cct, 3) << "openat exit(" << relpath << ")" << dendl;
return r;
}
return ret;
}
-int Client::close(int fd)
+int Client::_close(int fd)
{
- RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
- if (!mref_reader.is_state_satisfied())
- return -CEPHFS_ENOTCONN;
-
ldout(cct, 3) << "close enter(" << fd << ")" << dendl;
tout(cct) << "close" << std::endl;
tout(cct) << fd << std::endl;
- std::scoped_lock lock(client_lock);
Fh *fh = get_filehandle(fd);
if (!fh)
return -CEPHFS_EBADF;
return err;
}
+int Client::close(int fd) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied())
+ return -CEPHFS_ENOTCONN;
+
+ std::scoped_lock lock(client_lock);
+ return _close(fd);
+}
// ------------
// read, write
return r;
}
+int Client::statxat(int dirfd, const char *relpath,
+ struct ceph_statx *stx, const UserPerm& perms,
+ unsigned int want, unsigned int flags) {
+ RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+ if (!mref_reader.is_state_satisfied()) {
+ return -CEPHFS_ENOTCONN;
+ }
+
+ tout(cct) << __func__ << " flags " << hex << flags << " want " << want << dec << std::endl;
+ tout(cct) << dirfd << std::endl;
+ tout(cct) << relpath << std::endl;
+
+ unsigned mask = statx_to_mask(flags, want);
+
+ InodeRef dirinode;
+ std::scoped_lock lock(client_lock);
+ int r = get_fd_inode(dirfd, &dirinode);
+ if (r < 0) {
+ return r;
+ }
+
+ InodeRef in;
+ filepath path(relpath);
+ r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), mask, dirinode);
+ if (r < 0) {
+ return r;
+ }
+ r = _getattr(in, mask, perms);
+ if (r < 0) {
+ ldout(cct, 3) << __func__ << " exit on error!" << dendl;
+ return r;
+ }
+
+ fill_statx(in, mask, stx);
+ ldout(cct, 3) << __func__ << " dirfd" << dirfd << ", r= " << r << dendl;
+ return r;
+}
+
// not written yet, but i want to link!
int Client::chdir(const char *relpath, std::string &new_cwd,
// namespace ops
int opendir(const char *name, dir_result_t **dirpp, const UserPerm& perms);
+ int fdopendir(int dirfd, dir_result_t **dirpp, const UserPerm& perms);
int closedir(dir_result_t *dirp);
/**
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 unlinkat(int dirfd, const char *relpath, int flags, const UserPerm& perm);
int rename(const char *from, const char *to, const UserPerm& perm, std::string alternate_name="");
// dirs
int mkdir(const char *path, mode_t mode, const UserPerm& perm, std::string alternate_name="");
+ int mkdirat(int dirfd, const char *relpath, mode_t mode, const UserPerm& perm,
+ std::string alternate_name="");
int mkdirs(const char *path, mode_t mode, const UserPerm& perms);
int rmdir(const char *path, const UserPerm& perms);
// symlinks
int readlink(const char *path, char *buf, loff_t size, const UserPerm& perms);
+ int readlinkat(int dirfd, const char *relpath, char *buf, loff_t size, const UserPerm& perms);
int symlink(const char *existing, const char *newname, const UserPerm& perms, std::string alternate_name="");
+ int symlinkat(const char *target, int dirfd, const char *relpath, const UserPerm& perms,
+ std::string alternate_name="");
// path traversal for high-level interface
int walk(std::string_view path, struct walk_dentry_result* result, const UserPerm& perms, bool followsym=true);
int fsetattrx(int fd, struct ceph_statx *stx, int mask, const UserPerm& perms);
int chmod(const char *path, mode_t mode, const UserPerm& perms);
int fchmod(int fd, mode_t mode, const UserPerm& perms);
+ int chmodat(int dirfd, const char *relpath, mode_t mode, int flags, const UserPerm& perms);
int lchmod(const char *path, mode_t mode, const UserPerm& perms);
int chown(const char *path, uid_t new_uid, gid_t new_gid,
const UserPerm& perms);
int fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms);
int lchown(const char *path, uid_t new_uid, gid_t new_gid,
const UserPerm& perms);
+ int chownat(int dirfd, const char *relpath, uid_t new_uid, gid_t new_gid,
+ int flags, const UserPerm& perms);
int utime(const char *path, struct utimbuf *buf, const UserPerm& perms);
int lutime(const char *path, struct utimbuf *buf, const UserPerm& perms);
int futime(int fd, struct utimbuf *buf, const UserPerm& perms);
int lutimes(const char *relpath, struct timeval times[2], const UserPerm& perms);
int futimes(int fd, struct timeval times[2], const UserPerm& perms);
int futimens(int fd, struct timespec times[2], const UserPerm& perms);
+ int utimensat(int dirfd, const char *relpath, struct timespec times[2], int flags,
+ const UserPerm& perms);
int flock(int fd, int operation, uint64_t owner);
int truncate(const char *path, loff_t size, const UserPerm& perms);
// file ops
int mknod(const char *path, mode_t mode, const UserPerm& perms, dev_t rdev=0);
+
+ int create_and_open(std::optional<int> dirfd, const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool,
+ std::string alternate_name);
int open(const char *path, int flags, const UserPerm& perms, mode_t mode=0, std::string alternate_name="") {
return open(path, flags, perms, mode, 0, 0, 0, NULL, alternate_name);
}
int open(const char *path, int flags, const UserPerm& perms,
mode_t mode, int stripe_unit, int stripe_count, int object_size,
const char *data_pool, std::string alternate_name="");
+ int _openat(int dirfd, const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode=0, std::string alternate_name="");
+ int openat(int dirfd, const char *relpath, int flags, const UserPerm& perms,
+ mode_t mode, int stripe_unit, int stripe_count,
+ int object_size, const char *data_pool, std::string alternate_name);
+ int openat(int dirfd, const char *path, int flags, const UserPerm& perms, mode_t mode=0,
+ std::string alternate_name="") {
+ return openat(dirfd, path, flags, perms, mode, 0, 0, 0, NULL, alternate_name);
+ }
+
int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name,
const UserPerm& perms);
int lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode=NULL);
int lookup_name(Inode *in, Inode *parent, const UserPerm& perms);
+ int _close(int fd);
int close(int fd);
loff_t lseek(int fd, loff_t offset, int whence);
int read(int fd, char *buf, loff_t size, loff_t offset=-1);
int mask=CEPH_STAT_CAP_INODE_ALL);
int fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms,
unsigned int want, unsigned int flags);
+ int statxat(int dirfd, const char *relpath,
+ struct ceph_statx *stx, const UserPerm& perms,
+ unsigned int want, unsigned int flags);
int fallocate(int fd, int mode, loff_t offset, loff_t length);
// full path xattr ops
void handle_client_reply(const MConstRef<MClientReply>& reply);
bool is_dir_operation(MetaRequest *request);
- int path_walk(const filepath& fp, struct walk_dentry_result* result, const UserPerm& perms, bool followsym=true, int mask=0);
+ int path_walk(const filepath& fp, struct walk_dentry_result* result, const UserPerm& perms, bool followsym=true, int mask=0,
+ InodeRef dirinode=nullptr);
int path_walk(const filepath& fp, InodeRef *end, const UserPerm& perms,
- bool followsym=true, int mask=0);
+ bool followsym=true, int mask=0, InodeRef dirinode=nullptr);
// fake inode number for 32-bits ino_t
void _assign_faked_ino(Inode *in);
return NULL;
return it->second;
}
+ int get_fd_inode(int fd, InodeRef *in);
// helpers
void wake_up_session_caps(MetaSession *s, bool reconnect);
*/
int ceph_opendir(struct ceph_mount_info *cmount, const char *name, struct ceph_dir_result **dirpp);
+/**
+ * Open a directory referred to by a file descriptor
+ *
+ * @param cmount the ceph mount handle to use to open the directory
+ * @param dirfd open file descriptor for the directory
+ * @param dirpp the directory result pointer structure to fill in
+ * @returns 0 on success or negative error code otherwise
+ */
+int ceph_fdopendir(struct ceph_mount_info *cmount, int dirfd, struct ceph_dir_result **dirpp);
+
/**
* Close the open directory.
*
*/
int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode_t mode);
+/**
+ * Create a directory relative to a file descriptor
+ *
+ * @param cmount the ceph mount handle to use for making the directory.
+ * @param dirfd open file descriptor for a directory (or CEPHFS_AT_FDCWD)
+ * @param relpath the path of the directory to create.
+ * @param mode the permissions the directory should have once created.
+ * @returns 0 on success or a negative return code on error.
+ */
+int ceph_mkdirat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, mode_t mode);
+
/**
* Create a snapshot
*
*/
int ceph_readlink(struct ceph_mount_info *cmount, const char *path, char *buf, int64_t size);
+/**
+ * Read a symbolic link relative to a file descriptor
+ *
+ * @param cmount the ceph mount handle to use for creating the link.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the path to the symlink to read
+ * @param buf the buffer to hold the path of the file that the symlink points to.
+ * @param size the length of the buffer
+ * @returns number of bytes copied on success or negative error code on failure
+ */
+int ceph_readlinkat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, char *buf,
+ int64_t size);
+
/**
* Creates a symbolic link.
*
*/
int ceph_symlink(struct ceph_mount_info *cmount, const char *existing, const char *newname);
+/**
+ * Creates a symbolic link relative to a file descriptor
+ *
+ * @param cmount the ceph mount handle to use for creating the symbolic link.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param existing the path to the existing file/directory to link to.
+ * @param newname the path to the new file/directory to link from.
+ * @returns 0 on success or a negative return code on failure.
+ */
+int ceph_symlinkat(struct ceph_mount_info *cmount, const char *existing, int dirfd,
+ const char *newname);
+
/** @} links */
/**
*/
int ceph_unlink(struct ceph_mount_info *cmount, const char *path);
+/**
+ * Removes a file, link, or symbolic link relative to a file descriptor.
+ * If the file/link has multiple links to it, the file will not
+ * disappear from the namespace until all references to it are removed.
+ *
+ * @param cmount the ceph mount handle to use for performing the unlink.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the path of the file or link to unlink.
+ * @param flags bitfield that can be used to set AT_* modifier flags (only AT_REMOVEDIR)
+ * @returns 0 on success or negative error code on failure.
+ */
+int ceph_unlinkat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, int flags);
+
/**
* Rename a file or directory.
*
int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
unsigned int want, unsigned int flags);
+/**
+ * Get attributes of a file relative to a file descriptor
+ *
+ * @param cmount the ceph mount handle to use for performing the stat.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath to the file/directory to get statistics of
+ * @param stx the ceph_statx struct that will be filled in with the file's statistics.
+ * @param want bitfield of CEPH_STATX_* flags showing designed attributes
+ * @param flags bitfield that can be used to set AT_* modifier flags (only AT_NO_ATTR_SYNC and AT_SYMLINK_NOFOLLOW)
+ * @returns 0 on success or negative error code on failure.
+ */
+int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct ceph_statx *stx, unsigned int want, unsigned int flags);
+
/**
* Get a file's extended statistics and attributes.
*
*/
int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode);
+/**
+ * Change the mode bits (permissions) of a file relative to a file descriptor.
+ *
+ * @param cmount the ceph mount handle to use for performing the chown.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the relpath of the file/directory to change the ownership of.
+ * @param mode the new permissions to set.
+ * @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW)
+ * @returns 0 on success or negative error code on failure.
+ */
+int ceph_chmodat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ mode_t mode, int flags);
+
/**
* Change the ownership of a file/directory.
*
*/
int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int gid);
+/**
+ * Change the ownership of a file/directory releative to a file descriptor.
+ *
+ * @param cmount the ceph mount handle to use for performing the chown.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the relpath of the file/directory to change the ownership of.
+ * @param uid the user id to set on the file/directory.
+ * @param gid the group id to set on the file/directory.
+ * @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW)
+ * @returns 0 on success or negative error code on failure.
+ */
+int ceph_chownat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ uid_t uid, gid_t gid, int flags);
+
/**
* Change file/directory last access and modification times.
*
*/
int ceph_futimens(struct ceph_mount_info *cmount, int fd, struct timespec times[2]);
+/**
+ * Change file/directory last access and modification times relative
+ * to a file descriptor.
+ *
+ * @param cmount the ceph mount handle to use for performing the utime.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the relpath of the file/directory to change the ownership of.
+ * @param dirfd the fd of the open file/directory to set the time values of.
+ * @param times holding the access and modification times to set on the file.
+ * @param flags bitfield that can be used to set AT_* modifier flags (AT_SYMLINK_NOFOLLOW)
+ * @returns 0 on success or negative error code on failure.
+ */
+int ceph_utimensat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct timespec times[2], int flags);
+
/**
* Apply or remove an advisory lock.
*
*/
int ceph_open(struct ceph_mount_info *cmount, const char *path, int flags, mode_t mode);
+/**
+ * Create and/or open a file relative to a directory
+ *
+ * @param cmount the ceph mount handle to use for performing the open.
+ * @param dirfd open file descriptor (or CEPHFS_AT_FDCWD)
+ * @param relpath the path of the file to open. If the flags parameter includes O_CREAT,
+ * the file will first be created before opening.
+ * @param flags a set of option masks that control how the file is created/opened.
+ * @param mode the permissions to place on the file if the file does not exist and O_CREAT
+ * is specified in the flags.
+ * @returns a non-negative file descriptor number on success or a negative error code on failure.
+ */
+int ceph_openat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, int flags, mode_t mode);
+
/**
* Create and/or open a file with a specific file layout.
*
#define CEPHFS_ETIME 62
#define CEPHFS_EOLDSNAPC 85
+// taken from linux kernel: include/uapi/linux/fcntl.h
+#define CEPHFS_AT_FDCWD -100 /* Special value used to indicate
+ openat should use the current
+ working directory. */
// --------------------------------------
// ino
return cmount->get_client()->opendir(name, (dir_result_t **)dirpp, cmount->default_perms);
}
+extern "C" int ceph_fdopendir(struct ceph_mount_info *cmount, int dirfd,
+ struct ceph_dir_result **dirpp)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->fdopendir(dirfd, (dir_result_t **)dirpp, cmount->default_perms);
+}
+
extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
{
if (!cmount->is_mounted())
return cmount->get_client()->unlink(path, cmount->default_perms);
}
+extern "C" int ceph_unlinkat(struct ceph_mount_info *cmount, int dirfd, const char *relpath, int flags)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->unlinkat(dirfd, relpath, flags, cmount->default_perms);
+}
+
extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from,
const char *to)
{
return cmount->get_client()->mkdir(path, mode, cmount->default_perms);
}
+extern "C" int ceph_mkdirat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ mode_t mode)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->mkdirat(dirfd, relpath, mode, cmount->default_perms);
+}
+
extern "C" int ceph_mksnap(struct ceph_mount_info *cmount, const char *path, const char *name,
mode_t mode, struct snap_metadata *snap_metadata, size_t nr_snap_metadata)
{
return cmount->get_client()->readlink(path, buf, size, cmount->default_perms);
}
+extern "C" int ceph_readlinkat(struct ceph_mount_info *cmount, int dirfd,
+ const char *relpath, char *buf, int64_t size)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->readlinkat(dirfd, relpath, buf, size, cmount->default_perms);
+}
+
extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing,
const char *newname)
{
return cmount->get_client()->symlink(existing, newname, cmount->default_perms);
}
+extern "C" int ceph_symlinkat(struct ceph_mount_info *cmount, const char *existing, int dirfd,
+ const char *newname)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->symlinkat(existing, dirfd, newname, cmount->default_perms);
+}
+
extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
unsigned int want, unsigned int flags)
{
want, flags);
}
+extern "C" int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct ceph_statx *stx, unsigned int want, unsigned int flags)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ if (flags & ~CEPH_REQ_FLAG_MASK)
+ return -EINVAL;
+ return cmount->get_client()->statxat(dirfd, relpath, stx, cmount->default_perms,
+ want, flags);
+}
+
extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
struct ceph_statx *stx, unsigned int want, unsigned int flags)
{
return -ENOTCONN;
return cmount->get_client()->fchmod(fd, mode, cmount->default_perms);
}
+
+extern "C" int ceph_chmodat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ mode_t mode, int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->chmodat(dirfd, relpath, mode, flags, cmount->default_perms);
+}
+
extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path,
int uid, int gid)
{
return cmount->get_client()->lchown(path, uid, gid, cmount->default_perms);
}
+extern "C" int ceph_chownat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ uid_t uid, gid_t gid, int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->chownat(dirfd, relpath, uid, gid, flags, cmount->default_perms);
+}
extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path,
struct utimbuf *buf)
return cmount->get_client()->futimens(fd, times, cmount->default_perms);
}
+extern "C" int ceph_utimensat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ struct timespec times[2], int flags) {
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->utimensat(dirfd, relpath, times, flags, cmount->default_perms);
+}
+
extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation,
uint64_t owner)
{
return cmount->get_client()->open(path, flags, cmount->default_perms, mode);
}
+extern "C" int ceph_openat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
+ int flags, mode_t mode)
+{
+ if (!cmount->is_mounted())
+ return -ENOTCONN;
+ return cmount->get_client()->openat(dirfd, relpath, flags, cmount->default_perms, mode);
+}
+
extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags,
mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool)
{