mirror of
https://github.com/ceph/ceph
synced 2025-03-06 08:20:12 +00:00
Merge pull request #19684 from taoCH/wip-librgw-symbolic-link
librgw: support symbolic link Reviewed-by: Matt Benjamin <mbenjami@redhat.com>
This commit is contained in:
commit
e682970f35
@ -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
|
||||
*/
|
||||
|
@ -261,6 +261,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;
|
||||
@ -669,6 +692,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<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) {
|
||||
@ -1664,6 +1784,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<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
|
||||
*/
|
||||
@ -1978,6 +2127,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<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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user