OLD | NEW |
| (Empty) |
1 // Copyright 2006-2009 Google Inc. | |
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 | |
16 | |
17 #include "omaha/mi_exe_stub/tar.h" | |
18 #include <windows.h> | |
19 #pragma warning(push) | |
20 // C4310: cast truncates constant value | |
21 #pragma warning(disable : 4310) | |
22 #include "base/basictypes.h" | |
23 #pragma warning(pop) | |
24 | |
25 namespace omaha { | |
26 | |
27 namespace { | |
28 | |
29 const char kUstarMagic[] = "ustar"; | |
30 const char kUstarDone[5] = { '\0', '\0', '\0', '\0', '\0' }; | |
31 | |
32 } // namespace | |
33 | |
34 Tar::Tar(const CString& target_dir, HANDLE file_handle, bool delete_when_done) | |
35 : target_directory_name_(target_dir), | |
36 file_handle_(file_handle), | |
37 delete_when_done_(delete_when_done), | |
38 callback_(NULL), | |
39 callback_context_(NULL) {} | |
40 | |
41 Tar::~Tar() { | |
42 for (int i = 0; i != files_to_delete_.GetSize(); ++i) { | |
43 DeleteFile(files_to_delete_[i]); | |
44 } | |
45 } | |
46 | |
47 bool Tar::ExtractToDir() { | |
48 bool done = false; | |
49 do { | |
50 if (!ExtractOneFile(&done)) { | |
51 return false; | |
52 } | |
53 } while (!done); | |
54 return true; | |
55 } | |
56 | |
57 bool Tar::ExtractOneFile(bool *done) { | |
58 USTARHeader header; | |
59 DWORD bytes_handled; | |
60 bool result = true; | |
61 BOOL file_result; | |
62 | |
63 file_result = ::ReadFile(file_handle_, &header, sizeof(USTARHeader), | |
64 &bytes_handled, NULL); | |
65 if (!file_result || bytes_handled != sizeof(USTARHeader)) { | |
66 return false; | |
67 } | |
68 if (0 == memcmp(header.magic, kUstarDone, arraysize(kUstarDone) - 1)) { | |
69 // We're probably done, since we read the final block of all zeroes. | |
70 *done = true; | |
71 return true; | |
72 } | |
73 if (0 != memcmp(header.magic, kUstarMagic, arraysize(kUstarMagic) - 1)) { | |
74 return false; | |
75 } | |
76 CString new_filename(target_directory_name_); | |
77 new_filename += "\\"; | |
78 new_filename += header.name; | |
79 HANDLE new_file = ::CreateFile(new_filename, GENERIC_WRITE, 0, NULL, | |
80 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); | |
81 if (new_file == INVALID_HANDLE_VALUE) { | |
82 return false; | |
83 } | |
84 // We don't check for conversion errors because the input data is fixed at | |
85 // build time, so it'll either always work or never work, and we won't ship | |
86 // one that never works. | |
87 DWORD tar_file_size = strtol(header.size, NULL, 8); // NOLINT | |
88 DWORD next_offset = ::SetFilePointer(file_handle_, 0, NULL, FILE_CURRENT) + | |
89 tar_file_size + (512 - tar_file_size & 0x1ff); | |
90 while (tar_file_size > 0) { | |
91 const int kCopyBufferSize = 256 * 1024; | |
92 char copy_buffer[kCopyBufferSize]; | |
93 DWORD bytes_to_handle = kCopyBufferSize; | |
94 if (bytes_to_handle > tar_file_size) { | |
95 bytes_to_handle = tar_file_size; | |
96 } | |
97 file_result = ::ReadFile(file_handle_, copy_buffer, bytes_to_handle, | |
98 &bytes_handled, NULL); | |
99 if (!file_result) { | |
100 result = false; | |
101 break; | |
102 } else { | |
103 file_result = ::WriteFile(new_file, copy_buffer, bytes_to_handle, | |
104 &bytes_handled, NULL); | |
105 if (!file_result) { | |
106 result = false; | |
107 break; | |
108 } else { | |
109 tar_file_size -= bytes_to_handle; | |
110 } | |
111 } | |
112 } | |
113 CloseHandle(new_file); | |
114 if (result) { | |
115 if (delete_when_done_) { | |
116 files_to_delete_.Add(new_filename); | |
117 } | |
118 if (callback_ != NULL) { | |
119 callback_(callback_context_, new_filename); | |
120 } | |
121 } | |
122 | |
123 if (INVALID_SET_FILE_POINTER != next_offset) { | |
124 SetFilePointer(file_handle_, next_offset, NULL, FILE_BEGIN); | |
125 } | |
126 | |
127 return result; | |
128 } | |
129 | |
130 } // namespace omaha | |
OLD | NEW |