xref: /reactos/dll/win32/kernel32/client/file/delete.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/file/delete.c
5  * PURPOSE:         Deleting files
6  * PROGRAMMER:      Ariadne (ariadne@xs4all.nl)
7  * UPDATE HISTORY:
8  *                  Created 01/11/98
9  */
10 
11 /* INCLUDES ****************************************************************/
12 
13 #include <k32.h>
14 #define NDEBUG
15 #include <reactos/debug.h>
16 
17 /* FUNCTIONS ****************************************************************/
18 
19 /*
20  * @implemented
21  */
22 BOOL
23 WINAPI
DeleteFileA(IN LPCSTR lpFileName)24 DeleteFileA(IN LPCSTR lpFileName)
25 {
26     PUNICODE_STRING FileName;
27 
28     /* Convert the string to unicode, and call the wide function */
29     FileName = Basep8BitStringToStaticUnicodeString(lpFileName);
30     if (FileName) return DeleteFileW(FileName->Buffer);
31     return FALSE;
32 }
33 
34 /*
35  * @implemented
36  */
37 BOOL
38 WINAPI
DeleteFileW(IN LPCWSTR lpFileName)39 DeleteFileW(IN LPCWSTR lpFileName)
40 {
41     FILE_DISPOSITION_INFORMATION FileDispInfo;
42     OBJECT_ATTRIBUTES ObjectAttributes;
43     IO_STATUS_BLOCK IoStatusBlock;
44     UNICODE_STRING NtPathU;
45     HANDLE FileHandle;
46     NTSTATUS Status;
47     RTL_RELATIVE_NAME_U RelativeName;
48     PWCHAR PathBuffer;
49     FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
50 
51     /* Convert to NT path and get the relative name too */
52     if (!RtlDosPathNameToNtPathName_U(lpFileName,
53                                       &NtPathU,
54                                       NULL,
55                                       &RelativeName))
56     {
57         /* Bail out if the path name makes no sense */
58         SetLastError(ERROR_PATH_NOT_FOUND);
59         return FALSE;
60     }
61 
62     /* Save the path buffer in case we free it later */
63     PathBuffer = NtPathU.Buffer;
64 
65     /* If we have a relative name... */
66     if (RelativeName.RelativeName.Length)
67     {
68         /* Do a relative open with only the relative path set */
69         NtPathU = RelativeName.RelativeName;
70     }
71     else
72     {
73         /* Do a full path open with no containing directory */
74         RelativeName.ContainingDirectory = NULL;
75     }
76 
77     /* Now open the directory name that was passed in */
78     InitializeObjectAttributes(&ObjectAttributes,
79                                &NtPathU,
80                                OBJ_CASE_INSENSITIVE,
81                                RelativeName.ContainingDirectory,
82                                NULL);
83     Status = NtOpenFile(&FileHandle,
84                         DELETE | FILE_READ_ATTRIBUTES,
85                         &ObjectAttributes,
86                         &IoStatusBlock,
87                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
88                         FILE_NON_DIRECTORY_FILE |
89                         FILE_OPEN_FOR_BACKUP_INTENT |
90                         FILE_OPEN_REPARSE_POINT);
91     if (NT_SUCCESS(Status))
92     {
93         /* Check if there's a reparse point associated with this file handle */
94         Status = NtQueryInformationFile(FileHandle,
95                                         &IoStatusBlock,
96                                         &FileTagInformation,
97                                         sizeof(FileTagInformation),
98                                         FileAttributeTagInformation);
99         if ((NT_SUCCESS(Status)) &&
100             (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
101             (FileTagInformation.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT))
102         {
103             /* There is, so now try to open it with reparse behavior */
104             NtClose(FileHandle);
105             Status = NtOpenFile(&FileHandle,
106                                 DELETE,
107                                 &ObjectAttributes,
108                                 &IoStatusBlock,
109                                 FILE_SHARE_DELETE |
110                                 FILE_SHARE_READ |
111                                 FILE_SHARE_WRITE,
112                                 FILE_NON_DIRECTORY_FILE |
113                                 FILE_OPEN_FOR_BACKUP_INTENT);
114             if (!NT_SUCCESS(Status))
115             {
116                 /* We failed -- maybe whoever is handling this tag isn't there */
117                 if (Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED)
118                 {
119                     /* Try to open it for delete, without reparse behavior */
120                     Status = NtOpenFile(&FileHandle,
121                                         DELETE,
122                                         &ObjectAttributes,
123                                         &IoStatusBlock,
124                                         FILE_SHARE_READ |
125                                         FILE_SHARE_WRITE |
126                                         FILE_SHARE_DELETE,
127                                         FILE_NON_DIRECTORY_FILE |
128                                         FILE_OPEN_FOR_BACKUP_INTENT |
129                                         FILE_OPEN_REPARSE_POINT);
130                 }
131 
132                 if (!NT_SUCCESS(Status))
133                 {
134                      RtlReleaseRelativeName(&RelativeName);
135                      RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
136                      BaseSetLastNTError(Status);
137                      return FALSE;
138                 }
139             }
140         }
141         else if (!(NT_SUCCESS(Status)) &&
142                  (Status != STATUS_NOT_IMPLEMENTED) &&
143                  (Status != STATUS_INVALID_PARAMETER))
144         {
145             /* We had some critical error querying the attributes, bail out */
146             RtlReleaseRelativeName(&RelativeName);
147             RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
148             NtClose(FileHandle);
149             BaseSetLastNTError(Status);
150             return FALSE;
151         }
152     }
153     else
154     {
155         /* It's possible that FILE_OPEN_REPARSE_POINT was not understood */
156         if (Status == STATUS_INVALID_PARAMETER)
157         {
158             /* Try opening the file normally, with reparse behavior */
159             Status = NtOpenFile(&FileHandle,
160                                 DELETE,
161                                 &ObjectAttributes,
162                                 &IoStatusBlock,
163                                 FILE_SHARE_DELETE |
164                                 FILE_SHARE_READ |
165                                 FILE_SHARE_WRITE,
166                                 FILE_NON_DIRECTORY_FILE |
167                                 FILE_OPEN_FOR_BACKUP_INTENT);
168             if (!NT_SUCCESS(Status))
169             {
170                 /* This failed too, fail */
171                 RtlReleaseRelativeName(&RelativeName);
172                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
173                 BaseSetLastNTError(Status);
174                 return FALSE;
175             }
176         }
177         else
178         {
179             /* Maybe we didn't have READ_ATTRIBUTE rights? */
180             if (Status != STATUS_ACCESS_DENIED)
181             {
182                 /* Nope, it was something else, let's fail */
183                 RtlReleaseRelativeName(&RelativeName);
184                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
185                 BaseSetLastNTError(Status);
186                 return FALSE;
187             }
188 
189             /* Let's try again, without querying attributes */
190             Status = NtOpenFile(&FileHandle,
191                                 DELETE,
192                                 &ObjectAttributes,
193                                 &IoStatusBlock,
194                                 FILE_SHARE_DELETE |
195                                 FILE_SHARE_READ |
196                                 FILE_SHARE_WRITE,
197                                 FILE_NON_DIRECTORY_FILE |
198                                 FILE_OPEN_FOR_BACKUP_INTENT |
199                                 FILE_OPEN_REPARSE_POINT);
200             if (!NT_SUCCESS(Status))
201             {
202                 /* This failed too, so bail out */
203                 RtlReleaseRelativeName(&RelativeName);
204                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
205                 BaseSetLastNTError(Status);
206                 return FALSE;
207             }
208         }
209     }
210 
211     /* Ready to delete the file, so cleanup temporary data */
212     RtlReleaseRelativeName(&RelativeName);
213     RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
214 
215     /* Ask for the file to be deleted */
216     FileDispInfo.DeleteFile = TRUE;
217     Status = NtSetInformationFile(FileHandle,
218                                   &IoStatusBlock,
219                                   &FileDispInfo,
220                                   sizeof(FILE_DISPOSITION_INFORMATION),
221                                   FileDispositionInformation);
222     NtClose(FileHandle);
223     if (!NT_SUCCESS(Status))
224     {
225         /* Deletion failed, tell the caller */
226         BaseSetLastNTError(Status);
227         return FALSE;
228     }
229 
230     /* Tell the caller deletion worked */
231     return TRUE;
232 }
233 
234 /* EOF */
235