]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_file.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / rgw_file.cc
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#include "include/compat.h"
5#include "include/rados/rgw_file.h"
6
7#include <sys/types.h>
8#include <sys/stat.h>
9
10#include "rgw_lib.h"
7c673cae
FG
11#include "rgw_resolve.h"
12#include "rgw_op.h"
13#include "rgw_rest.h"
14#include "rgw_acl.h"
15#include "rgw_acl_s3.h"
16#include "rgw_frontend.h"
17#include "rgw_request.h"
18#include "rgw_process.h"
19#include "rgw_rest_user.h"
20#include "rgw_rest_s3.h"
21#include "rgw_os_lib.h"
22#include "rgw_auth_s3.h"
23#include "rgw_user.h"
24#include "rgw_bucket.h"
11fdf7f2 25#include "rgw_zone.h"
7c673cae
FG
26#include "rgw_file.h"
27#include "rgw_lib_frontend.h"
11fdf7f2 28#include "rgw_perf_counters.h"
28e407b8 29#include "common/errno.h"
7c673cae 30
9f95a23c
TL
31#include "services/svc_zone.h"
32
7c673cae
FG
33#include <atomic>
34
35#define dout_subsys ceph_subsys_rgw
36
20effc67 37using namespace std;
7c673cae
FG
38using namespace rgw;
39
40namespace rgw {
41
42 extern RGWLib rgwlib;
43
44 const string RGWFileHandle::root_name = "/";
45
46 std::atomic<uint32_t> RGWLibFS::fs_inst_counter;
47
48 uint32_t RGWLibFS::write_completion_interval_s = 10;
49
50 ceph::timer<ceph::mono_clock> RGWLibFS::write_timer{
51 ceph::construct_suspended};
52
53 inline int valid_fs_bucket_name(const string& name) {
54 int rc = valid_s3_bucket_name(name, false /* relaxed */);
55 if (rc != 0) {
56 if (name.size() > 255)
57 return -ENAMETOOLONG;
58 return -EINVAL;
59 }
60 return 0;
61 }
62
63 inline int valid_fs_object_name(const string& name) {
64 int rc = valid_s3_object_name(name);
65 if (rc != 0) {
66 if (name.size() > 1024)
67 return -ENAMETOOLONG;
68 return -EINVAL;
69 }
70 return 0;
71 }
72
f67539c2
TL
73 class XattrHash
74 {
75 public:
76 std::size_t operator()(const rgw_xattrstr& att) const noexcept {
77 return XXH64(att.val, att.len, 5882300);
78 }
79 };
80
81 class XattrEqual
82 {
83 public:
84 bool operator()(const rgw_xattrstr& lhs, const rgw_xattrstr& rhs) const {
85 return ((lhs.len == rhs.len) &&
86 (strncmp(lhs.val, rhs.val, lhs.len) == 0));
87 }
88 };
89
90 /* well-known attributes */
91 static const std::unordered_set<
92 rgw_xattrstr, XattrHash, XattrEqual> rgw_exposed_attrs = {
93 rgw_xattrstr{const_cast<char*>(RGW_ATTR_ETAG), sizeof(RGW_ATTR_ETAG)-1}
94 };
95
96 static inline bool is_exposed_attr(const rgw_xattrstr& k) {
97 return (rgw_exposed_attrs.find(k) != rgw_exposed_attrs.end());
98 }
99
31f18b77
FG
100 LookupFHResult RGWLibFS::stat_bucket(RGWFileHandle* parent, const char *path,
101 RGWLibFS::BucketStats& bs,
102 uint32_t flags)
7c673cae
FG
103 {
104 LookupFHResult fhr{nullptr, 0};
105 std::string bucket_name{path};
20effc67 106 RGWStatBucketRequest req(cct, user->clone(), bucket_name, bs);
7c673cae
FG
107
108 int rc = rgwlib.get_fe()->execute_req(&req);
109 if ((rc == 0) &&
110 (req.get_ret() == 0) &&
111 (req.matched())) {
112 fhr = lookup_fh(parent, path,
31f18b77 113 (flags & RGWFileHandle::FLAG_LOCKED)|
7c673cae
FG
114 RGWFileHandle::FLAG_CREATE|
115 RGWFileHandle::FLAG_BUCKET);
116 if (get<0>(fhr)) {
117 RGWFileHandle* rgw_fh = get<0>(fhr);
31f18b77
FG
118 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
119 rgw_fh->mtx.lock();
120 }
7c673cae
FG
121 rgw_fh->set_times(req.get_ctime());
122 /* restore attributes */
123 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
124 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
125 if (ux_key && ux_attrs) {
3efd9988
FG
126 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
127 if (get<0>(dar) || get<1>(dar)) {
128 update_fh(rgw_fh);
129 }
7c673cae 130 }
31f18b77
FG
131 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
132 rgw_fh->mtx.unlock();
133 }
7c673cae
FG
134 }
135 }
136 return fhr;
137 }
138
eafe8130
TL
139 LookupFHResult RGWLibFS::fake_leaf(RGWFileHandle* parent,
140 const char *path,
141 enum rgw_fh_type type,
142 struct stat *st, uint32_t st_mask,
143 uint32_t flags)
144 {
145 /* synthesize a minimal handle from parent, path, type, and st */
146 using std::get;
147
148 flags |= RGWFileHandle::FLAG_CREATE;
149
150 switch (type) {
151 case RGW_FS_TYPE_DIRECTORY:
152 flags |= RGWFileHandle::FLAG_DIRECTORY;
153 break;
154 default:
155 /* file */
156 break;
157 };
158
159 LookupFHResult fhr = lookup_fh(parent, path, flags);
160 if (get<0>(fhr)) {
161 RGWFileHandle* rgw_fh = get<0>(fhr);
162 if (st) {
163 lock_guard guard(rgw_fh->mtx);
164 if (st_mask & RGW_SETATTR_SIZE) {
165 rgw_fh->set_size(st->st_size);
166 }
167 if (st_mask & RGW_SETATTR_MTIME) {
168 rgw_fh->set_times(st->st_mtim);
169 }
170 } /* st */
171 } /* rgw_fh */
172 return fhr;
173 } /* RGWLibFS::fake_leaf */
174
7c673cae
FG
175 LookupFHResult RGWLibFS::stat_leaf(RGWFileHandle* parent,
176 const char *path,
177 enum rgw_fh_type type,
178 uint32_t flags)
179 {
180 /* find either-of <object_name>, <object_name/>, only one of
181 * which should exist; atomicity? */
182 using std::get;
183
184 LookupFHResult fhr{nullptr, 0};
185
186 /* XXX the need for two round-trip operations to identify file or
187 * directory leaf objects is unecessary--the current proposed
188 * mechanism to avoid this is to store leaf object names with an
189 * object locator w/o trailing slash */
190
31f18b77 191 std::string obj_path = parent->format_child_name(path, false);
7c673cae
FG
192
193 for (auto ix : { 0, 1, 2 }) {
194 switch (ix) {
195 case 0:
196 {
197 /* type hint */
198 if (type == RGW_FS_TYPE_DIRECTORY)
199 continue;
200
20effc67 201 RGWStatObjRequest req(cct, user->clone(),
7c673cae
FG
202 parent->bucket_name(), obj_path,
203 RGWStatObjRequest::FLAG_NONE);
204 int rc = rgwlib.get_fe()->execute_req(&req);
205 if ((rc == 0) &&
206 (req.get_ret() == 0)) {
207 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
208 if (get<0>(fhr)) {
209 RGWFileHandle* rgw_fh = get<0>(fhr);
210 lock_guard guard(rgw_fh->mtx);
211 rgw_fh->set_size(req.get_size());
212 rgw_fh->set_times(req.get_mtime());
213 /* restore attributes */
214 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
215 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
81eedcae
TL
216 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
217 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
f67539c2
TL
218 if (!(flags & RGWFileHandle::FLAG_IN_CB) &&
219 ux_key && ux_attrs) {
3efd9988
FG
220 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
221 if (get<0>(dar) || get<1>(dar)) {
222 update_fh(rgw_fh);
223 }
7c673cae
FG
224 }
225 }
226 goto done;
227 }
228 }
229 break;
230 case 1:
231 {
232 /* try dir form */
233 /* type hint */
234 if (type == RGW_FS_TYPE_FILE)
235 continue;
236
237 obj_path += "/";
20effc67 238 RGWStatObjRequest req(cct, user->clone(),
7c673cae
FG
239 parent->bucket_name(), obj_path,
240 RGWStatObjRequest::FLAG_NONE);
241 int rc = rgwlib.get_fe()->execute_req(&req);
242 if ((rc == 0) &&
243 (req.get_ret() == 0)) {
244 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_DIRECTORY);
245 if (get<0>(fhr)) {
246 RGWFileHandle* rgw_fh = get<0>(fhr);
247 lock_guard guard(rgw_fh->mtx);
248 rgw_fh->set_size(req.get_size());
249 rgw_fh->set_times(req.get_mtime());
250 /* restore attributes */
251 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
252 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
81eedcae
TL
253 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
254 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
f67539c2
TL
255 if (!(flags & RGWFileHandle::FLAG_IN_CB) &&
256 ux_key && ux_attrs) {
3efd9988
FG
257 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
258 if (get<0>(dar) || get<1>(dar)) {
259 update_fh(rgw_fh);
260 }
7c673cae
FG
261 }
262 }
263 goto done;
264 }
265 }
266 break;
267 case 2:
268 {
269 std::string object_name{path};
20effc67 270 RGWStatLeafRequest req(cct, user->clone(),
f67539c2 271 parent, object_name);
7c673cae
FG
272 int rc = rgwlib.get_fe()->execute_req(&req);
273 if ((rc == 0) &&
274 (req.get_ret() == 0)) {
275 if (req.matched) {
276 /* we need rgw object's key name equal to file name, if
277 * not return NULL */
278 if ((flags & RGWFileHandle::FLAG_EXACT_MATCH) &&
279 !req.exact_matched) {
280 lsubdout(get_context(), rgw, 15)
281 << __func__
282 << ": stat leaf not exact match file name = "
283 << path << dendl;
284 goto done;
285 }
286 fhr = lookup_fh(parent, path,
287 RGWFileHandle::FLAG_CREATE|
288 ((req.is_dir) ?
289 RGWFileHandle::FLAG_DIRECTORY :
290 RGWFileHandle::FLAG_NONE));
291 /* XXX we don't have an object--in general, there need not
292 * be one (just a path segment in some other object). In
293 * actual leaf an object exists, but we'd need another round
294 * trip to get attrs */
295 if (get<0>(fhr)) {
296 /* for now use the parent object's mtime */
297 RGWFileHandle* rgw_fh = get<0>(fhr);
298 lock_guard guard(rgw_fh->mtx);
299 rgw_fh->set_mtime(parent->get_mtime());
300 }
301 }
302 }
303 }
304 break;
305 default:
306 /* not reached */
307 break;
308 }
309 }
310 done:
311 return fhr;
312 } /* RGWLibFS::stat_leaf */
313
314 int RGWLibFS::read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
315 size_t* bytes_read, void* buffer, uint32_t flags)
316 {
317 if (! rgw_fh->is_file())
318 return -EINVAL;
319
320 if (rgw_fh->deleted())
321 return -ESTALE;
322
20effc67 323 RGWReadRequest req(get_context(), user->clone(), rgw_fh, offset, length, buffer);
7c673cae
FG
324
325 int rc = rgwlib.get_fe()->execute_req(&req);
326 if ((rc == 0) &&
522d829b 327 ((rc = req.get_ret()) == 0)) {
11fdf7f2
TL
328 lock_guard guard(rgw_fh->mtx);
329 rgw_fh->set_atime(real_clock::to_timespec(real_clock::now()));
330 *bytes_read = req.nread;
331 }
332
333 return rc;
334 }
335
336 int RGWLibFS::readlink(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
337 size_t* bytes_read, void* buffer, uint32_t flags)
338 {
339 if (! rgw_fh->is_link())
340 return -EINVAL;
341
342 if (rgw_fh->deleted())
343 return -ESTALE;
344
20effc67 345 RGWReadRequest req(get_context(), user->clone(), rgw_fh, offset, length, buffer);
11fdf7f2
TL
346
347 int rc = rgwlib.get_fe()->execute_req(&req);
348 if ((rc == 0) &&
522d829b 349 ((rc = req.get_ret()) == 0)) {
7c673cae
FG
350 lock_guard(rgw_fh->mtx);
351 rgw_fh->set_atime(real_clock::to_timespec(real_clock::now()));
352 *bytes_read = req.nread;
353 }
354
355 return rc;
356 }
357
358 int RGWLibFS::unlink(RGWFileHandle* rgw_fh, const char* name, uint32_t flags)
359 {
360 int rc = 0;
31f18b77 361 BucketStats bs;
7c673cae 362 RGWFileHandle* parent = nullptr;
31f18b77 363 RGWFileHandle* bkt_fh = nullptr;
7c673cae
FG
364
365 if (unlikely(flags & RGWFileHandle::FLAG_UNLINK_THIS)) {
366 /* LOCKED */
367 parent = rgw_fh->get_parent();
368 } else {
369 /* atomicity */
370 parent = rgw_fh;
371 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_LOCK);
372 rgw_fh = get<0>(fhr);
373 /* LOCKED */
374 }
375
376 if (parent->is_root()) {
31f18b77
FG
377 /* a bucket may have an object storing Unix attributes, check
378 * for and delete it */
379 LookupFHResult fhr;
380 fhr = stat_bucket(parent, name, bs, (rgw_fh) ?
381 RGWFileHandle::FLAG_LOCKED :
382 RGWFileHandle::FLAG_NONE);
383 bkt_fh = get<0>(fhr);
384 if (unlikely(! bkt_fh)) {
385 /* implies !rgw_fh, so also !LOCKED */
386 return -ENOENT;
387 }
388
389 if (bs.num_entries > 1) {
390 unref(bkt_fh); /* return stat_bucket ref */
391 if (likely(!! rgw_fh)) { /* return lock and ref from
392 * lookup_fh (or caller in the
393 * special case of
394 * RGWFileHandle::FLAG_UNLINK_THIS) */
395 rgw_fh->mtx.unlock();
396 unref(rgw_fh);
397 }
398 return -ENOTEMPTY;
399 } else {
400 /* delete object w/key "<bucket>/" (uxattrs), if any */
401 string oname{"/"};
20effc67 402 RGWDeleteObjRequest req(cct, user->clone(), bkt_fh->bucket_name(), oname);
31f18b77
FG
403 rc = rgwlib.get_fe()->execute_req(&req);
404 /* don't care if ENOENT */
405 unref(bkt_fh);
406 }
407
408 string bname{name};
20effc67 409 RGWDeleteBucketRequest req(cct, user->clone(), bname);
7c673cae
FG
410 rc = rgwlib.get_fe()->execute_req(&req);
411 if (! rc) {
412 rc = req.get_ret();
413 }
414 } else {
415 /*
416 * leaf object
417 */
418 if (! rgw_fh) {
419 /* XXX for now, peform a hard lookup to deduce the type of
420 * object to be deleted ("foo" vs. "foo/")--also, ensures
421 * atomicity at this endpoint */
422 struct rgw_file_handle *fh;
423 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &fh,
eafe8130 424 nullptr /* st */, 0 /* mask */,
7c673cae
FG
425 RGW_LOOKUP_FLAG_NONE);
426 if (!! rc)
427 return rc;
428
429 /* rgw_fh ref+ */
430 rgw_fh = get_rgwfh(fh);
431 rgw_fh->mtx.lock(); /* LOCKED */
432 }
433
434 std::string oname = rgw_fh->relative_object_name();
435 if (rgw_fh->is_dir()) {
436 /* for the duration of our cache timer, trust positive
437 * child cache */
438 if (rgw_fh->has_children()) {
439 rgw_fh->mtx.unlock();
440 unref(rgw_fh);
441 return(-ENOTEMPTY);
442 }
443 oname += "/";
444 }
20effc67 445 RGWDeleteObjRequest req(cct, user->clone(), parent->bucket_name(), oname);
7c673cae
FG
446 rc = rgwlib.get_fe()->execute_req(&req);
447 if (! rc) {
448 rc = req.get_ret();
449 }
450 }
451
31f18b77
FG
452 /* ENOENT when raced with other s3 gateway */
453 if (! rc || rc == -ENOENT) {
454 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
455 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
456 RGWFileHandle::FHCache::FLAG_LOCK);
457 }
7c673cae
FG
458
459 if (! rc) {
460 real_time t = real_clock::now();
461 parent->set_mtime(real_clock::to_timespec(t));
462 parent->set_ctime(real_clock::to_timespec(t));
463 }
464
465 rgw_fh->mtx.unlock();
466 unref(rgw_fh);
467
468 return rc;
469 } /* RGWLibFS::unlink */
470
471 int RGWLibFS::rename(RGWFileHandle* src_fh, RGWFileHandle* dst_fh,
472 const char *_src_name, const char *_dst_name)
473
474 {
475 /* XXX initial implementation: try-copy, and delete if copy
476 * succeeds */
477 int rc = -EINVAL;
7c673cae
FG
478 real_time t;
479
480 std::string src_name{_src_name};
481 std::string dst_name{_dst_name};
482
483 /* atomicity */
484 LookupFHResult fhr = lookup_fh(src_fh, _src_name, RGWFileHandle::FLAG_LOCK);
485 RGWFileHandle* rgw_fh = get<0>(fhr);
486
487 /* should not happen */
488 if (! rgw_fh) {
489 ldout(get_context(), 0) << __func__
490 << " BUG no such src renaming path="
491 << src_name
492 << dendl;
493 goto out;
494 }
495
496 /* forbid renaming of directories (unreasonable at scale) */
497 if (rgw_fh->is_dir()) {
498 ldout(get_context(), 12) << __func__
499 << " rejecting attempt to rename directory path="
500 << rgw_fh->full_object_name()
501 << dendl;
502 rc = -EPERM;
503 goto unlock;
504 }
505
506 /* forbid renaming open files (violates intent, for now) */
507 if (rgw_fh->is_open()) {
508 ldout(get_context(), 12) << __func__
509 << " rejecting attempt to rename open file path="
510 << rgw_fh->full_object_name()
511 << dendl;
512 rc = -EPERM;
513 goto unlock;
514 }
515
516 t = real_clock::now();
517
518 for (int ix : {0, 1}) {
519 switch (ix) {
520 case 0:
521 {
20effc67 522 RGWCopyObjRequest req(cct, user->clone(), src_fh, dst_fh, src_name, dst_name);
7c673cae
FG
523 int rc = rgwlib.get_fe()->execute_req(&req);
524 if ((rc != 0) ||
525 ((rc = req.get_ret()) != 0)) {
526 ldout(get_context(), 1)
527 << __func__
528 << " rename step 0 failed src="
529 << src_fh->full_object_name() << " " << src_name
530 << " dst=" << dst_fh->full_object_name()
531 << " " << dst_name
532 << "rc " << rc
533 << dendl;
534 goto unlock;
535 }
536 ldout(get_context(), 12)
537 << __func__
538 << " rename step 0 success src="
539 << src_fh->full_object_name() << " " << src_name
540 << " dst=" << dst_fh->full_object_name()
541 << " " << dst_name
542 << " rc " << rc
543 << dendl;
544 /* update dst change id */
545 dst_fh->set_times(t);
546 }
547 break;
548 case 1:
549 {
550 rc = this->unlink(rgw_fh /* LOCKED */, _src_name,
551 RGWFileHandle::FLAG_UNLINK_THIS);
552 /* !LOCKED, -ref */
553 if (! rc) {
554 ldout(get_context(), 12)
555 << __func__
556 << " rename step 1 success src="
557 << src_fh->full_object_name() << " " << src_name
558 << " dst=" << dst_fh->full_object_name()
559 << " " << dst_name
560 << " rc " << rc
561 << dendl;
562 /* update src change id */
563 src_fh->set_times(t);
564 } else {
565 ldout(get_context(), 1)
566 << __func__
567 << " rename step 1 failed src="
568 << src_fh->full_object_name() << " " << src_name
569 << " dst=" << dst_fh->full_object_name()
570 << " " << dst_name
571 << " rc " << rc
572 << dendl;
573 }
574 }
575 goto out;
576 default:
11fdf7f2 577 ceph_abort();
7c673cae
FG
578 } /* switch */
579 } /* ix */
580 unlock:
581 rgw_fh->mtx.unlock(); /* !LOCKED */
582 unref(rgw_fh); /* -ref */
583
584 out:
585 return rc;
586 } /* RGWLibFS::rename */
587
588 MkObjResult RGWLibFS::mkdir(RGWFileHandle* parent, const char *name,
589 struct stat *st, uint32_t mask, uint32_t flags)
590 {
7c673cae 591 int rc, rc2;
31f18b77
FG
592 rgw_file_handle *lfh;
593
594 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
eafe8130 595 nullptr /* st */, 0 /* mask */,
31f18b77
FG
596 RGW_LOOKUP_FLAG_NONE);
597 if (! rc) {
598 /* conflict! */
599 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 600 // ignore return code
31f18b77
FG
601 return MkObjResult{nullptr, -EEXIST};
602 }
7c673cae 603
31f18b77 604 MkObjResult mkr{nullptr, -EINVAL};
7c673cae
FG
605 LookupFHResult fhr;
606 RGWFileHandle* rgw_fh = nullptr;
607 buffer::list ux_key, ux_attrs;
608
609 fhr = lookup_fh(parent, name,
610 RGWFileHandle::FLAG_CREATE|
611 RGWFileHandle::FLAG_DIRECTORY|
612 RGWFileHandle::FLAG_LOCK);
613 rgw_fh = get<0>(fhr);
614 if (rgw_fh) {
615 rgw_fh->create_stat(st, mask);
616 rgw_fh->set_times(real_clock::now());
617 /* save attrs */
618 rgw_fh->encode_attrs(ux_key, ux_attrs);
619 if (st)
494da23a 620 rgw_fh->stat(st, RGWFileHandle::FLAG_LOCKED);
7c673cae
FG
621 get<0>(mkr) = rgw_fh;
622 } else {
623 get<1>(mkr) = -EIO;
624 return mkr;
625 }
626
627 if (parent->is_root()) {
628 /* bucket */
629 string bname{name};
630 /* enforce S3 name restrictions */
631 rc = valid_fs_bucket_name(bname);
632 if (rc != 0) {
633 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
634 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
635 RGWFileHandle::FHCache::FLAG_LOCK);
636 rgw_fh->mtx.unlock();
637 unref(rgw_fh);
638 get<0>(mkr) = nullptr;
639 get<1>(mkr) = rc;
640 return mkr;
641 }
642
20effc67 643 RGWCreateBucketRequest req(get_context(), user->clone(), bname);
7c673cae
FG
644
645 /* save attrs */
646 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
647 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
648
649 rc = rgwlib.get_fe()->execute_req(&req);
650 rc2 = req.get_ret();
651 } else {
652 /* create an object representing the directory */
653 buffer::list bl;
31f18b77 654 string dir_name = parent->format_child_name(name, true);
7c673cae
FG
655
656 /* need valid S3 name (characters, length <= 1024, etc) */
657 rc = valid_fs_object_name(dir_name);
658 if (rc != 0) {
659 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
660 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
661 RGWFileHandle::FHCache::FLAG_LOCK);
662 rgw_fh->mtx.unlock();
663 unref(rgw_fh);
664 get<0>(mkr) = nullptr;
665 get<1>(mkr) = rc;
666 return mkr;
667 }
668
20effc67 669 RGWPutObjRequest req(get_context(), user->clone(), parent->bucket_name(), dir_name, bl);
7c673cae
FG
670
671 /* save attrs */
672 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
673 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
674
675 rc = rgwlib.get_fe()->execute_req(&req);
676 rc2 = req.get_ret();
677 }
678
679 if (! ((rc == 0) &&
680 (rc2 == 0))) {
681 /* op failed */
682 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
683 rgw_fh->mtx.unlock(); /* !LOCKED */
684 unref(rgw_fh);
685 get<0>(mkr) = nullptr;
686 /* fixup rc */
687 if (!rc)
688 rc = rc2;
689 } else {
690 real_time t = real_clock::now();
691 parent->set_mtime(real_clock::to_timespec(t));
692 parent->set_ctime(real_clock::to_timespec(t));
693 rgw_fh->mtx.unlock(); /* !LOCKED */
694 }
695
696 get<1>(mkr) = rc;
697
698 return mkr;
699 } /* RGWLibFS::mkdir */
700
701 MkObjResult RGWLibFS::create(RGWFileHandle* parent, const char *name,
702 struct stat *st, uint32_t mask, uint32_t flags)
703 {
704 int rc, rc2;
705
706 using std::get;
707
708 rgw_file_handle *lfh;
709 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
eafe8130 710 nullptr /* st */, 0 /* mask */,
7c673cae
FG
711 RGW_LOOKUP_FLAG_NONE);
712 if (! rc) {
713 /* conflict! */
714 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 715 // ignore return code
7c673cae
FG
716 return MkObjResult{nullptr, -EEXIST};
717 }
718
719 /* expand and check name */
31f18b77 720 std::string obj_name = parent->format_child_name(name, false);
7c673cae
FG
721 rc = valid_fs_object_name(obj_name);
722 if (rc != 0) {
723 return MkObjResult{nullptr, rc};
724 }
725
726 /* create it */
727 buffer::list bl;
20effc67 728 RGWPutObjRequest req(cct, user->clone(), parent->bucket_name(), obj_name, bl);
7c673cae
FG
729 MkObjResult mkr{nullptr, -EINVAL};
730
731 rc = rgwlib.get_fe()->execute_req(&req);
732 rc2 = req.get_ret();
733
734 if ((rc == 0) &&
735 (rc2 == 0)) {
736 /* XXX atomicity */
737 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_CREATE |
738 RGWFileHandle::FLAG_LOCK);
739 RGWFileHandle* rgw_fh = get<0>(fhr);
740 if (rgw_fh) {
741 if (get<1>(fhr) & RGWFileHandle::FLAG_CREATE) {
742 /* fill in stat data */
743 real_time t = real_clock::now();
744 rgw_fh->create_stat(st, mask);
745 rgw_fh->set_times(t);
746
747 parent->set_mtime(real_clock::to_timespec(t));
748 parent->set_ctime(real_clock::to_timespec(t));
749 }
750 if (st)
494da23a 751 (void) rgw_fh->stat(st, RGWFileHandle::FLAG_LOCKED);
81eedcae
TL
752
753 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
754 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
755
7c673cae
FG
756 get<0>(mkr) = rgw_fh;
757 rgw_fh->mtx.unlock();
758 } else
759 rc = -EIO;
760 }
761
762 get<1>(mkr) = rc;
11fdf7f2
TL
763
764 /* case like : quota exceed will be considered as fail too*/
765 if(rc2 < 0)
766 get<1>(mkr) = rc2;
7c673cae
FG
767
768 return mkr;
769 } /* RGWLibFS::create */
770
11fdf7f2
TL
771 MkObjResult RGWLibFS::symlink(RGWFileHandle* parent, const char *name,
772 const char* link_path, struct stat *st, uint32_t mask, uint32_t flags)
773 {
774 int rc, rc2;
775
776 using std::get;
777
778 rgw_file_handle *lfh;
eafe8130
TL
779 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
780 nullptr /* st */, 0 /* mask */,
11fdf7f2
TL
781 RGW_LOOKUP_FLAG_NONE);
782 if (! rc) {
783 /* conflict! */
784 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 785 // ignore return code
11fdf7f2
TL
786 return MkObjResult{nullptr, -EEXIST};
787 }
788
789 MkObjResult mkr{nullptr, -EINVAL};
790 LookupFHResult fhr;
791 RGWFileHandle* rgw_fh = nullptr;
792 buffer::list ux_key, ux_attrs;
793
794 fhr = lookup_fh(parent, name,
795 RGWFileHandle::FLAG_CREATE|
796 RGWFileHandle::FLAG_SYMBOLIC_LINK|
797 RGWFileHandle::FLAG_LOCK);
798 rgw_fh = get<0>(fhr);
799 if (rgw_fh) {
800 rgw_fh->create_stat(st, mask);
801 rgw_fh->set_times(real_clock::now());
802 /* save attrs */
803 rgw_fh->encode_attrs(ux_key, ux_attrs);
804 if (st)
805 rgw_fh->stat(st);
806 get<0>(mkr) = rgw_fh;
807 } else {
808 get<1>(mkr) = -EIO;
809 return mkr;
810 }
811
812 /* need valid S3 name (characters, length <= 1024, etc) */
813 rc = valid_fs_object_name(name);
814 if (rc != 0) {
815 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
816 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
817 RGWFileHandle::FHCache::FLAG_LOCK);
818 rgw_fh->mtx.unlock();
819 unref(rgw_fh);
820 get<0>(mkr) = nullptr;
821 get<1>(mkr) = rc;
822 return mkr;
823 }
824
825 string obj_name = std::string(name);
826 /* create an object representing the directory */
827 buffer::list bl;
828
829 /* XXXX */
830#if 0
831 bl.push_back(
832 buffer::create_static(len, static_cast<char*>(buffer)));
833#else
834
835 bl.push_back(
836 buffer::copy(link_path, strlen(link_path)));
837#endif
838
20effc67 839 RGWPutObjRequest req(get_context(), user->clone(), parent->bucket_name(), obj_name, bl);
11fdf7f2
TL
840
841 /* save attrs */
842 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
843 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
844
845 rc = rgwlib.get_fe()->execute_req(&req);
846 rc2 = req.get_ret();
847 if (! ((rc == 0) &&
848 (rc2 == 0))) {
849 /* op failed */
850 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
851 rgw_fh->mtx.unlock(); /* !LOCKED */
852 unref(rgw_fh);
853 get<0>(mkr) = nullptr;
854 /* fixup rc */
855 if (!rc)
856 rc = rc2;
857 } else {
858 real_time t = real_clock::now();
859 parent->set_mtime(real_clock::to_timespec(t));
860 parent->set_ctime(real_clock::to_timespec(t));
861 rgw_fh->mtx.unlock(); /* !LOCKED */
862 }
863
864 get<1>(mkr) = rc;
865
866 return mkr;
867 } /* RGWLibFS::symlink */
868
7c673cae
FG
869 int RGWLibFS::getattr(RGWFileHandle* rgw_fh, struct stat* st)
870 {
871 switch(rgw_fh->fh.fh_type) {
872 case RGW_FS_TYPE_FILE:
873 {
874 if (rgw_fh->deleted())
875 return -ESTALE;
876 }
877 break;
878 default:
879 break;
880 };
494da23a 881 /* if rgw_fh is a directory, mtime will be advanced */
7c673cae
FG
882 return rgw_fh->stat(st);
883 } /* RGWLibFS::getattr */
884
885 int RGWLibFS::setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
886 uint32_t flags)
887 {
888 int rc, rc2;
889 buffer::list ux_key, ux_attrs;
81eedcae
TL
890 buffer::list etag = rgw_fh->get_etag();
891 buffer::list acls = rgw_fh->get_acls();
7c673cae
FG
892
893 lock_guard guard(rgw_fh->mtx);
894
895 switch(rgw_fh->fh.fh_type) {
896 case RGW_FS_TYPE_FILE:
897 {
898 if (rgw_fh->deleted())
899 return -ESTALE;
900 }
901 break;
902 default:
903 break;
904 };
905
906 string obj_name{rgw_fh->relative_object_name()};
907
31f18b77
FG
908 if (rgw_fh->is_dir() &&
909 (likely(! rgw_fh->is_bucket()))) {
7c673cae
FG
910 obj_name += "/";
911 }
912
20effc67 913 RGWSetAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
7c673cae
FG
914
915 rgw_fh->create_stat(st, mask);
916 rgw_fh->encode_attrs(ux_key, ux_attrs);
917
918 /* save attrs */
919 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
920 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
81eedcae
TL
921 req.emplace_attr(RGW_ATTR_ETAG, std::move(etag));
922 req.emplace_attr(RGW_ATTR_ACL, std::move(acls));
7c673cae
FG
923
924 rc = rgwlib.get_fe()->execute_req(&req);
925 rc2 = req.get_ret();
926
927 if (rc == -ENOENT) {
928 /* special case: materialize placeholder dir */
929 buffer::list bl;
20effc67 930 RGWPutObjRequest req(get_context(), user->clone(), rgw_fh->bucket_name(), obj_name, bl);
7c673cae
FG
931
932 rgw_fh->encode_attrs(ux_key, ux_attrs); /* because std::moved */
933
934 /* save attrs */
935 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
936 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
937
938 rc = rgwlib.get_fe()->execute_req(&req);
939 rc2 = req.get_ret();
940 }
941
942 if ((rc != 0) || (rc2 != 0)) {
943 return -EIO;
944 }
945
946 rgw_fh->set_ctime(real_clock::to_timespec(real_clock::now()));
947
948 return 0;
949 } /* RGWLibFS::setattr */
950
f67539c2
TL
951 static inline std::string prefix_xattr_keystr(const rgw_xattrstr& key) {
952 std::string keystr;
953 keystr.reserve(sizeof(RGW_ATTR_META_PREFIX) + key.len);
522d829b 954 keystr += string{RGW_ATTR_META_PREFIX};
f67539c2
TL
955 keystr += string{key.val, key.len};
956 return keystr;
957 }
958
959 static inline std::string_view unprefix_xattr_keystr(const std::string& key)
960 {
961 std::string_view svk{key};
962 auto pos = svk.find(RGW_ATTR_META_PREFIX);
963 if (pos == std::string_view::npos) {
964 return std::string_view{""};
965 } else if (pos == 0) {
966 svk.remove_prefix(sizeof(RGW_ATTR_META_PREFIX)-1);
967 }
968 return svk;
969 }
970
971 int RGWLibFS::getxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist *attrs,
972 rgw_getxattr_cb cb, void *cb_arg,
973 uint32_t flags)
974 {
975 /* cannot store on fs_root, should not on buckets? */
976 if ((rgw_fh->is_bucket()) ||
977 (rgw_fh->is_root())) {
978 return -EINVAL;
979 }
980
981 int rc, rc2, rc3;
982 string obj_name{rgw_fh->relative_object_name2()};
983
20effc67 984 RGWGetAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
f67539c2
TL
985
986 for (uint32_t ix = 0; ix < attrs->xattr_cnt; ++ix) {
987 auto& xattr = attrs->xattrs[ix];
988
989 /* pass exposed attr keys as given, else prefix */
990 std::string k = is_exposed_attr(xattr.key)
991 ? std::string{xattr.key.val, xattr.key.len}
992 : prefix_xattr_keystr(xattr.key);
993
994 req.emplace_key(std::move(k));
995 }
996
997 if (ldlog_p1(get_context(), ceph_subsys_rgw, 15)) {
998 lsubdout(get_context(), rgw, 15)
999 << __func__
1000 << " get keys for: "
1001 << rgw_fh->object_name()
1002 << " keys:"
1003 << dendl;
1004 for (const auto& attr: req.get_attrs()) {
1005 lsubdout(get_context(), rgw, 15)
1006 << "\tkey: " << attr.first << dendl;
1007 }
1008 }
1009
1010 rc = rgwlib.get_fe()->execute_req(&req);
1011 rc2 = req.get_ret();
1012 rc3 = ((rc == 0) && (rc2 == 0)) ? 0 : -EIO;
1013
1014 /* call back w/xattr data */
1015 if (rc3 == 0) {
1016 const auto& attrs = req.get_attrs();
1017 for (const auto& attr : attrs) {
1018
1019 if (!attr.second.has_value())
1020 continue;
1021
1022 const auto& k = attr.first;
1023 const auto& v = attr.second.value();
1024
1025 /* return exposed attr keys as given, else unprefix --
1026 * yes, we could have memoized the exposed check, but
1027 * to be efficient it would need to be saved with
1028 * RGWGetAttrs::attrs, I think */
1029 std::string_view svk =
1030 is_exposed_attr(rgw_xattrstr{const_cast<char*>(k.c_str()),
1031 uint32_t(k.length())})
1032 ? k
1033 : unprefix_xattr_keystr(k);
1034
1035 /* skip entries not matching prefix */
1036 if (svk.empty())
1037 continue;
1038
1039 rgw_xattrstr xattr_k = { const_cast<char*>(svk.data()),
1040 uint32_t(svk.length())};
1041 rgw_xattrstr xattr_v =
1042 {const_cast<char*>(const_cast<buffer::list&>(v).c_str()),
1043 uint32_t(v.length())};
1044 rgw_xattr xattr = { xattr_k, xattr_v };
1045 rgw_xattrlist xattrlist = { &xattr, 1 };
1046
1047 cb(&xattrlist, cb_arg, RGW_GETXATTR_FLAG_NONE);
1048 }
1049 }
1050
1051 return rc3;
1052 } /* RGWLibFS::getxattrs */
1053
1054 int RGWLibFS::lsxattrs(
1055 RGWFileHandle* rgw_fh, rgw_xattrstr *filter_prefix, rgw_getxattr_cb cb,
1056 void *cb_arg, uint32_t flags)
1057 {
1058 /* cannot store on fs_root, should not on buckets? */
1059 if ((rgw_fh->is_bucket()) ||
1060 (rgw_fh->is_root())) {
1061 return -EINVAL;
1062 }
1063
1064 int rc, rc2, rc3;
1065 string obj_name{rgw_fh->relative_object_name2()};
1066
20effc67 1067 RGWGetAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
f67539c2
TL
1068
1069 rc = rgwlib.get_fe()->execute_req(&req);
1070 rc2 = req.get_ret();
1071 rc3 = ((rc == 0) && (rc2 == 0)) ? 0 : -EIO;
1072
1073 /* call back w/xattr data--check for eof */
1074 if (rc3 == 0) {
1075 const auto& keys = req.get_attrs();
1076 for (const auto& k : keys) {
1077
1078 /* return exposed attr keys as given, else unprefix */
1079 std::string_view svk =
1080 is_exposed_attr(rgw_xattrstr{const_cast<char*>(k.first.c_str()),
1081 uint32_t(k.first.length())})
1082 ? k.first
1083 : unprefix_xattr_keystr(k.first);
1084
1085 /* skip entries not matching prefix */
1086 if (svk.empty())
1087 continue;
1088
1089 rgw_xattrstr xattr_k = { const_cast<char*>(svk.data()),
1090 uint32_t(svk.length())};
1091 rgw_xattrstr xattr_v = { nullptr, 0 };
1092 rgw_xattr xattr = { xattr_k, xattr_v };
1093 rgw_xattrlist xattrlist = { &xattr, 1 };
1094
1095 auto cbr = cb(&xattrlist, cb_arg, RGW_LSXATTR_FLAG_NONE);
1096 if (cbr & RGW_LSXATTR_FLAG_STOP)
1097 break;
1098 }
1099 }
1100
1101 return rc3;
1102 } /* RGWLibFS::lsxattrs */
1103
1104 int RGWLibFS::setxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist *attrs,
1105 uint32_t flags)
1106 {
1107 /* cannot store on fs_root, should not on buckets? */
1108 if ((rgw_fh->is_bucket()) ||
1109 (rgw_fh->is_root())) {
1110 return -EINVAL;
1111 }
1112
1113 int rc, rc2;
1114 string obj_name{rgw_fh->relative_object_name2()};
1115
20effc67 1116 RGWSetAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
f67539c2
TL
1117
1118 for (uint32_t ix = 0; ix < attrs->xattr_cnt; ++ix) {
1119 auto& xattr = attrs->xattrs[ix];
1120 buffer::list attr_bl;
1121 /* don't allow storing at RGW_ATTR_META_PREFIX */
1122 if (! (xattr.key.len > 0))
1123 continue;
1124
1125 /* reject lexical match with any exposed attr */
1126 if (is_exposed_attr(xattr.key))
1127 continue;
1128
1129 string k = prefix_xattr_keystr(xattr.key);
1130 attr_bl.append(xattr.val.val, xattr.val.len);
1131 req.emplace_attr(k.c_str(), std::move(attr_bl));
1132 }
1133
1134 /* don't send null requests */
1135 if (! (req.get_attrs().size() > 0)) {
1136 return -EINVAL;
1137 }
1138
1139 rc = rgwlib.get_fe()->execute_req(&req);
1140 rc2 = req.get_ret();
1141
1142 return (((rc == 0) && (rc2 == 0)) ? 0 : -EIO);
1143
1144 } /* RGWLibFS::setxattrs */
1145
1146 int RGWLibFS::rmxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist* attrs,
1147 uint32_t flags)
1148 {
1149 /* cannot store on fs_root, should not on buckets? */
1150 if ((rgw_fh->is_bucket()) ||
1151 (rgw_fh->is_root())) {
1152 return -EINVAL;
1153 }
1154
1155 int rc, rc2;
1156 string obj_name{rgw_fh->relative_object_name2()};
1157
20effc67 1158 RGWRMAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
f67539c2
TL
1159
1160 for (uint32_t ix = 0; ix < attrs->xattr_cnt; ++ix) {
1161 auto& xattr = attrs->xattrs[ix];
1162 /* don't allow storing at RGW_ATTR_META_PREFIX */
1163 if (! (xattr.key.len > 0)) {
1164 continue;
1165 }
1166 string k = prefix_xattr_keystr(xattr.key);
1167 req.emplace_key(std::move(k));
1168 }
1169
1170 /* don't send null requests */
1171 if (! (req.get_attrs().size() > 0)) {
1172 return -EINVAL;
1173 }
1174
1175 rc = rgwlib.get_fe()->execute_req(&req);
1176 rc2 = req.get_ret();
1177
1178 return (((rc == 0) && (rc2 == 0)) ? 0 : -EIO);
1179
1180 } /* RGWLibFS::rmxattrs */
1181
1182 /* called with rgw_fh->mtx held */
3efd9988 1183 void RGWLibFS::update_fh(RGWFileHandle *rgw_fh)
224ce89b
WB
1184 {
1185 int rc, rc2;
1186 string obj_name{rgw_fh->relative_object_name()};
1187 buffer::list ux_key, ux_attrs;
1188
1189 if (rgw_fh->is_dir() &&
1190 (likely(! rgw_fh->is_bucket()))) {
1191 obj_name += "/";
1192 }
1193
1194 lsubdout(get_context(), rgw, 17)
1195 << __func__
3efd9988 1196 << " update old versioned fh : " << obj_name
224ce89b
WB
1197 << dendl;
1198
20effc67 1199 RGWSetAttrsRequest req(cct, user->clone(), rgw_fh->bucket_name(), obj_name);
224ce89b
WB
1200
1201 rgw_fh->encode_attrs(ux_key, ux_attrs);
1202
224ce89b 1203 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
3efd9988 1204 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
224ce89b
WB
1205
1206 rc = rgwlib.get_fe()->execute_req(&req);
1207 rc2 = req.get_ret();
1208
1209 if ((rc != 0) || (rc2 != 0)) {
1210 lsubdout(get_context(), rgw, 17)
1211 << __func__
3efd9988 1212 << " update fh failed : " << obj_name
224ce89b
WB
1213 << dendl;
1214 }
3efd9988 1215 } /* RGWLibFS::update_fh */
224ce89b 1216
7c673cae
FG
1217 void RGWLibFS::close()
1218 {
1219 state.flags |= FLAG_CLOSED;
1220
1221 class ObjUnref
1222 {
1223 RGWLibFS* fs;
1224 public:
11fdf7f2 1225 explicit ObjUnref(RGWLibFS* _fs) : fs(_fs) {}
7c673cae
FG
1226 void operator()(RGWFileHandle* fh) const {
1227 lsubdout(fs->get_context(), rgw, 5)
f67539c2 1228 << __PRETTY_FUNCTION__
7c673cae
FG
1229 << fh->name
1230 << " before ObjUnref refs=" << fh->get_refcnt()
1231 << dendl;
31f18b77 1232 fs->unref(fh);
7c673cae
FG
1233 }
1234 };
1235
1236 /* force cache drain, forces objects to evict */
1237 fh_cache.drain(ObjUnref(this),
1238 RGWFileHandle::FHCache::FLAG_LOCK);
1239 rgwlib.get_fe()->get_process()->unregister_fs(this);
1240 rele();
1241 } /* RGWLibFS::close */
1242
494da23a
TL
1243 inline std::ostream& operator<<(std::ostream &os, fh_key const &fhk) {
1244 os << "<fh_key: bucket=";
1245 os << fhk.fh_hk.bucket;
1246 os << "; object=";
1247 os << fhk.fh_hk.object;
1248 os << ">";
1249 return os;
1250 }
1251
7c673cae
FG
1252 inline std::ostream& operator<<(std::ostream &os, struct timespec const &ts) {
1253 os << "<timespec: tv_sec=";
1254 os << ts.tv_sec;
1255 os << "; tv_nsec=";
1256 os << ts.tv_nsec;
1257 os << ">";
1258 return os;
1259 }
1260
1261 std::ostream& operator<<(std::ostream &os, RGWLibFS::event const &ev) {
1262 os << "<event:";
1263 switch (ev.t) {
1264 case RGWLibFS::event::type::READDIR:
1265 os << "type=READDIR;";
1266 break;
1267 default:
1268 os << "type=UNKNOWN;";
1269 break;
1270 };
1271 os << "fid=" << ev.fhk.fh_hk.bucket << ":" << ev.fhk.fh_hk.object
1272 << ";ts=" << ev.ts << ">";
1273 return os;
1274 }
1275
1276 void RGWLibFS::gc()
1277 {
1278 using std::get;
1279 using directory = RGWFileHandle::directory;
1280
1281 /* dirent invalidate timeout--basically, the upper-bound on
1282 * inconsistency with the S3 namespace */
1283 auto expire_s
1284 = get_context()->_conf->rgw_nfs_namespace_expire_secs;
1285
1286 /* max events to gc in one cycle */
c07f9fc5 1287 uint32_t max_ev = get_context()->_conf->rgw_nfs_max_gc;
7c673cae
FG
1288
1289 struct timespec now, expire_ts;
1290 event_vector ve;
1291 bool stop = false;
1292 std::deque<event> &events = state.events;
1293
1294 do {
1295 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
1296 lsubdout(get_context(), rgw, 15)
1297 << "GC: top of expire loop"
1298 << " now=" << now
1299 << " expire_s=" << expire_s
1300 << dendl;
1301 {
1302 lock_guard guard(state.mtx); /* LOCKED */
494da23a
TL
1303 lsubdout(get_context(), rgw, 15)
1304 << "GC: processing"
1305 << " count=" << events.size()
1306 << " events"
1307 << dendl;
1308 /* just return if no events */
7c673cae
FG
1309 if (events.empty()) {
1310 return;
1311 }
1312 uint32_t _max_ev =
1313 (events.size() < 500) ? max_ev : (events.size() / 4);
1314 for (uint32_t ix = 0; (ix < _max_ev) && (events.size() > 0); ++ix) {
1315 event& ev = events.front();
1316 expire_ts = ev.ts;
1317 expire_ts.tv_sec += expire_s;
1318 if (expire_ts > now) {
1319 stop = true;
1320 break;
1321 }
1322 ve.push_back(ev);
1323 events.pop_front();
1324 }
1325 } /* anon */
1326 /* !LOCKED */
1327 for (auto& ev : ve) {
1328 lsubdout(get_context(), rgw, 15)
1329 << "try-expire ev: " << ev << dendl;
1330 if (likely(ev.t == event::type::READDIR)) {
1331 RGWFileHandle* rgw_fh = lookup_handle(ev.fhk.fh_hk);
1332 lsubdout(get_context(), rgw, 15)
1333 << "ev rgw_fh: " << rgw_fh << dendl;
1334 if (rgw_fh) {
1335 RGWFileHandle::directory* d;
1336 if (unlikely(! rgw_fh->is_dir())) {
1337 lsubdout(get_context(), rgw, 0)
1338 << __func__
1339 << " BUG non-directory found with READDIR event "
1340 << "(" << rgw_fh->bucket_name() << ","
1341 << rgw_fh->object_name() << ")"
1342 << dendl;
1343 goto rele;
1344 }
1345 /* maybe clear state */
1346 d = get<directory>(&rgw_fh->variant_type);
1347 if (d) {
1348 struct timespec ev_ts = ev.ts;
1349 lock_guard guard(rgw_fh->mtx);
1350 struct timespec d_last_readdir = d->last_readdir;
1351 if (unlikely(ev_ts < d_last_readdir)) {
1352 /* readdir cycle in progress, don't invalidate */
1353 lsubdout(get_context(), rgw, 15)
1354 << "GC: delay expiration for "
1355 << rgw_fh->object_name()
1356 << " ev.ts=" << ev_ts
1357 << " last_readdir=" << d_last_readdir
1358 << dendl;
1359 continue;
1360 } else {
1361 lsubdout(get_context(), rgw, 15)
1362 << "GC: expiring "
1363 << rgw_fh->object_name()
1364 << dendl;
1365 rgw_fh->clear_state();
1366 rgw_fh->invalidate();
1367 }
1368 }
1369 rele:
1370 unref(rgw_fh);
1371 } /* rgw_fh */
1372 } /* event::type::READDIR */
1373 } /* ev */
1374 ve.clear();
1375 } while (! (stop || shutdown));
1376 } /* RGWLibFS::gc */
1377
1378 std::ostream& operator<<(std::ostream &os,
1379 RGWFileHandle const &rgw_fh)
1380 {
1381 const auto& fhk = rgw_fh.get_key();
1382 const auto& fh = const_cast<RGWFileHandle&>(rgw_fh).get_fh();
1383 os << "<RGWFileHandle:";
1384 os << "addr=" << &rgw_fh << ";";
1385 switch (fh->fh_type) {
1386 case RGW_FS_TYPE_DIRECTORY:
1387 os << "type=DIRECTORY;";
1388 break;
1389 case RGW_FS_TYPE_FILE:
1390 os << "type=FILE;";
1391 break;
1392 default:
1393 os << "type=UNKNOWN;";
1394 break;
1395 };
1396 os << "fid=" << fhk.fh_hk.bucket << ":" << fhk.fh_hk.object << ";";
1397 os << "name=" << rgw_fh.object_name() << ";";
1398 os << "refcnt=" << rgw_fh.get_refcnt() << ";";
1399 os << ">";
1400 return os;
1401 }
1402
1403 RGWFileHandle::~RGWFileHandle() {
28e407b8
AA
1404 /* !recycle case, handle may STILL be in handle table, BUT
1405 * the partition lock is not held in this path */
1406 if (fh_hook.is_linked()) {
1407 fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_LOCK);
1408 }
7c673cae 1409 /* cond-unref parent */
3efd9988 1410 if (parent && (! parent->is_mount())) {
7c673cae
FG
1411 /* safe because if parent->unref causes its deletion,
1412 * there are a) by refcnt, no other objects/paths pointing
1413 * to it and b) by the semantics of valid iteration of
1414 * fh_lru (observed, e.g., by cohort_lru<T,...>::drain())
1415 * no unsafe iterators reaching it either--n.b., this constraint
1416 * is binding oncode which may in future attempt to e.g.,
1417 * cause the eviction of objects in LRU order */
31f18b77 1418 (void) get_fs()->unref(parent);
7c673cae
FG
1419 }
1420 }
1421
494da23a
TL
1422 fh_key RGWFileHandle::make_fhk(const std::string& name)
1423 {
1424 std::string tenant = get_fs()->get_user()->user_id.to_str();
1425 if (depth == 0) {
1426 /* S3 bucket -- assert mount-at-bucket case reaches here */
1427 return fh_key(name, name, tenant);
1428 } else {
1429 std::string key_name = make_key_name(name.c_str());
1430 return fh_key(fhk.fh_hk.bucket, key_name.c_str(), tenant);
1431 }
1432 }
1433
7c673cae
FG
1434 void RGWFileHandle::encode_attrs(ceph::buffer::list& ux_key1,
1435 ceph::buffer::list& ux_attrs1)
1436 {
11fdf7f2 1437 using ceph::encode;
7c673cae 1438 fh_key fhk(this->fh.fh_hk);
11fdf7f2
TL
1439 encode(fhk, ux_key1);
1440 encode(*this, ux_attrs1);
7c673cae
FG
1441 } /* RGWFileHandle::encode_attrs */
1442
3efd9988
FG
1443 DecodeAttrsResult RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
1444 const ceph::buffer::list* ux_attrs1)
7c673cae 1445 {
11fdf7f2 1446 using ceph::decode;
3efd9988 1447 DecodeAttrsResult dar { false, false };
7c673cae 1448 fh_key fhk;
11fdf7f2
TL
1449 auto bl_iter_key1 = ux_key1->cbegin();
1450 decode(fhk, bl_iter_key1);
494da23a 1451 get<0>(dar) = true;
7c673cae 1452
11fdf7f2
TL
1453 auto bl_iter_unix1 = ux_attrs1->cbegin();
1454 decode(*this, bl_iter_unix1);
3efd9988
FG
1455 if (this->state.version < 2) {
1456 get<1>(dar) = true;
1457 }
224ce89b 1458
3efd9988 1459 return dar;
7c673cae
FG
1460 } /* RGWFileHandle::decode_attrs */
1461
f91f0fd5 1462 bool RGWFileHandle::reclaim(const cohort::lru::ObjectFactory* newobj_fac) {
7c673cae
FG
1463 lsubdout(fs->get_context(), rgw, 17)
1464 << __func__ << " " << *this
1465 << dendl;
f91f0fd5
TL
1466 auto factory = dynamic_cast<const RGWFileHandle::Factory*>(newobj_fac);
1467 if (factory == nullptr) {
1468 return false;
1469 }
1470 /* make sure the reclaiming object is the same partiton with newobject factory,
1471 * then we can recycle the object, and replace with newobject */
1472 if (!fs->fh_cache.is_same_partition(factory->fhk.fh_hk.object, fh.fh_hk.object)) {
1473 return false;
1474 }
b32b8144 1475 /* in the non-delete case, handle may still be in handle table */
7c673cae 1476 if (fh_hook.is_linked()) {
b32b8144
FG
1477 /* in this case, we are being called from a context which holds
1478 * the partition lock */
1479 fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_NONE);
7c673cae
FG
1480 }
1481 return true;
1482 } /* RGWFileHandle::reclaim */
1483
1484 bool RGWFileHandle::has_children() const
1485 {
1486 if (unlikely(! is_dir()))
1487 return false;
1488
f67539c2
TL
1489 RGWRMdirCheck req(fs->get_context(),
1490 rgwlib.get_store()->get_user(fs->get_user()->user_id),
1491 this);
7c673cae
FG
1492 int rc = rgwlib.get_fe()->execute_req(&req);
1493 if (! rc) {
1494 return req.valid && req.has_children;
1495 }
1496
1497 return false;
1498 }
1499
3efd9988
FG
1500 std::ostream& operator<<(std::ostream &os,
1501 RGWFileHandle::readdir_offset const &offset)
1502 {
1503 using boost::get;
1504 if (unlikely(!! get<uint64_t*>(&offset))) {
1505 uint64_t* ioff = get<uint64_t*>(offset);
1506 os << *ioff;
1507 }
1508 else
1509 os << get<const char*>(offset);
1510 return os;
1511 }
1512
1513 int RGWFileHandle::readdir(rgw_readdir_cb rcb, void *cb_arg,
1514 readdir_offset offset,
7c673cae
FG
1515 bool *eof, uint32_t flags)
1516 {
1517 using event = RGWLibFS::event;
3efd9988 1518 using boost::get;
7c673cae
FG
1519 int rc = 0;
1520 struct timespec now;
1521 CephContext* cct = fs->get_context();
1522
494da23a
TL
1523 lsubdout(cct, rgw, 10)
1524 << __func__ << " readdir called on "
1525 << object_name()
1526 << dendl;
1527
7c673cae
FG
1528 directory* d = get<directory>(&variant_type);
1529 if (d) {
1530 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1531 lock_guard guard(mtx);
1532 d->last_readdir = now;
1533 }
1534
3efd9988 1535 bool initial_off;
494da23a
TL
1536 char* mk{nullptr};
1537
3efd9988 1538 if (likely(!! get<const char*>(&offset))) {
494da23a
TL
1539 mk = const_cast<char*>(get<const char*>(offset));
1540 initial_off = !mk;
3efd9988
FG
1541 } else {
1542 initial_off = (*get<uint64_t*>(offset) == 0);
1543 }
1544
7c673cae 1545 if (is_root()) {
f67539c2
TL
1546 RGWListBucketsRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
1547 this, rcb, cb_arg, offset);
7c673cae
FG
1548 rc = rgwlib.get_fe()->execute_req(&req);
1549 if (! rc) {
1550 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1551 lock_guard guard(mtx);
1552 state.atime = now;
3efd9988 1553 if (initial_off)
7c673cae
FG
1554 set_nlink(2);
1555 inc_nlink(req.d_count);
1556 *eof = req.eof();
7c673cae
FG
1557 }
1558 } else {
f67539c2
TL
1559 RGWReaddirRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
1560 this, rcb, cb_arg, offset);
7c673cae
FG
1561 rc = rgwlib.get_fe()->execute_req(&req);
1562 if (! rc) {
1563 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1564 lock_guard guard(mtx);
1565 state.atime = now;
3efd9988 1566 if (initial_off)
7c673cae
FG
1567 set_nlink(2);
1568 inc_nlink(req.d_count);
1569 *eof = req.eof();
7c673cae
FG
1570 }
1571 }
1572
494da23a
TL
1573 event ev(event::type::READDIR, get_key(), state.atime);
1574 lock_guard sguard(fs->state.mtx);
1575 fs->state.push_event(ev);
1576
7c673cae
FG
1577 lsubdout(fs->get_context(), rgw, 15)
1578 << __func__
1579 << " final link count=" << state.nlink
1580 << dendl;
1581
1582 return rc;
1583 } /* RGWFileHandle::readdir */
1584
1585 int RGWFileHandle::write(uint64_t off, size_t len, size_t *bytes_written,
1586 void *buffer)
1587 {
1588 using std::get;
1589 using WriteCompletion = RGWLibFS::WriteCompletion;
1590
1591 lock_guard guard(mtx);
1592
1593 int rc = 0;
1594
1595 file* f = get<file>(&variant_type);
1596 if (! f)
1597 return -EISDIR;
1598
1599 if (deleted()) {
1600 lsubdout(fs->get_context(), rgw, 5)
1601 << __func__
1602 << " write attempted on deleted object "
1603 << this->object_name()
1604 << dendl;
1605 /* zap write transaction, if any */
1606 if (f->write_req) {
1607 delete f->write_req;
1608 f->write_req = nullptr;
1609 }
1610 return -ESTALE;
1611 }
1612
1613 if (! f->write_req) {
1614 /* guard--we do not support (e.g., COW-backed) partial writes */
1615 if (off != 0) {
1616 lsubdout(fs->get_context(), rgw, 5)
1617 << __func__
1618 << " " << object_name()
1619 << " non-0 initial write position " << off
11fdf7f2 1620 << " (mounting with -o sync required)"
7c673cae
FG
1621 << dendl;
1622 return -EIO;
1623 }
1624
1625 /* start */
1626 std::string object_name = relative_object_name();
1627 f->write_req =
f67539c2
TL
1628 new RGWWriteRequest(rgwlib.get_store(),
1629 rgwlib.get_store()->get_user(fs->get_user()->user_id),
1630 this, bucket_name(), object_name);
7c673cae
FG
1631 rc = rgwlib.get_fe()->start_req(f->write_req);
1632 if (rc < 0) {
1633 lsubdout(fs->get_context(), rgw, 5)
1634 << __func__
1635 << this->object_name()
1636 << " write start failed " << off
1637 << " (" << rc << ")"
1638 << dendl;
1639 /* zap failed write transaction */
1640 delete f->write_req;
1641 f->write_req = nullptr;
1642 return -EIO;
1643 } else {
1644 if (stateless_open()) {
1645 /* start write timer */
1646 f->write_req->timer_id =
1647 RGWLibFS::write_timer.add_event(
1648 std::chrono::seconds(RGWLibFS::write_completion_interval_s),
1649 WriteCompletion(*this));
1650 }
1651 }
1652 }
1653
3efd9988
FG
1654 int overlap = 0;
1655 if ((static_cast<off_t>(off) < f->write_req->real_ofs) &&
1656 ((f->write_req->real_ofs - off) <= len)) {
1657 overlap = f->write_req->real_ofs - off;
1658 off = f->write_req->real_ofs;
1659 buffer = static_cast<char*>(buffer) + overlap;
1660 len -= overlap;
1661 }
1662
7c673cae
FG
1663 buffer::list bl;
1664 /* XXXX */
1665#if 0
1666 bl.push_back(
1667 buffer::create_static(len, static_cast<char*>(buffer)));
1668#else
1669 bl.push_back(
1670 buffer::copy(static_cast<char*>(buffer), len));
1671#endif
1672
1673 f->write_req->put_data(off, bl);
1674 rc = f->write_req->exec_continue();
1675
1676 if (rc == 0) {
1677 size_t min_size = off + len;
1678 if (min_size > get_size())
1679 set_size(min_size);
1680 if (stateless_open()) {
1681 /* bump write timer */
1682 RGWLibFS::write_timer.adjust_event(
1683 f->write_req->timer_id, std::chrono::seconds(10));
1684 }
1685 } else {
1686 /* continuation failed (e.g., non-contiguous write position) */
1687 lsubdout(fs->get_context(), rgw, 5)
1688 << __func__
1689 << object_name()
1690 << " failed write at position " << off
1691 << " (fails write transaction) "
1692 << dendl;
1693 /* zap failed write transaction */
1694 delete f->write_req;
1695 f->write_req = nullptr;
1696 rc = -EIO;
1697 }
1698
3efd9988 1699 *bytes_written = (rc == 0) ? (len + overlap) : 0;
7c673cae
FG
1700 return rc;
1701 } /* RGWFileHandle::write */
1702
1703 int RGWFileHandle::write_finish(uint32_t flags)
1704 {
1705 unique_lock guard{mtx, std::defer_lock};
1706 int rc = 0;
1707
1708 if (! (flags & FLAG_LOCKED)) {
1709 guard.lock();
1710 }
1711
1712 file* f = get<file>(&variant_type);
1713 if (f && (f->write_req)) {
1714 lsubdout(fs->get_context(), rgw, 10)
1715 << __func__
1716 << " finishing write trans on " << object_name()
1717 << dendl;
1718 rc = rgwlib.get_fe()->finish_req(f->write_req);
1719 if (! rc) {
1720 rc = f->write_req->get_ret();
1721 }
1722 delete f->write_req;
1723 f->write_req = nullptr;
1724 }
1725
1726 return rc;
1727 } /* RGWFileHandle::write_finish */
1728
1729 int RGWFileHandle::close()
1730 {
1731 lock_guard guard(mtx);
1732
1733 int rc = write_finish(FLAG_LOCKED);
1734
1735 flags &= ~FLAG_OPEN;
31f18b77
FG
1736 flags &= ~FLAG_STATELESS_OPEN;
1737
7c673cae
FG
1738 return rc;
1739 } /* RGWFileHandle::close */
1740
1741 RGWFileHandle::file::~file()
1742 {
1743 delete write_req;
1744 }
1745
1746 void RGWFileHandle::clear_state()
1747 {
1748 directory* d = get<directory>(&variant_type);
1749 if (d) {
1750 state.nlink = 2;
1751 d->last_marker = rgw_obj_key{};
1752 }
1753 }
1754
494da23a
TL
1755 void RGWFileHandle::advance_mtime(uint32_t flags) {
1756 /* intended for use on directories, fast-forward mtime so as to
1757 * ensure a new, higher value for the change attribute */
1758 unique_lock uniq(mtx, std::defer_lock);
1759 if (likely(! (flags & RGWFileHandle::FLAG_LOCKED))) {
1760 uniq.lock();
1761 }
1762
1763 /* advance mtime only if stored mtime is older than the
1764 * configured namespace expiration */
1765 auto now = real_clock::now();
1766 auto cmptime = state.mtime;
1767 cmptime.tv_sec +=
1768 fs->get_context()->_conf->rgw_nfs_namespace_expire_secs;
1769 if (cmptime < real_clock::to_timespec(now)) {
1770 /* sets ctime as well as mtime, to avoid masking updates should
1771 * ctime inexplicably hold a higher value */
1772 set_times(now);
1773 }
1774 }
1775
7c673cae
FG
1776 void RGWFileHandle::invalidate() {
1777 RGWLibFS *fs = get_fs();
1778 if (fs->invalidate_cb) {
1779 fs->invalidate_cb(fs->invalidate_arg, get_key().fh_hk);
1780 }
1781 }
1782
1783 int RGWWriteRequest::exec_start() {
f67539c2
TL
1784 struct req_state* state = get_state();
1785
1786 /* Object needs a bucket from this point */
1787 state->object->set_bucket(state->bucket.get());
7c673cae 1788
224ce89b 1789 auto compression_type =
20effc67 1790 get_store()->get_zone()->get_params().get_compression_type(
f67539c2 1791 state->bucket->get_placement_rule());
224ce89b 1792
7c673cae 1793 /* not obviously supportable */
11fdf7f2
TL
1794 ceph_assert(! dlo_manifest);
1795 ceph_assert(! slo_info);
7c673cae
FG
1796
1797 perfcounter->inc(l_rgw_put);
1798 op_ret = -EINVAL;
1799
f67539c2
TL
1800 if (state->object->empty()) {
1801 ldout(state->cct, 0) << __func__ << " called on empty object" << dendl;
7c673cae
FG
1802 goto done;
1803 }
1804
f67539c2 1805 op_ret = get_params(null_yield);
7c673cae
FG
1806 if (op_ret < 0)
1807 goto done;
1808
f67539c2 1809 op_ret = get_system_versioning_params(state, &olh_epoch, &version_id);
7c673cae
FG
1810 if (op_ret < 0) {
1811 goto done;
1812 }
1813
1814 /* user-supplied MD5 check skipped (not supplied) */
1815 /* early quota check skipped--we don't have size yet */
1816 /* skipping user-supplied etag--we might have one in future, but
1817 * like data it and other attrs would arrive after open */
11fdf7f2 1818
f67539c2 1819 aio.emplace(state->cct->_conf->rgw_put_obj_min_window_size);
11fdf7f2 1820
f67539c2 1821 if (state->bucket->versioning_enabled()) {
11fdf7f2 1822 if (!version_id.empty()) {
f67539c2 1823 state->object->set_instance(version_id);
11fdf7f2 1824 } else {
f67539c2
TL
1825 state->object->gen_rand_obj_instance_name();
1826 version_id = state->object->get_instance();
11fdf7f2
TL
1827 }
1828 }
20effc67
TL
1829 processor = get_store()->get_atomic_writer(this, state->yield, state->object->clone(),
1830 state->bucket_owner.get_id(), *state->obj_ctx,
1831 &state->dest_placement, 0, state->req_id);
11fdf7f2 1832
f67539c2 1833 op_ret = processor->prepare(state->yield);
224ce89b 1834 if (op_ret < 0) {
f67539c2 1835 ldout(state->cct, 20) << "processor->prepare() returned ret=" << op_ret
224ce89b
WB
1836 << dendl;
1837 goto done;
1838 }
11fdf7f2 1839 filter = &*processor;
224ce89b 1840 if (compression_type != "none") {
f67539c2 1841 plugin = Compressor::create(state->cct, compression_type);
11fdf7f2 1842 if (! plugin) {
f67539c2 1843 ldout(state->cct, 1) << "Cannot load plugin for rgw_compression_type "
11fdf7f2
TL
1844 << compression_type << dendl;
1845 } else {
f67539c2 1846 compressor.emplace(state->cct, plugin, filter);
11fdf7f2
TL
1847 filter = &*compressor;
1848 }
224ce89b 1849 }
7c673cae
FG
1850
1851 done:
1852 return op_ret;
1853 } /* exec_start */
1854
1855 int RGWWriteRequest::exec_continue()
1856 {
f67539c2 1857 struct req_state* state = get_state();
7c673cae
FG
1858 op_ret = 0;
1859
1860 /* check guards (e.g., contig write) */
11fdf7f2 1861 if (eio) {
f67539c2 1862 ldout(state->cct, 5)
11fdf7f2
TL
1863 << " chunks arrived in wrong order"
1864 << " (mounting with -o sync required)"
1865 << dendl;
1866 return -EIO;
1867 }
1868
20effc67 1869 op_ret = state->bucket->check_quota(this, user_quota, bucket_quota, real_ofs, null_yield, true);
11fdf7f2
TL
1870 /* max_size exceed */
1871 if (op_ret < 0)
7c673cae
FG
1872 return -EIO;
1873
1874 size_t len = data.length();
1875 if (! len)
1876 return 0;
1877
11fdf7f2
TL
1878 hash.Update((const unsigned char *)data.c_str(), data.length());
1879 op_ret = filter->process(std::move(data), ofs);
7c673cae 1880 if (op_ret < 0) {
11fdf7f2 1881 goto done;
7c673cae
FG
1882 }
1883 bytes_written += len;
1884
1885 done:
1886 return op_ret;
1887 } /* exec_continue */
1888
1889 int RGWWriteRequest::exec_finish()
1890 {
1891 buffer::list bl, aclbl, ux_key, ux_attrs;
1892 map<string, string>::iterator iter;
1893 char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
1894 unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
f67539c2 1895 struct req_state* state = get_state();
7c673cae
FG
1896
1897 size_t osize = rgw_fh->get_size();
1898 struct timespec octime = rgw_fh->get_ctime();
1899 struct timespec omtime = rgw_fh->get_mtime();
1900 real_time appx_t = real_clock::now();
1901
f67539c2
TL
1902 state->obj_size = bytes_written;
1903 perfcounter->inc(l_rgw_put_b, state->obj_size);
7c673cae 1904
11fdf7f2 1905 // flush data in filters
f67539c2 1906 op_ret = filter->process({}, state->obj_size);
11fdf7f2
TL
1907 if (op_ret < 0) {
1908 goto done;
1909 }
1910
20effc67 1911 op_ret = state->bucket->check_quota(this, user_quota, bucket_quota, state->obj_size, null_yield, true);
11fdf7f2 1912 /* max_size exceed */
7c673cae
FG
1913 if (op_ret < 0) {
1914 goto done;
1915 }
1916
1917 hash.Final(m);
1918
224ce89b
WB
1919 if (compressor && compressor->is_compressed()) {
1920 bufferlist tmp;
1921 RGWCompressionInfo cs_info;
1922 cs_info.compression_type = plugin->get_type_name();
f67539c2 1923 cs_info.orig_size = state->obj_size;
224ce89b 1924 cs_info.blocks = std::move(compressor->get_compression_blocks());
11fdf7f2 1925 encode(cs_info, tmp);
224ce89b 1926 attrs[RGW_ATTR_COMPRESSION] = tmp;
b3b6e05e 1927 ldpp_dout(this, 20) << "storing " << RGW_ATTR_COMPRESSION
224ce89b
WB
1928 << " with type=" << cs_info.compression_type
1929 << ", orig_size=" << cs_info.orig_size
1930 << ", blocks=" << cs_info.blocks.size() << dendl;
1931 }
1932
7c673cae
FG
1933 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
1934 etag = calc_md5;
1935
1936 bl.append(etag.c_str(), etag.size() + 1);
1937 emplace_attr(RGW_ATTR_ETAG, std::move(bl));
1938
1939 policy.encode(aclbl);
1940 emplace_attr(RGW_ATTR_ACL, std::move(aclbl));
1941
1942 /* unix attrs */
1943 rgw_fh->set_mtime(real_clock::to_timespec(appx_t));
1944 rgw_fh->set_ctime(real_clock::to_timespec(appx_t));
1945 rgw_fh->set_size(bytes_written);
1946 rgw_fh->encode_attrs(ux_key, ux_attrs);
1947
1948 emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
1949 emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
1950
f67539c2 1951 for (iter = state->generic_attrs.begin(); iter != state->generic_attrs.end();
7c673cae
FG
1952 ++iter) {
1953 buffer::list& attrbl = attrs[iter->first];
1954 const string& val = iter->second;
1955 attrbl.append(val.c_str(), val.size() + 1);
1956 }
1957
b3b6e05e 1958 op_ret = rgw_get_request_metadata(this, state->cct, state->info, attrs);
3efd9988
FG
1959 if (op_ret < 0) {
1960 goto done;
1961 }
7c673cae
FG
1962 encode_delete_at_attr(delete_at, attrs);
1963
1964 /* Add a custom metadata to expose the information whether an object
1965 * is an SLO or not. Appending the attribute must be performed AFTER
1966 * processing any input from user in order to prohibit overwriting. */
1967 if (unlikely(!! slo_info)) {
1968 buffer::list slo_userindicator_bl;
11fdf7f2
TL
1969 using ceph::encode;
1970 encode("True", slo_userindicator_bl);
7c673cae
FG
1971 emplace_attr(RGW_ATTR_SLO_UINDICATOR, std::move(slo_userindicator_bl));
1972 }
1973
f67539c2 1974 op_ret = processor->complete(state->obj_size, etag, &mtime, real_time(), attrs,
7c673cae 1975 (delete_at ? *delete_at : real_time()),
9f95a23c 1976 if_match, if_nomatch, nullptr, nullptr, nullptr,
f67539c2 1977 state->yield);
7c673cae
FG
1978 if (op_ret != 0) {
1979 /* revert attr updates */
1980 rgw_fh->set_mtime(omtime);
1981 rgw_fh->set_ctime(octime);
1982 rgw_fh->set_size(osize);
1983 }
1984
1985 done:
f67539c2 1986 perfcounter->tinc(l_rgw_put_lat, state->time_elapsed());
7c673cae
FG
1987 return op_ret;
1988 } /* exec_finish */
1989
1990} /* namespace rgw */
1991
1992/* librgw */
1993extern "C" {
1994
1995void rgwfile_version(int *major, int *minor, int *extra)
1996{
1997 if (major)
1998 *major = LIBRGW_FILE_VER_MAJOR;
1999 if (minor)
2000 *minor = LIBRGW_FILE_VER_MINOR;
2001 if (extra)
2002 *extra = LIBRGW_FILE_VER_EXTRA;
2003}
2004
2005/*
2006 attach rgw namespace
2007*/
2008 int rgw_mount(librgw_t rgw, const char *uid, const char *acc_key,
2009 const char *sec_key, struct rgw_fs **rgw_fs,
2010 uint32_t flags)
2011{
2012 int rc = 0;
2013
2014 /* stash access data for "mount" */
2015 RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
3efd9988 2016 sec_key, "/");
11fdf7f2 2017 ceph_assert(new_fs);
3efd9988 2018
b3b6e05e
TL
2019 const DoutPrefix dp(rgwlib.get_store()->ctx(), dout_subsys, "rgw mount: ");
2020 rc = new_fs->authorize(&dp, rgwlib.get_store());
3efd9988
FG
2021 if (rc != 0) {
2022 delete new_fs;
2023 return -EINVAL;
2024 }
2025
2026 /* register fs for shared gc */
2027 rgwlib.get_fe()->get_process()->register_fs(new_fs);
2028
2029 struct rgw_fs *fs = new_fs->get_fs();
2030 fs->rgw = rgw;
2031
2032 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2033 * roots atm */
2034
2035 *rgw_fs = fs;
2036
2037 return 0;
2038}
2039
2040int rgw_mount2(librgw_t rgw, const char *uid, const char *acc_key,
2041 const char *sec_key, const char *root, struct rgw_fs **rgw_fs,
2042 uint32_t flags)
2043{
2044 int rc = 0;
2045
20effc67
TL
2046 /* if the config has no value for path/root, choose "/" */
2047 RGWLibFS* new_fs{nullptr};
2048 if(root &&
2049 (!strcmp(root, ""))) {
2050 /* stash access data for "mount" */
2051 new_fs = new RGWLibFS(
2052 static_cast<CephContext*>(rgw), uid, acc_key, sec_key, "/");
2053 }
2054 else {
2055 /* stash access data for "mount" */
2056 new_fs = new RGWLibFS(
2057 static_cast<CephContext*>(rgw), uid, acc_key, sec_key, root);
2058 }
2059
2060 ceph_assert(new_fs); /* should we be using ceph_assert? */
7c673cae 2061
b3b6e05e
TL
2062 const DoutPrefix dp(rgwlib.get_store()->ctx(), dout_subsys, "rgw mount2: ");
2063 rc = new_fs->authorize(&dp, rgwlib.get_store());
7c673cae
FG
2064 if (rc != 0) {
2065 delete new_fs;
2066 return -EINVAL;
2067 }
2068
2069 /* register fs for shared gc */
2070 rgwlib.get_fe()->get_process()->register_fs(new_fs);
2071
2072 struct rgw_fs *fs = new_fs->get_fs();
2073 fs->rgw = rgw;
2074
2075 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2076 * roots atm */
2077
2078 *rgw_fs = fs;
2079
2080 return 0;
2081}
2082
2083/*
2084 register invalidate callbacks
2085*/
2086int rgw_register_invalidate(struct rgw_fs *rgw_fs, rgw_fh_callback_t cb,
2087 void *arg, uint32_t flags)
2088
2089{
2090 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2091 return fs->register_invalidate(cb, arg, flags);
2092}
2093
2094/*
2095 detach rgw namespace
2096*/
2097int rgw_umount(struct rgw_fs *rgw_fs, uint32_t flags)
2098{
2099 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2100 fs->close();
7c673cae
FG
2101 return 0;
2102}
2103
2104/*
2105 get filesystem attributes
2106*/
2107int rgw_statfs(struct rgw_fs *rgw_fs,
2108 struct rgw_file_handle *parent_fh,
2109 struct rgw_statvfs *vfs_st, uint32_t flags)
2110{
2111 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
28e407b8
AA
2112 struct rados_cluster_stat_t stats;
2113
f67539c2
TL
2114 RGWGetClusterStatReq req(fs->get_context(),
2115 rgwlib.get_store()->get_user(fs->get_user()->user_id),
2116 stats);
28e407b8
AA
2117 int rc = rgwlib.get_fe()->execute_req(&req);
2118 if (rc < 0) {
2119 lderr(fs->get_context()) << "ERROR: getting total cluster usage"
2120 << cpp_strerror(-rc) << dendl;
2121 return rc;
2122 }
7c673cae 2123
28e407b8
AA
2124 //Set block size to 1M.
2125 constexpr uint32_t CEPH_BLOCK_SHIFT = 20;
2126 vfs_st->f_bsize = 1 << CEPH_BLOCK_SHIFT;
2127 vfs_st->f_frsize = 1 << CEPH_BLOCK_SHIFT;
2128 vfs_st->f_blocks = stats.kb >> (CEPH_BLOCK_SHIFT - 10);
2129 vfs_st->f_bfree = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
2130 vfs_st->f_bavail = stats.kb_avail >> (CEPH_BLOCK_SHIFT - 10);
2131 vfs_st->f_files = stats.num_objects;
2132 vfs_st->f_ffree = -1;
3efd9988
FG
2133 vfs_st->f_fsid[0] = fs->get_fsid();
2134 vfs_st->f_fsid[1] = fs->get_fsid();
7c673cae
FG
2135 vfs_st->f_flag = 0;
2136 vfs_st->f_namemax = 4096;
2137 return 0;
2138}
2139
2140/*
2141 generic create -- create an empty regular file
2142*/
2143int rgw_create(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
2144 const char *name, struct stat *st, uint32_t mask,
2145 struct rgw_file_handle **fh, uint32_t posix_flags,
2146 uint32_t flags)
2147{
2148 using std::get;
2149
2150 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2151 RGWFileHandle* parent = get_rgwfh(parent_fh);
2152
2153 if ((! parent) ||
2154 (parent->is_root()) ||
2155 (parent->is_file())) {
2156 /* bad parent */
2157 return -EINVAL;
2158 }
2159
2160 MkObjResult fhr = fs->create(parent, name, st, mask, flags);
2161 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2162
2163 if (nfh)
2164 *fh = nfh->get_fh();
2165
2166 return get<1>(fhr);
2167} /* rgw_create */
2168
11fdf7f2
TL
2169/*
2170 create a symbolic link
2171 */
2172int rgw_symlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
2173 const char *name, const char *link_path, struct stat *st, uint32_t mask,
2174 struct rgw_file_handle **fh, uint32_t posix_flags,
2175 uint32_t flags)
2176{
2177 using std::get;
2178
2179 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2180 RGWFileHandle* parent = get_rgwfh(parent_fh);
2181
2182 if ((! parent) ||
2183 (parent->is_root()) ||
2184 (parent->is_file())) {
2185 /* bad parent */
2186 return -EINVAL;
2187 }
2188
2189 MkObjResult fhr = fs->symlink(parent, name, link_path, st, mask, flags);
2190 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2191
2192 if (nfh)
2193 *fh = nfh->get_fh();
2194
2195 return get<1>(fhr);
2196} /* rgw_symlink */
2197
7c673cae
FG
2198/*
2199 create a new directory
2200*/
2201int rgw_mkdir(struct rgw_fs *rgw_fs,
2202 struct rgw_file_handle *parent_fh,
2203 const char *name, struct stat *st, uint32_t mask,
2204 struct rgw_file_handle **fh, uint32_t flags)
2205{
2206 using std::get;
2207
2208 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2209 RGWFileHandle* parent = get_rgwfh(parent_fh);
2210
2211 if (! parent) {
2212 /* bad parent */
2213 return -EINVAL;
2214 }
2215
2216 MkObjResult fhr = fs->mkdir(parent, name, st, mask, flags);
2217 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2218
2219 if (nfh)
2220 *fh = nfh->get_fh();
2221
2222 return get<1>(fhr);
2223} /* rgw_mkdir */
2224
2225/*
2226 rename object
2227*/
2228int rgw_rename(struct rgw_fs *rgw_fs,
2229 struct rgw_file_handle *src, const char* src_name,
2230 struct rgw_file_handle *dst, const char* dst_name,
2231 uint32_t flags)
2232{
2233 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2234
2235 RGWFileHandle* src_fh = get_rgwfh(src);
2236 RGWFileHandle* dst_fh = get_rgwfh(dst);
2237
2238 return fs->rename(src_fh, dst_fh, src_name, dst_name);
2239}
2240
2241/*
2242 remove file or directory
2243*/
2244int rgw_unlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
2245 const char *name, uint32_t flags)
2246{
2247 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2248 RGWFileHandle* parent = get_rgwfh(parent_fh);
2249
2250 return fs->unlink(parent, name);
2251}
2252
2253/*
2254 lookup object by name (POSIX style)
2255*/
2256int rgw_lookup(struct rgw_fs *rgw_fs,
2257 struct rgw_file_handle *parent_fh, const char* path,
eafe8130
TL
2258 struct rgw_file_handle **fh,
2259 struct stat *st, uint32_t mask, uint32_t flags)
7c673cae
FG
2260{
2261 //CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2262 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2263
2264 RGWFileHandle* parent = get_rgwfh(parent_fh);
2265 if ((! parent) ||
2266 (! parent->is_dir())) {
2267 /* bad parent */
2268 return -EINVAL;
2269 }
2270
2271 RGWFileHandle* rgw_fh;
2272 LookupFHResult fhr;
2273
2274 if (parent->is_root()) {
2275 /* special: parent lookup--note lack of ref()! */
2276 if (unlikely((strcmp(path, "..") == 0) ||
2277 (strcmp(path, "/") == 0))) {
2278 rgw_fh = parent;
2279 } else {
31f18b77
FG
2280 RGWLibFS::BucketStats bstat;
2281 fhr = fs->stat_bucket(parent, path, bstat, RGWFileHandle::FLAG_NONE);
7c673cae
FG
2282 rgw_fh = get<0>(fhr);
2283 if (! rgw_fh)
2284 return -ENOENT;
2285 }
2286 } else {
224ce89b
WB
2287 /* special: after readdir--note extra ref()! */
2288 if (unlikely((strcmp(path, "..") == 0))) {
2289 rgw_fh = parent;
2290 lsubdout(fs->get_context(), rgw, 17)
11fdf7f2 2291 << __func__ << " BANG"<< *rgw_fh
224ce89b
WB
2292 << dendl;
2293 fs->ref(rgw_fh);
2294 } else {
224ce89b
WB
2295 enum rgw_fh_type fh_type = fh_type_of(flags);
2296
2297 uint32_t sl_flags = (flags & RGW_LOOKUP_FLAG_RCB)
f67539c2 2298 ? RGWFileHandle::FLAG_IN_CB
224ce89b
WB
2299 : RGWFileHandle::FLAG_EXACT_MATCH;
2300
eafe8130
TL
2301 bool fast_attrs= fs->get_context()->_conf->rgw_nfs_s3_fast_attrs;
2302
2303 if ((flags & RGW_LOOKUP_FLAG_RCB) && fast_attrs) {
2304 /* FAKE STAT--this should mean, interpolate special
2305 * owner, group, and perms masks */
2306 fhr = fs->fake_leaf(parent, path, fh_type, st, mask, sl_flags);
2307 } else {
2308 if ((fh_type == RGW_FS_TYPE_DIRECTORY) && fast_attrs) {
2309 /* trust cached dir, if present */
2310 fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_DIRECTORY);
2311 if (get<0>(fhr)) {
2312 rgw_fh = get<0>(fhr);
2313 goto done;
2314 }
2315 }
2316 fhr = fs->stat_leaf(parent, path, fh_type, sl_flags);
2317 }
224ce89b
WB
2318 if (! get<0>(fhr)) {
2319 if (! (flags & RGW_LOOKUP_FLAG_CREATE))
2320 return -ENOENT;
2321 else
2322 fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
2323 }
2324 rgw_fh = get<0>(fhr);
7c673cae 2325 }
7c673cae
FG
2326 } /* !root */
2327
eafe8130 2328done:
7c673cae
FG
2329 struct rgw_file_handle *rfh = rgw_fh->get_fh();
2330 *fh = rfh;
2331
2332 return 0;
2333} /* rgw_lookup */
2334
2335/*
2336 lookup object by handle (NFS style)
2337*/
2338int rgw_lookup_handle(struct rgw_fs *rgw_fs, struct rgw_fh_hk *fh_hk,
2339 struct rgw_file_handle **fh, uint32_t flags)
2340{
2341 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2342
2343 RGWFileHandle* rgw_fh = fs->lookup_handle(*fh_hk);
2344 if (! rgw_fh) {
2345 /* not found */
2346 return -ENOENT;
2347 }
2348
2349 struct rgw_file_handle *rfh = rgw_fh->get_fh();
2350 *fh = rfh;
2351
2352 return 0;
2353}
2354
2355/*
2356 * release file handle
2357 */
2358int rgw_fh_rele(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2359 uint32_t flags)
2360{
2361 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2362 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2363
2364 lsubdout(fs->get_context(), rgw, 17)
2365 << __func__ << " " << *rgw_fh
2366 << dendl;
2367
2368 fs->unref(rgw_fh);
2369 return 0;
2370}
2371
2372/*
2373 get unix attributes for object
2374*/
2375int rgw_getattr(struct rgw_fs *rgw_fs,
2376 struct rgw_file_handle *fh, struct stat *st, uint32_t flags)
2377{
2378 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2379 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2380
2381 return fs->getattr(rgw_fh, st);
2382}
2383
2384/*
2385 set unix attributes for object
2386*/
2387int rgw_setattr(struct rgw_fs *rgw_fs,
2388 struct rgw_file_handle *fh, struct stat *st,
2389 uint32_t mask, uint32_t flags)
2390{
2391 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2392 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2393
2394 return fs->setattr(rgw_fh, st, mask, flags);
2395}
2396
2397/*
2398 truncate file
2399*/
2400int rgw_truncate(struct rgw_fs *rgw_fs,
2401 struct rgw_file_handle *fh, uint64_t size, uint32_t flags)
2402{
2403 return 0;
2404}
2405
2406/*
2407 open file
2408*/
2409int rgw_open(struct rgw_fs *rgw_fs,
2410 struct rgw_file_handle *fh, uint32_t posix_flags, uint32_t flags)
2411{
2412 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2413
28e407b8 2414 /* XXX
7c673cae
FG
2415 * need to track specific opens--at least read opens and
2416 * a write open; we need to know when a write open is returned,
2417 * that closes a write transaction
2418 *
2419 * for now, we will support single-open only, it's preferable to
2420 * anything we can otherwise do without access to the NFS state
2421 */
2422 if (! rgw_fh->is_file())
2423 return -EISDIR;
2424
2425 return rgw_fh->open(flags);
2426}
2427
2428/*
2429 close file
2430*/
2431int rgw_close(struct rgw_fs *rgw_fs,
2432 struct rgw_file_handle *fh, uint32_t flags)
2433{
2434 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2435 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2436 int rc = rgw_fh->close(/* XXX */);
2437
2438 if (flags & RGW_CLOSE_FLAG_RELE)
2439 fs->unref(rgw_fh);
2440
2441 return rc;
2442}
2443
2444int rgw_readdir(struct rgw_fs *rgw_fs,
2445 struct rgw_file_handle *parent_fh, uint64_t *offset,
2446 rgw_readdir_cb rcb, void *cb_arg, bool *eof,
2447 uint32_t flags)
2448{
2449 RGWFileHandle* parent = get_rgwfh(parent_fh);
2450 if (! parent) {
2451 /* bad parent */
2452 return -EINVAL;
2453 }
3efd9988
FG
2454
2455 lsubdout(parent->get_fs()->get_context(), rgw, 15)
2456 << __func__
2457 << " offset=" << *offset
2458 << dendl;
2459
2460 if ((*offset == 0) &&
2461 (flags & RGW_READDIR_FLAG_DOTDOT)) {
2462 /* send '.' and '..' with their NFS-defined offsets */
eafe8130
TL
2463 rcb(".", cb_arg, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
2464 rcb("..", cb_arg, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
3efd9988
FG
2465 }
2466
7c673cae
FG
2467 int rc = parent->readdir(rcb, cb_arg, offset, eof, flags);
2468 return rc;
3efd9988
FG
2469} /* rgw_readdir */
2470
2471/* enumeration continuing from name */
2472int rgw_readdir2(struct rgw_fs *rgw_fs,
2473 struct rgw_file_handle *parent_fh, const char *name,
2474 rgw_readdir_cb rcb, void *cb_arg, bool *eof,
2475 uint32_t flags)
2476{
2477 RGWFileHandle* parent = get_rgwfh(parent_fh);
2478 if (! parent) {
2479 /* bad parent */
2480 return -EINVAL;
2481 }
2482
2483 lsubdout(parent->get_fs()->get_context(), rgw, 15)
2484 << __func__
94b18763 2485 << " offset=" << ((name) ? name : "(nil)")
3efd9988
FG
2486 << dendl;
2487
2488 if ((! name) &&
2489 (flags & RGW_READDIR_FLAG_DOTDOT)) {
2490 /* send '.' and '..' with their NFS-defined offsets */
eafe8130
TL
2491 rcb(".", cb_arg, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
2492 rcb("..", cb_arg, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
3efd9988
FG
2493 }
2494
2495 int rc = parent->readdir(rcb, cb_arg, name, eof, flags);
2496 return rc;
2497} /* rgw_readdir2 */
7c673cae 2498
c07f9fc5
FG
2499/* project offset of dirent name */
2500int rgw_dirent_offset(struct rgw_fs *rgw_fs,
2501 struct rgw_file_handle *parent_fh,
2502 const char *name, int64_t *offset,
2503 uint32_t flags)
2504{
2505 RGWFileHandle* parent = get_rgwfh(parent_fh);
2506 if ((! parent)) {
2507 /* bad parent */
2508 return -EINVAL;
2509 }
2510 std::string sname{name};
2511 int rc = parent->offset_of(sname, offset, flags);
2512 return rc;
2513}
2514
7c673cae
FG
2515/*
2516 read data from file
2517*/
2518int rgw_read(struct rgw_fs *rgw_fs,
2519 struct rgw_file_handle *fh, uint64_t offset,
2520 size_t length, size_t *bytes_read, void *buffer,
2521 uint32_t flags)
2522{
2523 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2524 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2525
2526 return fs->read(rgw_fh, offset, length, bytes_read, buffer, flags);
2527}
2528
11fdf7f2
TL
2529/*
2530 read symbolic link
2531*/
2532int rgw_readlink(struct rgw_fs *rgw_fs,
2533 struct rgw_file_handle *fh, uint64_t offset,
2534 size_t length, size_t *bytes_read, void *buffer,
2535 uint32_t flags)
2536{
2537 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2538 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2539
2540 return fs->readlink(rgw_fh, offset, length, bytes_read, buffer, flags);
2541}
2542
7c673cae
FG
2543/*
2544 write data to file
2545*/
2546int rgw_write(struct rgw_fs *rgw_fs,
2547 struct rgw_file_handle *fh, uint64_t offset,
2548 size_t length, size_t *bytes_written, void *buffer,
2549 uint32_t flags)
2550{
2551 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2552 int rc;
2553
2554 *bytes_written = 0;
2555
2556 if (! rgw_fh->is_file())
2557 return -EISDIR;
2558
3efd9988
FG
2559 if (! rgw_fh->is_open()) {
2560 if (flags & RGW_OPEN_FLAG_V3) {
2561 rc = rgw_fh->open(flags);
2562 if (!! rc)
2563 return rc;
2564 } else
2565 return -EPERM;
2566 }
7c673cae
FG
2567
2568 rc = rgw_fh->write(offset, length, bytes_written, buffer);
2569
2570 return rc;
2571}
2572
2573/*
2574 read data from file (vector)
2575*/
2576class RGWReadV
2577{
2578 buffer::list bl;
2579 struct rgw_vio* vio;
2580
2581public:
2582 RGWReadV(buffer::list& _bl, rgw_vio* _vio) : vio(_vio) {
f67539c2 2583 bl = std::move(_bl);
7c673cae
FG
2584 }
2585
2586 struct rgw_vio* get_vio() { return vio; }
2587
11fdf7f2 2588 const auto& buffers() { return bl.buffers(); }
7c673cae
FG
2589
2590 unsigned /* XXX */ length() { return bl.length(); }
2591
2592};
2593
2594void rgw_readv_rele(struct rgw_uio *uio, uint32_t flags)
2595{
2596 RGWReadV* rdv = static_cast<RGWReadV*>(uio->uio_p1);
2597 rdv->~RGWReadV();
2598 ::operator delete(rdv);
2599}
2600
2601int rgw_readv(struct rgw_fs *rgw_fs,
2602 struct rgw_file_handle *fh, rgw_uio *uio, uint32_t flags)
2603{
2604#if 0 /* XXX */
2605 CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2606 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2607 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2608
2609 if (! rgw_fh->is_file())
2610 return -EINVAL;
2611
2612 int rc = 0;
2613
2614 buffer::list bl;
2615 RGWGetObjRequest req(cct, fs->get_user(), rgw_fh->bucket_name(),
2616 rgw_fh->object_name(), uio->uio_offset, uio->uio_resid,
2617 bl);
2618 req.do_hexdump = false;
2619
2620 rc = rgwlib.get_fe()->execute_req(&req);
2621
2622 if (! rc) {
2623 RGWReadV* rdv = static_cast<RGWReadV*>(
2624 ::operator new(sizeof(RGWReadV) +
2625 (bl.buffers().size() * sizeof(struct rgw_vio))));
2626
2627 (void) new (rdv)
2628 RGWReadV(bl, reinterpret_cast<rgw_vio*>(rdv+sizeof(RGWReadV)));
2629
2630 uio->uio_p1 = rdv;
2631 uio->uio_cnt = rdv->buffers().size();
2632 uio->uio_resid = rdv->length();
2633 uio->uio_vio = rdv->get_vio();
2634 uio->uio_rele = rgw_readv_rele;
2635
2636 int ix = 0;
2637 auto& buffers = rdv->buffers();
2638 for (auto& bp : buffers) {
2639 rgw_vio *vio = &(uio->uio_vio[ix]);
2640 vio->vio_base = const_cast<char*>(bp.c_str());
2641 vio->vio_len = bp.length();
2642 vio->vio_u1 = nullptr;
2643 vio->vio_p1 = nullptr;
2644 ++ix;
2645 }
2646 }
2647
2648 return rc;
2649#else
2650 return 0;
2651#endif
2652}
2653
2654/*
2655 write data to file (vector)
2656*/
2657int rgw_writev(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2658 rgw_uio *uio, uint32_t flags)
2659{
2660
f67539c2 2661 // not supported - rest of function is ignored
7c673cae
FG
2662 return -ENOTSUP;
2663
2664 CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2665 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2666 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2667
2668 if (! rgw_fh->is_file())
2669 return -EINVAL;
2670
2671 buffer::list bl;
2672 for (unsigned int ix = 0; ix < uio->uio_cnt; ++ix) {
2673 rgw_vio *vio = &(uio->uio_vio[ix]);
2674 bl.push_back(
2675 buffer::create_static(vio->vio_len,
2676 static_cast<char*>(vio->vio_base)));
2677 }
2678
2679 std::string oname = rgw_fh->relative_object_name();
f67539c2
TL
2680 RGWPutObjRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
2681 rgw_fh->bucket_name(), oname, bl);
7c673cae
FG
2682
2683 int rc = rgwlib.get_fe()->execute_req(&req);
2684
2685 /* XXX update size (in request) */
2686
2687 return rc;
2688}
2689
2690/*
2691 sync written data
2692*/
2693int rgw_fsync(struct rgw_fs *rgw_fs, struct rgw_file_handle *handle,
2694 uint32_t flags)
2695{
2696 return 0;
2697}
2698
2699int rgw_commit(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2700 uint64_t offset, uint64_t length, uint32_t flags)
2701{
2702 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2703
2704 return rgw_fh->commit(offset, length, RGWFileHandle::FLAG_NONE);
2705}
2706
f67539c2
TL
2707/*
2708 extended attributes
2709 */
2710
2711int rgw_getxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2712 rgw_xattrlist *attrs, rgw_getxattr_cb cb, void *cb_arg,
2713 uint32_t flags)
2714{
2715 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2716 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2717
2718 return fs->getxattrs(rgw_fh, attrs, cb, cb_arg, flags);
2719}
2720
2721int rgw_lsxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2722 rgw_xattrstr *filter_prefix /* ignored */,
2723 rgw_getxattr_cb cb, void *cb_arg, uint32_t flags)
2724{
2725 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2726 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2727
2728 return fs->lsxattrs(rgw_fh, filter_prefix, cb, cb_arg, flags);
2729}
2730
2731int rgw_setxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2732 rgw_xattrlist *attrs, uint32_t flags)
2733{
2734 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2735 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2736
2737 return fs->setxattrs(rgw_fh, attrs, flags);
2738}
2739
2740int rgw_rmxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2741 rgw_xattrlist *attrs, uint32_t flags)
2742{
2743 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2744 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2745
2746 return fs->rmxattrs(rgw_fh, attrs, flags);
2747}
2748
7c673cae 2749} /* extern "C" */