#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)
RGW_FS_TYPE_NIL = 0,
RGW_FS_TYPE_FILE,
RGW_FS_TYPE_DIRECTORY,
+ RGW_FS_TYPE_SYMBOLIC_LINK,
};
/*
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
*/
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
*/
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;
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<char*>(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) {
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<RGWLibFS*>(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
*/
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<RGWLibFS*>(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
*/
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;
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();
}
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;
}
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;
}
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;
}
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; }
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);
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);