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