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