#include #include #include int wmain(int argc, wchar_t *argv[]) { static BYTE reparse_data_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER *reparse_buffer = (REPARSE_DATA_BUFFER *)reparse_data_buffer; DWORD reparse_buffer_length; TOKEN_PRIVILEGES privileges; DWORD target_length; wchar_t *target; HANDLE handle; HANDLE token; BOOL success; DWORD i; if (argc != 3) { printf("Usage: %ls new_file target\n", argv[0]); return 1; } target = argv[2]; for (i = 0, target_length = 0; target[i]; i++, target_length++) { if (target[i] == L'\\') { if (target[i+1] == L'\\') { target[target_length] = L'\\'; i++; continue; } else if (target[i+1] == L'x' && target[i+2] >= L'0' && target[i+2] <= L'9' && target[i+3] >= L'0' && target[i+3] <= L'9') { target[target_length] = ((target[i+2]-L'0') << 4) | (target[i+3]-L'0'); i += 3; continue; } } target[target_length] = target[i]; } target_length *= sizeof(target[0]); reparse_buffer_length = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + target_length*2; if (reparse_buffer_length > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) { printf("Target path is too long\n"); return 1; } reparse_buffer->ReparseTag = IO_REPARSE_TAG_SYMLINK; reparse_buffer->ReparseDataLength = reparse_buffer_length - REPARSE_DATA_BUFFER_HEADER_SIZE; reparse_buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0; reparse_buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = target_length; reparse_buffer->SymbolicLinkReparseBuffer.PrintNameOffset = target_length; reparse_buffer->SymbolicLinkReparseBuffer.PrintNameLength = target_length; reparse_buffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE; memcpy(reparse_buffer->SymbolicLinkReparseBuffer.PathBuffer, target, target_length); memcpy(((BYTE*)reparse_buffer->SymbolicLinkReparseBuffer.PathBuffer)+target_length, target, target_length); if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) { if (LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &privileges.Privileges[0].Luid)) { privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; privileges.PrivilegeCount = 1; AdjustTokenPrivileges(token, FALSE, &privileges, sizeof(privileges), NULL, NULL); } CloseHandle(token); } handle = CreateFileW(argv[1], FILE_WRITE_DATA, FILE_SHARE_VALID_FLAGS, NULL, OPEN_ALWAYS, FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED) handle = CreateFileW(argv[1], FILE_WRITE_DATA, FILE_SHARE_VALID_FLAGS, NULL, OPEN_ALWAYS, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (handle == INVALID_HANDLE_VALUE) { printf("CreateFileW failed: %lu\n", GetLastError()); return 1; } success = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, reparse_buffer, reparse_buffer_length, NULL, 0, NULL, NULL); CloseHandle(handle); if (!success) { printf("FSCTL_SET_REPARSE_POINT failed: %lu\n", GetLastError()); return 1; } return 0; }