Chromium Code Reviews| Index: tools/hermetic_cygwin/MkLink/MkLink.c |
| =================================================================== |
| --- tools/hermetic_cygwin/MkLink/MkLink.c (revision 0) |
| +++ tools/hermetic_cygwin/MkLink/MkLink.c (revision 0) |
| @@ -0,0 +1,415 @@ |
| +/* |
| + * Copyright 2008, Google Inc. |
| + * All rights reserved. |
| + * |
| + * Redistribution and use in source and binary forms, with or without |
| + * modification, are permitted provided that the following conditions are |
| + * met: |
| + * |
| + * * Redistributions of source code must retain the above copyright |
| + * notice, this list of conditions and the following disclaimer. |
| + * * Redistributions in binary form must reproduce the above |
| + * copyright notice, this list of conditions and the following disclaimer |
| + * in the documentation and/or other materials provided with the |
| + * distribution. |
| + * * Neither the name of Google Inc. nor the names of its |
| + * contributors may be used to endorse or promote products derived from |
| + * this software without specific prior written permission. |
| + * |
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| + */ |
| + |
| +#include <windows.h> |
| +#include <commctrl.h> |
| +#include <nsis/pluginapi.h> |
| +#include <winternl.h> |
| + |
| +enum { kLargeBuf = 1024, kSmallBuf = 256 } ; |
| + |
| +#if defined(_MSC_VER) |
| +/* Ensure these are treated as functions and not inlined as intrinsics, or disable /Oi */ |
| +#pragma warning(disable:4164) /* intrinsic function not declared */ |
| +#pragma function(memcpy, memset, memcmp) |
| +#endif |
| + |
| +HMODULE hNrDll = NULL; |
| +NTSTATUS (NTAPI *fNtCreateFile) (PHANDLE FileHandle, |
| + ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, |
| + PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, |
| + ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, |
| + ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); |
| +NTSTATUS (NTAPI *fNtClose) (HANDLE Handle); |
| + |
| +HMODULE hKernel32 = NULL; |
| +BOOL (WINAPI *fCreateHardLink) (TCHAR * linkFileName, |
| + TCHAR * existingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); |
| +BOOL (WINAPI *fCreateSymbolicLink) (TCHAR * linkFileName, |
| + TCHAR * existingFileName, DWORD flags); |
| + |
| +#undef CreateHardLink |
| +#undef CreateSymbolicLink |
| +#ifdef UNICODE |
| +#define CreateHardLink "CreateHardLinkW" |
| +#define CreateSymbolicLink "CreateSymbolicLinkW" |
| +#else |
| +#define CreateHardLink "CreateHardLinkA" |
| +#define CreateSymbolicLink "CreateSymbolicLinkA" |
| +#endif |
| + |
| +BOOL MakeHardLink(TCHAR *linkFileName, TCHAR *existingFileName) { |
| + if (!hKernel32) |
| + hKernel32 = LoadLibrary(_T("KERNEL32.DLL")); |
| + if (hKernel32) { |
| + if (!fCreateHardLink) |
| + fCreateHardLink = GetProcAddress(hKernel32, CreateHardLink); |
| + if (fCreateHardLink) |
| + return fCreateHardLink(linkFileName, existingFileName, NULL); |
| + } |
| + return FALSE; |
| +} |
| + |
| +BOOL MakeSymLink(TCHAR *linkFileName, TCHAR *existingFileName, BOOL dirLink) { |
| + TCHAR *f1 = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| + TCHAR *f2 = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| + SECURITY_ATTRIBUTES sec_attr = { sizeof (SECURITY_ATTRIBUTES), NULL, FALSE}; |
| + OBJECT_ATTRIBUTES obj_attr; |
| + IO_STATUS_BLOCK io_block; |
| + TCHAR *p, *q; |
| + HANDLE f; |
| + BOOL status; |
| + if (!f1 || !f2) |
| + return FALSE; |
| + lstrcpy(f1, linkFileName); |
|
dpolukhin
2010/04/28 13:16:08
As far as I understand maximum path of 32,767 char
|
| + p = q = f1; |
| + while (q[0]) { |
| + do { |
| + q++; |
| + } while (q[0] && q[0] != '\\'); |
| + p = q; |
| + } |
| + if (p[0] = '\\') { |
| + TCHAR c = p[1]; |
| + p[1] = 0; |
| + status = GetVolumeInformation(f1, NULL, 0, NULL, NULL, NULL, |
| + f2, sizeof(f2)); |
| + p[1] = c; |
| + } else { |
| + status = GetVolumeInformation(NULL, NULL, 0, NULL, NULL, NULL, |
| + f2, sizeof(f2)); |
| + } |
| + /* If it's NFS then we can create real symbolic link. */ |
| + if (!lstrcmpi(f2, _T("NFS"))) { |
| + if (!hNrDll) |
| + hNrDll = LoadLibrary(_T("NTDLL.DLL")); |
| + if (hNrDll) { |
| + if (!fNtCreateFile) |
| + fNtCreateFile = GetProcAddress(hNrDll, "NtCreateFile"); |
| + if (!fNtClose) |
| + fNtClose = GetProcAddress(hNrDll, "NtClose"); |
| + if (fNtCreateFile && fNtClose) { |
| + struct { |
| + ULONG offset; |
| + UCHAR flags; |
| + UCHAR nameLength; |
| + USHORT valueLength; |
| + CHAR name[21]; |
| + /* To prevent troubles with alignment */ |
| + CHAR value[kLargeBuf*sizeof(WCHAR)]; |
| + } *ea_info = HeapAlloc(GetProcessHeap(), |
| + HEAP_ZERO_MEMORY, |
| + sizeof(*ea_info)); |
| + WCHAR *fn = HeapAlloc(GetProcessHeap(), |
| + 0, |
| + sizeof(TCHAR)*kLargeBuf); |
| + UNICODE_STRING n = { lstrlen(linkFileName), kLargeBuf, fn }; |
| + ea_info->nameLength = 20; |
| + lstrcpy(ea_info->name, "NfsSymlinkTargetName"); |
| +#ifdef UNICODE |
| + lstrcpy(fn, linkFileName); |
| + lstrcpy((LPWSTR)ea_info->value, existingFileName); |
| +#else |
| + MultiByteToWideChar(CP_ACP, 0, linkFileName, -1, fn, kLargeBuf); |
| + MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| + (LPWSTR)ea_info->value, |
| + sizeof(ea_info->value)/sizeof(WCHAR)); |
| +#endif |
| + ea_info->valueLength = |
| + lstrlenW((LPWSTR)ea_info->value)*sizeof(WCHAR); |
| + InitializeObjectAttributes(&obj_attr, &n, OBJ_CASE_INSENSITIVE, |
| + NULL, NULL); |
| + status = fNtCreateFile( |
| + &f, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE, &obj_attr, |
| + &io_block, NULL, FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ | |
| + FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, |
| + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, |
| + &ea_info, 1024 * sizeof (WCHAR)); |
| + if (NT_SUCCESS(status)) { |
| + fNtClose(f); |
| + HeapFree(GetProcessHeap(), 0, fn); |
| + HeapFree(GetProcessHeap(), 0, ea_info); |
| + HeapFree(GetProcessHeap(), 0, f2); |
| + HeapFree(GetProcessHeap(), 0, f1); |
| + return TRUE; |
| + } |
| + HeapFree(GetProcessHeap(), 0, fn); |
| + HeapFree(GetProcessHeap(), 0, ea_info); |
| + } |
| + } |
| + } |
| + lstrcpy(f2, existingFileName); |
| + if (!hKernel32) |
| + hKernel32 = LoadLibrary(_T("KERNEL32.DLL")); |
| + if (hKernel32) { |
| + if (!fCreateSymbolicLink) |
| + fCreateSymbolicLink = GetProcAddress(hKernel32, CreateSymbolicLink); |
| + if (fCreateSymbolicLink) { |
| + for (p = f1; p[0]; p++) |
| + if (p[0] == _T('/')) |
| + p[0] = _T('\\'); |
| + for (p = f2; p[0]; p++) |
| + if (p[0] == _T('/')) |
| + p[0] = _T('\\'); |
| + if (fCreateSymbolicLink(f1, f2, |
| + dirLink ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)) { |
| + HeapFree(GetProcessHeap(), 0, f2); |
| + HeapFree(GetProcessHeap(), 0, f1); |
| + return TRUE; |
| + } |
| + } |
| + } |
| + if (dirLink) { |
| + /* Ignore errors - file may already exist */ |
| + CreateDirectory(linkFileName, NULL); |
| + f = CreateFile(linkFileName, GENERIC_READ | GENERIC_WRITE, |
| + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, |
| + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, |
| + NULL ); |
| + if (f != INVALID_HANDLE_VALUE) { |
| + struct rp_info { |
| + DWORD tag; |
| + DWORD dataLength; |
| + WORD reserved1; |
| + WORD targetLength; |
| + WORD targetMaxLength; |
| + WORD reserved2; |
| + WCHAR target[kLargeBuf+4]; |
| + } *rp_info = HeapAlloc(GetProcessHeap(), |
| + HEAP_ZERO_MEMORY, |
| + sizeof(*rp_info)); |
| + DWORD len; |
| + WCHAR *startlink, *endlink; |
| + rp_info->tag = IO_REPARSE_TAG_MOUNT_POINT; |
| + rp_info->target[0] = L'\\'; |
| + rp_info->target[1] = L'?'; |
| + rp_info->target[2] = L'?'; |
| + rp_info->target[3] = L'\\'; |
| + if ((((existingFileName[0] == _T('\\')) || |
| + (existingFileName[0] == _T('/'))) & |
| + ((existingFileName[1] == _T('\\')) || |
| + (existingFileName[1] == _T('/')))) || |
| + ((existingFileName[1] == _T(':')) & |
| + ((existingFileName[2] == _T('\\')) || |
| + (existingFileName[2] == _T('/'))))) { |
| +#ifdef UNICODE |
| + lstrcpy(rp_info->target+4, existingFileName); |
| +#else |
| + MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| + rp_info->target+4, kLargeBuf); |
| +#endif |
| + } else { |
| +#ifdef UNICODE |
| + GetFullPathNameW(linkFileName, 1024, rp_info->target+4, &startlink); |
| + lstrcpy(startlink, existingFileName); |
| +#else |
| + MultiByteToWideChar(CP_ACP, 0, linkFileName, -1, |
| + (LPWSTR)f1, kLargeBuf/sizeof(WCHAR)); |
| + GetFullPathNameW(f1, 1024, rp_info->target+4, &startlink); |
| + MultiByteToWideChar(CP_ACP, 0, existingFileName, -1, |
| + startlink, kLargeBuf+4-(startlink-rp_info->target)); |
| +#endif |
| + } |
| + /* Remove "XXX/../" and replace "/" with "\" */ |
| + for (startlink = endlink = rp_info->target+4; |
| + endlink[0]; startlink++, endlink++) { |
| + startlink[0] = endlink[0]; |
| + if (startlink[0] == L'/') |
| + startlink[0] = L'\\'; |
| + if ((startlink[0] == L'\\') && |
| + (startlink[-1] == L'.') && |
| + (startlink[-2] == L'.')) { |
| + for (startlink--; startlink > rp_info->target+4 && |
| + startlink[0] != L'\\'; startlink--) |
| + { } |
| + for (startlink--; startlink > rp_info->target+4 && |
| + startlink[0] != L'\\'; startlink--) |
| + { } |
| + if (startlink < rp_info->target+4) |
| + startlink = rp_info->target+4; |
| + } |
| + } |
| + startlink[0] = endlink[0]; |
| + rp_info->targetLength = lstrlenW(rp_info->target)*sizeof(WCHAR); |
| + rp_info->targetMaxLength = rp_info->targetLength+sizeof(WCHAR); |
| + rp_info->dataLength = rp_info->targetMaxLength |
| + +FIELD_OFFSET(struct rp_info, target) |
| + -FIELD_OFFSET(struct rp_info, reserved1) |
| + +sizeof(WCHAR); |
| + if (DeviceIoControl(f, 0x900A4, rp_info, |
| + rp_info->dataLength |
| + +FIELD_OFFSET(struct rp_info, reserved1), |
| + NULL, 0, &len, NULL)) { |
| + CloseHandle(f); |
| + HeapFree(GetProcessHeap(), 0, rp_info); |
| + HeapFree(GetProcessHeap(), 0, f2); |
| + HeapFree(GetProcessHeap(), 0, f1); |
| + return TRUE; |
| + } |
| + CloseHandle(f); |
| + RemoveDirectory(linkFileName); |
| + HeapFree(GetProcessHeap(), 0, rp_info); |
| + } |
| + } |
| + for (p = f2; p[0]; p++) |
| + if (p[0] == _T('\\')) |
| + p[0] = _T('/'); |
| + f = CreateFile(linkFileName, GENERIC_READ | GENERIC_WRITE, |
| + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
| + CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, NULL); |
| + if (f != INVALID_HANDLE_VALUE) { |
| + struct { |
| + WCHAR sig[4]; |
| + WCHAR value[kLargeBuf]; |
| + } *link_info = HeapAlloc(GetProcessHeap(), |
| + HEAP_ZERO_MEMORY, |
| + sizeof(*link_info)); |
| + DWORD towrite, written; |
| + link_info->sig[0] = 0x6e49; |
| + link_info->sig[1] = 0x7874; |
| + link_info->sig[2] = 0x4e4c; |
| + link_info->sig[3] = 0x014b; |
| +#ifdef UNICODE |
| + lstrcpy(link_info->value, f2); |
| +#else |
| + MultiByteToWideChar(CP_ACP, 0, f2, -1, link_info->value, kLargeBuf); |
| +#endif |
| + towrite = lstrlenW(link_info->value)*sizeof(WCHAR)+sizeof(link_info->sig); |
| + WriteFile(f, link_info, towrite, &written, NULL); |
| + CloseHandle(f); |
| + if (written == towrite) { |
| + HeapFree(GetProcessHeap(), 0, link_info); |
| + HeapFree(GetProcessHeap(), 0, f2); |
| + HeapFree(GetProcessHeap(), 0, f1); |
| + return TRUE; |
| + } |
| + HeapFree(GetProcessHeap(), 0, link_info); |
| + } |
| + HeapFree(GetProcessHeap(), 0, f2); |
| + HeapFree(GetProcessHeap(), 0, f1); |
| + return FALSE; |
| +} |
| + |
| +HINSTANCE instance; |
| + |
| +HWND parent, list; |
| + |
| +/* |
| + * Show message in NSIS details window. |
| + */ |
| +void NSISprint(const TCHAR *str) { |
| + if (list && *str) { |
| + LVITEM item = { |
| + /* mask */ LVIF_TEXT, |
| + /* iItem */ SendMessage(list, LVM_GETITEMCOUNT, 0, 0), |
| + /* iSubItem */ 0, /* state */ 0, /* stateMask */ 0, |
| + /* pszText */ (TCHAR *) str, /* cchTextMax */ 0, |
| + /* iImage */ 0, /* lParam */ 0, /* iIndent */ 0, |
| + /* iGroupId */ 0, /* cColumns */ 0, /* puColumns */ NULL, |
| + /* piColFmt */ NULL, /* iGroup */ 0}; |
| + ListView_InsertItem(list, &item); |
| + ListView_EnsureVisible(list, item.iItem, 0); |
| + } |
| +} |
| + |
| +enum linktype { HARDLINK, SOFTLINKD, SOFTLINKF }; |
| + |
| +void makelink(HWND hwndParent, int string_size, TCHAR *variables, |
| + stack_t **stacktop, extra_parameters *extra, enum linktype type) { |
| + TCHAR *msg = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kLargeBuf); |
| + TCHAR *from = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kSmallBuf); |
| + TCHAR *to = HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR)*kSmallBuf); |
| + TCHAR *msgFormat = |
| + type == HARDLINK ? _T("Link: \"%s\" to \"%s\"%s") : |
| + type == SOFTLINKD ? _T("Symbolic Directory Link: \"%s\" to \"%s\"%s") : |
| + _T("Symbolic Link: \"%s\" to \"%s\"%s"); |
| + BOOL res; |
| + parent = hwndParent; |
| + list = FindWindowEx(FindWindowEx(parent, NULL, _T("#32770"), NULL), |
| + NULL, _T("SysListView32"), NULL); |
| + |
| + EXDLL_INIT(); |
| + |
| + if (!msg || !from || !to) { |
| + MessageBox(parent, _T("Fatal error: no memory for MkLink"), 0, MB_OK); |
| + } |
| + |
| + if (popstringn(from, kSmallBuf)) { |
| + MessageBox(parent, |
| + _T("Usage: MkLink::Hard \"to_file\" \"from_file\" "), 0, MB_OK); |
| + } |
| + |
| + if (popstringn(to, kSmallBuf)) { |
| + MessageBox(parent, |
| + _T("Usage: MkLink::Hard \"fo_file\" \"from_file\" "),0,MB_OK); |
| + } |
| + |
| + switch (type) { |
| + case HARDLINK: |
| + res = MakeHardLink(from, to); |
| + break; |
| + case SOFTLINKD: |
| + res = MakeSymLink(from, to, TRUE); |
| + break; |
| + case SOFTLINKF: |
| + res = MakeSymLink(from, to, FALSE); |
| + break; |
| + } |
| + wsprintf(msg, msgFormat, to, from, res ? _T("") : _T(" - fail...")); |
| + NSISprint(msg); |
| + |
| + HeapFree(GetProcessHeap(), 0, to); |
| + HeapFree(GetProcessHeap(), 0, from); |
| + HeapFree(GetProcessHeap(), 0, msg); |
| +} |
| + |
| +void __declspec(dllexport) Hard(HWND hwndParent, int string_size, |
| + TCHAR *variables, stack_t **stacktop, |
| + extra_parameters *extra) { |
| + makelink(hwndParent, string_size, variables, stacktop, extra, HARDLINK); |
| +} |
| + |
| +void __declspec(dllexport) SoftD(HWND hwndParent, int string_size, |
| + TCHAR *variables, stack_t **stacktop, |
| + extra_parameters *extra) { |
| + makelink(hwndParent, string_size, variables, stacktop, extra, SOFTLINKD); |
| +} |
| + |
| +void __declspec(dllexport) SoftF(HWND hwndParent, int string_size, |
| + TCHAR *variables, stack_t **stacktop, |
| + extra_parameters *extra) { |
| + makelink(hwndParent, string_size, variables, stacktop, extra, SOFTLINKF); |
| +} |
| + |
| +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { |
| + instance = hInst; |
| + return TRUE; |
| +} |
| Property changes on: tools/hermetic_cygwin/MkLink/MkLink.c |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |