-temporary and ugly fix/work-around for a bug that made CreateFileW crash
[reactos.git] / reactos / lib / ntdll / rtl / path.c
1 /* $Id: path.c,v 1.26 2003/11/30 20:48:07 gdalsnes Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/ntdll/rtl/path.c
6 * PURPOSE: Path and current directory functions
7 * UPDATE HISTORY:
8 * Created 03/02/00
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <ntdll/rtl.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <ddk/obfuncs.h>
19
20 #define NDEBUG
21 #include <ntdll/ntdll.h>
22
23 /* DEFINITONS and MACROS ******************************************************/
24
25 #define MAX_PFX_SIZE 16
26
27 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
28
29 /* GLOBALS ********************************************************************/
30
31 static const UNICODE_STRING _condev =
32 {
33 .Length = sizeof(L"\\\\.\\CON") - sizeof(WCHAR),
34 .MaximumLength = sizeof(L"\\\\.\\CON"),
35 .Buffer = L"\\\\.\\CON"
36 };
37
38 static const UNICODE_STRING _lpt =
39 {
40 .Length = sizeof(L"LPT") - sizeof(WCHAR),
41 .MaximumLength = sizeof(L"LPT"),
42 .Buffer = L"LPT"
43 };
44
45 static const UNICODE_STRING _com =
46 {
47 .Length = sizeof(L"COM") - sizeof(WCHAR),
48 .MaximumLength = sizeof(L"COM"),
49 .Buffer = L"COM"
50 };
51
52 static const UNICODE_STRING _prn =
53 {
54 .Length = sizeof(L"PRN") - sizeof(WCHAR),
55 .MaximumLength = sizeof(L"PRN"),
56 .Buffer = L"PRN"
57 };
58
59 static const UNICODE_STRING _aux =
60 {
61 .Length = sizeof(L"AUX") - sizeof(WCHAR),
62 .MaximumLength = sizeof(L"AUX"),
63 .Buffer = L"AUX"
64 };
65
66 static const UNICODE_STRING _con =
67 {
68 .Length = sizeof(L"CON") - sizeof(WCHAR),
69 .MaximumLength = sizeof(L"CON"),
70 .Buffer = L"CON"
71 };
72
73 static const UNICODE_STRING _nul =
74 {
75 .Length = sizeof(L"NUL") - sizeof(WCHAR),
76 .MaximumLength = sizeof(L"NUL"),
77 .Buffer = L"NUL"
78 };
79
80 /* FUNCTIONS *****************************************************************/
81
82 static ULONG RtlpGetDotSequence (PWSTR p)
83 {
84 ULONG Count = 0;
85
86 for (;;)
87 {
88 if (*p == '.')
89 Count++;
90 else if ((*p == '\\' || *p == '\0') && Count)
91 return Count;
92 else
93 return 0;
94 p++;
95 }
96 return 0;
97 }
98
99
100 static VOID RtlpEatPath (PWSTR Path)
101 {
102 PWSTR p, prev;
103
104 p = Path + 2;
105 prev = p;
106
107 while ((*p) != 0 || ((*p) == L'\\' && (*(p+1)) == 0))
108 {
109 ULONG DotLen;
110
111 DotLen = RtlpGetDotSequence (p+1);
112 DPRINT("DotSequenceLength %u\n", DotLen);
113 DPRINT("prev '%S' p '%S'\n",prev,p);
114
115 if (DotLen == 0)
116 {
117 prev = p;
118 p = wcschr(p + 1, L'\\');
119 if (p == NULL)
120 {
121 break;
122 }
123 }
124 else if (DotLen == 1)
125 {
126 wcscpy (p, p+2);
127 }
128 else
129 {
130 if (DotLen > 2)
131 {
132 int n = DotLen - 2;
133
134 while (n > 0 && prev > (Path + 2))
135 {
136 prev--;
137 if ((*prev) == L'\\')
138 n--;
139 }
140 }
141
142 if (*(p + DotLen + 1) == 0)
143 *(prev + 1) = 0;
144 else
145 wcscpy (prev, p + DotLen + 1);
146 p = prev;
147 if (prev > (Path + 2))
148 {
149 prev--;
150 while ((*prev) != L'\\')
151 {
152 prev--;
153 }
154 }
155 }
156 }
157 if (Path[2] == 0)
158 {
159 Path[2] = L'\\';
160 Path[3] = 0;
161 }
162 }
163
164
165 /*
166 * @implemented
167 */
168 ULONG STDCALL RtlGetLongestNtPathLength (VOID)
169 {
170 return (MAX_PATH + 9);
171 }
172
173
174 /*
175 * @implemented
176 */
177 ULONG STDCALL
178 RtlDetermineDosPathNameType_U(PWSTR Path)
179 {
180 DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
181
182 if (Path == NULL)
183 {
184 return 0;
185 }
186
187 if (IS_PATH_SEPARATOR(Path[0]))
188 {
189 if (!IS_PATH_SEPARATOR(Path[1]))
190 {
191 return 4; /* \xxx */
192 }
193
194 if (Path[2] != L'.')
195 return 1; /* \\xxx */
196
197 if (IS_PATH_SEPARATOR(Path[3]))
198 return 6; /* \\.\xxx */
199
200 if (Path[3])
201 return 1; /* \\.xxxx */
202
203 return 7; /* \\. */
204 }
205 else
206 {
207 if (Path[1] != L':')
208 return 5; /* xxx */
209
210 if (IS_PATH_SEPARATOR(Path[2]))
211 return 2; /* x:\xxx */
212
213 return 3; /* x:xxx */
214 }
215 }
216
217
218 /* returns 0 if name is not valid DOS device name, or DWORD with
219 * offset in bytes to DOS device name from beginning of buffer in high word
220 * and size in bytes of DOS device name in low word */
221
222 /*
223 * @implemented
224 */
225 ULONG STDCALL
226 RtlIsDosDeviceName_U(PWSTR DeviceName)
227 {
228 ULONG Type;
229 ULONG Length = 0;
230 ULONG Offset;
231 PWCHAR wc;
232 UNICODE_STRING DeviceNameU;
233
234 if (DeviceName == NULL)
235 {
236 return 0;
237 }
238
239 while (DeviceName[Length])
240 {
241 Length++;
242 }
243
244 Type = RtlDetermineDosPathNameType_U(DeviceName);
245 if (Type <= 1)
246 {
247 return 0;
248 }
249
250 if (Type == 6)
251 {
252 DeviceNameU.Length = DeviceNameU.MaximumLength = Length * sizeof(WCHAR);
253 DeviceNameU.Buffer = DeviceName;
254 if (Length == 7 &&
255 RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_condev, TRUE))
256 return 0x00080006;
257 return 0;
258 }
259
260 /* name can end with ':' */
261 if (Length && DeviceName[Length - 1 ] == L':')
262 {
263 Length--;
264 }
265
266 /* there can be spaces or points at the end of name */
267 wc = DeviceName + Length - 1;
268 while (Length && (*wc == L'.' || *wc == L' '))
269 {
270 Length--;
271 wc--;
272 }
273
274 /* let's find a beginning of name */
275 wc = DeviceName + Length - 1;
276 while (wc > DeviceName && !IS_PATH_SEPARATOR(*(wc - 1)))
277 {
278 wc--;
279 }
280 Offset = wc - DeviceName;
281 Length -= Offset;
282 DeviceNameU.Length = DeviceNameU.MaximumLength = 3 * sizeof(WCHAR);
283 DeviceNameU.Buffer = wc;
284
285 /* check for LPTx or COMx */
286 if (Length == 4 && wc[3] >= L'0' && wc[3] <= L'9')
287 {
288 if (wc[3] == L'0')
289 {
290 return 0;
291 }
292
293 if (RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_lpt, TRUE) ||
294 RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_com, TRUE))
295 {
296 return ((Offset * 2) << 16 ) | 8;
297 }
298 return 0;
299 }
300
301 /* check for PRN,AUX,NUL or CON */
302 if (Length == 3 &&
303 (RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_prn, TRUE) ||
304 RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_aux, TRUE) ||
305 RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_nul, TRUE) ||
306 RtlEqualUnicodeString(&DeviceNameU, (PUNICODE_STRING)&_con, TRUE)))
307 {
308 return ((Offset * 2) << 16) | 6;
309 }
310
311 return 0;
312 }
313
314
315 /*
316 * @implemented
317 */
318 ULONG STDCALL
319 RtlGetCurrentDirectory_U(ULONG MaximumLength,
320 PWSTR Buffer)
321 {
322 ULONG Length;
323 PCURDIR cd;
324
325 DPRINT ("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
326
327 RtlAcquirePebLock();
328
329 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
330 Length = cd->DosPath.Length / sizeof(WCHAR);
331 if (cd->DosPath.Buffer[Length - 1] == L'\\' &&
332 cd->DosPath.Buffer[Length - 2] != L':')
333 Length--;
334
335 DPRINT ("cd->DosPath.Buffer %S Length %d\n",
336 cd->DosPath.Buffer, Length);
337
338 if (MaximumLength / sizeof(WCHAR) > Length)
339 {
340 memcpy (Buffer,
341 cd->DosPath.Buffer,
342 Length * sizeof(WCHAR));
343 Buffer[Length] = 0;
344 }
345 else
346 {
347 Length++;
348 }
349
350 RtlReleasePebLock ();
351
352 DPRINT ("CurrentDirectory %S\n", Buffer);
353
354 return (Length * sizeof(WCHAR));
355 }
356
357
358 /*
359 * @implemented
360 */
361 NTSTATUS STDCALL
362 RtlSetCurrentDirectory_U(PUNICODE_STRING name)
363 {
364 UNICODE_STRING full;
365 UNICODE_STRING envvar;
366 OBJECT_ATTRIBUTES Attr;
367 IO_STATUS_BLOCK iosb;
368 PCURDIR cd;
369 NTSTATUS Status;
370 ULONG size;
371 HANDLE handle = NULL;
372 PWSTR wcs;
373 PWSTR buf = 0;
374 PFILE_NAME_INFORMATION filenameinfo;
375 ULONG backslashcount = 0;
376 PWSTR cntr;
377 WCHAR var[4];
378
379 DPRINT ("RtlSetCurrentDirectory %wZ\n", name);
380
381 RtlAcquirePebLock ();
382 cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName;
383
384 size = cd->DosPath.MaximumLength;
385 buf = RtlAllocateHeap (RtlGetProcessHeap(),
386 0,
387 size);
388 if (buf == NULL)
389 {
390 RtlReleasePebLock ();
391 return STATUS_NO_MEMORY;
392 }
393
394 size = RtlGetFullPathName_U (name->Buffer, size, buf, 0);
395 if (!size)
396 {
397 RtlFreeHeap (RtlGetProcessHeap (),
398 0,
399 buf);
400 RtlReleasePebLock ();
401 return STATUS_OBJECT_NAME_INVALID;
402 }
403
404 if (!RtlDosPathNameToNtPathName_U (buf, &full, 0, 0))
405 {
406 RtlFreeHeap (RtlGetProcessHeap (),
407 0,
408 buf);
409 RtlFreeHeap (RtlGetProcessHeap (),
410 0,
411 full.Buffer);
412 RtlReleasePebLock ();
413 return STATUS_OBJECT_NAME_INVALID;
414 }
415
416 InitializeObjectAttributes (&Attr,
417 &full,
418 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
419 NULL,
420 NULL);
421
422 Status = NtOpenFile (&handle,
423 SYNCHRONIZE | FILE_TRAVERSE,
424 &Attr,
425 &iosb,
426 FILE_SHARE_READ | FILE_SHARE_WRITE,
427 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
428 if (!NT_SUCCESS(Status))
429 {
430 RtlFreeHeap (RtlGetProcessHeap (),
431 0,
432 buf);
433 RtlFreeHeap (RtlGetProcessHeap (),
434 0,
435 full.Buffer);
436 RtlReleasePebLock ();
437 return Status;
438 }
439
440 filenameinfo = RtlAllocateHeap(RtlGetProcessHeap(),
441 0,
442 MAX_PATH*sizeof(WCHAR)+sizeof(ULONG));
443
444 Status = NtQueryInformationFile(handle,
445 &iosb,
446 filenameinfo,
447 MAX_PATH*sizeof(WCHAR)+sizeof(ULONG),
448 FileNameInformation);
449 if (!NT_SUCCESS(Status))
450 {
451 RtlFreeHeap(RtlGetProcessHeap(),
452 0,
453 filenameinfo);
454 RtlFreeHeap(RtlGetProcessHeap(),
455 0,
456 buf);
457 RtlFreeHeap(RtlGetProcessHeap(),
458 0,
459 full.Buffer);
460 RtlReleasePebLock();
461 return(Status);
462 }
463
464 if (filenameinfo->FileName[1]) // If it's just "\", we need special handling
465 {
466 wcs = buf + size / sizeof(WCHAR) - 1;
467 if (*wcs == L'\\')
468 {
469 *(wcs) = 0;
470 wcs--;
471 size -= sizeof(WCHAR);
472 }
473
474 for (cntr=filenameinfo->FileName;*cntr!=0;cntr++)
475 {
476 if (*cntr=='\\') backslashcount++;
477 }
478
479 DPRINT("%d \n",backslashcount);
480 for (;backslashcount;wcs--)
481 {
482 if (*wcs=='\\') backslashcount--;
483 }
484 wcs++;
485
486 wcscpy(wcs,filenameinfo->FileName);
487
488 size=((wcs-buf)+wcslen(filenameinfo->FileName))*sizeof(WCHAR);
489 }
490
491 RtlFreeHeap (RtlGetProcessHeap (),
492 0,
493 filenameinfo);
494
495 /* append backslash if missing */
496 wcs = buf + size / sizeof(WCHAR) - 1;
497 if (*wcs != L'\\')
498 {
499 *(++wcs) = L'\\';
500 *(++wcs) = 0;
501 size += sizeof(WCHAR);
502 }
503
504 memmove(cd->DosPath.Buffer,
505 buf,
506 size + sizeof(WCHAR));
507 cd->DosPath.Length = size;
508
509 if (cd->Handle)
510 NtClose(cd->Handle);
511 cd->Handle = handle;
512
513 if (cd->DosPath.Buffer[1]==':')
514 {
515 envvar.Length = 2 * swprintf (var, L"=%c:", cd->DosPath.Buffer[0]);
516 envvar.MaximumLength = 8;
517 envvar.Buffer = var;
518
519 RtlSetEnvironmentVariable(NULL,
520 &envvar,
521 &cd->DosPath);
522 }
523
524 RtlFreeHeap (RtlGetProcessHeap (),
525 0,
526 buf);
527
528 RtlFreeHeap (RtlGetProcessHeap (),
529 0,
530 full.Buffer);
531
532 RtlReleasePebLock();
533
534 return STATUS_SUCCESS;
535 }
536
537 /*
538 * @implemented
539 */
540 ULONG STDCALL
541 RtlGetFullPathName_U(PWSTR DosName,
542 ULONG size,
543 PWSTR buf,
544 PWSTR *FilePart)
545 {
546 WCHAR *wcs, var[4], drive;
547 ULONG len;
548 ULONG templen = 0;
549 DWORD offs, sz, type;
550 UNICODE_STRING usvar, pfx;
551 PCURDIR cd;
552 NTSTATUS Status;
553 WCHAR TempFullPathName[MAX_PATH] = L"";
554
555 DPRINT("RtlGetFullPathName_U %S %ld %p %p\n",
556 DosName, size, buf, FilePart);
557
558 /* FIXME: this code is a mess! We should use Wine's implementation
559 of this function, since it's cleaner and IMO better. -Gunnar */
560
561 if (!DosName || !*DosName)
562 return 0;
563
564 len = wcslen (DosName);
565
566 /* strip trailing spaces */
567 while (len && DosName[len - 1] == L' ')
568 len--;
569 if (!len)
570 return 0;
571
572 /* strip trailing path separator (but don't change '\') */
573 if ((len > 1) &&
574 IS_PATH_SEPARATOR(DosName[len - 1]))
575 len--;
576 if (FilePart)
577 *FilePart = NULL;
578 *buf = 0;
579
580 CHECKPOINT;
581 /* check for DOS device name */
582 sz = RtlIsDosDeviceName_U (DosName);
583 if (sz)
584 {
585 offs = sz >> 17;
586 sz &= 0x0000FFFF;
587 if (sz + 8 >= size)
588 return sz + 10;
589 wcscpy (buf, L"\\\\.\\");
590 wcsncat (buf, DosName + offs, sz / sizeof(WCHAR));
591 return sz + 8;
592 }
593
594 CHECKPOINT;
595 type = RtlDetermineDosPathNameType_U (DosName);
596
597 RtlAcquirePebLock();
598
599 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
600 DPRINT("type %ld\n", type);
601 switch (type)
602 {
603 case 1: /* \\xxx or \\.xxx */
604 case 6: /* \\.\xxx */
605 break;
606
607 case 2:
608 break;
609 #if 0
610 /* this makes a direct CreateFileW call crash! */
611
612 case 2: /* x:\xxx */
613 *DosName = RtlUpcaseUnicodeChar (*DosName);
614 break;
615 #endif
616
617 case 3: /* x:xxx */
618 drive = RtlUpcaseUnicodeChar (*DosName);
619 DosName += 2;
620 len -= 2;
621 CHECKPOINT;
622 if (drive == RtlUpcaseUnicodeChar (cd->DosPath.Buffer[0]))
623 {
624 CHECKPOINT;
625 memcpy (TempFullPathName, cd->DosPath.Buffer, cd->DosPath.Length);
626 templen = cd->DosPath.Length / sizeof(WCHAR);
627 }
628 else
629 {
630 CHECKPOINT;
631 var[0] = L'=';
632 var[1] = drive;
633 var[2] = L':';
634 var[3] = 0;
635 usvar.Length = 3 * sizeof(WCHAR);
636 usvar.MaximumLength = 4 * sizeof(WCHAR);
637 usvar.Buffer = var;
638 pfx.Length = 0;
639 pfx.MaximumLength = MAX_PATH;
640 pfx.Buffer = TempFullPathName;
641 Status = RtlQueryEnvironmentVariable_U (NULL,
642 &usvar,
643 &pfx);
644 CHECKPOINT;
645 if (!NT_SUCCESS(Status))
646 {
647 CHECKPOINT;
648 if (Status == STATUS_BUFFER_TOO_SMALL)
649 return pfx.Length + len * 2 + 2;
650 CHECKPOINT;
651 TempFullPathName[0] = drive;
652 TempFullPathName[1] = L':';
653 TempFullPathName[2] = L'\\';
654 TempFullPathName[3] = 0;
655 templen = 3;
656 }
657 else
658 {
659 CHECKPOINT;
660 templen = pfx.Length / sizeof(WCHAR);
661 }
662
663 }
664 break;
665
666 case 4: /* \xxx */
667 wcsncpy (TempFullPathName, cd->DosPath.Buffer, 2);
668 TempFullPathName[2] = 0;
669 templen = wcslen(TempFullPathName);
670 break;
671
672 case 5: /* xxx */
673 memcpy (TempFullPathName, cd->DosPath.Buffer, cd->DosPath.Length);
674 templen = cd->DosPath.Length / sizeof(WCHAR);
675 break;
676
677 case 7: /* \\. */
678 memcpy (TempFullPathName, L"\\\\.\\", 8);
679 templen = 4;
680 break;
681
682 default:
683 return 0;
684 }
685
686
687 RtlReleasePebLock();
688
689 DPRINT("TempFullPathName \'%S\' DosName \'%S\' len %ld\n", TempFullPathName, DosName, len);
690 /* add dosname to prefix */
691 memcpy (TempFullPathName + templen, DosName, len * sizeof(WCHAR));
692
693 /* dirty/temporary fix for the CreateFileW problem */
694 if (type == 2){
695 TempFullPathName[0] = RtlUpcaseUnicodeChar(TempFullPathName[0]);
696 }
697 len += templen;
698 TempFullPathName[len] = 0;
699
700 CHECKPOINT;
701 /* replace slashes */
702 wcs = wcschr(TempFullPathName, L'/');
703 while(wcs)
704 {
705 *wcs = L'\\';
706 wcs = wcschr(wcs + 1, L'/');
707 }
708
709 if (len == 2 && TempFullPathName[1] == L':')
710 {
711 TempFullPathName[len++] = L'\\';
712 TempFullPathName[len] = 0;
713 }
714
715
716 DPRINT("TempFullPathName \'%S\'\n", TempFullPathName);
717 RtlpEatPath (TempFullPathName);
718 DPRINT("TempFullPathName \'%S\'\n", TempFullPathName);
719
720 len = wcslen (TempFullPathName);
721
722 if (len < (size / sizeof(WCHAR)))
723 {
724 memcpy (buf, TempFullPathName, (len + 1) * sizeof(WCHAR));
725
726 /* find file part */
727 if (FilePart)
728 {
729 #if 0
730 *FilePart = wcsrchr(buf, L'\\');
731 if (*FilePart)
732 {
733 (*FilePart)++;
734 }
735 else
736 {
737 *FilePart = buf;
738 }
739 #else
740 *FilePart = buf + len;
741 while (*FilePart != buf && **FilePart != L'\\')
742 --(*FilePart);
743 if (**FilePart == L'\\')
744 ++(*FilePart);
745 #endif
746 }
747 }
748
749 return len * sizeof(WCHAR);
750 }
751
752
753 /*
754 * @implemented
755 */
756 BOOLEAN STDCALL
757 RtlDosPathNameToNtPathName_U(PWSTR dosname,
758 PUNICODE_STRING ntname,
759 PWSTR *FilePart,
760 PCURDIR nah)
761 {
762 UNICODE_STRING us;
763 PCURDIR cd;
764 ULONG Type;
765 ULONG Size;
766 ULONG Length;
767 ULONG tmpLength;
768 ULONG Offset;
769 WCHAR fullname[MAX_PATH + 1];
770 PWSTR Buffer = NULL;
771
772
773 RtlAcquirePebLock ();
774
775 RtlInitUnicodeString (&us, dosname);
776 if (us.Length > 8)
777 {
778 Buffer = us.Buffer;
779 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
780 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
781 Buffer[2] == L'?' && Buffer[3] == L'\\')
782 {
783 // if( f_77F68606( &us, ntname, shortname, nah ) )
784 // {
785 // RtlReleasePebLock ();
786 // return TRUE;
787 // }
788 Buffer = NULL;
789 RtlReleasePebLock ();
790 return FALSE;
791 }
792 }
793
794 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
795 0,
796 sizeof( fullname ) + MAX_PFX_SIZE);
797 if (Buffer == NULL)
798 {
799 RtlReleasePebLock ();
800 return FALSE;
801 }
802
803 Size = RtlGetFullPathName_U (dosname,
804 sizeof(fullname),
805 fullname,
806 FilePart);
807 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
808 {
809 RtlFreeHeap (RtlGetProcessHeap (),
810 0,
811 Buffer);
812 RtlReleasePebLock ();
813 return FALSE;
814 }
815
816 /* Set NT prefix */
817 Offset = 0;
818 memcpy (Buffer, L"\\??\\", 4 * sizeof(WCHAR));
819 tmpLength = 4;
820
821 Type = RtlDetermineDosPathNameType_U (fullname);
822 switch (Type)
823 {
824 case 1:
825 memcpy (Buffer + tmpLength, L"UNC\\", 4 * sizeof(WCHAR));
826 tmpLength += 4;
827 Offset = 2;
828 break; /* \\xxx */
829
830 case 6:
831 Offset = 4;
832 break; /* \\.\xxx */
833 }
834 Length = wcslen(fullname + Offset);
835 memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
836 Length += tmpLength;
837
838 /* set NT filename */
839 ntname->Length = Length * sizeof(WCHAR);
840 ntname->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
841 ntname->Buffer = Buffer;
842
843 /* set pointer to file part if possible */
844 if (FilePart && *FilePart)
845 *FilePart = Buffer + Length - wcslen (*FilePart);
846
847 /* Set name and handle structure if possible */
848 if (nah)
849 {
850 memset (nah, 0, sizeof(CURDIR));
851 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
852 if (Type == 5 && cd->Handle)
853 {
854 RtlInitUnicodeString(&us, fullname);
855 if (RtlEqualUnicodeString(&us, &cd->DosPath, TRUE))
856 {
857 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
858 nah->DosPath.Buffer = Buffer + Length;
859 nah->DosPath.Length = ntname->Length - (Length * sizeof(WCHAR));
860 nah->DosPath.MaximumLength = nah->DosPath.Length;
861 nah->Handle = cd->Handle;
862 }
863 }
864 }
865
866 RtlReleasePebLock();
867 return TRUE;
868 }
869
870
871 /*
872 * @implemented
873 */
874 ULONG
875 STDCALL
876 RtlDosSearchPath_U (
877 WCHAR *sp,
878 WCHAR *name,
879 WCHAR *ext,
880 ULONG buf_sz,
881 WCHAR *buffer,
882 PWSTR *FilePart
883 )
884 {
885 ULONG Type;
886 ULONG Length = 0;
887 PWSTR full_name;
888 PWSTR wcs;
889 PWSTR path;
890
891 Type = RtlDetermineDosPathNameType_U (name);
892
893 if (Type == 5)
894 {
895 Length = wcslen (sp);
896 Length += wcslen (name);
897 if (wcschr (name, L'.'))
898 ext = NULL;
899 if (ext != NULL)
900 Length += wcslen (ext);
901
902 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
903 0,
904 (Length + 1) * sizeof(WCHAR));
905 Length = 0;
906 if (full_name != NULL)
907 {
908 path = sp;
909 while (*path)
910 {
911 wcs = full_name;
912 while (*path && *path != L';')
913 *wcs++ = *path++;
914 if (*path)
915 path++;
916 if (wcs != full_name && *(wcs - 1) != L'\\')
917 *wcs++ = L'\\';
918 wcscpy (wcs, name);
919 if (ext)
920 wcscat (wcs, ext);
921 if (RtlDoesFileExists_U (full_name))
922 {
923 Length = RtlGetFullPathName_U (full_name,
924 buf_sz,
925 buffer,
926 FilePart);
927 break;
928 }
929 }
930
931 RtlFreeHeap (RtlGetProcessHeap (),
932 0,
933 full_name);
934 }
935 }
936 else if (RtlDoesFileExists_U (name))
937 {
938 Length = RtlGetFullPathName_U (name,
939 buf_sz,
940 buffer,
941 FilePart);
942 }
943
944 return Length;
945 }
946
947
948 /*
949 * @implemented
950 */
951 BOOLEAN STDCALL
952 RtlDoesFileExists_U(IN PWSTR FileName)
953 {
954 UNICODE_STRING NtFileName;
955 OBJECT_ATTRIBUTES Attr;
956 NTSTATUS Status;
957 CURDIR CurDir;
958 PWSTR Buffer;
959
960 /* only used by replacement code */
961 HANDLE FileHandle;
962 IO_STATUS_BLOCK StatusBlock;
963
964 if (!RtlDosPathNameToNtPathName_U (FileName,
965 &NtFileName,
966 NULL,
967 &CurDir))
968 return FALSE;
969
970 /* don't forget to free it! */
971 Buffer = NtFileName.Buffer;
972
973 if (CurDir.DosPath.Length)
974 NtFileName = CurDir.DosPath;
975 else
976 CurDir.Handle = 0;
977
978 InitializeObjectAttributes (&Attr,
979 &NtFileName,
980 OBJ_CASE_INSENSITIVE,
981 CurDir.Handle,
982 NULL);
983
984 /* FIXME: not implemented yet */
985 // Status = NtQueryAttributesFile (&Attr, NULL);
986
987 /* REPLACEMENT start */
988 Status = NtOpenFile (&FileHandle,
989 0x10001,
990 &Attr,
991 &StatusBlock,
992 1,
993 FILE_SYNCHRONOUS_IO_NONALERT);
994 if (NT_SUCCESS(Status))
995 NtClose (FileHandle);
996 /* REPLACEMENT end */
997
998 RtlFreeHeap (RtlGetProcessHeap (),
999 0,
1000 Buffer);
1001
1002 if (NT_SUCCESS(Status) ||
1003 Status == STATUS_SHARING_VIOLATION ||
1004 Status == STATUS_ACCESS_DENIED)
1005 return TRUE;
1006
1007 return FALSE;
1008 }
1009
1010 /* EOF */