1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/file/hardlink.c 5 * PURPOSE: Hardlink functions 6 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net) 7 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <k32.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* FUNCTIONS ****************************************************************/ 17 18 /* 19 * @implemented 20 */ 21 BOOL 22 WINAPI 23 CreateHardLinkW(IN LPCWSTR lpFileName, 24 IN LPCWSTR lpExistingFileName, 25 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 26 { 27 NTSTATUS Status; 28 BOOL Ret = FALSE; 29 ULONG NeededSize; 30 IO_STATUS_BLOCK IoStatusBlock; 31 OBJECT_ATTRIBUTES ObjectAttributes; 32 HANDLE hTarget = INVALID_HANDLE_VALUE; 33 PFILE_LINK_INFORMATION LinkInformation = NULL; 34 UNICODE_STRING LinkTarget, LinkName; 35 36 /* Initialize */ 37 LinkTarget.Buffer = LinkName.Buffer = NULL; 38 39 /* Validate parameters */ 40 if (!(lpFileName) || !(lpExistingFileName)) 41 { 42 SetLastError(ERROR_INVALID_PARAMETER); 43 return FALSE; 44 } 45 46 _SEH2_TRY 47 { 48 /* Get target UNC path */ 49 if (!RtlDosPathNameToNtPathName_U(lpExistingFileName, 50 &LinkTarget, 51 NULL, 52 NULL)) 53 { 54 /* Set the error and fail */ 55 SetLastError(ERROR_PATH_NOT_FOUND); 56 _SEH2_LEAVE; 57 } 58 59 /* Open target */ 60 InitializeObjectAttributes(&ObjectAttributes, 61 &LinkTarget, 62 OBJ_CASE_INSENSITIVE, 63 NULL, 64 lpSecurityAttributes ? 65 lpSecurityAttributes->lpSecurityDescriptor : 66 NULL); 67 Status = NtOpenFile(&hTarget, 68 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, 69 &ObjectAttributes, 70 &IoStatusBlock, 71 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 72 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT); 73 if (!NT_SUCCESS(Status)) 74 { 75 /* Convert the error and fail */ 76 BaseSetLastNTError(Status); 77 _SEH2_LEAVE; 78 } 79 80 /* Get UNC path name for link */ 81 if (!RtlDosPathNameToNtPathName_U(lpFileName, &LinkName, NULL, NULL)) 82 { 83 /* Set the error and fail */ 84 SetLastError(ERROR_PATH_NOT_FOUND); 85 _SEH2_LEAVE; 86 } 87 88 /* Allocate data for link */ 89 NeededSize = sizeof(FILE_LINK_INFORMATION) + LinkName.Length; 90 LinkInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, NeededSize); 91 if (!LinkInformation) 92 { 93 /* We're out of memory */ 94 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 95 _SEH2_LEAVE; 96 } 97 98 /* Setup data for link and create it */ 99 RtlMoveMemory(LinkInformation->FileName, LinkName.Buffer, LinkName.Length); 100 LinkInformation->ReplaceIfExists = FALSE; 101 LinkInformation->RootDirectory = 0; 102 LinkInformation->FileNameLength = LinkName.Length; 103 Status = NtSetInformationFile(hTarget, 104 &IoStatusBlock, 105 LinkInformation, 106 NeededSize, 107 FileLinkInformation); 108 if (NT_SUCCESS(Status)) 109 { 110 /* Set success code */ 111 Ret = TRUE; 112 } 113 else 114 { 115 /* Convert error code and return default (FALSE) */ 116 BaseSetLastNTError(Status); 117 } 118 } 119 _SEH2_FINALLY 120 { 121 /* Cleanup all allocations */ 122 if (LinkTarget.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkTarget.Buffer); 123 if (hTarget != INVALID_HANDLE_VALUE) NtClose(hTarget); 124 if (LinkName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkName.Buffer); 125 if (LinkInformation) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkInformation); 126 } 127 _SEH2_END; 128 return Ret; 129 } 130 131 /* 132 * @implemented 133 */ 134 BOOL 135 WINAPI 136 CreateHardLinkA(IN LPCSTR lpFileName, 137 IN LPCSTR lpExistingFileName, 138 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) 139 { 140 BOOL Ret; 141 PUNICODE_STRING lpFileNameW; 142 UNICODE_STRING ExistingFileNameW; 143 144 /* Convert the filename to unicode, using MAX_PATH limitations */ 145 lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); 146 if (!lpFileNameW) return FALSE; 147 148 /* Check if there's an existing name as well */ 149 if (lpExistingFileName) 150 { 151 /* We're already using the static string above, so do this dynamically */ 152 if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW, 153 lpExistingFileName)) 154 { 155 /* Out of memory -- fail */ 156 return FALSE; 157 } 158 } 159 else 160 { 161 /* No existing file name */ 162 ExistingFileNameW.Buffer = NULL; 163 } 164 165 /* Call the Wide function, and then free our dynamic string */ 166 Ret = CreateHardLinkW(lpFileNameW->Buffer, 167 ExistingFileNameW.Buffer, 168 lpSecurityAttributes); 169 RtlFreeUnicodeString(&ExistingFileNameW); 170 return Ret; 171 } 172 173 /* EOF */ 174