From 71cf1ccd66c8560114345f7218ad6b8d39e0ce7a Mon Sep 17 00:00:00 2001 From: taoCH Date: Wed, 7 Nov 2018 13:22:20 +0800 Subject: [PATCH] librgw: support symbolic link Signed-off-by: Tao Chen --- src/include/rados/rgw_file.h | 22 ++++- src/rgw/rgw_file.cc | 163 +++++++++++++++++++++++++++++++++++ src/rgw/rgw_file.h | 31 ++++++- 3 files changed, 214 insertions(+), 2 deletions(-) diff --git a/src/include/rados/rgw_file.h b/src/include/rados/rgw_file.h index 5c76c471c64..c1c31955093 100644 --- a/src/include/rados/rgw_file.h +++ b/src/include/rados/rgw_file.h @@ -27,7 +27,7 @@ extern "C" { #define LIBRGW_FILE_VER_MAJOR 1 #define LIBRGW_FILE_VER_MINOR 1 -#define LIBRGW_FILE_VER_EXTRA 6 +#define LIBRGW_FILE_VER_EXTRA 7 #define LIBRGW_FILE_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra) #define LIBRGW_FILE_VERSION_CODE LIBRGW_FILE_VERSION(LIBRGW_FILE_VER_MAJOR, LIBRGW_FILE_VER_MINOR, LIBRGW_FILE_VER_EXTRA) @@ -39,6 +39,7 @@ enum rgw_fh_type { RGW_FS_TYPE_NIL = 0, RGW_FS_TYPE_FILE, RGW_FS_TYPE_DIRECTORY, + RGW_FS_TYPE_SYMBOLIC_LINK, }; /* @@ -178,6 +179,15 @@ int rgw_create(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh, struct rgw_file_handle **fh, uint32_t posix_flags, uint32_t flags); +/* + create a symbolic link + */ +#define RGW_CREATELINK_FLAG_NONE 0x0000 +int rgw_symlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh, + const char *name, const char *link_path, struct stat *st, + uint32_t mask, struct rgw_file_handle **fh, uint32_t posix_flags, + uint32_t flags); + /* create a new directory */ @@ -293,6 +303,16 @@ int rgw_read(struct rgw_fs *rgw_fs, size_t length, size_t *bytes_read, void *buffer, uint32_t flags); +/* + read symbolic link +*/ +#define RGW_READLINK_FLAG_NONE 0x0000 + +int rgw_readlink(struct rgw_fs *rgw_fs, + struct rgw_file_handle *fh, uint64_t offset, + size_t length, size_t *bytes_read, void *buffer, + uint32_t flags); + /* write data to file */ diff --git a/src/rgw/rgw_file.cc b/src/rgw/rgw_file.cc index 702f9504f6b..9985c27448c 100644 --- a/src/rgw/rgw_file.cc +++ b/src/rgw/rgw_file.cc @@ -260,6 +260,29 @@ namespace rgw { return rc; } + int RGWLibFS::readlink(RGWFileHandle* rgw_fh, uint64_t offset, size_t length, + size_t* bytes_read, void* buffer, uint32_t flags) + { + if (! rgw_fh->is_link()) + return -EINVAL; + + if (rgw_fh->deleted()) + return -ESTALE; + + RGWReadRequest req(get_context(), get_user(), rgw_fh, offset, length, + buffer); + + int rc = rgwlib.get_fe()->execute_req(&req); + if ((rc == 0) && + (req.get_ret() == 0)) { + lock_guard(rgw_fh->mtx); + rgw_fh->set_atime(real_clock::to_timespec(real_clock::now())); + *bytes_read = req.nread; + } + + return rc; + } + int RGWLibFS::unlink(RGWFileHandle* rgw_fh, const char* name, uint32_t flags) { int rc = 0; @@ -664,6 +687,103 @@ namespace rgw { return mkr; } /* RGWLibFS::create */ + MkObjResult RGWLibFS::symlink(RGWFileHandle* parent, const char *name, + const char* link_path, struct stat *st, uint32_t mask, uint32_t flags) + { + int rc, rc2; + + using std::get; + + rgw_file_handle *lfh; + rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh, + RGW_LOOKUP_FLAG_NONE); + if (! rc) { + /* conflict! */ + rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE); + return MkObjResult{nullptr, -EEXIST}; + } + + MkObjResult mkr{nullptr, -EINVAL}; + LookupFHResult fhr; + RGWFileHandle* rgw_fh = nullptr; + buffer::list ux_key, ux_attrs; + + fhr = lookup_fh(parent, name, + RGWFileHandle::FLAG_CREATE| + RGWFileHandle::FLAG_SYMBOLIC_LINK| + RGWFileHandle::FLAG_LOCK); + rgw_fh = get<0>(fhr); + if (rgw_fh) { + rgw_fh->create_stat(st, mask); + rgw_fh->set_times(real_clock::now()); + /* save attrs */ + rgw_fh->encode_attrs(ux_key, ux_attrs); + if (st) + rgw_fh->stat(st); + get<0>(mkr) = rgw_fh; + } else { + get<1>(mkr) = -EIO; + return mkr; + } + + /* need valid S3 name (characters, length <= 1024, etc) */ + rc = valid_fs_object_name(name); + if (rc != 0) { + rgw_fh->flags |= RGWFileHandle::FLAG_DELETED; + fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh, + RGWFileHandle::FHCache::FLAG_LOCK); + rgw_fh->mtx.unlock(); + unref(rgw_fh); + get<0>(mkr) = nullptr; + get<1>(mkr) = rc; + return mkr; + } + + string obj_name = std::string(name); + /* create an object representing the directory */ + buffer::list bl; + + /* XXXX */ +#if 0 + bl.push_back( + buffer::create_static(len, static_cast(buffer))); +#else + + bl.push_back( + buffer::copy(link_path, strlen(link_path))); +#endif + + RGWPutObjRequest req(get_context(), get_user(), parent->bucket_name(), + obj_name, bl); + + /* save attrs */ + req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key)); + req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs)); + + rc = rgwlib.get_fe()->execute_req(&req); + rc2 = req.get_ret(); + if (! ((rc == 0) && + (rc2 == 0))) { + /* op failed */ + rgw_fh->flags |= RGWFileHandle::FLAG_DELETED; + rgw_fh->mtx.unlock(); /* !LOCKED */ + unref(rgw_fh); + get<0>(mkr) = nullptr; + /* fixup rc */ + if (!rc) + rc = rc2; + } else { + real_time t = real_clock::now(); + parent->set_mtime(real_clock::to_timespec(t)); + parent->set_ctime(real_clock::to_timespec(t)); + rgw_fh->mtx.unlock(); /* !LOCKED */ + } + + get<1>(mkr) = rc; + + return mkr; + } /* RGWLibFS::symlink */ + int RGWLibFS::getattr(RGWFileHandle* rgw_fh, struct stat* st) { switch(rgw_fh->fh.fh_type) { @@ -1652,6 +1772,35 @@ int rgw_create(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh, return get<1>(fhr); } /* rgw_create */ +/* + create a symbolic link + */ +int rgw_symlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh, + const char *name, const char *link_path, struct stat *st, uint32_t mask, + struct rgw_file_handle **fh, uint32_t posix_flags, + uint32_t flags) +{ + using std::get; + + RGWLibFS *fs = static_cast(rgw_fs->fs_private); + RGWFileHandle* parent = get_rgwfh(parent_fh); + + if ((! parent) || + (parent->is_root()) || + (parent->is_file())) { + /* bad parent */ + return -EINVAL; + } + + MkObjResult fhr = fs->symlink(parent, name, link_path, st, mask, flags); + RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success + + if (nfh) + *fh = nfh->get_fh(); + + return get<1>(fhr); +} /* rgw_symlink */ + /* create a new directory */ @@ -1966,6 +2115,20 @@ int rgw_read(struct rgw_fs *rgw_fs, return fs->read(rgw_fh, offset, length, bytes_read, buffer, flags); } +/* + read symbolic link +*/ +int rgw_readlink(struct rgw_fs *rgw_fs, + struct rgw_file_handle *fh, uint64_t offset, + size_t length, size_t *bytes_read, void *buffer, + uint32_t flags) +{ + RGWLibFS *fs = static_cast(rgw_fs->fs_private); + RGWFileHandle* rgw_fh = get_rgwfh(fh); + + return fs->readlink(rgw_fh, offset, length, bytes_read, buffer, flags); +} + /* write data to file */ diff --git a/src/rgw/rgw_file.h b/src/rgw/rgw_file.h index a98d2832e93..b44a954d631 100644 --- a/src/rgw/rgw_file.h +++ b/src/rgw/rgw_file.h @@ -247,6 +247,7 @@ namespace rgw { static constexpr uint32_t FLAG_ROOT = 0x0002; static constexpr uint32_t FLAG_CREATE = 0x0004; static constexpr uint32_t FLAG_CREATING = 0x0008; + static constexpr uint32_t FLAG_SYMBOLIC_LINK = 0x0009; static constexpr uint32_t FLAG_DIRECTORY = 0x0010; static constexpr uint32_t FLAG_BUCKET = 0x0020; static constexpr uint32_t FLAG_LOCK = 0x0040; @@ -318,7 +319,10 @@ namespace rgw { if (flags & FLAG_DIRECTORY) { fh.fh_type = RGW_FS_TYPE_DIRECTORY; variant_type = directory(); - } else { + } else if(flags & FLAG_SYMBOLIC_LINK) { + fh.fh_type = RGW_FS_TYPE_SYMBOLIC_LINK; + variant_type = file(); + } else { fh.fh_type = RGW_FS_TYPE_FILE; variant_type = file(); } @@ -338,6 +342,10 @@ namespace rgw { break; case RGW_FS_TYPE_FILE: state.unix_mode = RGW_RWMODE|S_IFREG; + break; + case RGW_FS_TYPE_SYMBOLIC_LINK: + state.unix_mode = RGW_RWMODE|S_IFLNK; + break; default: break; } @@ -388,6 +396,10 @@ namespace rgw { break; case RGW_FS_TYPE_FILE: state.unix_mode = st->st_mode|S_IFREG; + break; + case RGW_FS_TYPE_SYMBOLIC_LINK: + state.unix_mode = st->st_mode|S_IFLNK; + break; default: break; } @@ -431,6 +443,13 @@ namespace rgw { st->st_blksize = 4096; st->st_size = state.size; st->st_blocks = (state.size) / 512; + break; + case RGW_FS_TYPE_SYMBOLIC_LINK: + st->st_nlink = 1; + st->st_blksize = 4096; + st->st_size = state.size; + st->st_blocks = (state.size) / 512; + break; default: break; } @@ -542,6 +561,7 @@ namespace rgw { bool is_object() const { return !is_bucket(); } bool is_file() const { return (fh.fh_type == RGW_FS_TYPE_FILE); } bool is_dir() const { return (fh.fh_type == RGW_FS_TYPE_DIRECTORY); } + bool is_link() const { return (fh.fh_type == RGW_FS_TYPE_SYMBOLIC_LINK); } bool creating() const { return flags & FLAG_CREATING; } bool deleted() const { return flags & FLAG_DELETED; } bool stateless_open() const { return flags & FLAG_STATELESS_OPEN; } @@ -639,6 +659,9 @@ namespace rgw { DECODE_START(2, bl); uint32_t fh_type; decode(fh_type, bl); + if ((fh.fh_type != fh_type) && + (fh_type == RGW_FS_TYPE_SYMBOLIC_LINK)) + fh.fh_type = RGW_FS_TYPE_SYMBOLIC_LINK; ceph_assert(fh.fh_type == fh_type); decode(state.dev, bl); decode(state.size, bl); @@ -1135,11 +1158,17 @@ namespace rgw { int read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length, size_t* bytes_read, void* buffer, uint32_t flags); + int readlink(RGWFileHandle* rgw_fh, uint64_t offset, size_t length, + size_t* bytes_read, void* buffer, uint32_t flags); + int rename(RGWFileHandle* old_fh, RGWFileHandle* new_fh, const char *old_name, const char *new_name); MkObjResult create(RGWFileHandle* parent, const char *name, struct stat *st, uint32_t mask, uint32_t flags); + + MkObjResult symlink(RGWFileHandle* parent, const char *name, + const char *link_path, struct stat *st, uint32_t mask, uint32_t flags); MkObjResult mkdir(RGWFileHandle* parent, const char *name, struct stat *st, uint32_t mask, uint32_t flags); -- 2.39.5