Fix declaration of FILE_DISPOSITION_INFORMATION.
[reactos.git] / reactos / lib / kernel32 / file / dir.c
1 /* $Id: dir.c,v 1.48 2004/08/18 02:13:27 navaraf Exp $
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 "../include/debug.h"
22
23
24 /* FUNCTIONS *****************************************************************/
25
26 /*
27 * @implemented
28 */
29 BOOL
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 BOOL
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 BOOL 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 BOOL
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 BOOL
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 DPRINT ("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 BOOL
212 STDCALL
213 RemoveDirectoryA (
214 LPCSTR lpPathName
215 )
216 {
217 UNICODE_STRING PathNameU;
218 ANSI_STRING PathName;
219 BOOL 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 BOOL
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.DeleteFile = 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 nameW;
340 WCHAR bufferW[MAX_PATH];
341 DWORD ret, retW;
342 LPWSTR FilePart = NULL;
343
344 DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
345 "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
346
347 if (!lpFileName)
348 {
349 SetLastError(ERROR_INVALID_PARAMETER);
350 return 0;
351 }
352
353 if (!RtlCreateUnicodeStringFromAsciiz(&nameW, (LPSTR)lpFileName))
354 {
355 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
356 return 0;
357 }
358
359 if (lpFilePart)
360 {
361 *lpFilePart = NULL;
362 }
363
364 retW = GetFullPathNameW(nameW.Buffer, MAX_PATH, bufferW, &FilePart);
365
366 if (!retW)
367 {
368 ret = 0;
369 }
370 else if (retW > MAX_PATH)
371 {
372 SetLastError(ERROR_FILENAME_EXCED_RANGE);
373 ret = 0;
374 }
375 else
376 {
377 ANSI_STRING AnsiBuffer;
378 UNICODE_STRING UnicodeBuffer;
379
380 UnicodeBuffer.Length = wcslen(bufferW) * sizeof(WCHAR);
381 ret = nameW.Length;
382 if (nameW.Length <= nBufferLength)
383 {
384 UnicodeBuffer.Buffer = bufferW;
385 AnsiBuffer.MaximumLength = nBufferLength;
386 AnsiBuffer.Length = 0;
387 AnsiBuffer.Buffer = lpBuffer;
388 RtlUnicodeStringToAnsiString(&AnsiBuffer, &UnicodeBuffer, FALSE);
389
390 if (lpFilePart && FilePart != NULL)
391 {
392 *lpFilePart = (FilePart - bufferW) + lpBuffer;
393 }
394 }
395 }
396
397 RtlFreeUnicodeString(&nameW);
398
399 DPRINT("lpBuffer %s lpFilePart %s Length %ld\n",
400 lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart, nameW.Length);
401
402 return ret;
403 }
404
405
406 /*
407 * @implemented
408 */
409 DWORD
410 STDCALL
411 GetFullPathNameW (
412 LPCWSTR lpFileName,
413 DWORD nBufferLength,
414 LPWSTR lpBuffer,
415 LPWSTR *lpFilePart
416 )
417 {
418 ULONG Length;
419
420 DPRINT("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
421 "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart);
422
423 Length = RtlGetFullPathName_U ((LPWSTR)lpFileName,
424 nBufferLength * sizeof(WCHAR),
425 lpBuffer,
426 lpFilePart);
427
428 DPRINT("lpBuffer %S lpFilePart %S Length %ld\n",
429 lpBuffer, (lpFilePart == NULL) ? L"NULL" : *lpFilePart, Length / sizeof(WCHAR));
430
431 return (Length / sizeof(WCHAR));
432 }
433
434
435 /*
436 * NOTE: Copied from Wine.
437 * @implemented
438 */
439 DWORD
440 STDCALL
441 GetShortPathNameA (
442 LPCSTR longpath,
443 LPSTR shortpath,
444 DWORD shortlen
445 )
446 {
447 UNICODE_STRING longpathW;
448 WCHAR shortpathW[MAX_PATH];
449 DWORD ret, retW;
450
451 if (!longpath)
452 {
453 SetLastError(ERROR_INVALID_PARAMETER);
454 return 0;
455 }
456
457 if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath))
458 {
459 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
460 return 0;
461 }
462
463 retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH);
464
465 if (!retW)
466 ret = 0;
467 else if (retW > PATH_MAX)
468 {
469 SetLastError(ERROR_FILENAME_EXCED_RANGE);
470 ret = 0;
471 }
472 else
473 {
474 ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL);
475 if (ret <= shortlen)
476 {
477 WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL);
478 ret--; /* length without 0 */
479 }
480 }
481
482 RtlFreeUnicodeString(&longpathW);
483 return ret;
484 }
485
486
487 /*
488 * NOTE: Copied from Wine.
489 * @implemented
490 */
491 DWORD
492 STDCALL
493 GetShortPathNameW (
494 LPCWSTR longpath,
495 LPWSTR shortpath,
496 DWORD shortlen
497 )
498 {
499 WCHAR tmpshortpath[PATH_MAX];
500 LPCWSTR p;
501 DWORD sp = 0, lp = 0;
502 DWORD tmplen;
503 WIN32_FIND_DATAW wfd;
504 HANDLE goit;
505 UNICODE_STRING ustr;
506 WCHAR ustr_buf[8+1+3+1];
507
508 if (!longpath)
509 {
510 SetLastError(ERROR_INVALID_PARAMETER);
511 return 0;
512 }
513 if (!longpath[0])
514 {
515 SetLastError(ERROR_BAD_PATHNAME);
516 return 0;
517 }
518
519 /* check for drive letter */
520 if (longpath[1] == ':' )
521 {
522 tmpshortpath[0] = longpath[0];
523 tmpshortpath[1] = ':';
524 sp = lp = 2;
525 }
526
527 ustr.Buffer = ustr_buf;
528 ustr.Length = 0;
529 ustr.MaximumLength = sizeof(ustr_buf);
530
531 while (longpath[lp])
532 {
533 /* check for path delimiters and reproduce them */
534 if (longpath[lp] == '\\' || longpath[lp] == '/')
535 {
536 if (!sp || tmpshortpath[sp-1] != '\\')
537 {
538 /* strip double "\\" */
539 tmpshortpath[sp] = '\\';
540 sp++;
541 }
542 tmpshortpath[sp] = 0; /* terminate string */
543 lp++;
544 continue;
545 }
546
547 for (p = longpath + lp; *p && *p != '/' && *p != '\\'; p++);
548 tmplen = p - (longpath + lp);
549 lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1);
550 /* Check, if the current element is a valid dos name */
551 if (tmplen <= 8+1+3+1)
552 {
553 BOOLEAN spaces;
554 memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR));
555 ustr_buf[tmplen] = '\0';
556 ustr.Length = tmplen * sizeof(WCHAR);
557 if (RtlIsNameLegalDOS8Dot3(&ustr, NULL, &spaces) && !spaces)
558 {
559 sp += tmplen;
560 lp += tmplen;
561 continue;
562 }
563 }
564
565 /* Check if the file exists and use the existing short file name */
566 goit = FindFirstFileW(tmpshortpath, &wfd);
567 if (goit == INVALID_HANDLE_VALUE) goto notfound;
568 FindClose(goit);
569 lstrcpyW(tmpshortpath + sp, wfd.cAlternateFileName);
570 sp += lstrlenW(tmpshortpath + sp);
571 lp += tmplen;
572 }
573 tmpshortpath[sp] = 0;
574
575 tmplen = lstrlenW(tmpshortpath) + 1;
576 if (tmplen <= shortlen)
577 {
578 lstrcpyW(shortpath, tmpshortpath);
579 tmplen--; /* length without 0 */
580 }
581
582 return tmplen;
583
584 notfound:
585 SetLastError ( ERROR_FILE_NOT_FOUND );
586 return 0;
587 }
588
589
590 /*
591 * @implemented
592 */
593 DWORD
594 STDCALL
595 SearchPathA (
596 LPCSTR lpPath,
597 LPCSTR lpFileName,
598 LPCSTR lpExtension,
599 DWORD nBufferLength,
600 LPSTR lpBuffer,
601 LPSTR *lpFilePart
602 )
603 {
604 UNICODE_STRING PathU;
605 UNICODE_STRING FileNameU;
606 UNICODE_STRING ExtensionU;
607 UNICODE_STRING BufferU;
608 ANSI_STRING Path;
609 ANSI_STRING FileName;
610 ANSI_STRING Extension;
611 ANSI_STRING Buffer;
612 PWCHAR FilePartW;
613 DWORD RetValue;
614
615 RtlInitAnsiString (&Path,
616 (LPSTR)lpPath);
617 RtlInitAnsiString (&FileName,
618 (LPSTR)lpFileName);
619 RtlInitAnsiString (&Extension,
620 (LPSTR)lpExtension);
621
622 /* convert ansi (or oem) strings to unicode */
623 if (bIsFileApiAnsi)
624 {
625 RtlAnsiStringToUnicodeString (&PathU,
626 &Path,
627 TRUE);
628 RtlAnsiStringToUnicodeString (&FileNameU,
629 &FileName,
630 TRUE);
631 RtlAnsiStringToUnicodeString (&ExtensionU,
632 &Extension,
633 TRUE);
634 }
635 else
636 {
637 RtlOemStringToUnicodeString (&PathU,
638 &Path,
639 TRUE);
640 RtlOemStringToUnicodeString (&FileNameU,
641 &FileName,
642 TRUE);
643 RtlOemStringToUnicodeString (&ExtensionU,
644 &Extension,
645 TRUE);
646 }
647
648 BufferU.Length = 0;
649 BufferU.MaximumLength = nBufferLength * sizeof(WCHAR);
650 BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
651 0,
652 BufferU.MaximumLength);
653
654 Buffer.Length = 0;
655 Buffer.MaximumLength = nBufferLength;
656 Buffer.Buffer = lpBuffer;
657
658 RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer,
659 NULL == lpFileName ? NULL : FileNameU.Buffer,
660 NULL == lpExtension ? NULL : ExtensionU.Buffer,
661 nBufferLength,
662 BufferU.Buffer,
663 &FilePartW);
664
665 RtlFreeHeap (RtlGetProcessHeap (),
666 0,
667 PathU.Buffer);
668 RtlFreeHeap (RtlGetProcessHeap (),
669 0,
670 FileNameU.Buffer);
671 RtlFreeHeap (RtlGetProcessHeap (),
672 0,
673 ExtensionU.Buffer);
674
675 if (0 != RetValue)
676 {
677 BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR);
678 /* convert ansi (or oem) string to unicode */
679 if (bIsFileApiAnsi)
680 RtlUnicodeStringToAnsiString (&Buffer,
681 &BufferU,
682 FALSE);
683 else
684 RtlUnicodeStringToOemString (&Buffer,
685 &BufferU,
686 FALSE);
687 /* nul-terminate ascii string */
688 Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0';
689 }
690
691 RtlFreeHeap (RtlGetProcessHeap (),
692 0,
693 BufferU.Buffer);
694
695 if (NULL != lpFilePart)
696 {
697 *lpFilePart = strrchr (lpBuffer, '\\') + 1;
698 }
699
700 return RetValue;
701 }
702
703
704 /*
705 * @implemented
706 */
707 DWORD
708 STDCALL
709 SearchPathW (
710 LPCWSTR lpPath,
711 LPCWSTR lpFileName,
712 LPCWSTR lpExtension,
713 DWORD nBufferLength,
714 LPWSTR lpBuffer,
715 LPWSTR *lpFilePart
716 )
717 /*
718 * FUNCTION: Searches for the specified file
719 * ARGUMENTS:
720 * lpPath = Points to a null-terminated string that specified the
721 * path to be searched. If this parameters is NULL then
722 * the following directories are searched
723 * The directory from which the application loaded
724 * The current directory
725 * The system directory
726 * The 16-bit system directory
727 * The windows directory
728 * The directories listed in the PATH environment
729 * variable
730 * lpFileName = Specifies the filename to search for
731 * lpExtension = Points to the null-terminated string that specifies
732 * an extension to be added to the filename when
733 * searching for the file. The first character of the
734 * filename extension must be a period (.). The
735 * extension is only added if the specified filename
736 * doesn't end with an extension
737 *
738 * If the filename extension is not required or if the
739 * filename contains an extension, this parameters can be
740 * NULL
741 * nBufferLength = The length in characters of the buffer for output
742 * lpBuffer = Points to the buffer for the valid path and filename of
743 * file found
744 * lpFilePart = Points to the last component of the valid path and
745 * filename
746 * RETURNS: On success, the length, in characters, of the string copied to the
747 * buffer
748 * On failure, zero.
749 */
750 {
751 DWORD retCode = 0;
752 ULONG pos, len;
753 PWCHAR EnvironmentBufferW = NULL;
754 PWCHAR AppPathW = NULL;
755 WCHAR Buffer;
756 BOOL HasExtension;
757 LPCWSTR p;
758 PWCHAR Name;
759
760 DPRINT("SearchPath\n");
761
762 HasExtension = FALSE;
763 p = lpFileName + wcslen(lpFileName);
764 while (lpFileName < p &&
765 L'\\' != *(p - 1) &&
766 L'/' != *(p - 1) &&
767 L':' != *(p - 1))
768 {
769 HasExtension = HasExtension || L'.' == *(p - 1);
770 p--;
771 }
772 if (lpFileName < p)
773 {
774 if (HasExtension || NULL == lpExtension)
775 {
776 Name = (PWCHAR) lpFileName;
777 }
778 else
779 {
780 Name = RtlAllocateHeap(GetProcessHeap(),
781 HEAP_GENERATE_EXCEPTIONS,
782 (wcslen(lpFileName) + wcslen(lpExtension) + 1)
783 * sizeof(WCHAR));
784 if (NULL == Name)
785 {
786 SetLastError(ERROR_OUTOFMEMORY);
787 return 0;
788 }
789 wcscat(wcscpy(Name, lpFileName), lpExtension);
790 }
791 if (RtlDoesFileExists_U(Name))
792 {
793 retCode = RtlGetFullPathName_U (Name,
794 nBufferLength * sizeof(WCHAR),
795 lpBuffer,
796 lpFilePart);
797 }
798 if (Name != lpFileName)
799 {
800 RtlFreeHeap(GetProcessHeap(), 0, Name);
801 }
802 }
803 else
804 {
805 if (lpPath == NULL)
806 {
807
808 AppPathW = (PWCHAR) RtlAllocateHeap(GetProcessHeap(),
809 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
810 MAX_PATH * sizeof(WCHAR));
811
812
813 wcscat (AppPathW, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
814
815 len = wcslen (AppPathW);
816
817 while (len && AppPathW[len - 1] != L'\\')
818 len--;
819
820 if (len) AppPathW[len-1] = L'\0';
821
822 len = GetEnvironmentVariableW(L"PATH", &Buffer, 0);
823 len += 1 + GetCurrentDirectoryW(0, &Buffer);
824 len += 1 + GetSystemDirectoryW(&Buffer, 0);
825 len += 1 + GetWindowsDirectoryW(&Buffer, 0);
826 len += 1 + wcslen(AppPathW) * sizeof(WCHAR);
827
828 EnvironmentBufferW = (PWCHAR) RtlAllocateHeap(GetProcessHeap(),
829 HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,
830 len * sizeof(WCHAR));
831 if (EnvironmentBufferW == NULL)
832 {
833 SetLastError(ERROR_OUTOFMEMORY);
834 return 0;
835 }
836
837 pos = GetCurrentDirectoryW(len, EnvironmentBufferW);
838 EnvironmentBufferW[pos++] = L';';
839 EnvironmentBufferW[pos] = 0;
840 pos += GetSystemDirectoryW(&EnvironmentBufferW[pos], len - pos);
841 EnvironmentBufferW[pos++] = L';';
842 EnvironmentBufferW[pos] = 0;
843 pos += GetWindowsDirectoryW(&EnvironmentBufferW[pos], len - pos);
844 EnvironmentBufferW[pos++] = L';';
845 EnvironmentBufferW[pos] = 0;
846 pos += GetEnvironmentVariableW(L"PATH", &EnvironmentBufferW[pos], len - pos);
847 EnvironmentBufferW[pos++] = L';';
848 EnvironmentBufferW[pos] = 0;
849 wcscat (EnvironmentBufferW, AppPathW);
850
851 RtlFreeHeap (RtlGetProcessHeap (),
852 0,
853 AppPathW);
854
855 lpPath = EnvironmentBufferW;
856
857 }
858
859 retCode = RtlDosSearchPath_U ((PWCHAR)lpPath, (PWCHAR)lpFileName, (PWCHAR)lpExtension,
860 nBufferLength * sizeof(WCHAR), lpBuffer, lpFilePart);
861
862 if (EnvironmentBufferW != NULL)
863 {
864 RtlFreeHeap(GetProcessHeap(), 0, EnvironmentBufferW);
865 }
866 if (retCode == 0)
867 {
868 SetLastError(ERROR_FILE_NOT_FOUND);
869 }
870 }
871 return retCode / sizeof(WCHAR);
872 }
873
874 /* EOF */