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