From 241e1a0a0bcd7b0f5f5eb6017c9fdf1c90273afb Mon Sep 17 00:00:00 2001 From: Venky Shankar Date: Tue, 26 Jun 2018 00:08:20 -0400 Subject: [PATCH] libcephfs: extend support for changing file access/modification time Add calls for setting {a,m}time with microsecond granularity (with support for setting times on symbolic links and file descriptor based calls). Additionally, add support for setting {a,m}time with nanosecond granularity (for file descriptor call only). Signed-off-by: Venky Shankar --- src/client/Client.cc | 120 ++++++++++++++++++++++++++++----- src/client/Client.h | 5 ++ src/include/cephfs/libcephfs.h | 50 ++++++++++++++ src/libcephfs.cc | 40 +++++++++++ 4 files changed, 200 insertions(+), 15 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 61ba77eddf9..221ce6e44a2 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -7349,14 +7349,64 @@ int Client::lchown(const char *relpath, uid_t new_uid, gid_t new_gid, return _setattr(in, &attr, mask, perms); } +static void attr_set_atime_and_mtime(struct stat *attr, + const utime_t &atime, + const utime_t &mtime) +{ + stat_set_atime_sec(attr, atime.tv.tv_sec); + stat_set_atime_nsec(attr, atime.tv.tv_nsec); + stat_set_mtime_sec(attr, mtime.tv.tv_sec); + stat_set_mtime_nsec(attr, mtime.tv.tv_nsec); +} + +// for [l]utime() invoke the timeval variant as the timespec +// variant are not yet implemented. for futime[s](), invoke +// the timespec variant. int Client::utime(const char *relpath, struct utimbuf *buf, const UserPerm& perms) +{ + struct timeval tv[2]; + tv[0].tv_sec = buf->actime; + tv[0].tv_usec = 0; + tv[1].tv_sec = buf->modtime; + tv[1].tv_usec = 0; + + return utimes(relpath, tv, perms); +} + +int Client::lutime(const char *relpath, struct utimbuf *buf, + const UserPerm& perms) +{ + struct timeval tv[2]; + tv[0].tv_sec = buf->actime; + tv[0].tv_usec = 0; + tv[1].tv_sec = buf->modtime; + tv[1].tv_usec = 0; + + return lutimes(relpath, tv, perms); +} + +int Client::futime(int fd, struct utimbuf *buf, const UserPerm& perms) +{ + struct timespec ts[2]; + ts[0].tv_sec = buf->actime; + ts[0].tv_nsec = 0; + ts[1].tv_sec = buf->modtime; + ts[1].tv_nsec = 0; + + return futimens(fd, ts, perms); +} + +int Client::utimes(const char *relpath, struct timeval times[2], + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << __func__ << std::endl; tout(cct) << relpath << std::endl; - tout(cct) << buf->modtime << std::endl; - tout(cct) << buf->actime << std::endl; + tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_usec + << std::endl; + tout(cct) << "mtime: " << times[1].tv_sec << "." << times[1].tv_usec + << std::endl; if (unmounting) return -ENOTCONN; @@ -7367,39 +7417,79 @@ int Client::utime(const char *relpath, struct utimbuf *buf, if (r < 0) return r; struct stat attr; - stat_set_mtime_sec(&attr, buf->modtime); - stat_set_mtime_nsec(&attr, 0); - stat_set_atime_sec(&attr, buf->actime); - stat_set_atime_nsec(&attr, 0); + 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::lutime(const char *relpath, struct utimbuf *buf, - const UserPerm& perms) +int Client::lutimes(const char *relpath, struct timeval times[2], + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << __func__ << std::endl; tout(cct) << relpath << std::endl; - tout(cct) << buf->modtime << std::endl; - tout(cct) << buf->actime << std::endl; + tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_usec + << std::endl; + tout(cct) << "mtime: " << times[1].tv_sec << "." << times[1].tv_usec + << std::endl; if (unmounting) return -ENOTCONN; filepath path(relpath); InodeRef in; - // don't follow symlinks int r = path_walk(path, &in, perms, false); if (r < 0) return r; struct stat attr; - stat_set_mtime_sec(&attr, buf->modtime); - stat_set_mtime_nsec(&attr, 0); - stat_set_atime_sec(&attr, buf->actime); - stat_set_atime_nsec(&attr, 0); + 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::futimes(int fd, struct timeval times[2], const UserPerm& perms) +{ + struct timespec ts[2]; + ts[0].tv_sec = times[0].tv_sec; + ts[0].tv_nsec = times[0].tv_usec * 1000; + ts[1].tv_sec = times[1].tv_sec; + ts[1].tv_nsec = times[1].tv_usec * 1000; + + return futimens(fd, ts, perms); +} + +int Client::futimens(int fd, struct timespec times[2], const UserPerm& perms) +{ + Mutex::Locker lock(client_lock); + tout(cct) << __func__ << std::endl; + tout(cct) << fd << 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; + + if (unmounting) + return -ENOTCONN; + + Fh *f = get_filehandle(fd); + if (!f) + return -EBADF; +#if defined(__linux__) && defined(O_PATH) + if (f->flags & O_PATH) + return -EBADF; +#endif + struct stat attr; + utime_t atime(times[0]); + utime_t mtime(times[1]); + + attr_set_atime_and_mtime(&attr, atime, mtime); + return _setattr(f->inode, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME, perms); +} + int Client::flock(int fd, int operation, uint64_t owner) { Mutex::Locker lock(client_lock); diff --git a/src/client/Client.h b/src/client/Client.h index df61d07bbe2..2024bdd1963 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1048,6 +1048,11 @@ public: 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 utimes(const char *relpath, struct timeval times[2], 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 flock(int fd, int operation, uint64_t owner); int truncate(const char *path, loff_t size, const UserPerm& perms); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index e23bcf24d1b..b6328a60f6b 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -785,6 +785,56 @@ int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int g */ int ceph_utime(struct ceph_mount_info *cmount, const char *path, struct utimbuf *buf); +/** + * Change file/directory last access and modification times. + * + * @param cmount the ceph mount handle to use for performing the utime. + * @param fd the fd of the open file/directory to set the time values of. + * @param buf holding the access and modification times to set on the file. + * @returns 0 on success or negative error code on failure. + */ +int ceph_futime(struct ceph_mount_info *cmount, int fd, struct utimbuf *buf); + +/** + * Change file/directory last access and modification times. + * + * @param cmount the ceph mount handle to use for performing the utime. + * @param path the path to the file/directory to set the time values of. + * @param times holding the access and modification times to set on the file. + * @returns 0 on success or negative error code on failure. + */ +int ceph_utimes(struct ceph_mount_info *cmount, const char *path, struct timeval times[2]); + +/** + * Change file/directory last access and modification times, don't follow symlinks. + * + * @param cmount the ceph mount handle to use for performing the utime. + * @param path the path to the file/directory to set the time values of. + * @param times holding the access and modification times to set on the file. + * @returns 0 on success or negative error code on failure. + */ +int ceph_lutimes(struct ceph_mount_info *cmount, const char *path, struct timeval times[2]); + +/** + * Change file/directory last access and modification times. + * + * @param cmount the ceph mount handle to use for performing the utime. + * @param fd 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. + * @returns 0 on success or negative error code on failure. + */ +int ceph_futimes(struct ceph_mount_info *cmount, int fd, struct timeval times[2]); + +/** + * Change file/directory last access and modification times. + * + * @param cmount the ceph mount handle to use for performing the utime. + * @param fd 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. + * @returns 0 on success or negative error code on failure. + */ +int ceph_futimens(struct ceph_mount_info *cmount, int fd, struct timespec times[2]); + /** * Apply or remove an advisory lock. * diff --git a/src/libcephfs.cc b/src/libcephfs.cc index a65e763da7e..b742404fe43 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -815,6 +815,46 @@ extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path, return cmount->get_client()->utime(path, buf, cmount->default_perms); } +extern "C" int ceph_futime(struct ceph_mount_info *cmount, int fd, + struct utimbuf *buf) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->futime(fd, buf, cmount->default_perms); +} + +extern "C" int ceph_utimes(struct ceph_mount_info *cmount, const char *path, + struct timeval times[2]) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->utimes(path, times, cmount->default_perms); +} + +extern "C" int ceph_lutimes(struct ceph_mount_info *cmount, const char *path, + struct timeval times[2]) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->lutimes(path, times, cmount->default_perms); +} + +extern "C" int ceph_futimes(struct ceph_mount_info *cmount, int fd, + struct timeval times[2]) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->futimes(fd, times, cmount->default_perms); +} + +extern "C" int ceph_futimens(struct ceph_mount_info *cmount, int fd, + struct timespec times[2]) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->futimens(fd, times, cmount->default_perms); +} + extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation, uint64_t owner) { -- 2.39.5