* Extract the tar with the given filename in the directory * where the tar resides. * @param tar_filename the name of the tar to extract. * @param subdir The sub directory the tar is in. * @return false on failure. */
| 588 | * @return false on failure. |
| 589 | */ |
| 590 | bool ExtractTar(const std::string &tar_filename, Subdirectory subdir) |
| 591 | { |
| 592 | TarList::iterator it = _tar_list[subdir].find(tar_filename); |
| 593 | /* We don't know the file. */ |
| 594 | if (it == _tar_list[subdir].end()) return false; |
| 595 | |
| 596 | const auto &dirname = it->second; |
| 597 | |
| 598 | /* The file doesn't have a sub directory! */ |
| 599 | if (dirname.empty()) { |
| 600 | Debug(misc, 3, "Extracting {} failed; archive rejected, the contents must be in a sub directory", tar_filename); |
| 601 | return false; |
| 602 | } |
| 603 | |
| 604 | std::string filename = tar_filename; |
| 605 | auto p = filename.find_last_of(PATHSEPCHAR); |
| 606 | /* The file's path does not have a separator? */ |
| 607 | if (p == std::string::npos) return false; |
| 608 | |
| 609 | filename.replace(p + 1, std::string::npos, dirname); |
| 610 | Debug(misc, 8, "Extracting {} to directory {}", tar_filename, filename); |
| 611 | FioCreateDirectory(filename); |
| 612 | |
| 613 | for (auto &it2 : _tar_filelist[subdir]) { |
| 614 | if (tar_filename != it2.second.tar_filename) continue; |
| 615 | |
| 616 | /* it2.first is tarball + PATHSEPCHAR + name. */ |
| 617 | std::string_view name = it2.first; |
| 618 | name.remove_prefix(name.find_first_of(PATHSEPCHAR) + 1); |
| 619 | filename.replace(p + 1, std::string::npos, name); |
| 620 | |
| 621 | Debug(misc, 9, " extracting {}", filename); |
| 622 | |
| 623 | /* First open the file in the .tar. */ |
| 624 | size_t to_copy = 0; |
| 625 | auto in = FioFOpenFileTar(it2.second, &to_copy); |
| 626 | if (!in.has_value()) { |
| 627 | Debug(misc, 6, "Extracting {} failed; could not open {}", filename, tar_filename); |
| 628 | return false; |
| 629 | } |
| 630 | |
| 631 | /* Now open the 'output' file. */ |
| 632 | auto out = FileHandle::Open(filename, "wb"); |
| 633 | if (!out.has_value()) { |
| 634 | Debug(misc, 6, "Extracting {} failed; could not open {}", filename, filename); |
| 635 | return false; |
| 636 | } |
| 637 | |
| 638 | /* Now read from the tar and write it into the file. */ |
| 639 | char buffer[4096]; |
| 640 | size_t read; |
| 641 | for (; to_copy != 0; to_copy -= read) { |
| 642 | read = fread(buffer, 1, std::min(to_copy, lengthof(buffer)), *in); |
| 643 | if (read <= 0 || fwrite(buffer, 1, read, *out) != read) break; |
| 644 | } |
| 645 | |
| 646 | if (to_copy != 0) { |
| 647 | Debug(misc, 6, "Extracting {} failed; still {} bytes to copy", filename, to_copy); |
no test coverage detected