Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / installer / util / lzma_util.cc
blobdc7daf3502a8cf245ebe897528701e315f01fab8
1 // Copyright (c) 2012 The Chromium 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.
5 #include "chrome/installer/util/lzma_util.h"
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
11 extern "C" {
12 #include "third_party/lzma_sdk/7z.h"
13 #include "third_party/lzma_sdk/7zAlloc.h"
14 #include "third_party/lzma_sdk/7zCrc.h"
15 #include "third_party/lzma_sdk/7zFile.h"
19 namespace {
21 SRes LzmaReadFile(HANDLE file, void *data, size_t *size) {
22 if (*size == 0)
23 return SZ_OK;
25 size_t processedSize = 0;
26 DWORD maxSize = *size;
27 do {
28 DWORD processedLoc = 0;
29 BOOL res = ReadFile(file, data, maxSize, &processedLoc, NULL);
30 data = (void *)((unsigned char *) data + processedLoc);
31 maxSize -= processedLoc;
32 processedSize += processedLoc;
33 if (processedLoc == 0) {
34 if (res)
35 return SZ_ERROR_READ;
36 else
37 break;
39 } while (maxSize > 0);
41 *size = processedSize;
42 return SZ_OK;
45 SRes SzFileSeekImp(void *object, Int64 *pos, ESzSeek origin) {
46 CFileInStream *s = (CFileInStream *) object;
47 LARGE_INTEGER value;
48 value.LowPart = (DWORD) *pos;
49 value.HighPart = (LONG) ((UInt64) *pos >> 32);
50 DWORD moveMethod;
51 switch (origin) {
52 case SZ_SEEK_SET:
53 moveMethod = FILE_BEGIN;
54 break;
55 case SZ_SEEK_CUR:
56 moveMethod = FILE_CURRENT;
57 break;
58 case SZ_SEEK_END:
59 moveMethod = FILE_END;
60 break;
61 default:
62 return SZ_ERROR_PARAM;
64 value.LowPart = SetFilePointer(s->file.handle, value.LowPart, &value.HighPart,
65 moveMethod);
66 *pos = ((Int64)value.HighPart << 32) | value.LowPart;
67 return ((value.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) ?
68 SZ_ERROR_FAIL : SZ_OK;
71 SRes SzFileReadImp(void *object, void *buffer, size_t *size) {
72 CFileInStream *s = (CFileInStream *) object;
73 return LzmaReadFile(s->file.handle, buffer, size);
76 } // namespace
78 // static
79 int32 LzmaUtil::UnPackArchive(const std::wstring& archive,
80 const std::wstring& output_dir,
81 std::wstring* output_file) {
82 VLOG(1) << "Opening archive " << archive;
83 LzmaUtil lzma_util;
84 DWORD ret;
85 if ((ret = lzma_util.OpenArchive(archive)) != NO_ERROR) {
86 LOG(ERROR) << "Unable to open install archive: " << archive
87 << ", error: " << ret;
88 } else {
89 VLOG(1) << "Uncompressing archive to path " << output_dir;
90 if ((ret = lzma_util.UnPack(output_dir, output_file)) != NO_ERROR) {
91 LOG(ERROR) << "Unable to uncompress archive: " << archive
92 << ", error: " << ret;
94 lzma_util.CloseArchive();
97 return ret;
100 LzmaUtil::LzmaUtil() : archive_handle_(NULL) {}
102 LzmaUtil::~LzmaUtil() {
103 CloseArchive();
106 DWORD LzmaUtil::OpenArchive(const std::wstring& archivePath) {
107 // Make sure file is not already open.
108 CloseArchive();
110 DWORD ret = NO_ERROR;
111 archive_handle_ = CreateFile(archivePath.c_str(), GENERIC_READ,
112 FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
113 if (archive_handle_ == INVALID_HANDLE_VALUE) {
114 archive_handle_ = NULL; // The rest of the code only checks for NULL.
115 ret = GetLastError();
117 return ret;
120 DWORD LzmaUtil::UnPack(const std::wstring& location) {
121 return UnPack(location, NULL);
124 DWORD LzmaUtil::UnPack(const std::wstring& location,
125 std::wstring* output_file) {
126 if (!archive_handle_)
127 return ERROR_INVALID_HANDLE;
129 CFileInStream archiveStream;
130 CLookToRead lookStream;
131 CSzArEx db;
132 ISzAlloc allocImp;
133 ISzAlloc allocTempImp;
134 DWORD ret = NO_ERROR;
136 archiveStream.file.handle = archive_handle_;
137 archiveStream.s.Read = SzFileReadImp;
138 archiveStream.s.Seek = SzFileSeekImp;
139 LookToRead_CreateVTable(&lookStream, false);
140 lookStream.realStream = &archiveStream.s;
142 allocImp.Alloc = SzAlloc;
143 allocImp.Free = SzFree;
144 allocTempImp.Alloc = SzAllocTemp;
145 allocTempImp.Free = SzFreeTemp;
147 CrcGenerateTable();
148 SzArEx_Init(&db);
149 if ((ret = SzArEx_Open(&db, &lookStream.s,
150 &allocImp, &allocTempImp)) != SZ_OK) {
151 LOG(ERROR) << L"Error returned by SzArchiveOpen: " << ret;
152 return ERROR_INVALID_HANDLE;
155 Byte *outBuffer = 0; // it must be 0 before first call for each new archive
156 UInt32 blockIndex = 0xFFFFFFFF; // can have any value if outBuffer = 0
157 size_t outBufferSize = 0; // can have any value if outBuffer = 0
159 for (unsigned int i = 0; i < db.db.NumFiles; i++) {
160 DWORD written;
161 size_t offset;
162 size_t outSizeProcessed;
163 CSzFileItem *f = db.db.Files + i;
165 if ((ret = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex,
166 &outBuffer, &outBufferSize, &offset, &outSizeProcessed,
167 &allocImp, &allocTempImp)) != SZ_OK) {
168 LOG(ERROR) << L"Error returned by SzExtract: " << ret;
169 ret = ERROR_INVALID_HANDLE;
170 break;
173 size_t file_name_length = SzArEx_GetFileNameUtf16(&db, i, NULL);
174 if (file_name_length < 1) {
175 LOG(ERROR) << L"Couldn't get file name";
176 ret = ERROR_INVALID_HANDLE;
177 break;
179 std::vector<UInt16> file_name(file_name_length);
180 SzArEx_GetFileNameUtf16(&db, i, &file_name[0]);
181 // |file_name| is NULL-terminated.
182 base::FilePath file_path = base::FilePath(location).Append(
183 base::FilePath::StringType(file_name.begin(), file_name.end() - 1));
185 if (output_file)
186 *output_file = file_path.value();
188 // If archive entry is directory create it and move on to the next entry.
189 if (f->IsDir) {
190 CreateDirectory(file_path);
191 continue;
194 CreateDirectory(file_path.DirName());
196 HANDLE hFile;
197 hFile = CreateFile(file_path.value().c_str(), GENERIC_WRITE, 0, NULL,
198 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
199 if (hFile == INVALID_HANDLE_VALUE) {
200 ret = GetLastError();
201 LOG(ERROR) << L"Error returned by CreateFile: " << ret;
202 break;
205 if ((!WriteFile(hFile, outBuffer + offset, (DWORD) outSizeProcessed,
206 &written, NULL)) ||
207 (written != outSizeProcessed)) {
208 ret = GetLastError();
209 CloseHandle(hFile);
210 LOG(ERROR) << L"Error returned by WriteFile: " << ret;
211 break;
214 if (f->MTimeDefined) {
215 if (!SetFileTime(hFile, NULL, NULL,
216 (const FILETIME *)&(f->MTime))) {
217 ret = GetLastError();
218 CloseHandle(hFile);
219 LOG(ERROR) << L"Error returned by SetFileTime: " << ret;
220 break;
223 if (!CloseHandle(hFile)) {
224 ret = GetLastError();
225 LOG(ERROR) << L"Error returned by CloseHandle: " << ret;
226 break;
228 } // for loop
230 IAlloc_Free(&allocImp, outBuffer);
231 SzArEx_Free(&db, &allocImp);
232 return ret;
235 void LzmaUtil::CloseArchive() {
236 if (archive_handle_) {
237 CloseHandle(archive_handle_);
238 archive_handle_ = NULL;
242 bool LzmaUtil::CreateDirectory(const base::FilePath& dir) {
243 bool ret = true;
244 if (directories_created_.find(dir.value()) == directories_created_.end()) {
245 ret = base::CreateDirectory(dir);
246 if (ret)
247 directories_created_.insert(dir.value());
249 return ret;