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