OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2008, Google Inc. |
| 3 * All rights reserved. |
| 4 * |
| 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are |
| 7 * met: |
| 8 * |
| 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. |
| 11 * * Redistributions in binary form must reproduce the above |
| 12 * copyright notice, this list of conditions and the following disclaimer |
| 13 * in the documentation and/or other materials provided with the |
| 14 * distribution. |
| 15 * * Neither the name of Google Inc. nor the names of its |
| 16 * contributors may be used to endorse or promote products derived from |
| 17 * this software without specific prior written permission. |
| 18 * |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 */ |
| 31 |
| 32 #include <windows.h> |
| 33 #include <commctrl.h> |
| 34 #include <nsis/pluginapi.h> |
| 35 #include <winternl.h> |
| 36 |
| 37 enum { kLargeBuf = 1024, kSmallBuf = 256 } ; |
| 38 |
| 39 #if defined(_MSC_VER) |
| 40 /* Ensure these are treated as functions and not inlined as intrinsics, or disab
le /Oi */ |
| 41 #pragma warning(disable:4164) /* intrinsic function not declared */ |
| 42 #pragma function(memcpy, memset, memcmp) |
| 43 #endif |
| 44 |
| 45 HMODULE hNrDll = NULL; |
| 46 NTSTATUS (NTAPI *fNtCreateFile) (PHANDLE FileHandle, |
| 47 ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, |
| 48 PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, |
| 49 ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, |
| 50 ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); |
| 51 NTSTATUS (NTAPI *fNtClose) (HANDLE Handle); |
| 52 |
| 53 HMODULE hKernel32 = NULL; |
| 54 BOOL (WINAPI *fCreateHardLink) (TCHAR * linkFileName, |
| 55 TCHAR * existingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); |
| 56 BOOL (WINAPI *fCreateSymbolicLink) (TCHAR * linkFileName, |
| 57 TCHAR * existingFileName, DWORD flags); |
| 58 |
| 59 #undef CreateHardLink |
| 60 #undef CreateSymbolicLink |
| 61 #ifdef UNICODE |
| 62 #define CreateHardLink "CreateHardLinkW" |
| 63 #define CreateSymbolicLink "CreateSymbolicLinkW" |
| 64 #else |
| 65 #define CreateHardLink "CreateHardLinkA" |
| 66 #define CreateSymbolicLink "CreateSymbolicLinkA" |
| 67 #endif |
| 68 |
| 69 BOOL MakeHardLink(TCHAR *linkFileName, TCHAR *existingFileName) { |
| 70 if (!hKernel32) |
| 71 hKernel32 = LoadLibrary(_T("KERNEL32.DLL")); |
| 72 if (hKernel32) { |
| 73 if (!fCreateHardLink) |
| 74 fCreateHardLink = GetProcAddress(hKernel32, CreateHardLink); |
| 75 if (fCreateHardLink) |
| 76 return fCreateHardLink(linkFileName, existingFileName, NULL); |
| 77 } |
| 78 return FALSE; |
| 79 } |
| 80 |
| 81 BOOL MakeSymLink(TCHAR *linkFileName, TCHAR *existingFileName, BOOL dirLink) { |
| 82 TCHAR *f1 = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| 83 TCHAR *f2 = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| 84 SECURITY_ATTRIBUTES sec_attr = { sizeof (SECURITY_ATTRIBUTES), NULL, FALSE}; |
| 85 OBJECT_ATTRIBUTES obj_attr; |
| 86 IO_STATUS_BLOCK io_block; |
| 87 TCHAR *p, *q; |
| 88 HANDLE f; |
| 89 BOOL status; |
| 90 if (!f1 || !f2) |
| 91 return FALSE; |
| 92 lstrcpy(f1, linkFileName); |
| 93 p = q = f1; |
| 94 while (q[0]) { |
| 95 do { |
| 96 q++; |
| 97 } while (q[0] && q[0] != '\\'); |
| 98 p = q; |
| 99 } |
| 100 if (p[0] = '\\') { |
| 101 TCHAR c = p[1]; |
| 102 p[1] = 0; |
| 103 status = GetVolumeInformation(f1, NULL, 0, NULL, NULL, NULL, |
| 104 f2, sizeof(f2)); |
| 105 p[1] = c; |
| 106 } else { |
| 107 status = GetVolumeInformation(NULL, NULL, 0, NULL, NULL, NULL, |
| 108 f2, sizeof(f2)); |
| 109 } |
| 110 /* If it's NFS then we can create real symbolic link. */ |
| 111 if (!lstrcmpi(f2, _T("NFS"))) { |
| 112 if (!hNrDll) |
| 113 hNrDll = LoadLibrary(_T("NTDLL.DLL")); |
| 114 if (hNrDll) { |
| 115 if (!fNtCreateFile) |
| 116 fNtCreateFile = GetProcAddress(hNrDll, "NtCreateFile"); |
| 117 if (!fNtClose) |
| 118 fNtClose = GetProcAddress(hNrDll, "NtClose"); |
| 119 if (fNtCreateFile && fNtClose) { |
| 120 struct { |
| 121 ULONG offset; |
| 122 UCHAR flags; |
| 123 UCHAR nameLength; |
| 124 USHORT valueLength; |
| 125 CHAR name[21]; |
| 126 /* To prevent troubles with alignment */ |
| 127 CHAR value[kLargeBuf*sizeof(WCHAR)]; |
| 128 } *ea_info = HeapAlloc(GetProcessHeap(), |
| 129 HEAP_ZERO_MEMORY, |
| 130 sizeof(*ea_info)); |
| 131 WCHAR *fn = HeapAlloc(GetProcessHeap(), |
| 132 0, |
| 133 sizeof(TCHAR)*kLargeBuf); |
| 134 UNICODE_STRING n = { lstrlen(linkFileName), kLargeBuf, fn }; |
| 135 ea_info->nameLength = 20; |
| 136 lstrcpy(ea_info->name, "NfsSymlinkTargetName"); |
| 137 #ifdef UNICODE |
| 138 lstrcpy(fn, linkFileName); |
| 139 lstrcpy((LPWSTR)ea_info->value, existingFileName); |
| 140 #else |
| 141 MultiByteToWideChar(CP_ACP, 0, linkFileName, -1, fn, kLargeBuf); |
| 142 MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| 143 (LPWSTR)ea_info->value, |
| 144 sizeof(ea_info->value)/sizeof(WCHAR)); |
| 145 #endif |
| 146 ea_info->valueLength = |
| 147 lstrlenW((LPWSTR)ea_info->value)*sizeof(WCHAR); |
| 148 InitializeObjectAttributes(&obj_attr, &n, OBJ_CASE_INSENSITIVE, |
| 149 NULL, NULL); |
| 150 status = fNtCreateFile( |
| 151 &f, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE, &obj_attr, |
| 152 &io_block, NULL, FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ | |
| 153 FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, |
| 154 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, |
| 155 &ea_info, 1024 * sizeof (WCHAR)); |
| 156 if (NT_SUCCESS(status)) { |
| 157 fNtClose(f); |
| 158 HeapFree(GetProcessHeap(), 0, fn); |
| 159 HeapFree(GetProcessHeap(), 0, ea_info); |
| 160 HeapFree(GetProcessHeap(), 0, f2); |
| 161 HeapFree(GetProcessHeap(), 0, f1); |
| 162 return TRUE; |
| 163 } |
| 164 HeapFree(GetProcessHeap(), 0, fn); |
| 165 HeapFree(GetProcessHeap(), 0, ea_info); |
| 166 } |
| 167 } |
| 168 } |
| 169 lstrcpy(f2, existingFileName); |
| 170 if (!hKernel32) |
| 171 hKernel32 = LoadLibrary(_T("KERNEL32.DLL")); |
| 172 if (hKernel32) { |
| 173 if (!fCreateSymbolicLink) |
| 174 fCreateSymbolicLink = GetProcAddress(hKernel32, CreateSymbolicLink); |
| 175 if (fCreateSymbolicLink) { |
| 176 for (p = f1; p[0]; p++) |
| 177 if (p[0] == _T('/')) |
| 178 p[0] = _T('\\'); |
| 179 for (p = f2; p[0]; p++) |
| 180 if (p[0] == _T('/')) |
| 181 p[0] = _T('\\'); |
| 182 if (fCreateSymbolicLink(f1, f2, |
| 183 dirLink ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)) { |
| 184 HeapFree(GetProcessHeap(), 0, f2); |
| 185 HeapFree(GetProcessHeap(), 0, f1); |
| 186 return TRUE; |
| 187 } |
| 188 } |
| 189 } |
| 190 if (dirLink) { |
| 191 /* Ignore errors - file may already exist */ |
| 192 CreateDirectory(linkFileName, NULL); |
| 193 f = CreateFile(linkFileName, GENERIC_READ | GENERIC_WRITE, |
| 194 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, |
| 195 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, |
| 196 NULL ); |
| 197 if (f != INVALID_HANDLE_VALUE) { |
| 198 struct rp_info { |
| 199 DWORD tag; |
| 200 DWORD dataLength; |
| 201 WORD reserved1; |
| 202 WORD targetLength; |
| 203 WORD targetMaxLength; |
| 204 WORD reserved2; |
| 205 WCHAR target[kLargeBuf+4]; |
| 206 } *rp_info = HeapAlloc(GetProcessHeap(), |
| 207 HEAP_ZERO_MEMORY, |
| 208 sizeof(*rp_info)); |
| 209 DWORD len; |
| 210 WCHAR *startlink, *endlink; |
| 211 rp_info->tag = IO_REPARSE_TAG_MOUNT_POINT; |
| 212 rp_info->target[0] = L'\\'; |
| 213 rp_info->target[1] = L'?'; |
| 214 rp_info->target[2] = L'?'; |
| 215 rp_info->target[3] = L'\\'; |
| 216 if ((((existingFileName[0] == _T('\\')) || |
| 217 (existingFileName[0] == _T('/'))) & |
| 218 ((existingFileName[1] == _T('\\')) || |
| 219 (existingFileName[1] == _T('/')))) || |
| 220 ((existingFileName[1] == _T(':')) & |
| 221 ((existingFileName[2] == _T('\\')) || |
| 222 (existingFileName[2] == _T('/'))))) { |
| 223 #ifdef UNICODE |
| 224 lstrcpy(rp_info->target+4, existingFileName); |
| 225 #else |
| 226 MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| 227 rp_info->target+4, kLargeBuf); |
| 228 #endif |
| 229 } else { |
| 230 #ifdef UNICODE |
| 231 GetFullPathNameW(linkFileName, 1024, rp_info->target+4, &startlink); |
| 232 lstrcpy(startlink, existingFileName); |
| 233 #else |
| 234 MultiByteToWideChar(CP_ACP, 0, linkFileName, -1, |
| 235 (LPWSTR)f1, kLargeBuf/sizeof(WCHAR)); |
| 236 GetFullPathNameW(f1, 1024, rp_info->target+4, &startlink); |
| 237 MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| 238 startlink, kLargeBuf+4-(startlink-rp_info->target)); |
| 239 #endif |
| 240 } |
| 241 /* Remove "XXX/../" and replace "/" with "\" */ |
| 242 for (startlink = endlink = rp_info->target+4; |
| 243 endlink[0]; startlink++, endlink++) { |
| 244 startlink[0] = endlink[0]; |
| 245 if (startlink[0] == L'/') |
| 246 startlink[0] = L'\\'; |
| 247 if ((startlink[0] == L'\\') && |
| 248 (startlink[-1] == L'.') && |
| 249 (startlink[-2] == L'.')) { |
| 250 for (startlink--; startlink > rp_info->target+4 && |
| 251 startlink[0] != L'\\'; startlink--) |
| 252 { } |
| 253 for (startlink--; startlink > rp_info->target+4 && |
| 254 startlink[0] != L'\\'; startlink--) |
| 255 { } |
| 256 if (startlink < rp_info->target+4) |
| 257 startlink = rp_info->target+4; |
| 258 } |
| 259 } |
| 260 startlink[0] = endlink[0]; |
| 261 rp_info->targetLength = lstrlenW(rp_info->target)*sizeof(WCHAR); |
| 262 rp_info->targetMaxLength = rp_info->targetLength+sizeof(WCHAR); |
| 263 rp_info->dataLength = rp_info->targetMaxLength |
| 264 +FIELD_OFFSET(struct rp_info, target) |
| 265 -FIELD_OFFSET(struct rp_info, reserved1) |
| 266 +sizeof(WCHAR); |
| 267 if (DeviceIoControl(f, 0x900A4, rp_info, |
| 268 rp_info->dataLength |
| 269 +FIELD_OFFSET(struct rp_info, reserved1), |
| 270 NULL, 0, &len, NULL)) { |
| 271 CloseHandle(f); |
| 272 HeapFree(GetProcessHeap(), 0, rp_info); |
| 273 HeapFree(GetProcessHeap(), 0, f2); |
| 274 HeapFree(GetProcessHeap(), 0, f1); |
| 275 return TRUE; |
| 276 } |
| 277 CloseHandle(f); |
| 278 RemoveDirectory(linkFileName); |
| 279 HeapFree(GetProcessHeap(), 0, rp_info); |
| 280 } |
| 281 } |
| 282 for (p = f2; p[0]; p++) |
| 283 if (p[0] == _T('\\')) |
| 284 p[0] = _T('/'); |
| 285 f = CreateFile(linkFileName, GENERIC_READ | GENERIC_WRITE, |
| 286 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
| 287 CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, NULL); |
| 288 if (f != INVALID_HANDLE_VALUE) { |
| 289 struct { |
| 290 WCHAR sig[4]; |
| 291 WCHAR value[kLargeBuf]; |
| 292 } *link_info = HeapAlloc(GetProcessHeap(), |
| 293 HEAP_ZERO_MEMORY, |
| 294 sizeof(*link_info)); |
| 295 DWORD towrite, written; |
| 296 link_info->sig[0] = 0x6e49; |
| 297 link_info->sig[1] = 0x7874; |
| 298 link_info->sig[2] = 0x4e4c; |
| 299 link_info->sig[3] = 0x014b; |
| 300 #ifdef UNICODE |
| 301 lstrcpy(link_info->value, f2); |
| 302 #else |
| 303 MultiByteToWideChar(CP_ACP, 0, f2, -1, link_info->value, kLargeBuf); |
| 304 #endif |
| 305 towrite = lstrlenW(link_info->value)*sizeof(WCHAR)+sizeof(link_info->sig); |
| 306 WriteFile(f, link_info, towrite, &written, NULL); |
| 307 CloseHandle(f); |
| 308 if (written == towrite) { |
| 309 HeapFree(GetProcessHeap(), 0, link_info); |
| 310 HeapFree(GetProcessHeap(), 0, f2); |
| 311 HeapFree(GetProcessHeap(), 0, f1); |
| 312 return TRUE; |
| 313 } |
| 314 HeapFree(GetProcessHeap(), 0, link_info); |
| 315 } |
| 316 HeapFree(GetProcessHeap(), 0, f2); |
| 317 HeapFree(GetProcessHeap(), 0, f1); |
| 318 return FALSE; |
| 319 } |
| 320 |
| 321 HINSTANCE instance; |
| 322 |
| 323 HWND parent, list; |
| 324 |
| 325 /* |
| 326 * Show message in NSIS details window. |
| 327 */ |
| 328 void NSISprint(const TCHAR *str) { |
| 329 if (list && *str) { |
| 330 LVITEM item = { |
| 331 /* mask */ LVIF_TEXT, |
| 332 /* iItem */ SendMessage(list, LVM_GETITEMCOUNT, 0, 0), |
| 333 /* iSubItem */ 0, /* state */ 0, /* stateMask */ 0, |
| 334 /* pszText */ (TCHAR *) str, /* cchTextMax */ 0, |
| 335 /* iImage */ 0, /* lParam */ 0, /* iIndent */ 0, |
| 336 /* iGroupId */ 0, /* cColumns */ 0, /* puColumns */ NULL, |
| 337 /* piColFmt */ NULL, /* iGroup */ 0}; |
| 338 ListView_InsertItem(list, &item); |
| 339 ListView_EnsureVisible(list, item.iItem, 0); |
| 340 } |
| 341 } |
| 342 |
| 343 enum linktype { HARDLINK, SOFTLINKD, SOFTLINKF }; |
| 344 |
| 345 void makelink(HWND hwndParent, int string_size, TCHAR *variables, |
| 346 stack_t **stacktop, extra_parameters *extra, enum linktype type) { |
| 347 TCHAR *msg = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| 348 TCHAR *from = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kSmallBuf); |
| 349 TCHAR *to = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kSmallBuf); |
| 350 TCHAR *msgFormat = |
| 351 type == HARDLINK ? _T("Link: \"%s\" to \"%s\"%s") : |
| 352 type == SOFTLINKD ? _T("Symbolic Directory Link: \"%s\" to \"%s\"%s") : |
| 353 _T("Symbolic Link: \"%s\" to \"%s\"%s"); |
| 354 BOOL res; |
| 355 parent = hwndParent; |
| 356 list = FindWindowEx(FindWindowEx(parent, NULL, _T("#32770"), NULL), |
| 357 NULL, _T("SysListView32"), NULL); |
| 358 |
| 359 EXDLL_INIT(); |
| 360 |
| 361 if (!msg || !from || !to) { |
| 362 MessageBox(parent, _T("Fatal error: no memory for MkLink"), 0, MB_OK); |
| 363 } |
| 364 |
| 365 if (popstringn(from, kSmallBuf)) { |
| 366 MessageBox(parent, |
| 367 _T("Usage: MkLink::Hard \"to_file\" \"from_file\" "), 0, MB_OK); |
| 368 } |
| 369 |
| 370 if (popstringn(to, kSmallBuf)) { |
| 371 MessageBox(parent, |
| 372 _T("Usage: MkLink::Hard \"fo_file\" \"from_file\" "),0,MB_OK); |
| 373 } |
| 374 |
| 375 switch (type) { |
| 376 case HARDLINK: |
| 377 res = MakeHardLink(from, to); |
| 378 break; |
| 379 case SOFTLINKD: |
| 380 res = MakeSymLink(from, to, TRUE); |
| 381 break; |
| 382 case SOFTLINKF: |
| 383 res = MakeSymLink(from, to, FALSE); |
| 384 break; |
| 385 } |
| 386 wsprintf(msg, msgFormat, to, from, res ? _T("") : _T(" - fail...")); |
| 387 NSISprint(msg); |
| 388 |
| 389 HeapFree(GetProcessHeap(), 0, to); |
| 390 HeapFree(GetProcessHeap(), 0, from); |
| 391 HeapFree(GetProcessHeap(), 0, msg); |
| 392 } |
| 393 |
| 394 void __declspec(dllexport) Hard(HWND hwndParent, int string_size, |
| 395 TCHAR *variables, stack_t **stacktop, |
| 396 extra_parameters *extra) { |
| 397 makelink(hwndParent, string_size, variables, stacktop, extra, HARDLINK); |
| 398 } |
| 399 |
| 400 void __declspec(dllexport) SoftD(HWND hwndParent, int string_size, |
| 401 TCHAR *variables, stack_t **stacktop, |
| 402 extra_parameters *extra) { |
| 403 makelink(hwndParent, string_size, variables, stacktop, extra, SOFTLINKD); |
| 404 } |
| 405 |
| 406 void __declspec(dllexport) SoftF(HWND hwndParent, int string_size, |
| 407 TCHAR *variables, stack_t **stacktop, |
| 408 extra_parameters *extra) { |
| 409 makelink(hwndParent, string_size, variables, stacktop, extra, SOFTLINKF); |
| 410 } |
| 411 |
| 412 BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { |
| 413 instance = hInst; |
| 414 return TRUE; |
| 415 } |
OLD | NEW |