| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 The Chromium OS Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "compressor_archive_libarchive.h" | |
| 6 | |
| 7 #include <cerrno> | |
| 8 #include <cstring> | |
| 9 | |
| 10 #include "archive_entry.h" | |
| 11 #include "ppapi/cpp/logging.h" | |
| 12 | |
| 13 namespace { | |
| 14 // Nothing to do here because JavaScript takes care of file open operations. | |
| 15 int CustomArchiveOpen(archive* archive_object, void* client_data) { | |
| 16 return ARCHIVE_OK; | |
| 17 } | |
| 18 | |
| 19 // Called when any data chunk must be written on the archive. It copies data | |
| 20 // from the given buffer processed by libarchive to an array buffer and passes | |
| 21 // it to compressor_stream. | |
| 22 ssize_t CustomArchiveWrite(archive* archive_object, void* client_data, | |
| 23 const void* buffer, size_t length) { | |
| 24 CompressorArchiveLibarchive* compressor_libarchive = | |
| 25 static_cast<CompressorArchiveLibarchive*>(client_data); | |
| 26 | |
| 27 const char* char_buffer = static_cast<const char*>(buffer); | |
| 28 | |
| 29 // Copy the data in buffer to array_buffer. | |
| 30 PP_DCHECK(length > 0); | |
| 31 pp::VarArrayBuffer array_buffer(length); | |
| 32 char* array_buffer_data = static_cast<char*>(array_buffer.Map()); | |
| 33 memcpy(array_buffer_data, char_buffer, length); | |
| 34 array_buffer.Unmap(); | |
| 35 | |
| 36 ssize_t written_bytes = | |
| 37 compressor_libarchive->compressor_stream()->Write(length, array_buffer); | |
| 38 | |
| 39 // Negative written_bytes represents an error. | |
| 40 if (written_bytes < 0) { | |
| 41 // When writing fails, archive_set_error() should be called and -1 should | |
| 42 // be returned. | |
| 43 archive_set_error( | |
| 44 compressor_libarchive->archive(), EIO, "Failed to write a chunk."); | |
| 45 return -1; | |
| 46 } | |
| 47 return written_bytes; | |
| 48 } | |
| 49 | |
| 50 // Nothing to do here because JavaScript takes care of file close operations. | |
| 51 int CustomArchiveClose(archive* archive_object, void* client_data) { | |
| 52 return ARCHIVE_OK; | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 CompressorArchiveLibarchive::CompressorArchiveLibarchive( | |
| 57 CompressorStream* compressor_stream) | |
| 58 : CompressorArchive(compressor_stream), | |
| 59 compressor_stream_(compressor_stream) { | |
| 60 destination_buffer_ = | |
| 61 new char[compressor_archive_constants::kMaximumDataChunkSize]; | |
| 62 } | |
| 63 | |
| 64 CompressorArchiveLibarchive::~CompressorArchiveLibarchive() { | |
| 65 delete destination_buffer_; | |
| 66 } | |
| 67 | |
| 68 void CompressorArchiveLibarchive::CreateArchive() { | |
| 69 archive_ = archive_write_new(); | |
| 70 archive_write_set_format_zip(archive_); | |
| 71 | |
| 72 // Passing 1 as the second argument causes the final chunk not to be padded. | |
| 73 archive_write_set_bytes_in_last_block(archive_, 1); | |
| 74 archive_write_set_bytes_per_block( | |
| 75 archive_, compressor_archive_constants::kMaximumDataChunkSize); | |
| 76 archive_write_open(archive_, this, CustomArchiveOpen, | |
| 77 CustomArchiveWrite, CustomArchiveClose); | |
| 78 } | |
| 79 | |
| 80 void CompressorArchiveLibarchive::AddToArchive( | |
| 81 const std::string& filename, | |
| 82 int64_t file_size, | |
| 83 time_t modification_time, | |
| 84 bool is_directory) { | |
| 85 entry = archive_entry_new(); | |
| 86 | |
| 87 archive_entry_set_pathname(entry, filename.c_str()); | |
| 88 archive_entry_set_size(entry, file_size); | |
| 89 archive_entry_set_mtime(entry, modification_time, 0 /* millisecond */); | |
| 90 | |
| 91 if (is_directory) { | |
| 92 archive_entry_set_filetype(entry, AE_IFDIR); | |
| 93 archive_entry_set_perm( | |
| 94 entry, compressor_archive_constants::kDirectoryPermission); | |
| 95 } else { | |
| 96 archive_entry_set_filetype(entry, AE_IFREG); | |
| 97 archive_entry_set_perm( | |
| 98 entry, compressor_archive_constants::kFilePermission); | |
| 99 } | |
| 100 archive_write_header(archive_, entry); | |
| 101 // If archive_errno() returns 0, the header was written correctly. | |
| 102 if (archive_errno(archive_) != 0) { | |
| 103 CloseArchive(true /* hasError */); | |
| 104 return; | |
| 105 } | |
| 106 | |
| 107 if (!is_directory) { | |
| 108 int64_t remaining_size = file_size; | |
| 109 while (remaining_size > 0) { | |
| 110 int64_t chunk_size = std::min(remaining_size, | |
| 111 compressor_archive_constants::kMaximumDataChunkSize); | |
| 112 PP_DCHECK(chunk_size > 0); | |
| 113 | |
| 114 int64_t read_bytes = | |
| 115 compressor_stream_->Read(chunk_size, destination_buffer_); | |
| 116 // Negative read_bytes indicates an error occurred when reading chunks. | |
| 117 if (read_bytes < 0) { | |
| 118 CloseArchive(true /* hasError */); | |
| 119 break; | |
| 120 } | |
| 121 | |
| 122 int64_t written_bytes = | |
| 123 archive_write_data(archive_, destination_buffer_, read_bytes); | |
| 124 // If archive_errno() returns 0, the buffer was written correctly. | |
| 125 if (archive_errno(archive_) != 0) { | |
| 126 CloseArchive(true /* hasError */); | |
| 127 break; | |
| 128 } | |
| 129 PP_DCHECK(written_bytes > 0); | |
| 130 | |
| 131 remaining_size -= written_bytes; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 archive_entry_free(entry); | |
| 136 } | |
| 137 | |
| 138 void CompressorArchiveLibarchive::CloseArchive(bool has_error) { | |
| 139 // If has_error is true, mark the archive object as being unusable and | |
| 140 // release resources without writing no more data on the archive. | |
| 141 if (has_error) | |
| 142 archive_write_fail(archive_); | |
| 143 if (archive_) { | |
| 144 archive_write_free(archive_); | |
| 145 archive_ = NULL; | |
| 146 } | |
| 147 } | |
| OLD | NEW |