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