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
CreateHardLinkW(IN LPCWSTR lpFileName,IN LPCWSTR lpExistingFileName,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)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
CreateHardLinkA(IN LPCSTR lpFileName,IN LPCSTR lpExistingFileName,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)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