]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librgw: implement object rename
authorMatt Benjamin <mbenjamin@redhat.com>
Thu, 14 Jan 2016 22:40:17 +0000 (17:40 -0500)
committerMatt Benjamin <mbenjamin@redhat.com>
Fri, 12 Feb 2016 17:08:04 +0000 (12:08 -0500)
The implementation uses currently does a copy, followed by a
delete operation (if successful).

Signed-off-by: Matt Benjamin <mbenjamin@redhat.com>
src/rgw/rgw_file.cc
src/rgw/rgw_file.h

index 3a7aa0ebe4cb3595c862bb7ffb3b1d69a064eef0..900590bec6061ac343de289e59acfe427381a163 100644 (file)
@@ -145,6 +145,46 @@ namespace rgw {
     return fhr;
   } /* RGWLibFS::stat_leaf */
 
+  int RGWLibFS::rename(RGWFileHandle* src_fh, RGWFileHandle* dst_fh,
+                     const char *src_name, const char *dst_name)
+
+  {
+    /* XXX initial implementation: try-copy, and delete if copy
+     * succeeds */
+    for (int ix : {0, 1}) {
+      switch (ix) {
+      case 0:
+      {
+       RGWCopyObjRequest req(cct, get_user(), src_fh, dst_fh, src_name,
+                             dst_name);
+       int rc = rgwlib.get_fe()->execute_req(&req);
+       if ((rc != 0) ||
+           ((rc = req.get_ret()) != 0)) {
+         return rc;
+       }
+      }
+      break;
+      case 1:
+      {
+       RGWDeleteObjRequest req(cct, get_user(), src_fh->bucket_name(),
+                               src_name);
+       int rc = rgwlib.get_fe()->execute_req(&req);
+       if (! rc) {
+         rc = req.get_ret();
+         return rc;
+       }
+      }
+      break;
+      default:
+       abort();
+      } /* switch */
+
+      return -EINVAL;
+    }
+
+    return EINVAL;
+  } /* RGWLibFS::rename */
+
   int RGWLibFS::getattr(RGWFileHandle* rgw_fh, struct stat* st)
   {
     switch(rgw_fh->fh.fh_type) {
@@ -811,8 +851,12 @@ int rgw_rename(struct rgw_fs *rgw_fs,
               struct rgw_file_handle *newdir, const char* new_name,
               uint32_t flags)
 {
-  /* -ENOTSUP */
-  return -EINVAL;
+  RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
+
+  RGWFileHandle* old_fh = get_rgwfh(olddir);
+  RGWFileHandle* new_fh = get_rgwfh(newdir);
+
+  return -(fs->rename(old_fh, new_fh, old_name, new_name));
 }
 
 /*
index f1a4265b922c6ebaa1971c49177db471178ab930..fb96e0e8ea2055938b5842775aee8580a788852e 100644 (file)
@@ -355,7 +355,16 @@ namespace rgw {
     inline std::string relative_object_name() {
       return full_object_name(true /* omit_bucket */);
     }
-    
+
+    inline std::string format_child_name(const std::string& cbasename) {
+      std::string child_name{relative_object_name()};
+      if ((child_name.size() > 0) &&
+         (child_name.back() != '/'))
+       child_name += "/";
+      child_name += cbasename;
+      return child_name;
+    }
+
     inline std::string make_key_name(const char *name) {
       std::string key_name{full_object_name()};
       if (key_name.length() > 0)
@@ -733,6 +742,9 @@ namespace rgw {
     LookupFHResult stat_leaf(RGWFileHandle* parent, const char *path,
                             uint32_t flags);
 
+    int rename(RGWFileHandle* old_fh, RGWFileHandle* new_fh,
+              const char *old_name, const char *new_name);
+
     /* find existing RGWFileHandle */
     RGWFileHandle* lookup_handle(struct rgw_fh_hk fh_hk) {
 
@@ -1199,7 +1211,6 @@ static inline bool valid_s3_object_name(const string& name) {
 /*
   put object
 */
-
 class RGWPutObjRequest : public RGWLibRequest,
                         public RGWPutObj /* RGWOp */
 {
@@ -1807,6 +1818,89 @@ public:
   }
 }; /* RGWWriteRequest */
 
+/*
+  copy object
+*/
+class RGWCopyObjRequest : public RGWLibRequest,
+                         public RGWCopyObj /* RGWOp */
+{
+public:
+  RGWFileHandle* src_parent;
+  RGWFileHandle* dst_parent;
+  const std::string& src_name;
+  const std::string& dst_name;
+
+  RGWCopyObjRequest(CephContext* _cct, RGWUserInfo *_user,
+                   RGWFileHandle* _src_parent, RGWFileHandle* _dst_parent,
+                   const std::string& _src_name, const std::string& _dst_name)
+    : RGWLibRequest(_cct, _user), src_parent(_src_parent),
+      dst_parent(_dst_parent), src_name(_src_name), dst_name(_dst_name) {
+    magic = 82;
+    op = this;
+  }
+
+  virtual bool only_bucket() { return true; }
+
+  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"; // XXX check
+    s->op = OP_PUT;
+
+    src_bucket_name = src_parent->bucket_name();
+    // need s->src_bucket_name?
+    src_object.name = src_parent->format_child_name(src_name);
+    // need s->src_object?
+
+    dest_bucket_name = dst_parent->bucket_name();
+    // need s->bucket.name?
+    dest_object = dst_parent->format_child_name(dst_name);
+    // need s->object_name?
+
+    if (! valid_s3_object_name(dest_object))
+      return -ERR_INVALID_OBJECT_NAME;
+
+#if 0 /* XXX needed? */
+    s->relative_uri = uri;
+    s->info.request_uri = uri; // XXX
+    s->info.effective_uri = uri;
+    s->info.request_params = "";
+    s->info.domain = ""; /* XXX ? */
+#endif
+
+    // woo
+    s->user = user;
+
+    return 0;
+  }
+
+  virtual int get_params() {
+    struct req_state* s = get_state();
+    RGWAccessControlPolicy_S3 s3policy(s->cct);
+    /* we don't have (any) headers, so just create canned ACLs */
+    int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl);
+    dest_policy = s3policy;
+    return ret;
+  }
+
+  virtual void send_response() {}
+  virtual void send_partial_response(off_t ofs) {}
+
+}; /* RGWCopyObjRequest */
+
+
 } /* namespace rgw */
 
 #endif /* RGW_FILE_H */