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 |