};
WRITE_CLASS_ENCODER(cls_rgw_bi_log_list_ret)
-
-#endif
+#endif /* CEPH_CLS_RGW_OPS_H */
void zero(uint64_t off, uint64_t len);
void rmxattr(const char *name);
void setxattr(const char *name, const bufferlist& bl);
+ void setxattr(const char *name, const buffer::list&& bl);
void tmap_update(const bufferlist& cmdbl);
void tmap_put(const bufferlist& bl);
void clone_range(uint64_t dst_off,
o->setxattr(name, v);
}
+void librados::ObjectWriteOperation::setxattr(const char *name,
+ const buffer::list&& v)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->setxattr(name, std::move(v));
+}
+
+
void librados::ObjectWriteOperation::omap_set(
const map<string, bufferlist> &map)
{
RGW_OP_LIST_BUCKET_MULTIPARTS,
RGW_OP_DELETE_MULTI_OBJ,
RGW_OP_BULK_DELETE,
+ RGW_OP_SET_ATTRS,
/* rgw specific */
RGW_OP_ADMIN_SET_METADATA
return rgw_fh->stat(st);
} /* RGWLibFS::getattr */
+ int RGWLibFS::setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
+ uint32_t flags)
+ {
+ int rc, rc2;
+ buffer::list ux_key, ux_attrs;
+ string obj_name{rgw_fh->relative_object_name()};
+
+ RGWSetAttrsRequest req(cct, get_user(), rgw_fh->bucket_name(), obj_name);
+
+ rgw_fh->create_stat(st, mask);
+ rgw_fh->encode_attrs(ux_key, ux_attrs);
+
+ /* save attrs */
+ req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
+
+ rc = rgwlib.get_fe()->execute_req(&req);
+ rc2 = req.get_ret();
+
+ return (((rc == 0) && (rc2 == 0)) ? 0 : -EIO);
+ } /* RGWLibFS::setattr */
+
void RGWLibFS::close()
{
state.flags |= FLAG_CLOSED;
struct rgw_file_handle *fh, struct stat *st,
uint32_t mask, uint32_t flags)
{
- /* XXX no-op */
- return 0;
+ RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
+ RGWFileHandle* rgw_fh = get_rgwfh(fh);
+
+ return fs->setattr(rgw_fh, st, mask, flags);
}
/*
/*
write data to file (vector)
*/
- int rgw_writev(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
- rgw_uio *uio, uint32_t flags)
+int rgw_writev(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
+ rgw_uio *uio, uint32_t flags)
{
CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
switch (fh.fh_type) {
case RGW_FS_TYPE_DIRECTORY:
- st->st_mode = RGW_RWXMODE|S_IFDIR /* state.unix_mode|S_IFDIR */;
st->st_nlink = 3;
break;
case RGW_FS_TYPE_FILE:
- st->st_mode = RGW_RWMODE|S_IFREG /* state.unix_mode|S_IFREG */;
st->st_nlink = 1;
st->st_blksize = 4096;
st->st_size = state.size;
intrusive_ptr_release(this);
}
+ void release_evict(RGWFileHandle* fh) {
+ /* remove from cache, releases sentinel ref */
+ fh_cache.remove(fh->fh.fh_hk.object, fh,
+ RGWFileHandle::FHCache::FLAG_NONE);
+ /* release call-path ref */
+ (void) fh_lru.unref(fh, cohort::lru::FLAG_NONE);
+ }
+
int authorize(RGWRados* store) {
int ret = rgw_get_user_info_by_access_key(store, key.id, user);
if (ret == 0) {
int getattr(RGWFileHandle* rgw_fh, struct stat* st);
+ int setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
+ uint32_t flags);
+
LookupFHResult stat_bucket(RGWFileHandle* parent,
const char *path, uint32_t flags);
}; /* RGWCopyObjRequest */
+class RGWSetAttrsRequest : public RGWLibRequest,
+ public RGWSetAttrs /* RGWOp */
+{
+public:
+ const std::string& bucket_name;
+ const std::string& obj_name;
+
+ RGWSetAttrsRequest(CephContext* _cct, RGWUserInfo *_user,
+ const std::string& _bname, const std::string& _oname)
+ : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname) {
+ op = this;
+ }
+
+ virtual bool only_bucket() { return false; }
+
+ virtual int op_init() {
+ // assign store, s, and dialect_handler
+ RGWObjectCtx* rados_ctx
+ = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
+ // framework promises to call op_init after parent init
+ assert(rados_ctx);
+ RGWOp::init(rados_ctx->store, get_state(), this);
+ op = this; // assign self as op: REQUIRED
+ return 0;
+ }
+
+ virtual int header_init() {
+
+ struct req_state* s = get_state();
+ s->info.method = "PUT";
+ s->op = OP_PUT;
+
+ /* XXX derp derp derp */
+ std::string uri = make_uri(bucket_name, obj_name);
+ s->relative_uri = uri;
+ s->info.request_uri = uri; // XXX
+ s->info.effective_uri = uri;
+ s->info.request_params = "";
+ s->info.domain = ""; /* XXX ? */
+
+ // woo
+ s->user = user;
+
+ return 0;
+ }
+
+ virtual int get_params() {
+ return 0;
+ }
+
+ virtual void send_response() {}
+
+}; /* RGWSetAttrsRequest */
} /* namespace rgw */
acls = ss.str();
}
-
-
int RGWPutACLs::verify_permission()
{
bool perm;
return;
}
+int RGWSetAttrs::verify_permission()
+{
+ bool perm;
+ if (!s->object.empty()) {
+ perm = verify_object_permission(s, RGW_PERM_WRITE);
+ } else {
+ perm = verify_bucket_permission(s, RGW_PERM_WRITE);
+ }
+ if (!perm)
+ return -EACCES;
+
+ return 0;
+}
+
+void RGWSetAttrs::pre_exec()
+{
+ rgw_bucket_object_pre_exec(s);
+}
+
+void RGWSetAttrs::execute()
+{
+ op_ret = get_params();
+ if (op_ret < 0)
+ return;
+
+ rgw_obj obj(s->bucket, s->object);
+
+ store->set_atomic(s->obj_ctx, obj);
+
+ if (!s->object.empty()) {
+ op_ret = store->set_attrs(s->obj_ctx, obj, attrs, &attrs);
+ } else {
+ for (auto& iter : attrs) {
+ s->bucket_attrs[iter.first] = std::move(iter.second);
+ }
+ op_ret = rgw_bucket_set_attrs(store, s->bucket_info, s->bucket_attrs,
+ &s->bucket_info.objv_tracker);
+ }
+}
+
RGWHandler::~RGWHandler()
{
}
*etag = etag_buf_str;
} /* complete_etag */
+class RGWSetAttrs : public RGWOp {
+protected:
+ map<string, buffer::list> attrs;
+
+public:
+ RGWSetAttrs() {}
+ virtual ~RGWSetAttrs() {}
+
+ void emplace_attr(std::string&& key, buffer::list&& bl) {
+ attrs.emplace(std::move(key), std::move(bl));
+ }
+
+ int verify_permission();
+ void pre_exec();
+ void execute();
+
+ virtual int get_params() = 0;
+ virtual void send_response() = 0;
+ virtual const string name() { return "set_attrs"; }
+ virtual RGWOpType get_type() { return RGW_OP_SET_ATTRS; }
+ virtual uint32_t op_mask() { return RGW_OP_TYPE_WRITE; }
+};
+
#endif /* CEPH_RGW_OP_H */
uint32_t owner_uid = 867;
uint32_t owner_gid = 5309;
+
+ uint32_t magic_uid = 1701;
+ uint32_t magic_gid = 9876;
+
uint32_t create_mask = RGW_SETATTR_UID | RGW_SETATTR_GID | RGW_SETATTR_MODE;
string bucket_name("nfsroot");
: name(std::move(_name)), fh(_fh), parent_fh(_parent_fh),
rgw_fh(_rgw_fh) {}
+ void clear() {
+ fh = nullptr;
+ rgw_fh = nullptr;
+ }
+
void sync() {
if (fh)
rgw_fh = get_rgwfh(fh);
bool do_create = false;
bool do_delete = false;
bool do_rename = false;
+ bool do_setattr = false;
bool verbose = false;
string marker_dir("nfs_marker");
} /* dirs1 top-level !exist */
}
+TEST(LibRGW, SETATTR) {
+ if (do_dirs1) {
+ if (do_setattr) {
+
+ int rc;
+ struct stat st;
+
+ st.st_uid = owner_uid;
+ st.st_gid = owner_gid;
+ st.st_mode = 755;
+
+ std::string dname{"dir_0"};
+ obj_rec dir{dname, nullptr, dirs1_b.fh, nullptr};
+
+ /* dir_0 MUST exist and MUST be resident */
+ (void) rgw_lookup(fs, dir.parent_fh, dir.name.c_str(), &dir.fh,
+ RGW_LOOKUP_FLAG_NONE);
+
+ ASSERT_NE(dir.fh, nullptr);
+ dir.sync();
+ ASSERT_NE(dir.rgw_fh, nullptr);
+ ASSERT_TRUE(dir.rgw_fh->is_dir());
+
+ /* child file */
+ std::string sfname{"setattr_file_0"};
+ obj_rec sf{sfname, nullptr, dir.fh, nullptr};
+
+ (void) rgw_lookup(fs, sf.parent_fh, sf.name.c_str(), &sf.fh,
+ RGW_LOOKUP_FLAG_NONE);
+
+ if (! sf.fh) {
+ /* make a new file object (the hard way) */
+ rc = rgw_lookup(fs, sf.parent_fh, sf.name.c_str(), &sf.fh,
+ RGW_LOOKUP_FLAG_CREATE);
+ ASSERT_EQ(rc, 0);
+ sf.sync();
+ ASSERT_TRUE(sf.rgw_fh->is_file());
+
+ /* because we made it the hard way, fixup attributes */
+ st.st_uid = owner_uid;
+ st.st_gid = owner_gid;
+ st.st_mode = 644;
+ sf.rgw_fh->create_stat(&st, create_mask);
+
+ /* open handle */
+ rc = rgw_open(fs, sf.fh, 0 /* flags */);
+ ASSERT_EQ(rc, 0);
+ ASSERT_TRUE(sf.rgw_fh->is_open());
+ /* stage seq write */
+ size_t nbytes;
+ string data = "data for " + sf.name;
+ rc = rgw_write(fs, sf.fh, 0, data.length(), &nbytes,
+ (void*) data.c_str(), RGW_WRITE_FLAG_NONE);
+ ASSERT_EQ(rc, 0);
+ ASSERT_EQ(nbytes, data.length());
+ /* commit write transaction */
+ rc = rgw_close(fs, sf.fh, 0 /* flags */);
+ ASSERT_EQ(rc, 0);
+ } else {
+ sf.sync();
+ ASSERT_TRUE(sf.rgw_fh->is_file());
+ }
+
+ /* sf MUST now be materialized--now change it's attributes */
+ st.st_uid = magic_uid;
+ st.st_gid = magic_gid;
+
+ rc = rgw_setattr(fs, sf.fh, &st, create_mask, RGW_SETATTR_FLAG_NONE);
+ ASSERT_EQ(rc, 0);
+
+ /* force evict--subsequent lookups must reload */
+ static_cast<RGWLibFS*>(fs->fs_private)->release_evict(sf.rgw_fh);
+
+ sf.clear();
+
+ /* revalidate -- expect magic uid and gid */
+ (void) rgw_lookup(fs, sf.parent_fh, sf.name.c_str(), &sf.fh,
+ RGW_LOOKUP_FLAG_NONE);
+ sf.sync();
+ ASSERT_NE(sf.fh, nullptr);
+
+ memset(&st, 0, sizeof(struct stat)); /* nothing up my sleeve... */
+
+ rc = rgw_getattr(fs, sf.fh, &st, RGW_GETATTR_FLAG_NONE);
+ ASSERT_EQ(rc, 0);
+
+ ASSERT_EQ(st.st_uid, magic_uid);
+ ASSERT_EQ(st.st_gid, magic_gid);
+
+ /* release 1 ref on sf */
+ rgw_fh_rele(fs, sf.fh, RGW_FH_RELE_FLAG_NONE);
+
+ /* release 1 ref on dir */
+ rgw_fh_rele(fs, dir.fh, RGW_FH_RELE_FLAG_NONE);
+ } /* dirs1 */
+ }
+}
+
TEST(LibRGW, RGW_CREATE_DIRS1) {
/* verify rgw_create (create [empty] file objects the easy way) */
if (do_dirs1) {
} else if (ceph_argparse_flag(args, arg_iter, "--marker1",
(char*) nullptr)) {
do_marker1 = true;
+ } else if (ceph_argparse_flag(args, arg_iter, "--setattr",
+ (char*) nullptr)) {
+ do_setattr = true;
} else if (ceph_argparse_flag(args, arg_iter, "--create",
(char*) nullptr)) {
do_create = true;