branch update for HEAD-2003050101
[reactos.git] / lib / kernel32 / file / dir.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/kernel32/file/dir.c
6  * PURPOSE:         Directory functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11
12 /*
13  * NOTES: Changed to using ZwCreateFile
14  */
15
16 /* INCLUDES ******************************************************************/
17
18 #include <k32.h>
19
20 #define NDEBUG
21 #include <kernel32/kernel32.h>
22
23
24 /* FUNCTIONS *****************************************************************/
25
26 WINBOOL
27 STDCALL
28 CreateDirectoryA (
29         LPCSTR                  lpPathName,
30         LPSECURITY_ATTRIBUTES   lpSecurityAttributes
31         )
32 {
33         return CreateDirectoryExA (NULL,
34                                    lpPathName,
35                                    lpSecurityAttributes);
36 }
37
38 WINBOOL
39 STDCALL
40 CreateDirectoryExA (
41         LPCSTR                  lpTemplateDirectory,
42         LPCSTR                  lpNewDirectory,
43         LPSECURITY_ATTRIBUTES   lpSecurityAttributes)
44 {
45         UNICODE_STRING TmplDirU;
46         UNICODE_STRING NewDirU;
47         ANSI_STRING TmplDir;
48         ANSI_STRING NewDir;
49         WINBOOL Result;
50
51         RtlInitUnicodeString (&TmplDirU,
52                               NULL);
53
54         RtlInitUnicodeString (&NewDirU,
55                               NULL);
56
57         if (lpTemplateDirectory != NULL)
58         {
59                 RtlInitAnsiString (&TmplDir,
60                                    (LPSTR)lpTemplateDirectory);
61
62                 /* convert ansi (or oem) string to unicode */
63                 if (bIsFileApiAnsi)
64                         RtlAnsiStringToUnicodeString (&TmplDirU,
65                                                       &TmplDir,
66                                                       TRUE);
67                 else
68                         RtlOemStringToUnicodeString (&TmplDirU,
69                                                      &TmplDir,
70                                                      TRUE);
71         }
72
73         if (lpNewDirectory != NULL)
74         {
75                 RtlInitAnsiString (&NewDir,
76                                    (LPSTR)lpNewDirectory);
77
78                 /* convert ansi (or oem) string to unicode */
79                 if (bIsFileApiAnsi)
80                         RtlAnsiStringToUnicodeString (&NewDirU,
81                                                       &NewDir,
82                                                       TRUE);
83                 else
84                         RtlOemStringToUnicodeString (&NewDirU,
85                                                      &NewDir,
86                                                      TRUE);
87         }
88
89         Result = CreateDirectoryExW (TmplDirU.Buffer,
90                                      NewDirU.Buffer,
91                                      lpSecurityAttributes);
92
93         if (lpTemplateDirectory != NULL)
94                 RtlFreeHeap (RtlGetProcessHeap (),
95                              0,
96                              TmplDirU.Buffer);
97
98         if (lpNewDirectory != NULL)
99                 RtlFreeHeap (RtlGetProcessHeap (),
100                              0,
101                              NewDirU.Buffer);
102
103         return Result;
104 }
105
106
107 WINBOOL
108 STDCALL
109 CreateDirectoryW (
110         LPCWSTR                 lpPathName,
111         LPSECURITY_ATTRIBUTES   lpSecurityAttributes
112         )
113 {
114         return CreateDirectoryExW (NULL,
115                                    lpPathName,
116                                    lpSecurityAttributes);
117 }
118
119
120 WINBOOL
121 STDCALL
122 CreateDirectoryExW (
123         LPCWSTR                 lpTemplateDirectory,
124         LPCWSTR                 lpNewDirectory,
125         LPSECURITY_ATTRIBUTES   lpSecurityAttributes
126         )
127 {
128         OBJECT_ATTRIBUTES ObjectAttributes;
129         IO_STATUS_BLOCK IoStatusBlock;
130         UNICODE_STRING NtPathU;
131         HANDLE DirectoryHandle;
132         NTSTATUS Status;
133
134         DPRINT ("lpTemplateDirectory %S lpNewDirectory %S lpSecurityAttributes %p\n",
135                 lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes);
136   
137   // Can't create empty directory
138   if(lpNewDirectory == NULL || *lpNewDirectory == 0)
139   {
140     SetLastError(ERROR_PATH_NOT_FOUND);
141     return FALSE;
142   }
143
144         if (lpTemplateDirectory != NULL && *lpTemplateDirectory != 0)
145         {
146                 // get object attributes from template directory
147                 DPRINT("KERNEL32:FIXME:%s:%d\n",__FILE__,__LINE__);
148                 return FALSE;
149         }
150
151         if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewDirectory,
152                                            &NtPathU,
153                                            NULL,
154                                            NULL))
155                 return FALSE;
156
157         DPRINT1 ("NtPathU \'%wZ\'\n", &NtPathU);
158
159         ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
160         ObjectAttributes.RootDirectory = NULL;
161         ObjectAttributes.ObjectName = &NtPathU;
162         ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT;
163         ObjectAttributes.SecurityDescriptor = NULL;
164         ObjectAttributes.SecurityQualityOfService = NULL;
165
166         Status = NtCreateFile (&DirectoryHandle,
167                                DIRECTORY_ALL_ACCESS,
168                                &ObjectAttributes,
169                                &IoStatusBlock,
170                                NULL,
171                                FILE_ATTRIBUTE_DIRECTORY,
172                                0,
173                                FILE_CREATE,
174                                FILE_DIRECTORY_FILE,
175                                NULL,
176                                0);
177         DPRINT("Status: %lx\n", Status);
178
179         RtlFreeHeap (RtlGetProcessHeap (),
180                      0,
181                      NtPathU.Buffer);
182
183         if (!NT_SUCCESS(Status))
184         {
185                 SetLastErrorByStatus(Status);
186                 return FALSE;
187         }
188
189         NtClose (DirectoryHandle);
190
191         return TRUE;
192 }
193
194
195 WINBOOL
196 STDCALL
197 RemoveDirectoryA (
198         LPCSTR  lpPathName
199         )
200 {
201         UNICODE_STRING PathNameU;
202         ANSI_STRING PathName;
203         WINBOOL Result;
204
205         RtlInitAnsiString (&PathName,
206                            (LPSTR)lpPathName);
207
208         /* convert ansi (or oem) string to unicode */
209         if (bIsFileApiAnsi)
210                 RtlAnsiStringToUnicodeString (&PathNameU,
211                                               &PathName,
212                                               TRUE);
213         else
214                 RtlOemStringToUnicodeString (&PathNameU,
215                                              &PathName,
216                                              TRUE);
217
218         Result = RemoveDirectoryW (PathNameU.Buffer);
219
220         RtlFreeHeap (RtlGetProcessHeap (),
221                      0,
222                      PathNameU.Buffer);
223
224         return Result;
225 }
226
227
228 WINBOOL
229 STDCALL
230 RemoveDirectoryW (
231         LPCWSTR lpPathName
232         )
233 {
234         FILE_DISPOSITION_INFORMATION FileDispInfo;
235         OBJECT_ATTRIBUTES ObjectAttributes;
236         IO_STATUS_BLOCK IoStatusBlock;
237         UNICODE_STRING NtPathU;
238         HANDLE DirectoryHandle;
239         NTSTATUS Status;
240
241         DPRINT("lpPathName %S\n", lpPathName);
242
243         if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpPathName,
244                                            &NtPathU,
245                                            NULL,
246                                            NULL))
247                 return FALSE;
248
249         ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
250         ObjectAttributes.RootDirectory = NULL;
251         ObjectAttributes.ObjectName = &NtPathU;
252         ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
253         ObjectAttributes.SecurityDescriptor = NULL;
254         ObjectAttributes.SecurityQualityOfService = NULL;
255
256         DPRINT("NtPathU '%S'\n", NtPathU.Buffer);
257
258         Status = NtCreateFile (&DirectoryHandle,
259                                FILE_WRITE_ATTRIBUTES,    /* 0x110080 */
260                                &ObjectAttributes,
261                                &IoStatusBlock,
262                                NULL,
263                                FILE_ATTRIBUTE_DIRECTORY, /* 0x7 */
264                                0,
265                                FILE_OPEN,
266                                FILE_DIRECTORY_FILE,      /* 0x204021 */
267                                NULL,
268                                0);
269
270         RtlFreeHeap (RtlGetProcessHeap (),
271                      0,
272                      NtPathU.Buffer);
273
274         if (!NT_SUCCESS(Status))
275         {
276                 CHECKPOINT;
277                 SetLastErrorByStatus (Status);
278                 return FALSE;
279         }
280
281         FileDispInfo.DoDeleteFile = TRUE;
282
283         Status = NtSetInformationFile (DirectoryHandle,
284                                        &IoStatusBlock,
285                                        &FileDispInfo,
286                                        sizeof(FILE_DISPOSITION_INFORMATION),
287                                        FileDispositionInformation);
288         if (!NT_SUCCESS(Status))
289         {
290                 CHECKPOINT;
291                 NtClose(DirectoryHandle);
292                 SetLastErrorByStatus (Status);
293                 return FALSE;
294         }
295
296         Status = NtClose (DirectoryHandle);
297         if (!NT_SUCCESS(Status))
298         {
299                 CHECKPOINT;
300                 SetLastErrorByStatus (Status);
301                 return FALSE;
302         }
303
304         return TRUE;
305 }
306
307
308 DWORD
309 STDCALL
310 GetFullPathNameA (
311         LPCSTR  lpFileName,
312         DWORD   nBufferLength,
313         LPSTR   lpBuffer,
314         LPSTR   *lpFilePart
315         )
316 {
317         UNICODE_STRING FileNameU;
318         UNICODE_STRING FullNameU;
319         ANSI_STRING FileName;
320         ANSI_STRING FullName;
321         PWSTR FilePartU;
322         ULONG BufferLength;
323         ULONG Offset;
324
325         DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
326                "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
327
328         RtlInitAnsiString (&FileName,
329                            (LPSTR)lpFileName);
330
331         RtlAnsiStringToUnicodeString (&FileNameU,
332                                       &FileName,
333                                       TRUE);
334
335         BufferLength = nBufferLength * sizeof(WCHAR);
336
337         FullNameU.MaximumLength = BufferLength;
338         FullNameU.Length = 0;
339         FullNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
340                                             0,
341                                             BufferLength);
342
343         FullNameU.Length = RtlGetFullPathName_U (FileNameU.Buffer,
344                                                  BufferLength,
345                                                  FullNameU.Buffer,
346                                                  &FilePartU);
347
348         RtlFreeUnicodeString (&FileNameU);
349
350         FullName.MaximumLength = nBufferLength;
351         FullName.Length = 0;
352         FullName.Buffer = lpBuffer;
353
354         RtlUnicodeStringToAnsiString (&FullName,
355                                       &FullNameU,
356                                       FALSE);
357
358         if (lpFilePart != NULL)
359         {
360                 Offset = (ULONG)(FilePartU - FullNameU.Buffer);
361                 *lpFilePart = FullName.Buffer + Offset;
362         }
363
364         RtlFreeHeap (RtlGetProcessHeap (),
365                      0,
366                      FullNameU.Buffer);
367
368         DPRINT("lpBuffer %s lpFilePart %s Length %ld\n",
369                lpBuffer, lpFilePart, FullName.Length);
370
371         return FullName.Length;
372 }
373
374
375 DWORD
376 STDCALL
377 GetFullPathNameW (
378         LPCWSTR lpFileName,
379         DWORD   nBufferLength,
380         LPWSTR  lpBuffer,
381         LPWSTR  *lpFilePart
382         )
383 {
384         ULONG Length;
385
386         DPRINT("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
387                "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
388
389         Length = RtlGetFullPathName_U ((LPWSTR)lpFileName,
390                                        nBufferLength * sizeof(WCHAR),
391                                        lpBuffer,
392                                        lpFilePart);
393
394         DPRINT("lpBuffer %S lpFilePart %S Length %ld\n",
395                lpBuffer, lpFilePart, Length / sizeof(WCHAR));
396
397         return (Length / sizeof(WCHAR));
398 }
399
400
401 DWORD
402 STDCALL
403 GetShortPathNameA (
404         LPCSTR  lpszLongPath,
405         LPSTR   lpszShortPath,
406         DWORD   cchBuffer
407         )
408 {
409         //1 remove unicode chars and spaces
410         //2 remove preceding and trailing periods.
411         //3 remove embedded periods except the last one
412         
413         //4 Split the string in two parts before and after the period
414         //      truncate the part before the period to 6 chars and add ~1
415         //      truncate the part after the period to 3 chars
416         //3 Put the new name in uppercase
417         
418         //4 Increment the ~1 string if the resulting name allready exists
419
420         return 0;
421 }
422
423
424 DWORD
425 STDCALL
426 GetShortPathNameW (
427         LPCWSTR lpszLongPath,
428         LPWSTR  lpszShortPath,
429         DWORD   cchBuffer
430         )
431 {
432         return 0;
433 }
434
435
436 DWORD
437 STDCALL
438 SearchPathA (
439         LPCSTR  lpPath,
440         LPCSTR  lpFileName,
441         LPCSTR  lpExtension,
442         DWORD   nBufferLength,
443         LPSTR   lpBuffer,
444         LPSTR   *lpFilePart
445         )
446 {
447         UNICODE_STRING PathU;
448         UNICODE_STRING FileNameU;
449         UNICODE_STRING ExtensionU;
450         UNICODE_STRING BufferU;
451         ANSI_STRING Path;
452         ANSI_STRING FileName;
453         ANSI_STRING Extension;
454         ANSI_STRING Buffer;
455         PWCHAR FilePartW;
456         DWORD RetValue;
457
458         RtlInitAnsiString (&Path,
459                            (LPSTR)lpPath);
460         RtlInitAnsiString (&FileName,
461                            (LPSTR)lpFileName);
462         RtlInitAnsiString (&Extension,
463                            (LPSTR)lpExtension);
464
465         /* convert ansi (or oem) strings to unicode */
466         if (bIsFileApiAnsi)
467         {
468                 RtlAnsiStringToUnicodeString (&PathU,
469                                               &Path,
470                                               TRUE);
471                 RtlAnsiStringToUnicodeString (&FileNameU,
472                                               &FileName,
473                                               TRUE);
474                 RtlAnsiStringToUnicodeString (&ExtensionU,
475                                               &Extension,
476                                               TRUE);
477         }
478         else
479         {
480                 RtlOemStringToUnicodeString (&PathU,
481                                              &Path,
482                                              TRUE);
483                 RtlOemStringToUnicodeString (&FileNameU,
484                                              &FileName,
485                                              TRUE);
486                 RtlOemStringToUnicodeString (&ExtensionU,
487                                              &Extension,
488                                              TRUE);
489         }
490
491         BufferU.Length = 0;
492         BufferU.MaximumLength = nBufferLength * sizeof(WCHAR);
493         BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
494                                           0,
495                                           BufferU.MaximumLength);
496
497         Buffer.Length = 0;
498         Buffer.MaximumLength = nBufferLength;
499         Buffer.Buffer = lpBuffer;
500
501         RetValue = SearchPathW (PathU.Buffer,
502                                 FileNameU.Buffer,
503                                 ExtensionU.Buffer,
504                                 nBufferLength,
505                                 BufferU.Buffer,
506                                 &FilePartW);
507
508         RtlFreeHeap (RtlGetProcessHeap (),
509                      0,
510                      PathU.Buffer);
511         RtlFreeHeap (RtlGetProcessHeap (),
512                      0,
513                      FileNameU.Buffer);
514         RtlFreeHeap (RtlGetProcessHeap (),
515                      0,
516                      ExtensionU.Buffer);
517
518         /* convert ansi (or oem) string to unicode */
519         if (bIsFileApiAnsi)
520                 RtlUnicodeStringToAnsiString (&Buffer,
521                                               &BufferU,
522                                               FALSE);
523         else
524                 RtlUnicodeStringToOemString (&Buffer,
525                                              &BufferU,
526                                              FALSE);
527
528         RtlFreeHeap (RtlGetProcessHeap (),
529                      0,
530                      BufferU.Buffer);
531
532         *lpFilePart = strrchr (lpBuffer, '\\') + 1;
533
534         return RetValue;
535 }
536
537
538 DWORD
539 STDCALL
540 SearchPathW (
541         LPCWSTR lpPath,
542         LPCWSTR lpFileName,
543         LPCWSTR lpExtension,
544         DWORD   nBufferLength,
545         LPWSTR  lpBuffer,
546         LPWSTR  *lpFilePart
547         )
548 /*
549  * FUNCTION: Searches for the specified file
550  * ARGUMENTS:
551  *       lpPath = Points to a null-terminated string that specified the
552  *                path to be searched. If this parameters is NULL then
553  *                the following directories are searched
554  *                          The directory from which the application loaded
555  *                          The current directory
556  *                          The system directory
557  *                          The 16-bit system directory
558  *                          The windows directory
559  *                          The directories listed in the PATH environment
560  *                          variable
561  *        lpFileName = Specifies the filename to search for
562  *        lpExtension = Points to the null-terminated string that specifies
563  *                      an extension to be added to the filename when
564  *                      searching for the file. The first character of the
565  *                      filename extension must be a period (.). The
566  *                      extension is only added if the specified filename
567  *                      doesn't end with an extension
568  *                      
569  *                      If the filename extension is not required or if the
570  *                      filename contains an extension, this parameters can be
571  *                      NULL
572  *        nBufferLength = The length in characters of the buffer for output
573  *        lpBuffer = Points to the buffer for the valid path and filename of
574  *                   file found
575  *        lpFilePart = Points to the last component of the valid path and
576  *                     filename 
577  * RETURNS: On success, the length, in characters, of the string copied to the
578  *          buffer
579  *          On failure, zero.
580  */
581 {
582         DWORD retCode = 0;
583         ULONG pos, len;
584         PWCHAR EnvironmentBufferW = NULL;
585         WCHAR Buffer;
586
587         DPRINT("SearchPath\n");
588
589         if (lpPath == NULL)
590         {
591                 len = GetEnvironmentVariableW(L"PATH", &Buffer, 0);
592                 len += 1 + GetCurrentDirectoryW(0, &Buffer);
593                 len += 1 + GetSystemDirectoryW(&Buffer, 0);
594                 len += 1 + GetWindowsDirectoryW(&Buffer, 0);
595
596                 EnvironmentBufferW = (PWCHAR) RtlAllocateHeap(GetProcessHeap(), 
597                                                 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, 
598                                                 len * sizeof(WCHAR));
599                 if (EnvironmentBufferW == NULL)
600                 {
601                         SetLastError(ERROR_OUTOFMEMORY);
602                         return 0;
603                 }
604
605                 pos = GetCurrentDirectoryW(len, EnvironmentBufferW);
606                 EnvironmentBufferW[pos++] = L';';
607                 EnvironmentBufferW[pos] = 0;
608                 pos += GetSystemDirectoryW(&EnvironmentBufferW[pos], len - pos);
609                 EnvironmentBufferW[pos++] = L';';
610                 EnvironmentBufferW[pos] = 0;
611                 pos += GetWindowsDirectoryW(&EnvironmentBufferW[pos], len - pos);
612                 EnvironmentBufferW[pos++] = L';';
613                 EnvironmentBufferW[pos] = 0;
614                 pos += GetEnvironmentVariableW(L"PATH", &EnvironmentBufferW[pos], len - pos);
615                 lpPath = EnvironmentBufferW;
616         }
617
618         retCode = RtlDosSearchPath_U ((PWCHAR)lpPath, (PWCHAR)lpFileName, (PWCHAR)lpExtension, 
619                                       nBufferLength * sizeof(WCHAR), lpBuffer, lpFilePart);
620
621         if (EnvironmentBufferW != NULL)
622         {
623                 RtlFreeHeap(GetProcessHeap(), 0, EnvironmentBufferW);
624         }
625         if (retCode == 0)
626         {
627                 SetLastError(ERROR_FILE_NOT_FOUND);
628         }
629         return retCode / sizeof(WCHAR);
630 }
631
632 /* EOF */