- Optimize CallNamedPipeA too and remove accidental define.
[reactos.git] / reactos / lib / kernel32 / file / hardlink.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/hardlink.c
6 * PURPOSE: Hardlink functions
7 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * Created 13/03/2004
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include "../include/debug.h"
18
19
20 /* FUNCTIONS ****************************************************************/
21
22
23 /*
24 * @implemented
25 */
26 BOOL STDCALL
27 CreateHardLinkW(LPCWSTR lpFileName,
28 LPCWSTR lpExistingFileName,
29 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
30 {
31 UNICODE_STRING LinkTarget, LinkName;
32 LPVOID lpSecurityDescriptor;
33 PFILE_LINK_INFORMATION LinkInformation;
34 IO_STATUS_BLOCK IoStatus;
35 NTSTATUS Status;
36 BOOL Ret = FALSE;
37
38 if(!lpFileName || !lpExistingFileName)
39 {
40 SetLastError(ERROR_INVALID_PARAMETER);
41 return FALSE;
42 }
43
44 lpSecurityDescriptor = (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL);
45
46 if(RtlDetermineDosPathNameType_U((LPWSTR)lpFileName) == 1 ||
47 RtlDetermineDosPathNameType_U((LPWSTR)lpExistingFileName) == 1)
48 {
49 DPRINT1("CreateHardLinkW() cannot handle UNC Paths!\n");
50 SetLastError(ERROR_INVALID_NAME);
51 return FALSE;
52 }
53
54 if(RtlDosPathNameToNtPathName_U((LPWSTR)lpExistingFileName, &LinkTarget, NULL, NULL))
55 {
56 ULONG NeededSize = RtlGetFullPathName_U((LPWSTR)lpExistingFileName, 0, NULL, NULL);
57 if(NeededSize > 0)
58 {
59 LPWSTR lpNtLinkTarget = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize * sizeof(WCHAR));
60 if(lpNtLinkTarget != NULL)
61 {
62 LPWSTR lpFilePart;
63
64 if(RtlGetFullPathName_U((LPWSTR)lpExistingFileName, NeededSize, lpNtLinkTarget, &lpFilePart) &&
65 (*lpNtLinkTarget) != L'\0')
66 {
67 UNICODE_STRING CheckDrive, LinkDrive;
68 WCHAR wCheckDrive[10];
69
70 swprintf(wCheckDrive, L"\\??\\%c:", (WCHAR)(*lpNtLinkTarget));
71 RtlInitUnicodeString(&CheckDrive, wCheckDrive);
72
73 RtlZeroMemory(&LinkDrive, sizeof(UNICODE_STRING));
74
75 LinkDrive.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH + 1) * sizeof(WCHAR));
76 if(LinkDrive.Buffer != NULL)
77 {
78 HANDLE hFile, hTarget;
79 OBJECT_ATTRIBUTES ObjectAttributes;
80
81 InitializeObjectAttributes(&ObjectAttributes,
82 &CheckDrive,
83 OBJ_CASE_INSENSITIVE,
84 NULL,
85 NULL);
86
87 Status = NtOpenSymbolicLinkObject(&hFile, 1, &ObjectAttributes);
88 if(NT_SUCCESS(Status))
89 {
90 UNICODE_STRING LanManager;
91
92 RtlInitUnicodeString(&LanManager, L"\\Device\\LanmanRedirector\\");
93
94 NtQuerySymbolicLinkObject(hFile, &LinkDrive, NULL);
95
96 if(!RtlPrefixUnicodeString(&LanManager, &LinkDrive, TRUE))
97 {
98 InitializeObjectAttributes(&ObjectAttributes,
99 &LinkTarget,
100 OBJ_CASE_INSENSITIVE,
101 NULL,
102 lpSecurityDescriptor);
103 Status = NtOpenFile(&hTarget,
104 SYNCHRONIZE | DELETE,
105 &ObjectAttributes,
106 &IoStatus,
107 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
108 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
109 if(NT_SUCCESS(Status))
110 {
111 if(RtlDosPathNameToNtPathName_U((LPWSTR)lpFileName, &LinkName, NULL, NULL))
112 {
113 NeededSize = sizeof(FILE_LINK_INFORMATION) + LinkName.Length + sizeof(WCHAR);
114 LinkInformation = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize);
115 if(LinkInformation != NULL)
116 {
117 LinkInformation->ReplaceIfExists = FALSE;
118 LinkInformation->RootDirectory = 0;
119 LinkInformation->FileNameLength = LinkName.Length;
120 RtlCopyMemory(LinkInformation->FileName, LinkName.Buffer, LinkName.Length);
121
122 Status = NtSetInformationFile(hTarget, &IoStatus, LinkInformation, NeededSize, FileLinkInformation);
123 if(NT_SUCCESS(Status))
124 {
125 Ret = TRUE;
126 }
127 else
128 {
129 SetLastErrorByStatus(Status);
130 }
131
132 RtlFreeHeap(RtlGetProcessHeap(), 0, LinkInformation);
133 }
134 else
135 {
136 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
137 }
138 }
139 else
140 {
141 SetLastError(ERROR_PATH_NOT_FOUND);
142 }
143 NtClose(hTarget);
144 }
145 else
146 {
147 DPRINT1("Unable to open link destination \"%wZ\"!\n", &LinkTarget);
148 SetLastErrorByStatus(Status);
149 }
150 }
151 else
152 {
153 DPRINT1("Path \"%wZ\" must not be a mapped drive!\n", &LinkDrive);
154 SetLastError(ERROR_INVALID_NAME);
155 }
156
157 NtClose(hFile);
158 }
159 else
160 {
161 SetLastErrorByStatus(Status);
162 }
163 }
164 else
165 {
166 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
167 }
168 }
169 else
170 {
171 SetLastError(ERROR_INVALID_NAME);
172 }
173 RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
174 }
175 else
176 {
177 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
178 }
179 }
180 else
181 {
182 SetLastError(ERROR_INVALID_NAME);
183 }
184 RtlFreeUnicodeString(&LinkTarget);
185 }
186 else
187 {
188 SetLastError(ERROR_PATH_NOT_FOUND);
189 }
190
191 return Ret;
192 }
193
194
195 /*
196 * @implemented
197 */
198 BOOL STDCALL
199 CreateHardLinkA(LPCSTR lpFileName,
200 LPCSTR lpExistingFileName,
201 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
202 {
203 PWCHAR FileNameW, ExistingFileNameW;
204 BOOL Ret;
205
206 if(!lpFileName || !lpExistingFileName)
207 {
208 SetLastError(ERROR_INVALID_PARAMETER);
209 return FALSE;
210 }
211
212 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
213 return FALSE;
214
215 if (!(ExistingFileNameW = FilenameA2W(lpExistingFileName, TRUE)))
216 return FALSE;
217
218 Ret = CreateHardLinkW(FileNameW , ExistingFileNameW , lpSecurityAttributes);
219
220 RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingFileNameW);
221
222 return Ret;
223 }
224
225 /* EOF */