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