[RTL]
[reactos.git] / lib / rtl / path.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/path.c
5 * PURPOSE: Path and current directory functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <rtl.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* DEFINITONS and MACROS ******************************************************/
17
18 #define MAX_PFX_SIZE 16
19
20 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
21
22
23 /* GLOBALS ********************************************************************/
24
25 static const WCHAR DeviceRootW[] = L"\\\\.\\";
26
27 static const UNICODE_STRING _condev = RTL_CONSTANT_STRING(L"\\\\.\\CON");
28
29 static const UNICODE_STRING _lpt = RTL_CONSTANT_STRING(L"LPT");
30
31 static const UNICODE_STRING _com = RTL_CONSTANT_STRING(L"COM");
32
33 static const UNICODE_STRING _prn = RTL_CONSTANT_STRING(L"PRN");
34
35 static const UNICODE_STRING _aux = RTL_CONSTANT_STRING(L"AUX");
36
37 static const UNICODE_STRING _con = RTL_CONSTANT_STRING(L"CON");
38
39 static const UNICODE_STRING _nul = RTL_CONSTANT_STRING(L"NUL");
40
41 /* FUNCTIONS *****************************************************************/
42
43
44 /*
45 * @implemented
46 */
47 ULONG NTAPI RtlGetLongestNtPathLength (VOID)
48 {
49 return (MAX_PATH + 9);
50 }
51
52
53 /*
54 * @implemented
55 *
56 */
57 ULONG NTAPI
58 RtlDetermineDosPathNameType_U(PCWSTR Path)
59 {
60 DPRINT("RtlDetermineDosPathNameType_U %S\n", Path);
61
62 if (Path == NULL)
63 {
64 return RtlPathTypeUnknown;
65 }
66
67 if (IS_PATH_SEPARATOR(Path[0]))
68 {
69 if (!IS_PATH_SEPARATOR(Path[1])) return RtlPathTypeRooted; /* \xxx */
70 if (Path[2] != L'.') return RtlPathTypeUncAbsolute; /* \\xxx */
71 if (IS_PATH_SEPARATOR(Path[3])) return RtlPathTypeLocalDevice; /* \\.\xxx */
72 if (Path[3]) return RtlPathTypeUncAbsolute; /* \\.xxxx */
73
74 return RtlPathTypeRootLocalDevice; /* \\. */
75 }
76 else
77 {
78 if (!Path[0] || Path[1] != L':') return RtlPathTypeRelative; /* xxx */
79 if (IS_PATH_SEPARATOR(Path[2])) return RtlPathTypeDriveAbsolute; /* x:\xxx */
80
81 return RtlPathTypeDriveRelative; /* x:xxx */
82 }
83 }
84
85
86 /* returns 0 if name is not valid DOS device name, or DWORD with
87 * offset in bytes to DOS device name from beginning of buffer in high word
88 * and size in bytes of DOS device name in low word */
89
90 /*
91 * @implemented
92 */
93 ULONG NTAPI
94 RtlIsDosDeviceName_U(PWSTR dos_name)
95 {
96 static const WCHAR consoleW[] = {'\\','\\','.','\\','C','O','N',0};
97 static const WCHAR auxW[3] = {'A','U','X'};
98 static const WCHAR comW[3] = {'C','O','M'};
99 static const WCHAR conW[3] = {'C','O','N'};
100 static const WCHAR lptW[3] = {'L','P','T'};
101 static const WCHAR nulW[3] = {'N','U','L'};
102 static const WCHAR prnW[3] = {'P','R','N'};
103
104 const WCHAR *start, *end, *p;
105
106 switch(RtlDetermineDosPathNameType_U( dos_name ))
107 {
108 case RtlPathTypeUnknown:
109 case RtlPathTypeUncAbsolute:
110 return 0;
111 case RtlPathTypeLocalDevice:
112 if (!_wcsicmp( dos_name, consoleW ))
113 return MAKELONG( sizeof(conW), 4 * sizeof(WCHAR) ); /* 4 is length of \\.\ prefix */
114 return 0;
115 default:
116 break;
117 }
118
119 end = dos_name + wcslen(dos_name) - 1;
120 while (end >= dos_name && *end == ':') end--; /* remove all trailing ':' */
121
122 /* find start of file name */
123 for (start = end; start >= dos_name; start--)
124 {
125 if (IS_PATH_SEPARATOR(start[0])) break;
126 /* check for ':' but ignore if before extension (for things like NUL:.txt) */
127 if (start[0] == ':' && start[1] != '.') break;
128 }
129 start++;
130
131 /* remove extension */
132 if ((p = wcschr( start, '.' )))
133 {
134 end = p - 1;
135 if (end >= dos_name && *end == ':') end--; /* remove trailing ':' before extension */
136 }
137 /* remove trailing spaces */
138 while (end >= dos_name && *end == ' ') end--;
139
140 /* now we have a potential device name between start and end, check it */
141 switch(end - start + 1)
142 {
143 case 3:
144 if (_wcsnicmp( start, auxW, 3 ) &&
145 _wcsnicmp( start, conW, 3 ) &&
146 _wcsnicmp( start, nulW, 3 ) &&
147 _wcsnicmp( start, prnW, 3 )) break;
148 return MAKELONG( 3 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) );
149 case 4:
150 if (_wcsnicmp( start, comW, 3 ) && _wcsnicmp( start, lptW, 3 )) break;
151 if (*end <= '0' || *end > '9') break;
152 return MAKELONG( 4 * sizeof(WCHAR), (start - dos_name) * sizeof(WCHAR) );
153 default: /* can't match anything */
154 break;
155 }
156 return 0;
157 }
158
159
160 /*
161 * @implemented
162 */
163 ULONG NTAPI
164 RtlGetCurrentDirectory_U(ULONG MaximumLength,
165 PWSTR Buffer)
166 {
167 ULONG Length;
168 PCURDIR cd;
169
170 DPRINT ("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
171
172 RtlAcquirePebLock();
173
174 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath);
175 Length = cd->DosPath.Length / sizeof(WCHAR);
176 if (cd->DosPath.Buffer[Length - 1] == L'\\' &&
177 cd->DosPath.Buffer[Length - 2] != L':')
178 Length--;
179
180 DPRINT ("cd->DosPath.Buffer %S Length %lu\n",
181 cd->DosPath.Buffer, Length);
182
183 if (MaximumLength / sizeof(WCHAR) > Length)
184 {
185 memcpy (Buffer,
186 cd->DosPath.Buffer,
187 Length * sizeof(WCHAR));
188 Buffer[Length] = 0;
189 }
190 else
191 {
192 Length++;
193 }
194
195 RtlReleasePebLock ();
196
197 DPRINT ("CurrentDirectory %S\n", Buffer);
198
199 return (Length * sizeof(WCHAR));
200 }
201
202
203 /*
204 * @implemented
205 */
206 NTSTATUS NTAPI
207 RtlSetCurrentDirectory_U(PUNICODE_STRING dir)
208 {
209 UNICODE_STRING full;
210 FILE_FS_DEVICE_INFORMATION device_info;
211 OBJECT_ATTRIBUTES Attr;
212 IO_STATUS_BLOCK iosb;
213 PCURDIR cd;
214 NTSTATUS Status;
215 ULONG size;
216 HANDLE handle = NULL;
217 PWSTR ptr;
218
219 DPRINT("RtlSetCurrentDirectory %wZ\n", dir);
220
221 RtlAcquirePebLock ();
222
223 cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath;
224
225 if (!RtlDosPathNameToNtPathName_U (dir->Buffer, &full, 0, 0))
226 {
227 RtlReleasePebLock ();
228 return STATUS_OBJECT_NAME_INVALID;
229 }
230
231 DPRINT("RtlSetCurrentDirectory: full %wZ\n",&full);
232
233 InitializeObjectAttributes (&Attr,
234 &full,
235 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
236 NULL,
237 NULL);
238
239 Status = ZwOpenFile (&handle,
240 SYNCHRONIZE | FILE_TRAVERSE,
241 &Attr,
242 &iosb,
243 FILE_SHARE_READ | FILE_SHARE_WRITE,
244 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
245
246 if (!NT_SUCCESS(Status))
247 {
248 RtlFreeUnicodeString( &full);
249 RtlReleasePebLock ();
250 return Status;
251 }
252
253 /* don't keep the directory handle open on removable media */
254 if (NT_SUCCESS(ZwQueryVolumeInformationFile( handle, &iosb, &device_info,
255 sizeof(device_info), FileFsDeviceInformation )) &&
256 (device_info.Characteristics & FILE_REMOVABLE_MEDIA))
257 {
258 DPRINT1("don't keep the directory handle open on removable media\n");
259 ZwClose( handle );
260 handle = 0;
261 }
262
263 if (cd->Handle)
264 ZwClose(cd->Handle);
265 cd->Handle = handle;
266
267 /* append trailing \ if missing */
268 size = full.Length / sizeof(WCHAR);
269 ptr = full.Buffer;
270 ptr += 4; /* skip \??\ prefix */
271 size -= 4;
272
273 /* This is ok because RtlDosPathNameToNtPathName_U returns a nullterminated string.
274 * So the nullterm is replaced with \
275 * -Gunnar
276 */
277 if (size && ptr[size - 1] != '\\') ptr[size++] = '\\';
278
279 memcpy( cd->DosPath.Buffer, ptr, size * sizeof(WCHAR));
280 cd->DosPath.Buffer[size] = 0;
281 cd->DosPath.Length = size * sizeof(WCHAR);
282
283 RtlFreeUnicodeString( &full);
284 RtlReleasePebLock();
285
286 return STATUS_SUCCESS;
287 }
288
289
290
291 /******************************************************************
292 * collapse_path
293 *
294 * Helper for RtlGetFullPathName_U.
295 * 1) Convert slashes into backslashes
296 * 2) Get rid of duplicate backslashes
297 * 3) Get rid of . and .. components in the path.
298 */
299 static __inline void collapse_path( WCHAR *path, UINT mark )
300 {
301 WCHAR *p, *next;
302
303 /* convert every / into a \ */
304 for (p = path; *p; p++) if (*p == '/') *p = '\\';
305
306 /* collapse duplicate backslashes */
307 next = path + max( 1, mark );
308 for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p;
309 *next = 0;
310
311 p = path + mark;
312 while (*p)
313 {
314 if (*p == '.')
315 {
316 switch(p[1])
317 {
318 case '\\': /* .\ component */
319 next = p + 2;
320 memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
321 continue;
322 case 0: /* final . */
323 if (p > path + mark) p--;
324 *p = 0;
325 continue;
326 case '.':
327 if (p[2] == '\\') /* ..\ component */
328 {
329 next = p + 3;
330 if (p > path + mark)
331 {
332 p--;
333 while (p > path + mark && p[-1] != '\\') p--;
334 }
335 memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
336 continue;
337 }
338 else if (!p[2]) /* final .. */
339 {
340 if (p > path + mark)
341 {
342 p--;
343 while (p > path + mark && p[-1] != '\\') p--;
344 if (p > path + mark) p--;
345 }
346 *p = 0;
347 continue;
348 }
349 break;
350 }
351 }
352 /* skip to the next component */
353 while (*p && *p != '\\') p++;
354 if (*p == '\\')
355 {
356 /* remove last dot in previous dir name */
357 if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) );
358 else p++;
359 }
360 }
361
362 /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */
363 while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--;
364 *p = 0;
365 }
366
367
368
369 /******************************************************************
370 * skip_unc_prefix
371 *
372 * Skip the \\share\dir\ part of a file name. Helper for RtlGetFullPathName_U.
373 */
374 static const WCHAR *skip_unc_prefix( const WCHAR *ptr )
375 {
376 ptr += 2;
377 while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* share name */
378 while (IS_PATH_SEPARATOR(*ptr)) ptr++;
379 while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* dir name */
380 while (IS_PATH_SEPARATOR(*ptr)) ptr++;
381 return ptr;
382 }
383
384
385 /******************************************************************
386 * get_full_path_helper
387 *
388 * Helper for RtlGetFullPathName_U
389 * Note: name and buffer are allowed to point to the same memory spot
390 */
391 static ULONG get_full_path_helper(
392 LPCWSTR name,
393 LPWSTR buffer,
394 ULONG size)
395 {
396 ULONG reqsize = 0, mark = 0, dep = 0, deplen;
397 LPWSTR ins_str = NULL;
398 LPCWSTR ptr;
399 const UNICODE_STRING* cd;
400 WCHAR tmp[4];
401
402 /* return error if name only consists of spaces */
403 for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
404 if (!*ptr) return 0;
405
406 RtlAcquirePebLock();
407
408 //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
409 cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath;
410
411 switch (RtlDetermineDosPathNameType_U(name))
412 {
413 case RtlPathTypeUncAbsolute: /* \\foo */
414 ptr = skip_unc_prefix( name );
415 mark = (ptr - name);
416 break;
417
418 case RtlPathTypeLocalDevice: /* \\.\foo */
419 mark = 4;
420 break;
421
422 case RtlPathTypeDriveAbsolute: /* c:\foo */
423 reqsize = sizeof(WCHAR);
424 tmp[0] = towupper(name[0]);
425 ins_str = tmp;
426 dep = 1;
427 mark = 3;
428 break;
429
430 case RtlPathTypeDriveRelative: /* c:foo */
431 dep = 2;
432 if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':')
433 {
434 UNICODE_STRING var, val;
435
436 tmp[0] = '=';
437 tmp[1] = name[0];
438 tmp[2] = ':';
439 tmp[3] = '\0';
440 var.Length = 3 * sizeof(WCHAR);
441 var.MaximumLength = 4 * sizeof(WCHAR);
442 var.Buffer = tmp;
443 val.Length = 0;
444 val.MaximumLength = size;
445 val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size);
446 if (val.Buffer == NULL)
447 {
448 reqsize = 0;
449 goto done;
450 }
451
452 switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
453 {
454 case STATUS_SUCCESS:
455 /* FIXME: Win2k seems to check that the environment variable actually points
456 * to an existing directory. If not, root of the drive is used
457 * (this seems also to be the only spot in RtlGetFullPathName that the
458 * existence of a part of a path is checked)
459 */
460 /* fall thru */
461 case STATUS_BUFFER_TOO_SMALL:
462 reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
463 val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
464 ins_str = val.Buffer;
465 break;
466 case STATUS_VARIABLE_NOT_FOUND:
467 reqsize = 3 * sizeof(WCHAR);
468 tmp[0] = name[0];
469 tmp[1] = ':';
470 tmp[2] = '\\';
471 ins_str = tmp;
472 break;
473 default:
474 DPRINT1("Unsupported status code\n");
475 break;
476 }
477 mark = 3;
478 break;
479 }
480 /* fall through */
481
482 case RtlPathTypeRelative: /* foo */
483 reqsize = cd->Length;
484 ins_str = cd->Buffer;
485 if (cd->Buffer[1] != ':')
486 {
487 ptr = skip_unc_prefix( cd->Buffer );
488 mark = ptr - cd->Buffer;
489 }
490 else mark = 3;
491 break;
492
493 case RtlPathTypeRooted: /* \xxx */
494 #ifdef __WINE__
495 if (name[0] == '/') /* may be a Unix path */
496 {
497 const WCHAR *ptr = name;
498 int drive = find_drive_root( &ptr );
499 if (drive != -1)
500 {
501 reqsize = 3 * sizeof(WCHAR);
502 tmp[0] = 'A' + drive;
503 tmp[1] = ':';
504 tmp[2] = '\\';
505 ins_str = tmp;
506 mark = 3;
507 dep = ptr - name;
508 break;
509 }
510 }
511 #endif
512 if (cd->Buffer[1] == ':')
513 {
514 reqsize = 2 * sizeof(WCHAR);
515 tmp[0] = cd->Buffer[0];
516 tmp[1] = ':';
517 ins_str = tmp;
518 mark = 3;
519 }
520 else
521 {
522 ptr = skip_unc_prefix( cd->Buffer );
523 reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
524 mark = reqsize / sizeof(WCHAR);
525 ins_str = cd->Buffer;
526 }
527 break;
528
529 case RtlPathTypeRootLocalDevice: /* \\. */
530 reqsize = 4 * sizeof(WCHAR);
531 dep = 3;
532 tmp[0] = '\\';
533 tmp[1] = '\\';
534 tmp[2] = '.';
535 tmp[3] = '\\';
536 ins_str = tmp;
537 mark = 4;
538 break;
539
540 case RtlPathTypeUnknown:
541 goto done;
542 }
543
544 /* enough space ? */
545 deplen = wcslen(name + dep) * sizeof(WCHAR);
546 if (reqsize + deplen + sizeof(WCHAR) > size)
547 {
548 /* not enough space, return need size (including terminating '\0') */
549 reqsize += deplen + sizeof(WCHAR);
550 goto done;
551 }
552
553 memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
554 if (reqsize) memcpy(buffer, ins_str, reqsize);
555 reqsize += deplen;
556
557 if (ins_str && ins_str != tmp && ins_str != cd->Buffer)
558 RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str);
559
560 collapse_path( buffer, mark );
561 reqsize = wcslen(buffer) * sizeof(WCHAR);
562
563 done:
564 RtlReleasePebLock();
565 return reqsize;
566 }
567
568
569 /******************************************************************
570 * RtlGetFullPathName_U (NTDLL.@)
571 *
572 * Returns the number of bytes written to buffer (not including the
573 * terminating NULL) if the function succeeds, or the required number of bytes
574 * (including the terminating NULL) if the buffer is too small.
575 *
576 * file_part will point to the filename part inside buffer (except if we use
577 * DOS device name, in which case file_in_buf is NULL)
578 *
579 * @implemented
580 */
581 ULONG NTAPI RtlGetFullPathName_U(
582 const WCHAR* name,
583 ULONG size,
584 WCHAR* buffer,
585 WCHAR** file_part)
586 {
587 WCHAR* ptr;
588 ULONG dosdev;
589 ULONG reqsize;
590
591 DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
592
593 if (!name || !*name) return 0;
594
595 if (file_part) *file_part = NULL;
596
597 /* check for DOS device name */
598 dosdev = RtlIsDosDeviceName_U((WCHAR*)name);
599 if (dosdev)
600 {
601 DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
602 DWORD sz = LOWORD(dosdev); /* in bytes */
603
604 if (8 + sz + 2 > size) return sz + 10;
605 wcscpy(buffer, DeviceRootW);
606 memmove(buffer + 4, name + offset, sz);
607 buffer[4 + sz / sizeof(WCHAR)] = '\0';
608 /* file_part isn't set in this case */
609 return sz + 8;
610 }
611
612 reqsize = get_full_path_helper(name, buffer, size);
613 if (!reqsize) return 0;
614 if (reqsize > size)
615 {
616 LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize);
617 if (tmp == NULL)
618 return 0;
619 reqsize = get_full_path_helper(name, tmp, reqsize);
620 if (reqsize > size) /* it may have worked the second time */
621 {
622 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
623 return reqsize + sizeof(WCHAR);
624 }
625 memcpy( buffer, tmp, reqsize + sizeof(WCHAR) );
626 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
627 }
628
629 /* find file part */
630 if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr)
631 *file_part = ptr;
632 return reqsize;
633 }
634
635
636 /*
637 * @implemented
638 */
639 BOOLEAN NTAPI
640 RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName,
641 OUT PUNICODE_STRING NtPathName,
642 OUT PCWSTR *NtFileNamePart,
643 OUT CURDIR *DirectoryInfo)
644 {
645 UNICODE_STRING us;
646 PCURDIR cd;
647 ULONG Type;
648 ULONG Size;
649 ULONG Length;
650 ULONG tmpLength;
651 ULONG Offset;
652 WCHAR fullname[MAX_PATH + 1];
653 PWSTR Buffer = NULL;
654
655 RtlInitUnicodeString (&us, DosPathName);
656 if (us.Length > 8)
657 {
658 Buffer = us.Buffer;
659 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
660 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
661 Buffer[2] == L'?' && Buffer[3] == L'\\')
662 {
663 /* allocate the new string and simply copy it */
664 NtPathName->Length = us.Length;
665 NtPathName->MaximumLength = us.Length + sizeof(WCHAR);
666 NtPathName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
667 0,
668 NtPathName->MaximumLength);
669 if (NtPathName->Buffer == NULL)
670 {
671 return FALSE;
672 }
673
674 /* copy the string */
675 RtlCopyMemory(NtPathName->Buffer,
676 us.Buffer,
677 NtPathName->Length);
678 NtPathName->Buffer[us.Length / sizeof(WCHAR)] = L'\0';
679
680 /* change the \\?\ prefix to \??\ */
681 NtPathName->Buffer[1] = L'?';
682
683 if (NtFileNamePart != NULL)
684 {
685 PWSTR FilePart = NULL;
686 PWSTR s;
687
688 /* try to find the last separator */
689 s = NtPathName->Buffer + (NtPathName->Length / sizeof(WCHAR));
690 while (s != NtPathName->Buffer)
691 {
692 if (*s == L'\\')
693 {
694 FilePart = s + 1;
695 break;
696 }
697 s--;
698 }
699
700 *NtFileNamePart = FilePart;
701 }
702
703 if (DirectoryInfo != NULL)
704 {
705 DirectoryInfo->DosPath.Length = 0;
706 DirectoryInfo->DosPath.MaximumLength = 0;
707 DirectoryInfo->DosPath.Buffer = NULL;
708 DirectoryInfo->Handle = NULL;
709 }
710
711 return TRUE;
712 }
713 }
714
715 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
716 0,
717 sizeof( fullname ) + MAX_PFX_SIZE);
718 if (Buffer == NULL)
719 {
720 return FALSE;
721 }
722
723 RtlAcquirePebLock ();
724
725 Size = RtlGetFullPathName_U (DosPathName,
726 sizeof(fullname),
727 fullname,
728 (PWSTR*)NtFileNamePart);
729 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
730 {
731 RtlFreeHeap (RtlGetProcessHeap (),
732 0,
733 Buffer);
734 RtlReleasePebLock ();
735 return FALSE;
736 }
737
738 /* Set NT prefix */
739 Offset = 0;
740 memcpy (Buffer, L"\\??\\", 4 * sizeof(WCHAR));
741 tmpLength = 4;
742
743 Type = RtlDetermineDosPathNameType_U (fullname);
744 switch (Type)
745 {
746 case 1:
747 memcpy (Buffer + tmpLength, L"UNC\\", 4 * sizeof(WCHAR));
748 tmpLength += 4;
749 Offset = 2;
750 break; /* \\xxx */
751
752 case 6:
753 Offset = 4;
754 break; /* \\.\xxx */
755 }
756 Length = wcslen(fullname + Offset);
757 memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
758 Length += tmpLength;
759 if (Type == RtlPathTypeDriveAbsolute ||
760 Type == RtlPathTypeDriveRelative)
761 {
762 /* make the drive letter to uppercase */
763 Buffer[tmpLength] = towupper(Buffer[tmpLength]);
764 }
765
766 /* set NT filename */
767 NtPathName->Length = Length * sizeof(WCHAR);
768 NtPathName->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
769 NtPathName->Buffer = Buffer;
770
771 /* set pointer to file part if possible */
772 if (NtFileNamePart && *NtFileNamePart)
773 *NtFileNamePart = Buffer + Length - wcslen (*NtFileNamePart);
774
775 /* Set name and handle structure if possible */
776 if (DirectoryInfo)
777 {
778 memset (DirectoryInfo, 0, sizeof(CURDIR));
779 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath);
780 if (Type == 5 && cd->Handle)
781 {
782 RtlInitUnicodeString(&us, fullname);
783 if (RtlEqualUnicodeString(&us, &cd->DosPath, TRUE))
784 {
785 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
786 DirectoryInfo->DosPath.Buffer = Buffer + Length;
787 DirectoryInfo->DosPath.Length = NtPathName->Length - (Length * sizeof(WCHAR));
788 DirectoryInfo->DosPath.MaximumLength = DirectoryInfo->DosPath.Length;
789 DirectoryInfo->Handle = cd->Handle;
790 }
791 }
792 }
793
794 RtlReleasePebLock();
795 return TRUE;
796 }
797
798
799 /*
800 * @implemented
801 */
802 ULONG
803 NTAPI
804 RtlDosSearchPath_U (
805 PCWSTR sp,
806 PCWSTR name,
807 PCWSTR ext,
808 ULONG buf_sz,
809 WCHAR *buffer,
810 PWSTR *FilePart
811 )
812 {
813 ULONG Type;
814 ULONG Length = 0;
815 PWSTR full_name;
816 PWSTR wcs;
817 PCWSTR path;
818
819 Type = RtlDetermineDosPathNameType_U (name);
820
821 if (Type == 5)
822 {
823 Length = wcslen (sp);
824 Length += wcslen (name);
825 if (wcschr (name, L'.'))
826 ext = NULL;
827 if (ext != NULL)
828 Length += wcslen (ext);
829
830 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
831 0,
832 (Length + 1) * sizeof(WCHAR));
833 Length = 0;
834 if (full_name != NULL)
835 {
836 path = sp;
837 while (*path)
838 {
839 wcs = full_name;
840 while (*path && *path != L';')
841 *wcs++ = *path++;
842 if (*path)
843 path++;
844 if (wcs != full_name && *(wcs - 1) != L'\\')
845 *wcs++ = L'\\';
846 wcscpy (wcs, name);
847 if (ext)
848 wcscat (wcs, ext);
849 if (RtlDoesFileExists_U (full_name))
850 {
851 Length = RtlGetFullPathName_U (full_name,
852 buf_sz,
853 buffer,
854 FilePart);
855 break;
856 }
857 }
858
859 RtlFreeHeap (RtlGetProcessHeap (),
860 0,
861 full_name);
862 }
863 }
864 else if (RtlDoesFileExists_U (name))
865 {
866 Length = RtlGetFullPathName_U (name,
867 buf_sz,
868 buffer,
869 FilePart);
870 }
871
872 return Length;
873 }
874
875
876 /*
877 * @implemented
878 */
879 BOOLEAN NTAPI
880 RtlDoesFileExists_U(IN PCWSTR FileName)
881 {
882 UNICODE_STRING NtFileName;
883 OBJECT_ATTRIBUTES Attr;
884 FILE_BASIC_INFORMATION Info;
885 NTSTATUS Status;
886 CURDIR CurDir;
887
888
889 if (!RtlDosPathNameToNtPathName_U (FileName,
890 &NtFileName,
891 NULL,
892 &CurDir))
893 return FALSE;
894
895 if (CurDir.DosPath.Length)
896 NtFileName = CurDir.DosPath;
897 else
898 CurDir.Handle = 0;
899
900 InitializeObjectAttributes (&Attr,
901 &NtFileName,
902 OBJ_CASE_INSENSITIVE,
903 CurDir.Handle,
904 NULL);
905
906 Status = ZwQueryAttributesFile (&Attr, &Info);
907
908 RtlFreeUnicodeString(&NtFileName);
909
910
911 if (NT_SUCCESS(Status) ||
912 Status == STATUS_SHARING_VIOLATION ||
913 Status == STATUS_ACCESS_DENIED)
914 return TRUE;
915
916 return FALSE;
917 }
918
919
920 /*
921 * @unimplemented
922 */
923 BOOLEAN NTAPI
924 RtlDosPathNameToRelativeNtPathName_U(PVOID Unknown1,
925 PVOID Unknown2,
926 PVOID Unknown3,
927 PVOID Unknown4)
928 {
929 DPRINT1("RtlDosPathNameToRelativeNtPathName_U(0x%p, 0x%p, 0x%p, 0x%p) UNIMPLEMENTED!\n",
930 Unknown1, Unknown2, Unknown3, Unknown4);
931 return FALSE;
932 }
933
934
935 /*
936 * @unimplemented
937 */
938 VOID NTAPI
939 RtlReleaseRelativeName(PVOID Unknown)
940 {
941 DPRINT1("RtlReleaseRelativeName(0x%p) UNIMPLEMENTED\n", Unknown);
942 }
943
944 NTSTATUS NTAPI
945 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
946 {
947 DPRINT1("RtlpEnsureBufferSize: stub\n");
948 return STATUS_NOT_IMPLEMENTED;
949 }
950
951 NTSTATUS NTAPI
952 RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
953 {
954 DPRINT1("RtlNtPathNameToDosPathName: stub\n");
955 return STATUS_NOT_IMPLEMENTED;
956 }
957
958 /* EOF */