update for HEAD-2003091401
[reactos.git] / lib / ntdll / rtl / path.c
1 /* $Id$
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    size = cd->DosPath.MaximumLength;
384    
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         if (!DosName || !*DosName)
559                 return 0;
560
561         len = wcslen (DosName);
562
563         /* strip trailing spaces */
564         while (len && DosName[len - 1] == L' ')
565                 len--;
566         if (!len)
567                 return 0;
568         
569         /* strip trailing path separator (but don't change '\') */
570         if ((len > 1) &&
571             IS_PATH_SEPARATOR(DosName[len - 1]))
572                 len--;
573         if (FilePart)
574                 *FilePart = NULL;
575         *buf = 0;
576
577 CHECKPOINT;
578         /* check for DOS device name */
579         sz = RtlIsDosDeviceName_U (DosName);
580         if (sz)
581         {
582                 offs = sz >> 17;
583                 sz &= 0x0000FFFF;
584                 if (sz + 8 >= size)
585                     return sz + 10;
586                 wcscpy (buf, L"\\\\.\\");
587                 wcsncat (buf, DosName + offs, sz / sizeof(WCHAR));
588                 return sz + 8;
589         }
590
591 CHECKPOINT;
592         type = RtlDetermineDosPathNameType_U (DosName);
593
594         RtlAcquirePebLock();
595
596         cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
597 DPRINT("type %ld\n", type);
598         switch (type)
599         {
600                 case 1:         /* \\xxx or \\.xxx */
601                 case 6:         /* \\.\xxx */
602                         break;
603
604                 case 2:         /* x:\xxx  */
605                         *DosName = RtlUpcaseUnicodeChar (*DosName);
606                         break;
607
608                 case 3:         /* x:xxx   */
609                         drive = RtlUpcaseUnicodeChar (*DosName);
610                         DosName += 2;
611                         len     -= 2;
612 CHECKPOINT;
613                         if (drive == RtlUpcaseUnicodeChar (cd->DosPath.Buffer[0]))
614                         {
615 CHECKPOINT;
616                                 memcpy (TempFullPathName, cd->DosPath.Buffer, cd->DosPath.Length);
617                                 templen = cd->DosPath.Length / sizeof(WCHAR);
618                         }
619                         else
620                         {
621 CHECKPOINT;
622                                 var[0] = L'=';
623                                 var[1] = drive;
624                                 var[2] = L':';
625                                 var[3] = 0;
626                                 usvar.Length = 3 * sizeof(WCHAR);
627                                 usvar.MaximumLength = 4 * sizeof(WCHAR);
628                                 usvar.Buffer = var;
629                                 pfx.Length = 0;
630                                 pfx.MaximumLength = MAX_PATH;
631                                 pfx.Buffer = TempFullPathName;
632                                 Status = RtlQueryEnvironmentVariable_U (NULL,
633                                                                         &usvar,
634                                                                         &pfx);
635 CHECKPOINT;
636                                 if (!NT_SUCCESS(Status))
637                                 {
638 CHECKPOINT;
639                                         if (Status == STATUS_BUFFER_TOO_SMALL)
640                                                 return pfx.Length + len * 2 + 2;
641                                         memcpy (TempFullPathName, var, 6);
642                                         templen = 3;
643                                 }
644                                 else
645                                 {
646                                         templen = pfx.Length / sizeof(WCHAR);
647                                 }
648
649                         }
650                         break;
651
652                 case 4:         /* \xxx    */
653                         wcsncpy (TempFullPathName, cd->DosPath.Buffer, 2);
654                         TempFullPathName[2] = 0;
655                         templen = wcslen(TempFullPathName);
656                         break;
657
658                 case 5:         /* xxx     */
659                         memcpy (TempFullPathName, cd->DosPath.Buffer, cd->DosPath.Length);
660                         templen = cd->DosPath.Length / sizeof(WCHAR);
661                         break;
662
663                 case 7:         /* \\.     */
664                         memcpy (TempFullPathName, L"\\\\.\\", 8);
665                         templen = 4;
666                         break;
667
668                 default:
669                         return 0;
670         }
671
672         RtlReleasePebLock();
673
674         DPRINT("TempFullPathName \'%S\' DosName \'%S\' len %ld\n", TempFullPathName, DosName, len);
675         /* add dosname to prefix */
676         memcpy (TempFullPathName + templen, DosName, len * sizeof(WCHAR));
677         len += templen;
678         TempFullPathName[len] = 0;
679
680         CHECKPOINT;
681         /* replace slashes */
682         wcs = wcschr(TempFullPathName, L'/');
683         while(wcs)
684         {
685             *wcs = L'\\';
686             wcs = wcschr(wcs + 1, L'/');
687         }
688
689         if (len == 2 && TempFullPathName[1] == L':')
690         {
691                 TempFullPathName[len++] = L'\\';
692                 TempFullPathName[len] = 0;
693         }
694
695
696         DPRINT("TempFullPathName \'%S\'\n", TempFullPathName);
697         RtlpEatPath (TempFullPathName);
698         DPRINT("TempFullPathName \'%S\'\n", TempFullPathName);
699
700         len = wcslen (TempFullPathName);
701
702         if (len < (size / sizeof(WCHAR)))
703         {
704                 memcpy (buf, TempFullPathName, (len + 1) * sizeof(WCHAR));
705
706                 /* find file part */
707                 if (FilePart)
708                 {
709                         *FilePart = wcsrchr(buf, L'\\');
710                         if (*FilePart)
711                         {
712                             (*FilePart)++;
713                         }
714                         else
715                         {
716                             *FilePart = buf;
717                         }
718                 }
719         }
720
721         return len * sizeof(WCHAR);
722 }
723
724
725 /*
726  * @unimplemented
727  */
728 BOOLEAN STDCALL
729 RtlDosPathNameToNtPathName_U(PWSTR dosname,
730                              PUNICODE_STRING ntname,
731                              PWSTR *FilePart,
732                              PCURDIR nah)
733 {
734         UNICODE_STRING  us;
735         PCURDIR cd;
736         ULONG Type;
737         ULONG Size;
738         ULONG Length;
739         ULONG tmpLength;
740         ULONG Offset;
741         WCHAR fullname[MAX_PATH + 1];
742         PWSTR Buffer = NULL;
743
744         RtlAcquirePebLock ();
745
746         RtlInitUnicodeString (&us, dosname);
747         if (us.Length > 8)
748         {
749                 Buffer = us.Buffer;
750                 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
751                 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
752                     Buffer[2] == L'?' && Buffer[3] == L'\\')
753                 {
754 //                      if( f_77F68606( &us, ntname, shortname, nah ) )
755 //                      {
756 //                              RtlReleasePebLock ();
757 //                              return TRUE;
758 //                      }
759                         Buffer = NULL;
760                         RtlReleasePebLock ();
761                         return FALSE;
762                 }
763         }
764
765         Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
766                                   0,
767                                   sizeof( fullname ) + MAX_PFX_SIZE);
768         if (Buffer == NULL)
769         {
770                 RtlReleasePebLock ();
771                 return FALSE;
772         }
773
774         Size = RtlGetFullPathName_U (dosname,
775                                      sizeof(fullname),
776                                      fullname,
777                                      FilePart);
778         if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
779         {
780                 RtlFreeHeap (RtlGetProcessHeap (),
781                              0,
782                              Buffer);
783                 RtlReleasePebLock ();
784                 return FALSE;
785         }
786
787         /* Set NT prefix */
788         Offset = 0;
789         memcpy (Buffer, L"\\??\\", 4 * sizeof(WCHAR));
790         tmpLength = 4;
791
792         Type = RtlDetermineDosPathNameType_U (fullname);
793         switch (Type)
794         {
795                 case 1:
796                         memcpy (Buffer + tmpLength, L"UNC\\", 4 * sizeof(WCHAR));
797                         tmpLength += 4;
798                         Offset = 2;
799                         break; /* \\xxx   */
800
801                 case 6:
802                         Offset = 4;
803                         break; /* \\.\xxx */
804         }
805         Length = wcslen(fullname + Offset);
806         memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
807         Length += tmpLength;
808
809         /* set NT filename */
810         ntname->Length        = Length * sizeof(WCHAR);
811         ntname->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
812         ntname->Buffer        = Buffer;
813
814         /* set pointer to file part if possible */
815         if (FilePart && *FilePart)
816                 *FilePart = Buffer + Length - wcslen (*FilePart);
817
818         /* Set name and handle structure if possible */
819         if (nah)
820         {
821                 memset (nah, 0, sizeof(CURDIR));
822                 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectoryName);
823                 if (Type == 5 && cd->Handle)
824                 {
825                     RtlInitUnicodeString(&us, fullname);
826                     if (RtlEqualUnicodeString(&us, &cd->DosPath, TRUE))
827                     {
828                         Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
829                         nah->DosPath.Buffer = Buffer + Length;
830                         nah->DosPath.Length = ntname->Length - (Length * sizeof(WCHAR));
831                         nah->DosPath.MaximumLength = nah->DosPath.Length;
832                         nah->Handle = cd->Handle;
833                     }
834                 }
835         }
836
837         RtlReleasePebLock();
838
839         return TRUE;
840 }
841
842
843 /*
844  * @implemented
845  */
846 ULONG
847 STDCALL
848 RtlDosSearchPath_U (
849         WCHAR *sp,
850         WCHAR *name,
851         WCHAR *ext,
852         ULONG buf_sz,
853         WCHAR *buffer,
854         PWSTR *FilePart
855         )
856 {
857         ULONG Type;
858         ULONG Length = 0;
859         PWSTR full_name;
860         PWSTR wcs;
861         PWSTR path;
862
863         Type = RtlDetermineDosPathNameType_U (name);
864
865         if (Type == 5)
866         {
867                 Length = wcslen (sp);
868                 Length += wcslen (name);
869                 if (wcschr (name, L'.'))
870                         ext = NULL;
871                 if (ext != NULL)
872                         Length += wcslen (ext);
873
874                 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
875                                                      0,
876                                                      (Length + 1) * sizeof(WCHAR));
877                 Length = 0;
878                 if (full_name != NULL)
879                 {
880                         path = sp;
881                         while (*path)
882                         {
883                                 wcs = full_name;
884                                 while (*path && *path != L';')
885                                         *wcs++ = *path++;
886                                 if (*path)
887                                         path++;
888                                 if (wcs != full_name && *(wcs - 1) != L'\\')
889                                         *wcs++ = L'\\';
890                                 wcscpy (wcs, name);
891                                 if (ext)
892                                         wcscat (wcs, ext);
893                                 if (RtlDoesFileExists_U (full_name))
894                                 {
895                                         Length = RtlGetFullPathName_U (full_name,
896                                                                        buf_sz,
897                                                                        buffer,
898                                                                        FilePart);
899                                         break;
900                                 }
901                         }
902
903                         RtlFreeHeap (RtlGetProcessHeap (),
904                                      0,
905                                      full_name);
906                 }
907         }
908         else if (RtlDoesFileExists_U (name))
909         {
910                 Length = RtlGetFullPathName_U (name,
911                                                buf_sz,
912                                                buffer,
913                                                FilePart);
914         }
915
916         return Length;
917 }
918
919
920 /*
921  * @unimplemented
922  */
923 BOOLEAN STDCALL
924 RtlDoesFileExists_U(IN PWSTR FileName)
925 {
926         UNICODE_STRING NtFileName;
927         OBJECT_ATTRIBUTES Attr;
928         NTSTATUS Status;
929         CURDIR CurDir;
930         PWSTR Buffer;
931
932         /* only used by replacement code */
933         HANDLE FileHandle;
934         IO_STATUS_BLOCK StatusBlock;
935
936         if (!RtlDosPathNameToNtPathName_U (FileName,
937                                            &NtFileName,
938                                            NULL,
939                                            &CurDir))
940                 return FALSE;
941
942         /* don't forget to free it! */
943         Buffer = NtFileName.Buffer;
944
945         if (CurDir.DosPath.Length)
946                 NtFileName = CurDir.DosPath;
947         else
948                 CurDir.Handle = 0;
949
950         InitializeObjectAttributes (&Attr,
951                                     &NtFileName,
952                                     OBJ_CASE_INSENSITIVE,
953                                     CurDir.Handle,
954                                     NULL);
955
956         /* FIXME: not implemented yet */
957 //      Status = NtQueryAttributesFile (&Attr, NULL);
958
959         /* REPLACEMENT start */
960         Status = NtOpenFile (&FileHandle,
961                              0x10001,
962                              &Attr,
963                              &StatusBlock,
964                              1,
965                              FILE_SYNCHRONOUS_IO_NONALERT);
966         if (NT_SUCCESS(Status))
967                 NtClose (FileHandle);
968         /* REPLACEMENT end */
969
970         RtlFreeHeap (RtlGetProcessHeap (),
971                      0,
972                      Buffer);
973
974         if (NT_SUCCESS(Status) ||
975             Status == STATUS_SHARING_VIOLATION ||
976             Status == STATUS_ACCESS_DENIED)
977                 return TRUE;
978
979         return FALSE;
980 }
981
982 /* EOF */