]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_file.h
update sources to 12.2.7
[ceph.git] / ceph / src / rgw / rgw_file.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#ifndef RGW_FILE_H
5#define RGW_FILE_H
6
7#include "include/rados/rgw_file.h"
8
9/* internal header */
10#include <string.h>
11#include <sys/stat.h>
12#include <stdint.h>
13
14#include <atomic>
15#include <chrono>
16#include <thread>
17#include <mutex>
18#include <vector>
19#include <deque>
20#include <algorithm>
21#include <functional>
22#include <boost/intrusive_ptr.hpp>
23#include <boost/range/adaptor/reversed.hpp>
24#include <boost/container/flat_map.hpp>
25#include <boost/variant.hpp>
26#include <boost/utility/string_ref.hpp>
27#include <boost/optional.hpp>
28#include "xxhash.h"
29#include "include/buffer.h"
30#include "common/cohort_lru.h"
31#include "common/ceph_timer.h"
32#include "rgw_common.h"
33#include "rgw_user.h"
34#include "rgw_lib.h"
35#include "rgw_ldap.h"
36#include "rgw_token.h"
224ce89b 37#include "rgw_compression.h"
7c673cae
FG
38
39
40/* XXX
41 * ASSERT_H somehow not defined after all the above (which bring
42 * in common/debug.h [e.g., dout])
43 */
44#include "include/assert.h"
45
46
47#define RGW_RWXMODE (S_IRWXU | S_IRWXG | S_IRWXO)
48
49#define RGW_RWMODE (RGW_RWXMODE & \
50 ~(S_IXUSR | S_IXGRP | S_IXOTH))
51
52
53namespace rgw {
54
55 template <typename T>
56 static inline void ignore(T &&) {}
57
58
59 namespace bi = boost::intrusive;
60
61 class RGWLibFS;
62 class RGWFileHandle;
63 class RGWWriteRequest;
64
65 static inline bool operator <(const struct timespec& lhs,
66 const struct timespec& rhs) {
67 if (lhs.tv_sec == rhs.tv_sec)
68 return lhs.tv_nsec < rhs.tv_nsec;
69 else
70 return lhs.tv_sec < rhs.tv_sec;
71 }
72
73 static inline bool operator ==(const struct timespec& lhs,
74 const struct timespec& rhs) {
75 return ((lhs.tv_sec == rhs.tv_sec) &&
76 (lhs.tv_nsec == rhs.tv_nsec));
77 }
78
79 /*
80 * XXX
81 * The current 64-bit, non-cryptographic hash used here is intended
82 * for prototyping only.
83 *
84 * However, the invariant being prototyped is that objects be
85 * identifiable by their hash components alone. We believe this can
86 * be legitimately implemented using 128-hash values for bucket and
87 * object components, together with a cluster-resident cryptographic
88 * key. Since an MD5 or SHA-1 key is 128 bits and the (fast),
89 * non-cryptographic CityHash128 hash algorithm takes a 128-bit seed,
90 * speculatively we could use that for the final hash computations.
91 */
92 struct fh_key
93 {
94 rgw_fh_hk fh_hk;
224ce89b 95 uint32_t version;
7c673cae
FG
96
97 static constexpr uint64_t seed = 8675309;
98
224ce89b 99 fh_key() : version(0) {}
7c673cae
FG
100
101 fh_key(const rgw_fh_hk& _hk)
224ce89b 102 : fh_hk(_hk), version(0) {
7c673cae
FG
103 // nothing
104 }
105
224ce89b
WB
106 fh_key(const uint64_t bk, const uint64_t ok)
107 : version(0) {
7c673cae
FG
108 fh_hk.bucket = bk;
109 fh_hk.object = ok;
110 }
111
224ce89b
WB
112 fh_key(const uint64_t bk, const char *_o)
113 : version(0) {
7c673cae
FG
114 fh_hk.bucket = bk;
115 fh_hk.object = XXH64(_o, ::strlen(_o), seed);
116 }
117
224ce89b
WB
118 fh_key(const std::string& _b, const std::string& _o)
119 : version(0) {
7c673cae
FG
120 fh_hk.bucket = XXH64(_b.c_str(), _o.length(), seed);
121 fh_hk.object = XXH64(_o.c_str(), _o.length(), seed);
122 }
123
124 void encode(buffer::list& bl) const {
224ce89b 125 ENCODE_START(2, 1, bl);
7c673cae
FG
126 ::encode(fh_hk.bucket, bl);
127 ::encode(fh_hk.object, bl);
224ce89b 128 ::encode((uint32_t)2, bl);
7c673cae
FG
129 ENCODE_FINISH(bl);
130 }
131
132 void decode(bufferlist::iterator& bl) {
224ce89b 133 DECODE_START(2, bl);
7c673cae
FG
134 ::decode(fh_hk.bucket, bl);
135 ::decode(fh_hk.object, bl);
224ce89b
WB
136 if (struct_v >= 2) {
137 ::decode(version, bl);
138 }
7c673cae
FG
139 DECODE_FINISH(bl);
140 }
141 }; /* fh_key */
142
143 WRITE_CLASS_ENCODER(fh_key);
144
145 inline bool operator<(const fh_key& lhs, const fh_key& rhs)
146 {
147 return ((lhs.fh_hk.bucket < rhs.fh_hk.bucket) ||
148 ((lhs.fh_hk.bucket == rhs.fh_hk.bucket) &&
149 (lhs.fh_hk.object < rhs.fh_hk.object)));
150 }
151
152 inline bool operator>(const fh_key& lhs, const fh_key& rhs)
153 {
154 return (rhs < lhs);
155 }
156
157 inline bool operator==(const fh_key& lhs, const fh_key& rhs)
158 {
159 return ((lhs.fh_hk.bucket == rhs.fh_hk.bucket) &&
160 (lhs.fh_hk.object == rhs.fh_hk.object));
161 }
162
163 inline bool operator!=(const fh_key& lhs, const fh_key& rhs)
164 {
165 return !(lhs == rhs);
166 }
167
168 inline bool operator<=(const fh_key& lhs, const fh_key& rhs)
169 {
170 return (lhs < rhs) || (lhs == rhs);
171 }
172
173 using boost::variant;
174 using boost::container::flat_map;
175
3efd9988
FG
176 typedef std::tuple<bool, bool> DecodeAttrsResult;
177
7c673cae
FG
178 class RGWFileHandle : public cohort::lru::Object
179 {
180 struct rgw_file_handle fh;
181 std::mutex mtx;
182
183 RGWLibFS* fs;
184 RGWFileHandle* bucket;
185 RGWFileHandle* parent;
186 /* const */ std::string name; /* XXX file or bucket name */
187 /* const */ fh_key fhk;
188
189 using lock_guard = std::lock_guard<std::mutex>;
190 using unique_lock = std::unique_lock<std::mutex>;
191
192 /* TODO: keeping just the last marker is sufficient for
193 * nfs-ganesha 2.4.5; in the near future, nfs-ganesha will
194 * be able to hint the name of the next dirent required,
195 * from which we can directly synthesize a RADOS marker.
196 * using marker_cache_t = flat_map<uint64_t, rgw_obj_key>;
197 */
198
199 struct State {
200 uint64_t dev;
201 uint64_t size;
202 uint64_t nlink;
203 uint32_t owner_uid; /* XXX need Unix attr */
204 uint32_t owner_gid; /* XXX need Unix attr */
205 mode_t unix_mode;
206 struct timespec ctime;
207 struct timespec mtime;
208 struct timespec atime;
3efd9988 209 uint32_t version;
7c673cae 210 State() : dev(0), size(0), nlink(1), owner_uid(0), owner_gid(0),
3efd9988 211 ctime{0,0}, mtime{0,0}, atime{0,0}, version(0) {}
7c673cae
FG
212 } state;
213
214 struct file {
215 RGWWriteRequest* write_req;
216 file() : write_req(nullptr) {}
217 ~file();
218 };
219
220 struct directory {
221
222 static constexpr uint32_t FLAG_NONE = 0x0000;
223
224 uint32_t flags;
225 rgw_obj_key last_marker;
226 struct timespec last_readdir;
227
228 directory() : flags(FLAG_NONE), last_readdir{0,0} {}
229 };
230
231 void clear_state();
232
233 boost::variant<file, directory> variant_type;
234
235 uint16_t depth;
236 uint32_t flags;
237
238 public:
239 const static std::string root_name;
240
241 static constexpr uint16_t MAX_DEPTH = 256;
242
243 static constexpr uint32_t FLAG_NONE = 0x0000;
244 static constexpr uint32_t FLAG_OPEN = 0x0001;
245 static constexpr uint32_t FLAG_ROOT = 0x0002;
246 static constexpr uint32_t FLAG_CREATE = 0x0004;
247 static constexpr uint32_t FLAG_CREATING = 0x0008;
248 static constexpr uint32_t FLAG_DIRECTORY = 0x0010;
249 static constexpr uint32_t FLAG_BUCKET = 0x0020;
250 static constexpr uint32_t FLAG_LOCK = 0x0040;
251 static constexpr uint32_t FLAG_DELETED = 0x0080;
252 static constexpr uint32_t FLAG_UNLINK_THIS = 0x0100;
253 static constexpr uint32_t FLAG_LOCKED = 0x0200;
254 static constexpr uint32_t FLAG_STATELESS_OPEN = 0x0400;
255 static constexpr uint32_t FLAG_EXACT_MATCH = 0x0800;
3efd9988 256 static constexpr uint32_t FLAG_MOUNT = 0x1000;
7c673cae
FG
257
258#define CREATE_FLAGS(x) \
259 ((x) & ~(RGWFileHandle::FLAG_CREATE|RGWFileHandle::FLAG_LOCK))
260
261 friend class RGWLibFS;
262
263 private:
3efd9988 264 RGWFileHandle(RGWLibFS* _fs)
7c673cae 265 : fs(_fs), bucket(nullptr), parent(nullptr), variant_type{directory()},
3efd9988 266 depth(0), flags(FLAG_NONE)
7c673cae
FG
267 {
268 /* root */
269 fh.fh_type = RGW_FS_TYPE_DIRECTORY;
270 variant_type = directory();
271 /* stat */
7c673cae
FG
272 state.unix_mode = RGW_RWXMODE|S_IFDIR;
273 /* pointer to self */
274 fh.fh_private = this;
275 }
276
3efd9988
FG
277 uint64_t init_fsid(std::string& uid) {
278 return XXH64(uid.c_str(), uid.length(), fh_key::seed);
279 }
280
281 void init_rootfs(std::string& fsid, const std::string& object_name,
282 bool is_bucket) {
7c673cae
FG
283 /* fh_key */
284 fh.fh_hk.bucket = XXH64(fsid.c_str(), fsid.length(), fh_key::seed);
285 fh.fh_hk.object = XXH64(object_name.c_str(), object_name.length(),
286 fh_key::seed);
287 fhk = fh.fh_hk;
288 name = object_name;
3efd9988
FG
289
290 state.dev = init_fsid(fsid);
291
292 if (is_bucket) {
293 flags |= RGWFileHandle::FLAG_BUCKET | RGWFileHandle::FLAG_MOUNT;
294 bucket = this;
295 depth = 1;
296 } else {
297 flags |= RGWFileHandle::FLAG_ROOT | RGWFileHandle::FLAG_MOUNT;
298 }
7c673cae
FG
299 }
300
301 public:
3efd9988 302 RGWFileHandle(RGWLibFS* _fs, RGWFileHandle* _parent,
7c673cae 303 const fh_key& _fhk, std::string& _name, uint32_t _flags)
3efd9988 304 : fs(_fs), bucket(nullptr), parent(_parent), name(std::move(_name)),
7c673cae
FG
305 fhk(_fhk), flags(_flags) {
306
307 if (parent->is_root()) {
308 fh.fh_type = RGW_FS_TYPE_DIRECTORY;
309 variant_type = directory();
310 flags |= FLAG_BUCKET;
311 } else {
31f18b77 312 bucket = parent->is_bucket() ? parent
7c673cae
FG
313 : parent->bucket;
314 if (flags & FLAG_DIRECTORY) {
315 fh.fh_type = RGW_FS_TYPE_DIRECTORY;
316 variant_type = directory();
317 } else {
318 fh.fh_type = RGW_FS_TYPE_FILE;
319 variant_type = file();
320 }
321 }
322
323 depth = parent->depth + 1;
324
325 /* save constant fhk */
326 fh.fh_hk = fhk.fh_hk; /* XXX redundant in fh_hk */
327
3efd9988
FG
328 /* inherits parent's fsid */
329 state.dev = parent->state.dev;
7c673cae
FG
330
331 switch (fh.fh_type) {
332 case RGW_FS_TYPE_DIRECTORY:
333 state.unix_mode = RGW_RWXMODE|S_IFDIR;
334 break;
335 case RGW_FS_TYPE_FILE:
336 state.unix_mode = RGW_RWMODE|S_IFREG;
337 default:
338 break;
339 }
340
341 /* pointer to self */
342 fh.fh_private = this;
343 }
344
345 const fh_key& get_key() const {
346 return fhk;
347 }
348
349 directory* get_directory() {
350 return get<directory>(&variant_type);
351 }
352
353 size_t get_size() const { return state.size; }
354
355 const char* stype() {
356 return is_dir() ? "DIR" : "FILE";
357 }
358
359 uint16_t get_depth() const { return depth; }
360
361 struct rgw_file_handle* get_fh() { return &fh; }
362
363 RGWLibFS* get_fs() { return fs; }
364
365 RGWFileHandle* get_parent() { return parent; }
366
367 uint32_t get_owner_uid() const { return state.owner_uid; }
368 uint32_t get_owner_gid() const { return state.owner_gid; }
369
370 struct timespec get_ctime() const { return state.ctime; }
371 struct timespec get_mtime() const { return state.mtime; }
372
373 void create_stat(struct stat* st, uint32_t mask) {
374 if (mask & RGW_SETATTR_UID)
375 state.owner_uid = st->st_uid;
376
377 if (mask & RGW_SETATTR_GID)
378 state.owner_gid = st->st_gid;
379
380 if (mask & RGW_SETATTR_MODE) {
381 switch (fh.fh_type) {
382 case RGW_FS_TYPE_DIRECTORY:
383 state.unix_mode = st->st_mode|S_IFDIR;
384 break;
385 case RGW_FS_TYPE_FILE:
386 state.unix_mode = st->st_mode|S_IFREG;
387 default:
388 break;
389 }
390 }
391
392 if (mask & RGW_SETATTR_ATIME)
393 state.atime = st->st_atim;
394 if (mask & RGW_SETATTR_MTIME)
395 state.mtime = st->st_mtim;
396 if (mask & RGW_SETATTR_CTIME)
397 state.ctime = st->st_ctim;
398 }
399
400 int stat(struct stat* st) {
401 /* partial Unix attrs */
402 memset(st, 0, sizeof(struct stat));
403 st->st_dev = state.dev;
404 st->st_ino = fh.fh_hk.object; // XXX
405
406 st->st_uid = state.owner_uid;
407 st->st_gid = state.owner_gid;
408
409 st->st_mode = state.unix_mode;
410
411#ifdef HAVE_STAT_ST_MTIMESPEC_TV_NSEC
412 st->st_atimespec = state.atime;
413 st->st_mtimespec = state.mtime;
414 st->st_ctimespec = state.ctime;
415#else
416 st->st_atim = state.atime;
417 st->st_mtim = state.mtime;
418 st->st_ctim = state.ctime;
419#endif
420
421 switch (fh.fh_type) {
422 case RGW_FS_TYPE_DIRECTORY:
423 st->st_nlink = state.nlink;
424 break;
425 case RGW_FS_TYPE_FILE:
426 st->st_nlink = 1;
427 st->st_blksize = 4096;
428 st->st_size = state.size;
429 st->st_blocks = (state.size) / 512;
430 default:
431 break;
432 }
433
434 return 0;
435 }
436
437 const std::string& bucket_name() const {
438 if (is_root())
439 return root_name;
31f18b77 440 if (is_bucket())
7c673cae
FG
441 return name;
442 return bucket->object_name();
443 }
444
445 const std::string& object_name() const { return name; }
446
447 std::string full_object_name(bool omit_bucket = false) const {
448 std::string path;
449 std::vector<const std::string*> segments;
450 int reserve = 0;
451 const RGWFileHandle* tfh = this;
452 while (tfh && !tfh->is_root() && !(tfh->is_bucket() && omit_bucket)) {
453 segments.push_back(&tfh->object_name());
454 reserve += (1 + tfh->object_name().length());
455 tfh = tfh->parent;
456 }
457 bool first = true;
458 path.reserve(reserve);
459 for (auto& s : boost::adaptors::reverse(segments)) {
460 if (! first)
461 path += "/";
462 else {
463 if (!omit_bucket && (path.front() != '/')) // pretty-print
464 path += "/";
465 first = false;
466 }
467 path += *s;
468 }
469 return path;
470 }
471
472 inline std::string relative_object_name() const {
473 return full_object_name(true /* omit_bucket */);
474 }
475
31f18b77
FG
476 inline std::string format_child_name(const std::string& cbasename,
477 bool is_dir) const {
7c673cae
FG
478 std::string child_name{relative_object_name()};
479 if ((child_name.size() > 0) &&
480 (child_name.back() != '/'))
481 child_name += "/";
482 child_name += cbasename;
31f18b77
FG
483 if (is_dir)
484 child_name += "/";
7c673cae
FG
485 return child_name;
486 }
487
488 inline std::string make_key_name(const char *name) const {
489 std::string key_name{full_object_name()};
490 if (key_name.length() > 0)
491 key_name += "/";
492 key_name += name;
493 return key_name;
494 }
495
496 fh_key make_fhk(const std::string& name) const {
497 if (depth <= 1)
498 return fh_key(fhk.fh_hk.object, name.c_str());
499 else {
500 std::string key_name = make_key_name(name.c_str());
501 return fh_key(fhk.fh_hk.bucket, key_name.c_str());
502 }
503 }
504
505 void add_marker(uint64_t off, const rgw_obj_key& marker,
506 uint8_t obj_type) {
507 using std::get;
508 directory* d = get<directory>(&variant_type);
509 if (d) {
510 unique_lock guard(mtx);
511 d->last_marker = marker;
512 }
513 }
514
515 const rgw_obj_key* find_marker(uint64_t off) const {
516 using std::get;
517 if (off > 0) {
518 const directory* d = get<directory>(&variant_type);
519 if (d ) {
520 return &d->last_marker;
521 }
522 }
523 return nullptr;
524 }
525
c07f9fc5
FG
526 int offset_of(const std::string& name, int64_t *offset, uint32_t flags) {
527 if (unlikely(! is_dir())) {
528 return -EINVAL;
529 }
530 *offset = XXH64(name.c_str(), name.length(), fh_key::seed);
531 return 0;
532 }
533
7c673cae
FG
534 bool is_open() const { return flags & FLAG_OPEN; }
535 bool is_root() const { return flags & FLAG_ROOT; }
3efd9988 536 bool is_mount() const { return flags & FLAG_MOUNT; }
7c673cae
FG
537 bool is_bucket() const { return flags & FLAG_BUCKET; }
538 bool is_object() const { return !is_bucket(); }
539 bool is_file() const { return (fh.fh_type == RGW_FS_TYPE_FILE); }
540 bool is_dir() const { return (fh.fh_type == RGW_FS_TYPE_DIRECTORY); }
541 bool creating() const { return flags & FLAG_CREATING; }
542 bool deleted() const { return flags & FLAG_DELETED; }
543 bool stateless_open() const { return flags & FLAG_STATELESS_OPEN; }
544 bool has_children() const;
545
546 int open(uint32_t gsh_flags) {
547 lock_guard guard(mtx);
31f18b77 548 if (! is_open()) {
7c673cae
FG
549 if (gsh_flags & RGW_OPEN_FLAG_V3) {
550 flags |= FLAG_STATELESS_OPEN;
551 }
552 flags |= FLAG_OPEN;
553 return 0;
554 }
555 return -EPERM;
556 }
557
3efd9988
FG
558 typedef boost::variant<uint64_t*, const char*> readdir_offset;
559
560 int readdir(rgw_readdir_cb rcb, void *cb_arg, readdir_offset offset,
561 bool *eof, uint32_t flags);
562
7c673cae
FG
563 int write(uint64_t off, size_t len, size_t *nbytes, void *buffer);
564
565 int commit(uint64_t offset, uint64_t length, uint32_t flags) {
566 /* NFS3 and NFSv4 COMMIT implementation
567 * the current atomic update strategy doesn't actually permit
568 * clients to read-stable until either CLOSE (NFSv4+) or the
569 * expiration of the active write timer (NFS3). In the
570 * interim, the client may send an arbitrary number of COMMIT
571 * operations which must return a success result */
572 return 0;
573 }
574
575 int write_finish(uint32_t flags = FLAG_NONE);
576 int close();
577
578 void open_for_create() {
579 lock_guard guard(mtx);
580 flags |= FLAG_CREATING;
581 }
582
583 void clear_creating() {
584 lock_guard guard(mtx);
585 flags &= ~FLAG_CREATING;
586 }
587
588 void inc_nlink(const uint64_t n) {
589 state.nlink += n;
590 }
591
592 void set_nlink(const uint64_t n) {
593 state.nlink = n;
594 }
595
596 void set_size(const size_t size) {
597 state.size = size;
598 }
599
600 void set_times(real_time t) {
601 state.ctime = real_clock::to_timespec(t);
602 state.mtime = state.ctime;
603 state.atime = state.ctime;
604 }
605
606 void set_ctime(const struct timespec &ts) {
607 state.ctime = ts;
608 }
609
610 void set_mtime(const struct timespec &ts) {
611 state.mtime = ts;
612 }
613
614 void set_atime(const struct timespec &ts) {
615 state.atime = ts;
616 }
617
618 void encode(buffer::list& bl) const {
3efd9988 619 ENCODE_START(2, 1, bl);
7c673cae
FG
620 ::encode(uint32_t(fh.fh_type), bl);
621 ::encode(state.dev, bl);
622 ::encode(state.size, bl);
623 ::encode(state.nlink, bl);
624 ::encode(state.owner_uid, bl);
625 ::encode(state.owner_gid, bl);
626 ::encode(state.unix_mode, bl);
627 for (const auto& t : { state.ctime, state.mtime, state.atime }) {
628 ::encode(real_clock::from_timespec(t), bl);
629 }
3efd9988 630 ::encode((uint32_t)2, bl);
7c673cae
FG
631 ENCODE_FINISH(bl);
632 }
633
634 void decode(bufferlist::iterator& bl) {
3efd9988 635 DECODE_START(2, bl);
7c673cae
FG
636 uint32_t fh_type;
637 ::decode(fh_type, bl);
638 assert(fh.fh_type == fh_type);
639 ::decode(state.dev, bl);
640 ::decode(state.size, bl);
641 ::decode(state.nlink, bl);
642 ::decode(state.owner_uid, bl);
643 ::decode(state.owner_gid, bl);
644 ::decode(state.unix_mode, bl);
645 ceph::real_time enc_time;
646 for (auto t : { &(state.ctime), &(state.mtime), &(state.atime) }) {
647 ::decode(enc_time, bl);
648 *t = real_clock::to_timespec(enc_time);
649 }
3efd9988
FG
650 if (struct_v >= 2) {
651 ::decode(state.version, bl);
652 }
7c673cae
FG
653 DECODE_FINISH(bl);
654 }
655
656 void encode_attrs(ceph::buffer::list& ux_key1,
657 ceph::buffer::list& ux_attrs1);
658
3efd9988
FG
659 DecodeAttrsResult decode_attrs(const ceph::buffer::list* ux_key1,
660 const ceph::buffer::list* ux_attrs1);
7c673cae
FG
661
662 void invalidate();
663
664 bool reclaim() override;
665
666 typedef cohort::lru::LRU<std::mutex> FhLRU;
667
668 struct FhLT
669 {
670 // for internal ordering
671 bool operator()(const RGWFileHandle& lhs, const RGWFileHandle& rhs) const
672 { return (lhs.get_key() < rhs.get_key()); }
673
674 // for external search by fh_key
675 bool operator()(const fh_key& k, const RGWFileHandle& fh) const
676 { return k < fh.get_key(); }
677
678 bool operator()(const RGWFileHandle& fh, const fh_key& k) const
679 { return fh.get_key() < k; }
680 };
681
682 struct FhEQ
683 {
684 bool operator()(const RGWFileHandle& lhs, const RGWFileHandle& rhs) const
685 { return (lhs.get_key() == rhs.get_key()); }
686
687 bool operator()(const fh_key& k, const RGWFileHandle& fh) const
688 { return k == fh.get_key(); }
689
690 bool operator()(const RGWFileHandle& fh, const fh_key& k) const
691 { return fh.get_key() == k; }
692 };
693
694 typedef bi::link_mode<bi::safe_link> link_mode; /* XXX normal */
695#if defined(FHCACHE_AVL)
696 typedef bi::avl_set_member_hook<link_mode> tree_hook_type;
697#else
698 /* RBT */
699 typedef bi::set_member_hook<link_mode> tree_hook_type;
700#endif
701 tree_hook_type fh_hook;
702
703 typedef bi::member_hook<
704 RGWFileHandle, tree_hook_type, &RGWFileHandle::fh_hook> FhHook;
705
706#if defined(FHCACHE_AVL)
707 typedef bi::avltree<RGWFileHandle, bi::compare<FhLT>, FhHook> FHTree;
708#else
709 typedef bi::rbtree<RGWFileHandle, bi::compare<FhLT>, FhHook> FhTree;
710#endif
711 typedef cohort::lru::TreeX<RGWFileHandle, FhTree, FhLT, FhEQ, fh_key,
712 std::mutex> FHCache;
713
714 ~RGWFileHandle() override;
715
716 friend std::ostream& operator<<(std::ostream &os,
717 RGWFileHandle const &rgw_fh);
718
719 class Factory : public cohort::lru::ObjectFactory
720 {
721 public:
722 RGWLibFS* fs;
7c673cae
FG
723 RGWFileHandle* parent;
724 const fh_key& fhk;
725 std::string& name;
726 uint32_t flags;
727
728 Factory() = delete;
729
3efd9988
FG
730 Factory(RGWLibFS* _fs, RGWFileHandle* _parent,
731 const fh_key& _fhk, std::string& _name, uint32_t _flags)
732 : fs(_fs), parent(_parent), fhk(_fhk), name(_name),
733 flags(_flags) {}
7c673cae
FG
734
735 void recycle (cohort::lru::Object* o) override {
736 /* re-use an existing object */
737 o->~Object(); // call lru::Object virtual dtor
738 // placement new!
3efd9988 739 new (o) RGWFileHandle(fs, parent, fhk, name, flags);
7c673cae
FG
740 }
741
742 cohort::lru::Object* alloc() override {
3efd9988 743 return new RGWFileHandle(fs, parent, fhk, name, flags);
7c673cae
FG
744 }
745 }; /* Factory */
746
747 }; /* RGWFileHandle */
748
749 WRITE_CLASS_ENCODER(RGWFileHandle);
750
751 static inline RGWFileHandle* get_rgwfh(struct rgw_file_handle* fh) {
752 return static_cast<RGWFileHandle*>(fh->fh_private);
753 }
754
755 static inline enum rgw_fh_type fh_type_of(uint32_t flags) {
756 enum rgw_fh_type fh_type;
757 switch(flags & RGW_LOOKUP_TYPE_FLAGS)
758 {
759 case RGW_LOOKUP_FLAG_DIR:
760 fh_type = RGW_FS_TYPE_DIRECTORY;
761 break;
762 case RGW_LOOKUP_FLAG_FILE:
763 fh_type = RGW_FS_TYPE_FILE;
764 break;
765 default:
766 fh_type = RGW_FS_TYPE_NIL;
767 };
768 return fh_type;
769 }
770
771 typedef std::tuple<RGWFileHandle*, uint32_t> LookupFHResult;
772 typedef std::tuple<RGWFileHandle*, int> MkObjResult;
773
774 class RGWLibFS
775 {
776 CephContext* cct;
224ce89b 777 struct rgw_fs fs{};
7c673cae
FG
778 RGWFileHandle root_fh;
779 rgw_fh_callback_t invalidate_cb;
780 void *invalidate_arg;
781 bool shutdown;
782
783 mutable std::atomic<uint64_t> refcnt;
784
785 RGWFileHandle::FHCache fh_cache;
786 RGWFileHandle::FhLRU fh_lru;
787
788 std::string uid; // should match user.user_id, iiuc
789
790 RGWUserInfo user;
791 RGWAccessKey key; // XXXX acc_key
792
793 static std::atomic<uint32_t> fs_inst_counter;
794
795 static uint32_t write_completion_interval_s;
7c673cae
FG
796
797 using lock_guard = std::lock_guard<std::mutex>;
798 using unique_lock = std::unique_lock<std::mutex>;
799
800 struct event
801 {
802 enum class type : uint8_t { READDIR } ;
803 type t;
804 const fh_key fhk;
805 struct timespec ts;
806 event(type t, const fh_key& k, const struct timespec& ts)
807 : t(t), fhk(k), ts(ts) {}
808 };
809
810 friend std::ostream& operator<<(std::ostream &os,
811 RGWLibFS::event const &ev);
812
813 using event_vector = /* boost::small_vector<event, 16> */
814 std::vector<event>;
815
816 struct WriteCompletion
817 {
818 RGWFileHandle& rgw_fh;
819
820 WriteCompletion(RGWFileHandle& _fh) : rgw_fh(_fh) {
821 rgw_fh.get_fs()->ref(&rgw_fh);
822 }
823
824 void operator()() {
31f18b77 825 rgw_fh.close(); /* will finish in-progress write */
7c673cae
FG
826 rgw_fh.get_fs()->unref(&rgw_fh);
827 }
828 };
829
830 static ceph::timer<ceph::mono_clock> write_timer;
831
832 struct State {
833 std::mutex mtx;
834 std::atomic<uint32_t> flags;
835 std::deque<event> events;
836
837 State() : flags(0) {}
838
839 void push_event(const event& ev) {
840 events.push_back(ev);
841 }
842 } state;
843
844 uint32_t new_inst() {
845 return ++fs_inst_counter;
846 }
847
848 friend class RGWFileHandle;
849 friend class RGWLibProcess;
850
851 public:
852
853 static constexpr uint32_t FLAG_NONE = 0x0000;
854 static constexpr uint32_t FLAG_CLOSED = 0x0001;
855
31f18b77
FG
856 struct BucketStats {
857 size_t size;
858 size_t size_rounded;
859 real_time creation_time;
860 uint64_t num_entries;
861 };
862
7c673cae 863 RGWLibFS(CephContext* _cct, const char *_uid, const char *_user_id,
3efd9988
FG
864 const char* _key, const char *root)
865 : cct(_cct), root_fh(this), invalidate_cb(nullptr),
7c673cae
FG
866 invalidate_arg(nullptr), shutdown(false), refcnt(1),
867 fh_cache(cct->_conf->rgw_nfs_fhcache_partitions,
868 cct->_conf->rgw_nfs_fhcache_size),
869 fh_lru(cct->_conf->rgw_nfs_lru_lanes,
870 cct->_conf->rgw_nfs_lru_lane_hiwat),
871 uid(_uid), key(_user_id, _key) {
872
3efd9988
FG
873 if (!root || !strcmp(root, "/")) {
874 root_fh.init_rootfs(uid, RGWFileHandle::root_name, false);
875 } else {
876 root_fh.init_rootfs(uid, root, true);
877 }
7c673cae
FG
878
879 /* pointer to self */
880 fs.fs_private = this;
881
882 /* expose public root fh */
883 fs.root_fh = root_fh.get_fh();
3efd9988
FG
884
885 new_inst();
7c673cae
FG
886 }
887
888 friend void intrusive_ptr_add_ref(const RGWLibFS* fs) {
889 fs->refcnt.fetch_add(1, std::memory_order_relaxed);
890 }
891
892 friend void intrusive_ptr_release(const RGWLibFS* fs) {
893 if (fs->refcnt.fetch_sub(1, std::memory_order_release) == 0) {
894 std::atomic_thread_fence(std::memory_order_acquire);
895 delete fs;
896 }
897 }
898
899 RGWLibFS* ref() {
900 intrusive_ptr_add_ref(this);
901 return this;
902 }
903
904 inline void rele() {
905 intrusive_ptr_release(this);
906 }
907
908 void stop() { shutdown = true; }
909
910 void release_evict(RGWFileHandle* fh) {
911 /* remove from cache, releases sentinel ref */
912 fh_cache.remove(fh->fh.fh_hk.object, fh,
913 RGWFileHandle::FHCache::FLAG_LOCK);
914 /* release call-path ref */
915 (void) fh_lru.unref(fh, cohort::lru::FLAG_NONE);
916 }
917
918 int authorize(RGWRados* store) {
919 int ret = rgw_get_user_info_by_access_key(store, key.id, user);
920 if (ret == 0) {
921 RGWAccessKey* key0 = user.get_key0();
922 if (!key0 ||
923 (key0->key != key.key))
924 return -EINVAL;
925 if (user.suspended)
926 return -ERR_USER_SUSPENDED;
927 } else {
928 /* try external authenticators (ldap for now) */
929 rgw::LDAPHelper* ldh = rgwlib.get_ldh(); /* !nullptr */
930 RGWToken token;
931 /* boost filters and/or string_ref may throw on invalid input */
932 try {
933 token = rgw::from_base64(key.id);
934 } catch(...) {
935 token = std::string("");
936 }
937 if (token.valid() && (ldh->auth(token.id, token.key) == 0)) {
938 /* try to store user if it doesn't already exist */
939 if (rgw_get_user_info_by_uid(store, token.id, user) < 0) {
940 int ret = rgw_store_user_info(store, user, NULL, NULL, real_time(),
941 true);
942 if (ret < 0) {
943 lsubdout(get_context(), rgw, 10)
944 << "NOTICE: failed to store new user's info: ret=" << ret
945 << dendl;
946 }
947 }
948 } /* auth success */
949 }
950 return ret;
951 } /* authorize */
952
953 int register_invalidate(rgw_fh_callback_t cb, void *arg, uint32_t flags) {
954 invalidate_cb = cb;
955 invalidate_arg = arg;
956 return 0;
957 }
958
959 /* find RGWFileHandle by id */
960 LookupFHResult lookup_fh(const fh_key& fhk,
961 const uint32_t flags = RGWFileHandle::FLAG_NONE) {
962 using std::get;
963
964 // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang
965 // the cast transfers a lvalue into a rvalue in the ctor
966 // check the commit message for the full details
967 LookupFHResult fhr { nullptr, uint32_t(RGWFileHandle::FLAG_NONE) };
968
969 RGWFileHandle::FHCache::Latch lat;
31f18b77 970 bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED;
7c673cae
FG
971
972 retry:
973 RGWFileHandle* fh =
974 fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/,
975 fhk /* key */, lat /* serializer */,
976 RGWFileHandle::FHCache::FLAG_LOCK);
977 /* LATCHED */
978 if (fh) {
31f18b77
FG
979 if (likely(! fh_locked))
980 fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
7c673cae
FG
981 /* need initial ref from LRU (fast path) */
982 if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) {
983 lat.lock->unlock();
31f18b77
FG
984 if (likely(! fh_locked))
985 fh->mtx.unlock();
7c673cae
FG
986 goto retry; /* !LATCHED */
987 }
988 /* LATCHED, LOCKED */
989 if (! (flags & RGWFileHandle::FLAG_LOCK))
990 fh->mtx.unlock(); /* ! LOCKED */
991 }
992 lat.lock->unlock(); /* !LATCHED */
993 get<0>(fhr) = fh;
994 if (fh) {
995 lsubdout(get_context(), rgw, 17)
996 << __func__ << " 1 " << *fh
997 << dendl;
998 }
999 return fhr;
1000 } /* lookup_fh(const fh_key&) */
1001
1002 /* find or create an RGWFileHandle */
1003 LookupFHResult lookup_fh(RGWFileHandle* parent, const char *name,
1004 const uint32_t flags = RGWFileHandle::FLAG_NONE) {
1005 using std::get;
1006
1007 // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang
1008 // the cast transfers a lvalue into a rvalue in the ctor
1009 // check the commit message for the full details
1010 LookupFHResult fhr { nullptr, uint32_t(RGWFileHandle::FLAG_NONE) };
1011
1012 /* mount is stale? */
1013 if (state.flags & FLAG_CLOSED)
1014 return fhr;
1015
1016 RGWFileHandle::FHCache::Latch lat;
31f18b77 1017 bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED;
7c673cae
FG
1018
1019 std::string obj_name{name};
1020 std::string key_name{parent->make_key_name(name)};
1021
1022 lsubdout(get_context(), rgw, 10)
1023 << __func__ << " lookup called on "
1024 << parent->object_name() << " for " << key_name
1025 << " (" << obj_name << ")"
1026 << dendl;
1027
224ce89b 1028 fh_key fhk = parent->make_fhk(obj_name);
7c673cae
FG
1029
1030 retry:
1031 RGWFileHandle* fh =
1032 fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/,
1033 fhk /* key */, lat /* serializer */,
1034 RGWFileHandle::FHCache::FLAG_LOCK);
1035 /* LATCHED */
1036 if (fh) {
31f18b77
FG
1037 if (likely(! fh_locked))
1038 fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
7c673cae
FG
1039 if (fh->flags & RGWFileHandle::FLAG_DELETED) {
1040 /* for now, delay briefly and retry */
1041 lat.lock->unlock();
31f18b77
FG
1042 if (likely(! fh_locked))
1043 fh->mtx.unlock();
7c673cae
FG
1044 std::this_thread::sleep_for(std::chrono::milliseconds(20));
1045 goto retry; /* !LATCHED */
1046 }
1047 /* need initial ref from LRU (fast path) */
1048 if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) {
1049 lat.lock->unlock();
31f18b77
FG
1050 if (likely(! fh_locked))
1051 fh->mtx.unlock();
7c673cae
FG
1052 goto retry; /* !LATCHED */
1053 }
1054 /* LATCHED, LOCKED */
1055 if (! (flags & RGWFileHandle::FLAG_LOCK))
31f18b77
FG
1056 if (likely(! fh_locked))
1057 fh->mtx.unlock(); /* ! LOCKED */
7c673cae
FG
1058 } else {
1059 /* make or re-use handle */
3efd9988 1060 RGWFileHandle::Factory prototype(this, parent, fhk,
7c673cae 1061 obj_name, CREATE_FLAGS(flags));
b32b8144 1062 uint32_t iflags{cohort::lru::FLAG_INITIAL};
7c673cae
FG
1063 fh = static_cast<RGWFileHandle*>(
1064 fh_lru.insert(&prototype,
1065 cohort::lru::Edge::MRU,
b32b8144 1066 iflags));
7c673cae
FG
1067 if (fh) {
1068 /* lock fh (LATCHED) */
1069 if (flags & RGWFileHandle::FLAG_LOCK)
1070 fh->mtx.lock();
b32b8144
FG
1071 if (likely(! (iflags & cohort::lru::FLAG_RECYCLE))) {
1072 /* inserts at cached insert iterator, releasing latch */
1073 fh_cache.insert_latched(
1074 fh, lat, RGWFileHandle::FHCache::FLAG_UNLOCK);
1075 } else {
1076 /* recycle step invalidates Latch */
1077 fh_cache.insert(
1078 fhk.fh_hk.object, fh, RGWFileHandle::FHCache::FLAG_NONE);
1079 lat.lock->unlock(); /* !LATCHED */
1080 }
7c673cae
FG
1081 get<1>(fhr) |= RGWFileHandle::FLAG_CREATE;
1082 /* ref parent (non-initial ref cannot fail on valid object) */
3efd9988 1083 if (! parent->is_mount()) {
7c673cae
FG
1084 (void) fh_lru.ref(parent, cohort::lru::FLAG_NONE);
1085 }
1086 goto out; /* !LATCHED */
1087 } else {
1088 lat.lock->unlock();
1089 goto retry; /* !LATCHED */
1090 }
1091 }
1092 lat.lock->unlock(); /* !LATCHED */
1093 out:
1094 get<0>(fhr) = fh;
1095 if (fh) {
1096 lsubdout(get_context(), rgw, 17)
1097 << __func__ << " 2 " << *fh
1098 << dendl;
1099 }
1100 return fhr;
1101 } /* lookup_fh(RGWFileHandle*, const char *, const uint32_t) */
1102
1103 inline void unref(RGWFileHandle* fh) {
3efd9988 1104 if (likely(! fh->is_mount())) {
7c673cae
FG
1105 (void) fh_lru.unref(fh, cohort::lru::FLAG_NONE);
1106 }
1107 }
1108
1109 inline RGWFileHandle* ref(RGWFileHandle* fh) {
3efd9988 1110 if (likely(! fh->is_mount())) {
7c673cae
FG
1111 fh_lru.ref(fh, cohort::lru::FLAG_NONE);
1112 }
1113 return fh;
1114 }
1115
1116 int getattr(RGWFileHandle* rgw_fh, struct stat* st);
1117
1118 int setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
1119 uint32_t flags);
1120
3efd9988 1121 void update_fh(RGWFileHandle *rgw_fh);
224ce89b 1122
31f18b77
FG
1123 LookupFHResult stat_bucket(RGWFileHandle* parent, const char *path,
1124 RGWLibFS::BucketStats& bs,
1125 uint32_t flags);
7c673cae
FG
1126
1127 LookupFHResult stat_leaf(RGWFileHandle* parent, const char *path,
1128 enum rgw_fh_type type = RGW_FS_TYPE_NIL,
1129 uint32_t flags = RGWFileHandle::FLAG_NONE);
1130
1131 int read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
1132 size_t* bytes_read, void* buffer, uint32_t flags);
1133
1134 int rename(RGWFileHandle* old_fh, RGWFileHandle* new_fh,
1135 const char *old_name, const char *new_name);
1136
1137 MkObjResult create(RGWFileHandle* parent, const char *name, struct stat *st,
1138 uint32_t mask, uint32_t flags);
1139
1140 MkObjResult mkdir(RGWFileHandle* parent, const char *name, struct stat *st,
1141 uint32_t mask, uint32_t flags);
7c673cae
FG
1142
1143 int unlink(RGWFileHandle* rgw_fh, const char *name,
1144 uint32_t flags = FLAG_NONE);
1145
1146 /* find existing RGWFileHandle */
1147 RGWFileHandle* lookup_handle(struct rgw_fh_hk fh_hk) {
1148
1149 if (state.flags & FLAG_CLOSED)
1150 return nullptr;
1151
1152 RGWFileHandle::FHCache::Latch lat;
1153 fh_key fhk(fh_hk);
1154
1155 retry:
1156 RGWFileHandle* fh =
1157 fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/,
1158 fhk /* key */, lat /* serializer */,
1159 RGWFileHandle::FHCache::FLAG_LOCK);
1160 /* LATCHED */
1161 if (! fh) {
1162 lsubdout(get_context(), rgw, 0)
1163 << __func__ << " handle lookup failed <"
1164 << fhk.fh_hk.bucket << "," << fhk.fh_hk.object << ">"
1165 << "(need persistent handles)"
1166 << dendl;
1167 goto out;
1168 }
1169 fh->mtx.lock();
1170 if (fh->flags & RGWFileHandle::FLAG_DELETED) {
1171 /* for now, delay briefly and retry */
1172 lat.lock->unlock();
1173 fh->mtx.unlock(); /* !LOCKED */
1174 std::this_thread::sleep_for(std::chrono::milliseconds(20));
1175 goto retry; /* !LATCHED */
1176 }
1177 if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) {
1178 lat.lock->unlock();
1179 fh->mtx.unlock();
1180 goto retry; /* !LATCHED */
1181 }
1182 /* LATCHED */
1183 fh->mtx.unlock(); /* !LOCKED */
1184 out:
1185 lat.lock->unlock(); /* !LATCHED */
1186
1187 /* special case: lookup root_fh */
1188 if (! fh) {
1189 if (unlikely(fh_hk == root_fh.fh.fh_hk)) {
1190 fh = &root_fh;
7c673cae
FG
1191 }
1192 }
1193
1194 return fh;
1195 }
1196
1197 CephContext* get_context() {
1198 return cct;
1199 }
1200
1201 struct rgw_fs* get_fs() { return &fs; }
1202
3efd9988 1203 uint64_t get_fsid() { return root_fh.state.dev; }
7c673cae
FG
1204
1205 RGWUserInfo* get_user() { return &user; }
1206
1207 void close();
1208 void gc();
1209 }; /* RGWLibFS */
1210
1211static inline std::string make_uri(const std::string& bucket_name,
1212 const std::string& object_name) {
1213 std::string uri("/");
1214 uri.reserve(bucket_name.length() + object_name.length() + 2);
1215 uri += bucket_name;
1216 uri += "/";
1217 uri += object_name;
1218 return uri;
1219}
1220
1221/*
1222 read directory content (buckets)
1223*/
1224
1225class RGWListBucketsRequest : public RGWLibRequest,
1226 public RGWListBuckets /* RGWOp */
1227{
1228public:
1229 RGWFileHandle* rgw_fh;
3efd9988 1230 RGWFileHandle::readdir_offset offset;
7c673cae
FG
1231 void* cb_arg;
1232 rgw_readdir_cb rcb;
3efd9988 1233 uint64_t* ioff;
7c673cae
FG
1234 size_t ix;
1235 uint32_t d_count;
1236
1237 RGWListBucketsRequest(CephContext* _cct, RGWUserInfo *_user,
1238 RGWFileHandle* _rgw_fh, rgw_readdir_cb _rcb,
3efd9988 1239 void* _cb_arg, RGWFileHandle::readdir_offset& _offset)
7c673cae 1240 : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), offset(_offset),
3efd9988
FG
1241 cb_arg(_cb_arg), rcb(_rcb), ioff(nullptr), ix(0), d_count(0) {
1242
1243 using boost::get;
1244
1245 if (unlikely(!! get<uint64_t*>(&offset))) {
1246 ioff = get<uint64_t*>(offset);
1247 const auto& mk = rgw_fh->find_marker(*ioff);
1248 if (mk) {
1249 marker = mk->name;
1250 }
1251 } else {
1252 const char* mk = get<const char*>(offset);
1253 if (mk) {
1254 marker = mk;
1255 }
7c673cae
FG
1256 }
1257 op = this;
1258 }
1259
1260 bool only_bucket() override { return false; }
1261
1262 int op_init() override {
1263 // assign store, s, and dialect_handler
1264 RGWObjectCtx* rados_ctx
1265 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1266 // framework promises to call op_init after parent init
1267 assert(rados_ctx);
1268 RGWOp::init(rados_ctx->store, get_state(), this);
1269 op = this; // assign self as op: REQUIRED
1270 return 0;
1271 }
1272
1273 int header_init() override {
1274 struct req_state* s = get_state();
1275 s->info.method = "GET";
1276 s->op = OP_GET;
1277
1278 /* XXX derp derp derp */
1279 s->relative_uri = "/";
1280 s->info.request_uri = "/"; // XXX
1281 s->info.effective_uri = "/";
1282 s->info.request_params = "";
1283 s->info.domain = ""; /* XXX ? */
1284
1285 // woo
1286 s->user = user;
1287
1288 return 0;
1289 }
1290
1291 int get_params() override {
1292 limit = -1; /* no limit */
1293 return 0;
1294 }
1295
1296 void send_response_begin(bool has_buckets) override {
1297 sent_data = true;
1298 }
1299
1300 void send_response_data(RGWUserBuckets& buckets) override {
1301 if (!sent_data)
1302 return;
1303 map<string, RGWBucketEnt>& m = buckets.get_buckets();
1304 for (const auto& iter : m) {
1305 boost::string_ref marker{iter.first};
1306 const RGWBucketEnt& ent = iter.second;
1307 if (! this->operator()(ent.bucket.name, marker)) {
1308 /* caller cannot accept more */
1309 lsubdout(cct, rgw, 5) << "ListBuckets rcb failed"
1310 << " dirent=" << ent.bucket.name
1311 << " call count=" << ix
1312 << dendl;
1313 return;
1314 }
1315 ++ix;
1316 }
1317 } /* send_response_data */
1318
1319 void send_response_end() override {
1320 // do nothing
1321 }
1322
1323 int operator()(const boost::string_ref& name,
1324 const boost::string_ref& marker) {
1325 uint64_t off = XXH64(name.data(), name.length(), fh_key::seed);
3efd9988
FG
1326 if (!! ioff) {
1327 *ioff = off;
1328 }
7c673cae
FG
1329 /* update traversal cache */
1330 rgw_fh->add_marker(off, rgw_obj_key{marker.data(), ""},
1331 RGW_FS_TYPE_DIRECTORY);
1332 ++d_count;
1333 return rcb(name.data(), cb_arg, off, RGW_LOOKUP_FLAG_DIR);
1334 }
1335
1336 bool eof() {
94b18763
FG
1337 if (unlikely(cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15))) {
1338 bool is_offset =
1339 unlikely(! get<const char*>(&offset)) ||
1340 !! get<const char*>(offset);
1341 lsubdout(cct, rgw, 15) << "READDIR offset: " <<
1342 ((is_offset) ? offset : "(nil)")
1343 << " is_truncated: " << is_truncated
1344 << dendl;
1345 }
7c673cae
FG
1346 return !is_truncated;
1347 }
1348
1349}; /* RGWListBucketsRequest */
1350
1351/*
1352 read directory content (bucket objects)
1353*/
1354
1355class RGWReaddirRequest : public RGWLibRequest,
1356 public RGWListBucket /* RGWOp */
1357{
1358public:
1359 RGWFileHandle* rgw_fh;
3efd9988 1360 RGWFileHandle::readdir_offset offset;
7c673cae
FG
1361 void* cb_arg;
1362 rgw_readdir_cb rcb;
3efd9988 1363 uint64_t* ioff;
7c673cae
FG
1364 size_t ix;
1365 uint32_t d_count;
1366
1367 RGWReaddirRequest(CephContext* _cct, RGWUserInfo *_user,
1368 RGWFileHandle* _rgw_fh, rgw_readdir_cb _rcb,
3efd9988 1369 void* _cb_arg, RGWFileHandle::readdir_offset& _offset)
7c673cae 1370 : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), offset(_offset),
3efd9988
FG
1371 cb_arg(_cb_arg), rcb(_rcb), ioff(nullptr), ix(0), d_count(0) {
1372
1373 using boost::get;
1374
1375 if (unlikely(!! get<uint64_t*>(&offset))) {
1376 ioff = get<uint64_t*>(offset);
1377 const auto& mk = rgw_fh->find_marker(*ioff);
1378 if (mk) {
1379 marker = *mk;
1380 }
1381 } else {
1382 const char* mk = get<const char*>(offset);
1383 if (mk) {
1384 std::string tmark{rgw_fh->relative_object_name()};
1385 tmark += "/";
1386 tmark += mk;
1387 marker = rgw_obj_key{std::move(tmark), "", ""};
1388 }
7c673cae 1389 }
3efd9988 1390
7c673cae
FG
1391 default_max = 1000; // XXX was being omitted
1392 op = this;
1393 }
1394
224ce89b 1395 bool only_bucket() override { return true; }
7c673cae
FG
1396
1397 int op_init() override {
1398 // assign store, s, and dialect_handler
1399 RGWObjectCtx* rados_ctx
1400 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1401 // framework promises to call op_init after parent init
1402 assert(rados_ctx);
1403 RGWOp::init(rados_ctx->store, get_state(), this);
1404 op = this; // assign self as op: REQUIRED
1405 return 0;
1406 }
1407
1408 int header_init() override {
1409 struct req_state* s = get_state();
1410 s->info.method = "GET";
1411 s->op = OP_GET;
1412
1413 /* XXX derp derp derp */
1414 std::string uri = "/" + rgw_fh->bucket_name() + "/";
1415 s->relative_uri = uri;
1416 s->info.request_uri = uri; // XXX
1417 s->info.effective_uri = uri;
1418 s->info.request_params = "";
1419 s->info.domain = ""; /* XXX ? */
1420
1421 // woo
1422 s->user = user;
1423
1424 prefix = rgw_fh->relative_object_name();
1425 if (prefix.length() > 0)
1426 prefix += "/";
1427 delimiter = '/';
1428
1429 return 0;
1430 }
1431
1432 int operator()(const boost::string_ref name, const rgw_obj_key& marker,
1433 uint8_t type) {
1434
1435 assert(name.length() > 0); // XXX
1436
1437 /* hash offset of name in parent (short name) for NFS readdir cookie */
1438 uint64_t off = XXH64(name.data(), name.length(), fh_key::seed);
3efd9988
FG
1439 if (unlikely(!! ioff)) {
1440 *ioff = off;
1441 }
7c673cae
FG
1442 /* update traversal cache */
1443 rgw_fh->add_marker(off, marker, type);
1444 ++d_count;
1445 return rcb(name.data(), cb_arg, off,
1446 (type == RGW_FS_TYPE_DIRECTORY) ?
1447 RGW_LOOKUP_FLAG_DIR :
1448 RGW_LOOKUP_FLAG_FILE);
1449 }
1450
1451 int get_params() override {
1452 max = default_max;
1453 return 0;
1454 }
1455
1456 void send_response() override {
1457 struct req_state* s = get_state();
1458 for (const auto& iter : objs) {
1459
1460 boost::string_ref sref {iter.key.name};
1461
1462 lsubdout(cct, rgw, 15) << "readdir objects prefix: " << prefix
1463 << " obj: " << sref << dendl;
1464
1465 size_t last_del = sref.find_last_of('/');
1466 if (last_del != string::npos)
1467 sref.remove_prefix(last_del+1);
1468
1469 /* leaf directory? */
1470 if (sref.empty())
1471 continue;
1472
1473 lsubdout(cct, rgw, 15) << "RGWReaddirRequest "
1474 << __func__ << " "
1475 << "list uri=" << s->relative_uri << " "
1476 << " prefix=" << prefix << " "
1477 << " obj path=" << iter.key.name
1478 << " (" << sref << ")" << ""
1479 << dendl;
1480
1481 if(! this->operator()(sref, next_marker, RGW_FS_TYPE_FILE)) {
1482 /* caller cannot accept more */
1483 lsubdout(cct, rgw, 5) << "readdir rcb failed"
1484 << " dirent=" << sref.data()
1485 << " call count=" << ix
1486 << dendl;
1487 return;
1488 }
1489 ++ix;
1490 }
1491 for (auto& iter : common_prefixes) {
1492
1493 lsubdout(cct, rgw, 15) << "readdir common prefixes prefix: " << prefix
1494 << " iter first: " << iter.first
1495 << " iter second: " << iter.second
1496 << dendl;
1497
1498 /* XXX aieee--I have seen this case! */
1499 if (iter.first == "/")
1500 continue;
1501
1502 /* it's safest to modify the element in place--a suffix-modifying
1503 * string_ref operation is problematic since ULP rgw_file callers
1504 * will ultimately need a c-string */
1505 if (iter.first.back() == '/')
1506 const_cast<std::string&>(iter.first).pop_back();
1507
1508 boost::string_ref sref{iter.first};
1509
1510 size_t last_del = sref.find_last_of('/');
1511 if (last_del != string::npos)
1512 sref.remove_prefix(last_del+1);
1513
1514 lsubdout(cct, rgw, 15) << "RGWReaddirRequest "
1515 << __func__ << " "
1516 << "list uri=" << s->relative_uri << " "
1517 << " prefix=" << prefix << " "
1518 << " cpref=" << sref
1519 << dendl;
1520
1521 this->operator()(sref, next_marker, RGW_FS_TYPE_DIRECTORY);
1522 ++ix;
1523 }
1524 }
1525
1526 virtual void send_versioned_response() {
1527 send_response();
1528 }
1529
1530 bool eof() {
94b18763
FG
1531 if (unlikely(cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15))) {
1532 bool is_offset =
1533 unlikely(! get<const char*>(&offset)) ||
1534 !! get<const char*>(offset);
1535 lsubdout(cct, rgw, 15) << "READDIR offset: " <<
1536 ((is_offset) ? offset : "(nil)")
1537 << " next marker: " << next_marker
1538 << " is_truncated: " << is_truncated
1539 << dendl;
1540 }
7c673cae
FG
1541 return !is_truncated;
1542 }
1543
1544}; /* RGWReaddirRequest */
1545
1546/*
1547 dir has-children predicate (bucket objects)
1548*/
1549
1550class RGWRMdirCheck : public RGWLibRequest,
1551 public RGWListBucket /* RGWOp */
1552{
1553public:
1554 const RGWFileHandle* rgw_fh;
1555 bool valid;
1556 bool has_children;
1557
1558 RGWRMdirCheck (CephContext* _cct, RGWUserInfo *_user,
1559 const RGWFileHandle* _rgw_fh)
1560 : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), valid(false),
1561 has_children(false) {
1562 default_max = 2;
1563 op = this;
1564 }
1565
224ce89b 1566 bool only_bucket() override { return true; }
7c673cae
FG
1567
1568 int op_init() override {
1569 // assign store, s, and dialect_handler
1570 RGWObjectCtx* rados_ctx
1571 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1572 // framework promises to call op_init after parent init
1573 assert(rados_ctx);
1574 RGWOp::init(rados_ctx->store, get_state(), this);
1575 op = this; // assign self as op: REQUIRED
1576 return 0;
1577 }
1578
1579 int header_init() override {
1580 struct req_state* s = get_state();
1581 s->info.method = "GET";
1582 s->op = OP_GET;
1583
1584 std::string uri = "/" + rgw_fh->bucket_name() + "/";
1585 s->relative_uri = uri;
1586 s->info.request_uri = uri;
1587 s->info.effective_uri = uri;
1588 s->info.request_params = "";
1589 s->info.domain = ""; /* XXX ? */
1590
1591 s->user = user;
1592
1593 prefix = rgw_fh->relative_object_name();
1594 if (prefix.length() > 0)
1595 prefix += "/";
1596 delimiter = '/';
1597
1598 return 0;
1599 }
1600
1601 int get_params() override {
1602 max = default_max;
1603 return 0;
1604 }
1605
1606 void send_response() override {
1607 valid = true;
1608 if ((objs.size() > 1) ||
1609 (! objs.empty() &&
1610 (objs.front().key.name != prefix))) {
1611 has_children = true;
1612 return;
1613 }
1614 for (auto& iter : common_prefixes) {
1615 /* readdir never produces a name for this case */
1616 if (iter.first == "/")
1617 continue;
1618 has_children = true;
1619 break;
1620 }
1621 }
1622
1623 virtual void send_versioned_response() {
1624 send_response();
1625 }
1626
1627}; /* RGWRMdirCheck */
1628
1629/*
1630 create bucket
1631*/
1632
1633class RGWCreateBucketRequest : public RGWLibRequest,
1634 public RGWCreateBucket /* RGWOp */
1635{
1636public:
31f18b77 1637 const std::string& bucket_name;
7c673cae
FG
1638
1639 RGWCreateBucketRequest(CephContext* _cct, RGWUserInfo *_user,
31f18b77
FG
1640 std::string& _bname)
1641 : RGWLibRequest(_cct, _user), bucket_name(_bname) {
7c673cae
FG
1642 op = this;
1643 }
1644
1645 bool only_bucket() override { return false; }
1646
1647 int read_permissions(RGWOp* op_obj) override {
1648 /* we ARE a 'create bucket' request (cf. rgw_rest.cc, ll. 1305-6) */
1649 return 0;
1650 }
1651
1652 int op_init() override {
1653 // assign store, s, and dialect_handler
1654 RGWObjectCtx* rados_ctx
1655 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1656 // framework promises to call op_init after parent init
1657 assert(rados_ctx);
1658 RGWOp::init(rados_ctx->store, get_state(), this);
1659 op = this; // assign self as op: REQUIRED
1660 return 0;
1661 }
1662
1663 int header_init() override {
1664
1665 struct req_state* s = get_state();
1666 s->info.method = "PUT";
1667 s->op = OP_PUT;
1668
31f18b77 1669 string uri = "/" + bucket_name;
7c673cae
FG
1670 /* XXX derp derp derp */
1671 s->relative_uri = uri;
1672 s->info.request_uri = uri; // XXX
1673 s->info.effective_uri = uri;
1674 s->info.request_params = "";
1675 s->info.domain = ""; /* XXX ? */
1676
1677 // woo
1678 s->user = user;
1679
1680 return 0;
1681 }
1682
1683 int get_params() override {
1684 struct req_state* s = get_state();
1685 RGWAccessControlPolicy_S3 s3policy(s->cct);
1686 /* we don't have (any) headers, so just create canned ACLs */
1687 int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl);
1688 policy = s3policy;
1689 return ret;
1690 }
1691
1692 void send_response() override {
1693 /* TODO: something (maybe) */
1694 }
1695}; /* RGWCreateBucketRequest */
1696
1697/*
1698 delete bucket
1699*/
1700
1701class RGWDeleteBucketRequest : public RGWLibRequest,
1702 public RGWDeleteBucket /* RGWOp */
1703{
1704public:
31f18b77 1705 const std::string& bucket_name;
7c673cae
FG
1706
1707 RGWDeleteBucketRequest(CephContext* _cct, RGWUserInfo *_user,
31f18b77
FG
1708 std::string& _bname)
1709 : RGWLibRequest(_cct, _user), bucket_name(_bname) {
7c673cae
FG
1710 op = this;
1711 }
1712
1713 bool only_bucket() override { return true; }
1714
1715 int op_init() override {
1716 // assign store, s, and dialect_handler
1717 RGWObjectCtx* rados_ctx
1718 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1719 // framework promises to call op_init after parent init
1720 assert(rados_ctx);
1721 RGWOp::init(rados_ctx->store, get_state(), this);
1722 op = this; // assign self as op: REQUIRED
1723 return 0;
1724 }
1725
1726 int header_init() override {
1727
1728 struct req_state* s = get_state();
1729 s->info.method = "DELETE";
1730 s->op = OP_DELETE;
1731
31f18b77 1732 string uri = "/" + bucket_name;
7c673cae
FG
1733 /* XXX derp derp derp */
1734 s->relative_uri = uri;
1735 s->info.request_uri = uri; // XXX
1736 s->info.effective_uri = uri;
1737 s->info.request_params = "";
1738 s->info.domain = ""; /* XXX ? */
1739
1740 // woo
1741 s->user = user;
1742
1743 return 0;
1744 }
1745
1746 void send_response() override {}
1747
1748}; /* RGWDeleteBucketRequest */
1749
1750/*
1751 put object
1752*/
1753class RGWPutObjRequest : public RGWLibRequest,
1754 public RGWPutObj /* RGWOp */
1755{
1756public:
1757 const std::string& bucket_name;
1758 const std::string& obj_name;
1759 buffer::list& bl; /* XXX */
1760 size_t bytes_written;
1761
1762 RGWPutObjRequest(CephContext* _cct, RGWUserInfo *_user,
1763 const std::string& _bname, const std::string& _oname,
1764 buffer::list& _bl)
1765 : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname),
1766 bl(_bl), bytes_written(0) {
1767 op = this;
1768 }
1769
1770 bool only_bucket() override { return true; }
1771
1772 int op_init() override {
1773 // assign store, s, and dialect_handler
1774 RGWObjectCtx* rados_ctx
1775 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1776 // framework promises to call op_init after parent init
1777 assert(rados_ctx);
1778 RGWOp::init(rados_ctx->store, get_state(), this);
1779 op = this; // assign self as op: REQUIRED
1780
1781 int rc = valid_s3_object_name(obj_name);
1782 if (rc != 0)
1783 return rc;
1784
1785 return 0;
1786 }
1787
1788 int header_init() override {
1789
1790 struct req_state* s = get_state();
1791 s->info.method = "PUT";
1792 s->op = OP_PUT;
1793
1794 /* XXX derp derp derp */
1795 std::string uri = make_uri(bucket_name, obj_name);
1796 s->relative_uri = uri;
1797 s->info.request_uri = uri; // XXX
1798 s->info.effective_uri = uri;
1799 s->info.request_params = "";
1800 s->info.domain = ""; /* XXX ? */
1801
1802 /* XXX required in RGWOp::execute() */
1803 s->content_length = bl.length();
1804
1805 // woo
1806 s->user = user;
1807
1808 return 0;
1809 }
1810
1811 int get_params() override {
1812 struct req_state* s = get_state();
1813 RGWAccessControlPolicy_S3 s3policy(s->cct);
1814 /* we don't have (any) headers, so just create canned ACLs */
1815 int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl);
1816 policy = s3policy;
1817 return ret;
1818 }
1819
1820 int get_data(buffer::list& _bl) override {
1821 /* XXX for now, use sharing semantics */
1822 _bl.claim(bl);
1823 uint32_t len = _bl.length();
1824 bytes_written += len;
1825 return len;
1826 }
1827
1828 void send_response() override {}
1829
1830 int verify_params() override {
1831 if (bl.length() > cct->_conf->rgw_max_put_size)
1832 return -ERR_TOO_LARGE;
1833 return 0;
1834 }
1835
1836}; /* RGWPutObjRequest */
1837
1838/*
1839 get object
1840*/
1841
1842class RGWReadRequest : public RGWLibRequest,
1843 public RGWGetObj /* RGWOp */
1844{
1845public:
1846 RGWFileHandle* rgw_fh;
1847 void *ulp_buffer;
1848 size_t nread;
1849 size_t read_resid; /* initialize to len, <= sizeof(ulp_buffer) */
1850 bool do_hexdump = false;
1851
1852 RGWReadRequest(CephContext* _cct, RGWUserInfo *_user,
1853 RGWFileHandle* _rgw_fh, uint64_t off, uint64_t len,
1854 void *_ulp_buffer)
1855 : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), ulp_buffer(_ulp_buffer),
1856 nread(0), read_resid(len) {
1857 op = this;
1858
1859 /* fixup RGWGetObj (already know range parameters) */
1860 RGWGetObj::range_parsed = true;
1861 RGWGetObj::get_data = true; // XXX
1862 RGWGetObj::partial_content = true;
1863 RGWGetObj::ofs = off;
1864 RGWGetObj::end = off + len;
1865 }
1866
1867 bool only_bucket() override { return false; }
1868
1869 int op_init() override {
1870 // assign store, s, and dialect_handler
1871 RGWObjectCtx* rados_ctx
1872 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1873 // framework promises to call op_init after parent init
1874 assert(rados_ctx);
1875 RGWOp::init(rados_ctx->store, get_state(), this);
1876 op = this; // assign self as op: REQUIRED
1877 return 0;
1878 }
1879
1880 int header_init() override {
1881
1882 struct req_state* s = get_state();
1883 s->info.method = "GET";
1884 s->op = OP_GET;
1885
1886 /* XXX derp derp derp */
1887 s->relative_uri = make_uri(rgw_fh->bucket_name(),
1888 rgw_fh->relative_object_name());
1889 s->info.request_uri = s->relative_uri; // XXX
1890 s->info.effective_uri = s->relative_uri;
1891 s->info.request_params = "";
1892 s->info.domain = ""; /* XXX ? */
1893
1894 // woo
1895 s->user = user;
1896
1897 return 0;
1898 }
1899
1900 int get_params() override {
1901 return 0;
1902 }
1903
1904 int send_response_data(ceph::buffer::list& bl, off_t bl_off,
1905 off_t bl_len) override {
1906 size_t bytes;
1907 for (auto& bp : bl.buffers()) {
1908 /* if for some reason bl_off indicates the start-of-data is not at
1909 * the current buffer::ptr, skip it and account */
1910 if (bl_off > bp.length()) {
1911 bl_off -= bp.length();
1912 continue;
1913 }
1914 /* read no more than read_resid */
1915 bytes = std::min(read_resid, size_t(bp.length()-bl_off));
1916 memcpy(static_cast<char*>(ulp_buffer)+nread, bp.c_str()+bl_off, bytes);
1917 read_resid -= bytes; /* reduce read_resid by bytes read */
1918 nread += bytes;
1919 bl_off = 0;
1920 /* stop if we have no residual ulp_buffer */
1921 if (! read_resid)
1922 break;
1923 }
1924 return 0;
1925 }
1926
1927 int send_response_data_error() override {
1928 /* S3 implementation just sends nothing--there is no side effect
1929 * to simulate here */
1930 return 0;
1931 }
1932
1933}; /* RGWReadRequest */
1934
1935/*
1936 delete object
1937*/
1938
1939class RGWDeleteObjRequest : public RGWLibRequest,
1940 public RGWDeleteObj /* RGWOp */
1941{
1942public:
1943 const std::string& bucket_name;
1944 const std::string& obj_name;
1945
1946 RGWDeleteObjRequest(CephContext* _cct, RGWUserInfo *_user,
1947 const std::string& _bname, const std::string& _oname)
1948 : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname) {
1949 op = this;
1950 }
1951
1952 bool only_bucket() override { return true; }
1953
1954 int op_init() override {
1955 // assign store, s, and dialect_handler
1956 RGWObjectCtx* rados_ctx
1957 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
1958 // framework promises to call op_init after parent init
1959 assert(rados_ctx);
1960 RGWOp::init(rados_ctx->store, get_state(), this);
1961 op = this; // assign self as op: REQUIRED
1962 return 0;
1963 }
1964
1965 int header_init() override {
1966
1967 struct req_state* s = get_state();
1968 s->info.method = "DELETE";
1969 s->op = OP_DELETE;
1970
1971 /* XXX derp derp derp */
1972 std::string uri = make_uri(bucket_name, obj_name);
1973 s->relative_uri = uri;
1974 s->info.request_uri = uri; // XXX
1975 s->info.effective_uri = uri;
1976 s->info.request_params = "";
1977 s->info.domain = ""; /* XXX ? */
1978
1979 // woo
1980 s->user = user;
1981
1982 return 0;
1983 }
1984
1985 void send_response() override {}
1986
1987}; /* RGWDeleteObjRequest */
1988
1989class RGWStatObjRequest : public RGWLibRequest,
1990 public RGWGetObj /* RGWOp */
1991{
1992public:
1993 const std::string& bucket_name;
1994 const std::string& obj_name;
1995 uint64_t _size;
1996 uint32_t flags;
1997
1998 static constexpr uint32_t FLAG_NONE = 0x000;
1999
2000 RGWStatObjRequest(CephContext* _cct, RGWUserInfo *_user,
2001 const std::string& _bname, const std::string& _oname,
2002 uint32_t _flags)
2003 : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname),
2004 _size(0), flags(_flags) {
2005 op = this;
2006
2007 /* fixup RGWGetObj (already know range parameters) */
2008 RGWGetObj::range_parsed = true;
2009 RGWGetObj::get_data = false; // XXX
2010 RGWGetObj::partial_content = true;
2011 RGWGetObj::ofs = 0;
2012 RGWGetObj::end = UINT64_MAX;
2013 }
2014
2015 const string name() override { return "stat_obj"; }
2016 RGWOpType get_type() override { return RGW_OP_STAT_OBJ; }
2017
2018 real_time get_mtime() const {
2019 return lastmod;
2020 }
2021
2022 /* attributes */
2023 uint64_t get_size() { return _size; }
2024 real_time ctime() { return mod_time; } // XXX
2025 real_time mtime() { return mod_time; }
2026 std::map<string, bufferlist>& get_attrs() { return attrs; }
2027
2028 buffer::list* get_attr(const std::string& k) {
2029 auto iter = attrs.find(k);
2030 return (iter != attrs.end()) ? &(iter->second) : nullptr;
2031 }
2032
2033 bool only_bucket() override { return false; }
2034
2035 int op_init() override {
2036 // assign store, s, and dialect_handler
2037 RGWObjectCtx* rados_ctx
2038 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2039 // framework promises to call op_init after parent init
2040 assert(rados_ctx);
2041 RGWOp::init(rados_ctx->store, get_state(), this);
2042 op = this; // assign self as op: REQUIRED
2043 return 0;
2044 }
2045
2046 int header_init() override {
2047
2048 struct req_state* s = get_state();
2049 s->info.method = "GET";
2050 s->op = OP_GET;
2051
2052 /* XXX derp derp derp */
2053 s->relative_uri = make_uri(bucket_name, obj_name);
2054 s->info.request_uri = s->relative_uri; // XXX
2055 s->info.effective_uri = s->relative_uri;
2056 s->info.request_params = "";
2057 s->info.domain = ""; /* XXX ? */
2058
2059 // woo
2060 s->user = user;
2061
2062 return 0;
2063 }
2064
2065 int get_params() override {
2066 return 0;
2067 }
2068
2069 int send_response_data(ceph::buffer::list& _bl, off_t s_off,
2070 off_t e_off) override {
2071 /* NOP */
2072 /* XXX save attrs? */
2073 return 0;
2074 }
2075
2076 int send_response_data_error() override {
2077 /* NOP */
2078 return 0;
2079 }
2080
2081 void execute() override {
2082 RGWGetObj::execute();
2083 _size = get_state()->obj_size;
2084 }
2085
2086}; /* RGWStatObjRequest */
2087
2088class RGWStatBucketRequest : public RGWLibRequest,
2089 public RGWStatBucket /* RGWOp */
2090{
2091public:
2092 std::string uri;
2093 std::map<std::string, buffer::list> attrs;
31f18b77 2094 RGWLibFS::BucketStats& bs;
7c673cae
FG
2095
2096 RGWStatBucketRequest(CephContext* _cct, RGWUserInfo *_user,
31f18b77
FG
2097 const std::string& _path,
2098 RGWLibFS::BucketStats& _stats)
2099 : RGWLibRequest(_cct, _user), bs(_stats) {
7c673cae
FG
2100 uri = "/" + _path;
2101 op = this;
2102 }
2103
2104 buffer::list* get_attr(const std::string& k) {
2105 auto iter = attrs.find(k);
2106 return (iter != attrs.end()) ? &(iter->second) : nullptr;
2107 }
2108
2109 real_time get_ctime() const {
2110 return bucket.creation_time;
2111 }
2112
2113 bool only_bucket() override { return false; }
2114
2115 int op_init() override {
2116 // assign store, s, and dialect_handler
2117 RGWObjectCtx* rados_ctx
2118 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2119 // framework promises to call op_init after parent init
2120 assert(rados_ctx);
2121 RGWOp::init(rados_ctx->store, get_state(), this);
2122 op = this; // assign self as op: REQUIRED
2123 return 0;
2124 }
2125
2126 int header_init() override {
2127
2128 struct req_state* s = get_state();
2129 s->info.method = "GET";
2130 s->op = OP_GET;
2131
2132 /* XXX derp derp derp */
2133 s->relative_uri = uri;
2134 s->info.request_uri = uri; // XXX
2135 s->info.effective_uri = uri;
2136 s->info.request_params = "";
2137 s->info.domain = ""; /* XXX ? */
2138
2139 // woo
2140 s->user = user;
2141
2142 return 0;
2143 }
2144
2145 virtual int get_params() {
2146 return 0;
2147 }
2148
2149 void send_response() override {
2150 bucket.creation_time = get_state()->bucket_info.creation_time;
31f18b77
FG
2151 bs.size = bucket.size;
2152 bs.size_rounded = bucket.size_rounded;
2153 bs.creation_time = bucket.creation_time;
2154 bs.num_entries = bucket.count;
7c673cae
FG
2155 std::swap(attrs, get_state()->bucket_attrs);
2156 }
2157
2158 bool matched() {
2159 return (bucket.bucket.name.length() > 0);
2160 }
2161
2162}; /* RGWStatBucketRequest */
2163
2164class RGWStatLeafRequest : public RGWLibRequest,
2165 public RGWListBucket /* RGWOp */
2166{
2167public:
2168 RGWFileHandle* rgw_fh;
2169 std::string path;
2170 bool matched;
2171 bool is_dir;
2172 bool exact_matched;
2173
2174 RGWStatLeafRequest(CephContext* _cct, RGWUserInfo *_user,
2175 RGWFileHandle* _rgw_fh, const std::string& _path)
2176 : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), path(_path),
2177 matched(false), is_dir(false), exact_matched(false) {
2178 default_max = 1000; // logical max {"foo", "foo/"}
2179 op = this;
2180 }
2181
224ce89b 2182 bool only_bucket() override { return true; }
7c673cae
FG
2183
2184 int op_init() override {
2185 // assign store, s, and dialect_handler
2186 RGWObjectCtx* rados_ctx
2187 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2188 // framework promises to call op_init after parent init
2189 assert(rados_ctx);
2190 RGWOp::init(rados_ctx->store, get_state(), this);
2191 op = this; // assign self as op: REQUIRED
2192 return 0;
2193 }
2194
2195 int header_init() override {
2196
2197 struct req_state* s = get_state();
2198 s->info.method = "GET";
2199 s->op = OP_GET;
2200
2201 /* XXX derp derp derp */
2202 std::string uri = "/" + rgw_fh->bucket_name() + "/";
2203 s->relative_uri = uri;
2204 s->info.request_uri = uri; // XXX
2205 s->info.effective_uri = uri;
2206 s->info.request_params = "";
2207 s->info.domain = ""; /* XXX ? */
2208
2209 // woo
2210 s->user = user;
2211
2212 prefix = rgw_fh->relative_object_name();
2213 if (prefix.length() > 0)
2214 prefix += "/";
2215 prefix += path;
2216 delimiter = '/';
2217
2218 return 0;
2219 }
2220
2221 int get_params() override {
2222 max = default_max;
2223 return 0;
2224 }
2225
2226 void send_response() override {
2227 struct req_state* s = get_state();
2228 // try objects
2229 for (const auto& iter : objs) {
2230 auto& name = iter.key.name;
2231 lsubdout(cct, rgw, 15) << "RGWStatLeafRequest "
2232 << __func__ << " "
2233 << "list uri=" << s->relative_uri << " "
2234 << " prefix=" << prefix << " "
2235 << " obj path=" << name << ""
2236 << " target = " << path << ""
2237 << dendl;
2238 /* XXX is there a missing match-dir case (trailing '/')? */
2239 matched = true;
2240 if (name == path)
2241 exact_matched = true;
2242 return;
2243 }
2244 // try prefixes
2245 for (auto& iter : common_prefixes) {
2246 auto& name = iter.first;
2247 lsubdout(cct, rgw, 15) << "RGWStatLeafRequest "
2248 << __func__ << " "
2249 << "list uri=" << s->relative_uri << " "
2250 << " prefix=" << prefix << " "
2251 << " pref path=" << name << " (not chomped)"
2252 << " target = " << path << ""
2253 << dendl;
2254 matched = true;
2255 is_dir = true;
2256 break;
2257 }
2258 }
2259
2260 virtual void send_versioned_response() {
2261 send_response();
2262 }
2263}; /* RGWStatLeafRequest */
2264
2265/*
2266 put object
2267*/
2268
2269class RGWWriteRequest : public RGWLibContinuedReq,
2270 public RGWPutObj /* RGWOp */
2271{
2272public:
2273 const std::string& bucket_name;
2274 const std::string& obj_name;
2275 RGWFileHandle* rgw_fh;
224ce89b
WB
2276 RGWPutObjProcessor* processor;
2277 RGWPutObjDataProcessor* filter;
2278 boost::optional<RGWPutObj_Compress> compressor;
2279 CompressorRef plugin;
7c673cae
FG
2280 buffer::list data;
2281 uint64_t timer_id;
2282 MD5 hash;
2283 off_t real_ofs;
2284 size_t bytes_written;
2285 bool multipart;
2286 bool eio;
2287
2288 RGWWriteRequest(CephContext* _cct, RGWUserInfo *_user, RGWFileHandle* _fh,
2289 const std::string& _bname, const std::string& _oname)
2290 : RGWLibContinuedReq(_cct, _user), bucket_name(_bname), obj_name(_oname),
224ce89b
WB
2291 rgw_fh(_fh), processor(nullptr), filter(nullptr), real_ofs(0),
2292 bytes_written(0), multipart(false), eio(false) {
7c673cae
FG
2293
2294 int ret = header_init();
2295 if (ret == 0) {
2296 ret = init_from_header(get_state());
2297 }
2298 op = this;
2299 }
2300
2301 bool only_bucket() override { return true; }
2302
2303 int op_init() override {
2304 // assign store, s, and dialect_handler
2305 RGWObjectCtx* rados_ctx
2306 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2307 // framework promises to call op_init after parent init
2308 assert(rados_ctx);
2309 RGWOp::init(rados_ctx->store, get_state(), this);
2310 op = this; // assign self as op: REQUIRED
2311 return 0;
2312 }
2313
2314 int header_init() override {
2315
2316 struct req_state* s = get_state();
2317 s->info.method = "PUT";
2318 s->op = OP_PUT;
2319
2320 /* XXX derp derp derp */
2321 std::string uri = make_uri(bucket_name, obj_name);
2322 s->relative_uri = uri;
2323 s->info.request_uri = uri; // XXX
2324 s->info.effective_uri = uri;
2325 s->info.request_params = "";
2326 s->info.domain = ""; /* XXX ? */
2327
2328 // woo
2329 s->user = user;
2330
2331 return 0;
2332 }
2333
2334 RGWPutObjProcessor *select_processor(RGWObjectCtx& obj_ctx,
2335 bool *is_multipart) override {
2336 struct req_state* s = get_state();
2337 uint64_t part_size = s->cct->_conf->rgw_obj_stripe_size;
2338 RGWPutObjProcessor_Atomic *processor =
2339 new RGWPutObjProcessor_Atomic(obj_ctx, s->bucket_info, s->bucket,
2340 s->object.name, part_size, s->req_id,
2341 s->bucket_info.versioning_enabled());
2342 processor->set_olh_epoch(olh_epoch);
2343 processor->set_version_id(version_id);
2344 return processor;
2345 }
2346
2347 int get_params() override {
2348 struct req_state* s = get_state();
2349 RGWAccessControlPolicy_S3 s3policy(s->cct);
2350 /* we don't have (any) headers, so just create canned ACLs */
2351 int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl);
2352 policy = s3policy;
2353 return ret;
2354 }
2355
2356 int get_data(buffer::list& _bl) override {
2357 /* XXX for now, use sharing semantics */
2358 uint32_t len = data.length();
2359 _bl.claim(data);
2360 bytes_written += len;
2361 return len;
2362 }
2363
2364 void put_data(off_t off, buffer::list& _bl) {
2365 if (off != real_ofs) {
2366 eio = true;
2367 }
2368 data.claim(_bl);
2369 real_ofs += data.length();
2370 ofs = off; /* consumed in exec_continue() */
2371 }
2372
2373 int exec_start() override;
2374 int exec_continue() override;
2375 int exec_finish() override;
2376
2377 void send_response() override {}
2378
2379 int verify_params() override {
2380 return 0;
2381 }
2382}; /* RGWWriteRequest */
2383
2384/*
2385 copy object
2386*/
2387class RGWCopyObjRequest : public RGWLibRequest,
2388 public RGWCopyObj /* RGWOp */
2389{
2390public:
2391 RGWFileHandle* src_parent;
2392 RGWFileHandle* dst_parent;
2393 const std::string& src_name;
2394 const std::string& dst_name;
2395
2396 RGWCopyObjRequest(CephContext* _cct, RGWUserInfo *_user,
2397 RGWFileHandle* _src_parent, RGWFileHandle* _dst_parent,
2398 const std::string& _src_name, const std::string& _dst_name)
2399 : RGWLibRequest(_cct, _user), src_parent(_src_parent),
2400 dst_parent(_dst_parent), src_name(_src_name), dst_name(_dst_name) {
2401 /* all requests have this */
2402 op = this;
2403
2404 /* allow this request to replace selected attrs */
2405 attrs_mod = RGWRados::ATTRSMOD_MERGE;
2406 }
2407
2408 bool only_bucket() override { return true; }
2409
2410 int op_init() override {
2411 // assign store, s, and dialect_handler
2412 RGWObjectCtx* rados_ctx
2413 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2414 // framework promises to call op_init after parent init
2415 assert(rados_ctx);
2416 RGWOp::init(rados_ctx->store, get_state(), this);
2417 op = this; // assign self as op: REQUIRED
2418
2419 return 0;
2420 }
2421
2422 int header_init() override {
2423
2424 struct req_state* s = get_state();
2425 s->info.method = "PUT"; // XXX check
2426 s->op = OP_PUT;
2427
2428 src_bucket_name = src_parent->bucket_name();
2429 // need s->src_bucket_name?
31f18b77 2430 src_object.name = src_parent->format_child_name(src_name, false);
7c673cae
FG
2431 // need s->src_object?
2432
2433 dest_bucket_name = dst_parent->bucket_name();
2434 // need s->bucket.name?
31f18b77 2435 dest_object = dst_parent->format_child_name(dst_name, false);
7c673cae
FG
2436 // need s->object_name?
2437
2438 int rc = valid_s3_object_name(dest_object);
2439 if (rc != 0)
2440 return rc;
2441
2442 /* XXX and fixup key attr (could optimize w/string ref and
2443 * dest_object) */
2444 buffer::list ux_key;
224ce89b 2445 fh_key fhk = dst_parent->make_fhk(dst_name);
7c673cae
FG
2446 rgw::encode(fhk, ux_key);
2447 emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
2448
2449#if 0 /* XXX needed? */
2450 s->relative_uri = uri;
2451 s->info.request_uri = uri; // XXX
2452 s->info.effective_uri = uri;
2453 s->info.request_params = "";
2454 s->info.domain = ""; /* XXX ? */
2455#endif
2456
2457 // woo
2458 s->user = user;
2459
2460 return 0;
2461 }
2462
2463 int get_params() override {
2464 struct req_state* s = get_state();
2465 RGWAccessControlPolicy_S3 s3policy(s->cct);
2466 /* we don't have (any) headers, so just create canned ACLs */
2467 int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl);
2468 dest_policy = s3policy;
2469 return ret;
2470 }
2471
2472 void send_response() override {}
2473 void send_partial_response(off_t ofs) override {}
2474
2475}; /* RGWCopyObjRequest */
2476
2477class RGWSetAttrsRequest : public RGWLibRequest,
2478 public RGWSetAttrs /* RGWOp */
2479{
2480public:
2481 const std::string& bucket_name;
2482 const std::string& obj_name;
2483
2484 RGWSetAttrsRequest(CephContext* _cct, RGWUserInfo *_user,
2485 const std::string& _bname, const std::string& _oname)
2486 : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname) {
2487 op = this;
2488 }
2489
2490 bool only_bucket() override { return false; }
2491
2492 int op_init() override {
2493 // assign store, s, and dialect_handler
2494 RGWObjectCtx* rados_ctx
2495 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2496 // framework promises to call op_init after parent init
2497 assert(rados_ctx);
2498 RGWOp::init(rados_ctx->store, get_state(), this);
2499 op = this; // assign self as op: REQUIRED
2500 return 0;
2501 }
2502
2503 int header_init() override {
2504
2505 struct req_state* s = get_state();
2506 s->info.method = "PUT";
2507 s->op = OP_PUT;
2508
2509 /* XXX derp derp derp */
2510 std::string uri = make_uri(bucket_name, obj_name);
2511 s->relative_uri = uri;
2512 s->info.request_uri = uri; // XXX
2513 s->info.effective_uri = uri;
2514 s->info.request_params = "";
2515 s->info.domain = ""; /* XXX ? */
2516
2517 // woo
2518 s->user = user;
2519
2520 return 0;
2521 }
2522
2523 int get_params() override {
2524 return 0;
2525 }
2526
2527 void send_response() override {}
2528
2529}; /* RGWSetAttrsRequest */
2530
28e407b8
AA
2531/*
2532 * Send request to get the rados cluster stats
2533 */
2534class RGWGetClusterStatReq : public RGWLibRequest,
2535 public RGWGetClusterStat {
2536public:
2537 struct rados_cluster_stat_t& stats_req;
2538 RGWGetClusterStatReq(CephContext* _cct,RGWUserInfo *_user,
2539 rados_cluster_stat_t& _stats):
2540 RGWLibRequest(_cct, _user), stats_req(_stats){
2541 op = this;
2542 }
2543
2544 int op_init() override {
2545 // assign store, s, and dialect_handler
2546 RGWObjectCtx* rados_ctx
2547 = static_cast<RGWObjectCtx*>(get_state()->obj_ctx);
2548 // framework promises to call op_init after parent init
2549 assert(rados_ctx);
2550 RGWOp::init(rados_ctx->store, get_state(), this);
2551 op = this; // assign self as op: REQUIRED
2552 return 0;
2553 }
2554
2555 int header_init() override {
2556 struct req_state* s = get_state();
2557 s->info.method = "GET";
2558 s->op = OP_GET;
2559 s->user = user;
2560 return 0;
2561 }
2562
2563 int get_params() override { return 0; }
2564 bool only_bucket() override { return false; }
2565 void send_response() override {
2566 stats_req.kb = stats_op.kb;
2567 stats_req.kb_avail = stats_op.kb_avail;
2568 stats_req.kb_used = stats_op.kb_used;
2569 stats_req.num_objects = stats_op.num_objects;
2570 }
2571}; /* RGWGetClusterStatReq */
2572
2573
7c673cae
FG
2574} /* namespace rgw */
2575
2576#endif /* RGW_FILE_H */