// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include #include #include "absl/flags/flag.h" #include "absl/flags/parse.h" #include "absl/log/globals.h" #include "absl/log/initialize.h" #include "contrib/libzip/sandboxed.h" #include "contrib/libzip/utils/utils_zip.h" ABSL_FLAG(bool, list, false, "list files"); ABSL_FLAG(std::string, unzip, "", "unzip"); ABSL_FLAG(std::string, add_file, "", "add file"); ABSL_FLAG(std::string, delete, "", "delete"); absl::Status ListFiles(LibZip& zip) { SAPI_ASSIGN_OR_RETURN(int64_t num, zip.GetNumberEntries()); for (uint64_t i = 0; i < num; i++) { SAPI_ASSIGN_OR_RETURN(std::string name, zip.GetName(i)); std::cout << name << "\n"; } return absl::OkStatus(); } absl::Status UnzipToStdout(LibZip& zip, const std::string& filename) { SAPI_ASSIGN_OR_RETURN(std::vector buf, zip.ReadFile(filename)); std::cout << buf.data(); return absl::OkStatus(); } absl::Status AddFile(LibZip& zip, const std::string& filename) { int fd = open(filename.c_str(), O_RDONLY); if (fd < 0) { return absl::UnavailableError( absl::StrCat("Unable to open file ", filename)); } // The fd will be consumed SAPI_ASSIGN_OR_RETURN(uint64_t index, zip.AddFile(filename, fd)); return absl::OkStatus(); } absl::Status DeleteFile(LibZip& zip, const std::string& filename) { int64_t index = -1; SAPI_ASSIGN_OR_RETURN(int64_t num, zip.GetNumberEntries()); for (uint64_t i = 0; i < num; i++) { SAPI_ASSIGN_OR_RETURN(std::string name, zip.GetName(i)); if (name == filename) { index = i; break; } } if (index == -1) { return absl::UnavailableError( absl::StrCat("Unable to remove file ", filename)); } return zip.DeleteFile(index); } int main(int argc, char* argv[]) { std::string prog_name(argv[0]); absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo); std::vector args = absl::ParseCommandLine(argc, argv); absl::InitializeLog(); if (args.size() < 2 || args.size() > 3) { std::cerr << "Usage:\n " << prog_name << " ZIPFILE [OUTFILE]\n"; return EXIT_FAILURE; } std::string filename(args[1]); ZipSapiSandbox sandbox; if (!sandbox.Init().ok()) { std::cerr << "Unable to start sandbox\n"; return EXIT_FAILURE; } LibZip zip(&sandbox, filename, 0); if (!zip.IsOpen()) { std::cerr << "Unable to open file " << filename << "\n"; return EXIT_FAILURE; } int outfd = -1; if (args.size() == 3) { outfd = open(args[2], O_WRONLY | O_CREAT); if (outfd < 0) { std::cerr << "Unable to open file " << args[2] << "\n"; return EXIT_FAILURE; } } bool needs_saving = false; absl::Status status; if (absl::GetFlag(FLAGS_list)) { status = ListFiles(zip); } if (!absl::GetFlag(FLAGS_unzip).empty()) { status = UnzipToStdout(zip, absl::GetFlag(FLAGS_unzip)); } if (!absl::GetFlag(FLAGS_add_file).empty()) { status = AddFile(zip, absl::GetFlag(FLAGS_add_file)); needs_saving = true; } if (!absl::GetFlag(FLAGS_delete).empty()) { status = DeleteFile(zip, absl::GetFlag(FLAGS_delete)); needs_saving = true; } if (!status.ok()) { std::cerr << status << "\n"; return EXIT_FAILURE; } status = zip.Finish(); if (!status.ok()) { std::cerr << status << "\n"; return EXIT_FAILURE; } if (needs_saving) { if (outfd == -1) { status = zip.Save(); } else { status = zip.Save(outfd); } if (!status.ok()) { std::cerr << status << "\n"; return EXIT_FAILURE; } } return EXIT_SUCCESS; }