Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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. | |
| 4 | |
| 5 #include <windows.h> // NOLINT | |
| 6 #include <fcntl.h> // for _O_* constants | |
| 7 #include <fdi.h> | |
| 8 | |
| 9 #include "chrome/installer/mini_installer/decompress.h" | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 FNALLOC(Alloc) { | |
| 14 return ::HeapAlloc(::GetProcessHeap(), 0, cb); | |
| 15 } | |
| 16 | |
| 17 FNFREE(Free) { | |
| 18 ::HeapFree(::GetProcessHeap(), 0, pv); | |
| 19 } | |
| 20 | |
| 21 char* WideToUtf8(const wchar_t* str) { | |
|
amit
2011/03/15 20:54:35
nit: we probably need mini_installer_utils.h/cc fo
tommi (sloooow) - chröme
2011/03/16 02:43:30
Yes, eventually. However right now, we don't need
amit
2011/03/16 15:50:26
That's reasonable.
| |
| 22 char* ret = NULL; | |
| 23 int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); | |
| 24 if (size) { | |
| 25 ret = reinterpret_cast<char*>(Alloc(size * sizeof(ret[0]))); | |
| 26 if (ret) | |
| 27 WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL); | |
| 28 } | |
| 29 return ret; | |
| 30 } | |
| 31 | |
| 32 wchar_t* Utf8ToWide(const char* str) { | |
| 33 wchar_t* ret = NULL; | |
| 34 int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); | |
| 35 if (size) { | |
| 36 ret = reinterpret_cast<wchar_t*>(Alloc(size * sizeof(ret[0]))); | |
| 37 if (ret) | |
| 38 MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, size); | |
| 39 } | |
| 40 return ret; | |
| 41 } | |
| 42 | |
| 43 template <typename T> | |
| 44 class scoped_ptr { | |
| 45 public: | |
| 46 explicit scoped_ptr(T* a) : a_(a) { | |
| 47 } | |
| 48 ~scoped_ptr() { | |
| 49 if (a_) | |
| 50 Free(a_); | |
| 51 } | |
| 52 operator T*() { | |
| 53 return a_; | |
| 54 } | |
| 55 private: | |
| 56 T* a_; | |
| 57 }; | |
| 58 | |
| 59 FNOPEN(Open) { | |
| 60 DWORD access = 0; | |
| 61 DWORD disposition = 0; | |
| 62 | |
| 63 if (oflag & _O_RDWR) { | |
| 64 access = GENERIC_READ | GENERIC_WRITE; | |
| 65 } else if (oflag & _O_WRONLY) { | |
| 66 access = GENERIC_WRITE; | |
| 67 } else { | |
| 68 access = GENERIC_READ; | |
| 69 } | |
| 70 | |
| 71 if (oflag & _O_CREAT) { | |
| 72 disposition = CREATE_ALWAYS; | |
| 73 } else { | |
| 74 disposition = OPEN_EXISTING; | |
| 75 } | |
| 76 | |
| 77 scoped_ptr<wchar_t> path(Utf8ToWide(pszFile)); | |
| 78 HANDLE file = CreateFileW(path, access, FILE_SHARE_READ, NULL, disposition, | |
| 79 FILE_ATTRIBUTE_NORMAL, NULL); | |
| 80 return reinterpret_cast<INT_PTR>(file); | |
| 81 } | |
| 82 | |
| 83 FNREAD(Read) { | |
| 84 DWORD read = 0; | |
| 85 if (!::ReadFile(reinterpret_cast<HANDLE>(hf), pv, cb, &read, NULL)) | |
| 86 read = static_cast<DWORD>(-1L); | |
| 87 return read; | |
| 88 } | |
| 89 | |
| 90 FNWRITE(Write) { | |
| 91 DWORD written = 0; | |
| 92 if (!::WriteFile(reinterpret_cast<HANDLE>(hf), pv, cb, &written, NULL)) | |
| 93 written = static_cast<DWORD>(-1L); | |
| 94 return written; | |
| 95 } | |
| 96 | |
| 97 FNCLOSE(Close) { | |
| 98 return ::CloseHandle(reinterpret_cast<HANDLE>(hf)) ? 0 : -1; | |
| 99 } | |
| 100 | |
| 101 FNSEEK(Seek) { | |
| 102 return ::SetFilePointer(reinterpret_cast<HANDLE>(hf), dist, NULL, seektype); | |
| 103 } | |
| 104 | |
| 105 FNFDINOTIFY(Notify) { | |
| 106 INT_PTR result = 0; | |
| 107 | |
| 108 switch (fdint) { | |
| 109 case fdintCOPY_FILE: { | |
| 110 // Since we will only ever be decompressing a single file at a time | |
| 111 // we take a shortcut and provide a pointer to the wide destination file | |
| 112 // of the file we want to write. This way we don't have to bother with | |
| 113 // utf8/wide conversion and concatenation of directory and file name. | |
| 114 const wchar_t* destination = reinterpret_cast<const wchar_t*>(pfdin->pv); | |
| 115 result = reinterpret_cast<INT_PTR>(::CreateFileW(destination, | |
| 116 GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, | |
| 117 FILE_ATTRIBUTE_NORMAL, NULL)); | |
| 118 break; | |
| 119 } | |
| 120 | |
| 121 case fdintCLOSE_FILE_INFO: { | |
| 122 FILETIME file_time; | |
| 123 FILETIME local; | |
| 124 FILE_BASIC_INFO fbi; | |
| 125 | |
| 126 // Converts MS-DOS date and time values to a file time | |
| 127 if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &file_time) && | |
| 128 LocalFileTimeToFileTime(&file_time, &local)) { | |
| 129 fbi.CreationTime.LowPart = local.dwLowDateTime; | |
| 130 fbi.CreationTime.HighPart = local.dwHighDateTime; | |
| 131 fbi.LastWriteTime.QuadPart = -1; | |
| 132 fbi.ChangeTime.QuadPart = -1; | |
| 133 fbi.LastAccessTime.QuadPart = -1; | |
| 134 fbi.FileAttributes = pfdin->attribs; | |
| 135 fbi.FileAttributes &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | | |
| 136 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE; | |
| 137 SetFileInformationByHandle(reinterpret_cast<HANDLE>(pfdin->hf), | |
| 138 FileBasicInfo, &fbi, sizeof(fbi)); | |
| 139 } | |
| 140 | |
| 141 result = !Close(pfdin->hf); | |
| 142 break; | |
| 143 } | |
| 144 | |
| 145 case fdintCABINET_INFO: | |
| 146 case fdintENUMERATE: | |
| 147 // OK. continue as normal. | |
| 148 result = 0; | |
| 149 break; | |
| 150 | |
| 151 case fdintPARTIAL_FILE: | |
| 152 case fdintNEXT_CABINET: | |
| 153 default: | |
| 154 // Error case. | |
| 155 result = -1; | |
| 156 break; | |
| 157 } | |
| 158 | |
| 159 return result; | |
| 160 } | |
| 161 | |
| 162 // Module handle of cabinet.dll | |
| 163 HMODULE g_fdi = NULL; | |
| 164 | |
| 165 // API prototypes. | |
| 166 typedef HFDI (DIAMONDAPI* FDICreateFn)(PFNALLOC alloc, PFNFREE free, | |
| 167 PFNOPEN open, PFNREAD read, | |
| 168 PFNWRITE write, PFNCLOSE close, | |
| 169 PFNSEEK seek, int cpu_type, PERF perf); | |
| 170 typedef BOOL (DIAMONDAPI* FDIDestroyFn)(HFDI fdi); | |
| 171 typedef BOOL (DIAMONDAPI* FDICopyFn)(HFDI fdi, char* cab, char* cab_path, | |
| 172 int flags, PFNFDINOTIFY notify, | |
| 173 PFNFDIDECRYPT decrypt, void* context); | |
| 174 FDICreateFn g_FDICreate = NULL; | |
| 175 FDIDestroyFn g_FDIDestroy = NULL; | |
| 176 FDICopyFn g_FDICopy = NULL; | |
| 177 | |
| 178 bool InitializeFdi() { | |
| 179 if (!g_fdi) { | |
| 180 // This DLL should be available on all supported versions of Windows. | |
| 181 g_fdi = ::LoadLibraryW(L"cabinet.dll"); | |
|
amit
2011/03/15 20:54:35
shouldn't this be loaded from a known path, to pre
tommi (sloooow) - chröme
2011/03/16 02:43:30
We don't have a lib for cabinet.dll but this is ef
amit
2011/03/16 15:50:26
sounds good
tommi (sloooow) - chröme
2011/03/16 20:22:20
Done.
| |
| 182 g_FDICreate = | |
| 183 reinterpret_cast<FDICreateFn>(::GetProcAddress(g_fdi, "FDICreate")); | |
| 184 g_FDIDestroy = | |
| 185 reinterpret_cast<FDIDestroyFn>(::GetProcAddress(g_fdi, "FDIDestroy")); | |
| 186 g_FDICopy = | |
| 187 reinterpret_cast<FDICopyFn>(::GetProcAddress(g_fdi, "FDICopy")); | |
| 188 } | |
| 189 | |
| 190 return g_FDICreate && g_FDIDestroy && g_FDICopy; | |
| 191 } | |
| 192 | |
| 193 } // namespace | |
| 194 | |
| 195 namespace mini_installer { | |
| 196 | |
| 197 bool Expand(wchar_t* source, const wchar_t* destination) { | |
| 198 if (!InitializeFdi()) | |
| 199 return false; | |
| 200 | |
| 201 // Start by splitting up the source path and convert to utf8 since the | |
| 202 // cabinet API doesn't support wide strings. | |
| 203 wchar_t* source_name = source + lstrlenW(source); | |
| 204 while (source_name > source && *source_name != L'\\') | |
| 205 --source_name; | |
| 206 if (source_name == source) | |
| 207 return false; | |
| 208 | |
| 209 // Convert the name to utf8. | |
| 210 source_name++; | |
| 211 scoped_ptr<char> source_name_utf8(WideToUtf8(source_name)); | |
| 212 // The directory part is assumed to have a trailing backslash. | |
| 213 wchar_t save = source_name[0]; | |
| 214 *source_name = L'\0'; | |
| 215 scoped_ptr<char> source_path_utf8(WideToUtf8(source)); | |
| 216 *source_name = save; | |
| 217 | |
| 218 scoped_ptr<char> dest_utf8(WideToUtf8(destination)); | |
| 219 if (!dest_utf8 || !source_name_utf8 || !source_path_utf8) | |
| 220 return false; | |
| 221 | |
| 222 bool success = false; | |
| 223 | |
| 224 ERF erf = {0}; | |
| 225 HFDI fdi = g_FDICreate(&Alloc, &Free, &Open, &Read, &Write, &Close, &Seek, | |
| 226 cpuUNKNOWN, &erf); | |
| 227 if (fdi) { | |
| 228 if (g_FDICopy(fdi, source_name_utf8, source_path_utf8, 0, | |
| 229 &Notify, NULL, const_cast<wchar_t*>(destination))) { | |
| 230 success = true; | |
| 231 } | |
| 232 g_FDIDestroy(fdi); | |
| 233 } | |
| 234 | |
| 235 return success; | |
| 236 } | |
| 237 | |
| 238 } // namespace mini_installer | |
| OLD | NEW |