return -EINVAL;
}
- if (! parent->is_root()) {
- /* cannot create a bucket in a bucket */
- return -ENOTDIR;
- }
-
- // XXXX fix this
- uri += "/";
- uri += name;
- RGWCreateBucketRequest req(cct, fs->get_user(), uri);
- rc = librgw.get_fe()->execute_req(&req);
-
/* XXX: atomicity */
LookupFHResult fhr = fs->lookup_fh(parent, name);
RGWFileHandle* rgw_fh = get<0>(fhr);
+ if (parent->is_root()) {
+ /* mkdir in root creates a new bucket */
+ uri += "/"; /* XXX */
+ uri += name;
+ RGWCreateBucketRequest req(cct, fs->get_user(), uri);
+ rc = librgw.get_fe()->execute_req(&req);
+ } else
+ rgw_fh->set_pseudo();
+
struct rgw_file_handle *rfh = rgw_fh->get_fh();
*fh = rfh;
// nothing
}
+ fh_key(const uint64_t bk, const uint64_t ok) {
+ fh_hk.bucket = bk;
+ fh_hk.object = ok;
+ }
+
fh_key(const uint64_t bk, const char *_o) {
fh_hk.bucket = bk;
fh_hk.object = XXH64(_o, ::strlen(_o), seed);
static constexpr uint32_t FLAG_OPEN = 0x0001;
static constexpr uint32_t FLAG_ROOT = 0x0002;
static constexpr uint32_t FLAG_CREATE = 0x0004;
+ static constexpr uint32_t FLAG_PSEUDO = 0x0008;
friend class RGWLibFS;
public:
RGWFileHandle(RGWLibFS* fs, uint32_t fs_inst, RGWFileHandle* _parent,
- const fh_key& _fhk, const char *_name)
- : parent(_parent), name(_name), fhk(_fhk), flags(FLAG_NONE) {
+ const fh_key& _fhk, std::string& _name)
+ : parent(_parent), name(std::move(_name)), fhk(_fhk), flags(FLAG_NONE) {
fh.fh_type = parent->is_root()
? RGW_FS_TYPE_DIRECTORY : RGW_FS_TYPE_FILE;
depth = parent->depth + 1;
/* save constant fhk */
- fh_key fhk(parent->name, name);
+ fh_key fhk(parent->bucket_name(), make_path());
fh.fh_hk = fhk.fh_hk; /* XXX redundant in fh_hk */
/* pointer to self */
bool first = true;
path.reserve(reserve);
for (auto& s : boost::adaptors::reverse(segments)) {
- if (! first) {
+ if (! first)
path += "/";
+ else
first = false;
- }
path += *s;
}
return path;
}
+ fh_key make_fhk(const std::string& name) {
+ if (depth <= 1)
+ return fh_key(fhk.fh_hk.object, name.c_str());
+ else {
+ std::vector<const std::string*> segments = { &object_name(), &name };
+ while (parent && !parent->is_bucket())
+ segments.push_back(&parent->object_name());
+ /* hash path */
+ XXH64_state_t hs;
+ XXH64_reset(&hs, fh_key::seed);
+ bool first = true;
+ for (auto& s : boost::adaptors::reverse(segments)) {
+ if (! first)
+ (void) XXH64_update(&hs, (void*) "/", 1);
+ else
+ first = false;
+ (void) XXH64_update(&hs, s->c_str(), s->size());
+ }
+ return fh_key(fhk.fh_hk.object, XXH64_digest(&hs));
+ }
+ }
+
bool is_open() const { return flags & FLAG_OPEN; }
bool is_root() const { return flags & FLAG_ROOT; }
bool is_bucket() const { return (fh.fh_type == RGW_FS_TYPE_DIRECTORY); }
flags |= FLAG_CREATE;
}
+ void set_pseudo() {
+ flags |= FLAG_PSEUDO;
+ }
+
void set_nlink(const uint64_t n) {
state.nlink = n;
}
/* find or create an RGWFileHandle */
LookupFHResult lookup_fh(RGWFileHandle* parent, const char *name) {
+ std::string sname(name);
RGWFileHandle::FHCache::Latch lat;
- fh_key fhk(parent->fhk.fh_hk.object, name);
+ fh_key fhk = parent->make_fhk(sname);
LookupFHResult fhr { nullptr, RGWFileHandle::FLAG_NONE };
using std::get;
RGWFileHandle::FHCache::FLAG_LOCK);
/* LATCHED */
if (! fh) {
- fh = new RGWFileHandle(this, get_inst(), parent, fhk, name);
+ fh = new RGWFileHandle(this, get_inst(), parent, fhk, sname);
intrusive_ptr_add_ref(fh); /* sentinel ref */
fh_cache.insert_latched(fh, lat,
RGWFileHandle::FHCache::FLAG_NONE);