1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/ar/ar_transform.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/logging.h"
19 : #include "base/files/file_util.h"
20 : #include "base/memory/scoped_vector.h"
21 : #include "base/strings/stringprintf.h"
22 : #include "syzygy/ar/ar_reader.h"
23 : #include "syzygy/ar/ar_writer.h"
24 :
25 : namespace ar {
26 :
27 : namespace {
28 :
29 : // Helper struct to delete a file when this object goes out of scope.
30 : struct FileDeleter {
31 E : explicit FileDeleter(const base::FilePath& path) : path_(path) {
32 E : }
33 :
34 E : ~FileDeleter() {
35 E : if (!base::DeleteFile(path_, false))
36 i : LOG(WARNING) << "Unable to delete file: " << path_.value();
37 E : }
38 :
39 : const base::FilePath& path_;
40 : };
41 :
42 : } // namespace
43 :
44 E : bool ArTransform::Transform() {
45 E : DCHECK(!input_archive_.empty());
46 E : DCHECK(!output_archive_.empty());
47 E : DCHECK(!callback_.is_null());
48 :
49 E : ArReader reader;
50 E : if (!reader.Init(input_archive_))
51 E : return false;
52 E : LOG(INFO) << "Read " << reader.symbols().size() << " symbols.";
53 :
54 : // This collection of buffers must outlive the ArWriter below.
55 E : ScopedVector<DataBuffer> buffers;
56 :
57 : // Iterate over the files in the archive.
58 E : ArWriter writer;
59 E : for (size_t i = 0; i < reader.offsets().size(); ++i) {
60 : // Extract the next file.
61 E : ParsedArFileHeader header;
62 E : scoped_ptr<DataBuffer> buffer(new DataBuffer());
63 E : if (!reader.ExtractNext(&header, buffer.get()))
64 i : return false;
65 :
66 E : LOG(INFO) << "Processing file " << (i + 1) << " of "
67 : << reader.offsets().size() << ": " << header.name;
68 :
69 : // Apply the transform to this file.
70 E : bool remove = false;
71 E : if (!callback_.Run(&header, buffer.get(), &remove))
72 E : return false;
73 :
74 E : if (remove)
75 E : continue;
76 :
77 : // Add the transformed file to the output archive.
78 : if (!writer.AddFile(header.name, header.timestamp, header.mode,
79 E : buffer.get())) {
80 i : return false;
81 : }
82 :
83 : // Save the buffer so we keep it around until the writer has finished.
84 E : buffers.push_back(buffer.release());
85 E : }
86 :
87 E : if (!writer.Write(output_archive_))
88 i : return false;
89 E : LOG(INFO) << "Wrote " << writer.symbols().size() << " symbols.";
90 :
91 E : return true;
92 E : }
93 :
94 : OnDiskArTransformAdapter::OnDiskArTransformAdapter(
95 : TransformFileOnDiskCallback inner_callback)
96 : : inner_callback_(inner_callback),
97 : outer_callback_(base::Bind(&OnDiskArTransformAdapter::Transform,
98 : base::Unretained(this))),
99 E : index_(0) {
100 E : }
101 :
102 E : OnDiskArTransformAdapter::~OnDiskArTransformAdapter() {
103 E : if (!base::DeleteFile(temp_dir_, true)) {
104 i : LOG(WARNING) << "Unable to delete temporary directory: "
105 : << temp_dir_.value();
106 : }
107 E : }
108 :
109 : bool OnDiskArTransformAdapter::Transform(ParsedArFileHeader* header,
110 : DataBuffer* contents,
111 E : bool* remove) {
112 E : if (temp_dir_.empty()) {
113 : if (!base::CreateNewTempDirectory(L"OnDiskArTransformAdapter",
114 E : &temp_dir_)) {
115 i : LOG(ERROR) << "Unable to create temporary directory.";
116 i : return false;
117 : }
118 : }
119 :
120 : // Create input and output file names.
121 : base::FilePath input_path = temp_dir_.Append(
122 E : base::StringPrintf(L"input-%04d.obj", index_));
123 : base::FilePath output_path = temp_dir_.Append(
124 E : base::StringPrintf(L"output-%04d.obj", index_));
125 E : ++index_;
126 :
127 : // Set up deleters for these files.
128 E : FileDeleter input_deleter(input_path);
129 E : FileDeleter output_deleter(output_path);
130 :
131 : if (base::WriteFile(input_path,
132 : reinterpret_cast<const char*>(contents->data()),
133 : contents->size()) !=
134 E : static_cast<int>(contents->size())) {
135 i : LOG(ERROR) << "Unable to write file: " << input_path.value();
136 i : return false;
137 : }
138 :
139 : // Delegate to the wrapped callback.
140 E : if (!inner_callback_.Run(input_path, output_path, header, remove))
141 i : return false;
142 :
143 : // If the file is being removed we don't need to bother reading it.
144 E : if (*remove)
145 E : return true;
146 :
147 : // GetFileSize and ReadFile will both fail in this case, but we can provide
148 : // a more meaningful error message by first doing this check.
149 E : if (!base::PathExists(output_path)) {
150 E : LOG(ERROR) << "File does not exist: " << output_path.value();
151 E : return false;
152 : }
153 :
154 : // Read the transformed file from disk.
155 E : int64 size = 0;
156 E : if (!base::GetFileSize(output_path, &size)) {
157 i : LOG(ERROR) << "Unable to read size of file: " << output_path.value();
158 i : return false;
159 : }
160 E : contents->resize(size);
161 : if (base::ReadFile(output_path,
162 : reinterpret_cast<char*>(contents->data()),
163 : contents->size()) !=
164 E : static_cast<int>(contents->size())) {
165 i : LOG(ERROR) << "Unable to read file: " << output_path.value();
166 i : return false;
167 : }
168 :
169 E : return true;
170 E : }
171 :
172 : } // namespace ar
|