| 523 | } |
| 524 | |
| 525 | Status DeleteDirContents(const GcsPath& p, bool missing_dir_ok, |
| 526 | const io::IOContext& io_context) { |
| 527 | // If the directory marker exists, it better be a directory. |
| 528 | auto dir = client_.GetObjectMetadata(p.bucket, p.object); |
| 529 | if (dir && !IsDirectory(*dir)) return NotDirectoryError(*dir); |
| 530 | |
| 531 | // Deleting large directories can be fairly slow, we need to parallelize the |
| 532 | // operation. |
| 533 | const auto& canonical = |
| 534 | p.object.empty() ? p.object : internal::EnsureTrailingSlash(p.object); |
| 535 | auto async_delete = |
| 536 | [&, this](const google::cloud::StatusOr<gcs::ObjectMetadata>& o) -> Status { |
| 537 | if (!o) return internal::ToArrowStatus(o.status()); |
| 538 | // The list includes the directory, skip it. DeleteDir() takes care of it. |
| 539 | if (o->bucket() == p.bucket && o->name() == canonical) return Status::OK(); |
| 540 | return internal::ToArrowStatus( |
| 541 | client_.DeleteObject(o->bucket(), o->name(), gcs::Generation(o->generation()))); |
| 542 | }; |
| 543 | |
| 544 | std::vector<Future<>> submitted; |
| 545 | // This iterates over all the objects, and schedules parallel deletes. |
| 546 | auto prefix = p.object.empty() ? gcs::Prefix() : gcs::Prefix(canonical); |
| 547 | bool at_least_one_obj = false; |
| 548 | for (const auto& o : client_.ListObjects(p.bucket, prefix)) { |
| 549 | at_least_one_obj = true; |
| 550 | submitted.push_back(DeferNotOk(io_context.executor()->Submit(async_delete, o))); |
| 551 | } |
| 552 | |
| 553 | if (!missing_dir_ok && !at_least_one_obj && !dir && !p.object.empty()) { |
| 554 | // No files were found and no directory marker exists |
| 555 | return Status::IOError("No such directory: ", p.full_path); |
| 556 | } |
| 557 | |
| 558 | return AllFinished(submitted).status(); |
| 559 | } |
| 560 | |
| 561 | Status DeleteFile(const GcsPath& p) { |
| 562 | if (!p.object.empty()) { |
nothing calls this directly
no test coverage detected