spaces -> tabs
[reactos.git] / reactos / 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 RTL_PATH_TYPE type;
398 LPWSTR ins_str = NULL;
399 LPCWSTR ptr;
400 const UNICODE_STRING* cd;
401 WCHAR tmp[4];
402
403 /* return error if name only consists of spaces */
404 for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
405 if (!*ptr) return 0;
406
407 RtlAcquirePebLock();
408
409 //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
410 cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath;
411
412 switch (type = RtlDetermineDosPathNameType_U(name))
413 {
414 case RtlPathTypeUncAbsolute: /* \\foo */
415 ptr = skip_unc_prefix( name );
416 mark = (ptr - name);
417 break;
418
419 case RtlPathTypeLocalDevice: /* \\.\foo */
420 mark = 4;
421 break;
422
423 case RtlPathTypeDriveAbsolute: /* c:\foo */
424 reqsize = sizeof(WCHAR);
425 tmp[0] = towupper(name[0]);
426 ins_str = tmp;
427 dep = 1;
428 mark = 3;
429 break;
430
431 case RtlPathTypeDriveRelative: /* c:foo */
432 dep = 2;
433 if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':')
434 {
435 UNICODE_STRING var, val;
436
437 tmp[0] = '=';
438 tmp[1] = name[0];
439 tmp[2] = ':';
440 tmp[3] = '\0';
441 var.Length = 3 * sizeof(WCHAR);
442 var.MaximumLength = 4 * sizeof(WCHAR);
443 var.Buffer = tmp;
444 val.Length = 0;
445 val.MaximumLength = size;
446 val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size);
447 if (val.Buffer == NULL)
448 {
449 reqsize = 0;
450 goto done;
451 }
452
453 switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
454 {
455 case STATUS_SUCCESS:
456 /* FIXME: Win2k seems to check that the environment variable actually points
457 * to an existing directory. If not, root of the drive is used
458 * (this seems also to be the only spot in RtlGetFullPathName that the
459 * existence of a part of a path is checked)
460 */
461 /* fall thru */
462 case STATUS_BUFFER_TOO_SMALL:
463 reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
464 val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
465 ins_str = val.Buffer;
466 break;
467 case STATUS_VARIABLE_NOT_FOUND:
468 reqsize = 3 * sizeof(WCHAR);
469 tmp[0] = name[0];
470 tmp[1] = ':';
471 tmp[2] = '\\';
472 ins_str = tmp;
473 break;
474 default:
475 DPRINT1("Unsupported status code\n");
476 break;
477 }
478 mark = 3;
479 break;
480 }
481 /* fall through */
482
483 case RtlPathTypeRelative: /* foo */
484 reqsize = cd->Length;
485 ins_str = cd->Buffer;
486 if (cd->Buffer[1] != ':')
487 {
488 ptr = skip_unc_prefix( cd->Buffer );
489 mark = ptr - cd->Buffer;
490 }
491 else mark = 3;
492 break;
493
494 case RtlPathTypeRooted: /* \xxx */
495 #ifdef __WINE__
496 if (name[0] == '/') /* may be a Unix path */
497 {
498 const WCHAR *ptr = name;
499 int drive = find_drive_root( &ptr );
500 if (drive != -1)
501 {
502 reqsize = 3 * sizeof(WCHAR);
503 tmp[0] = 'A' + drive;
504 tmp[1] = ':';
505 tmp[2] = '\\';
506 ins_str = tmp;
507 mark = 3;
508 dep = ptr - name;
509 break;
510 }
511 }
512 #endif
513 if (cd->Buffer[1] == ':')
514 {
515 reqsize = 2 * sizeof(WCHAR);
516 tmp[0] = cd->Buffer[0];
517 tmp[1] = ':';
518 ins_str = tmp;
519 mark = 3;
520 }
521 else
522 {
523 ptr = skip_unc_prefix( cd->Buffer );
524 reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
525 mark = reqsize / sizeof(WCHAR);
526 ins_str = cd->Buffer;
527 }
528 break;
529
530 case RtlPathTypeRootLocalDevice: /* \\. */
531 reqsize = 4 * sizeof(WCHAR);
532 dep = 3;
533 tmp[0] = '\\';
534 tmp[1] = '\\';
535 tmp[2] = '.';
536 tmp[3] = '\\';
537 ins_str = tmp;
538 mark = 4;
539 break;
540
541 case RtlPathTypeUnknown:
542 goto done;
543 }
544
545 /* enough space ? */
546 deplen = wcslen(name + dep) * sizeof(WCHAR);
547 if (reqsize + deplen + sizeof(WCHAR) > size)
548 {
549 /* not enough space, return need size (including terminating '\0') */
550 reqsize += deplen + sizeof(WCHAR);
551 goto done;
552 }
553
554 memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
555 if (reqsize) memcpy(buffer, ins_str, reqsize);
556 reqsize += deplen;
557
558 if (ins_str && ins_str != tmp && ins_str != cd->Buffer)
559 RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str);
560
561 collapse_path( buffer, mark );
562 reqsize = wcslen(buffer) * sizeof(WCHAR);
563
564 done:
565 RtlReleasePebLock();
566 return reqsize;
567 }
568
569
570 /******************************************************************
571 * RtlGetFullPathName_U (NTDLL.@)
572 *
573 * Returns the number of bytes written to buffer (not including the
574 * terminating NULL) if the function succeeds, or the required number of bytes
575 * (including the terminating NULL) if the buffer is too small.
576 *
577 * file_part will point to the filename part inside buffer (except if we use
578 * DOS device name, in which case file_in_buf is NULL)
579 *
580 * @implemented
581 */
582 ULONG NTAPI RtlGetFullPathName_U(
583 const WCHAR* name,
584 ULONG size,
585 WCHAR* buffer,
586 WCHAR** file_part)
587 {
588 WCHAR* ptr;
589 ULONG dosdev;
590 ULONG reqsize;
591
592 DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
593
594 if (!name || !*name) return 0;
595
596 if (file_part) *file_part = NULL;
597
598 /* check for DOS device name */
599 dosdev = RtlIsDosDeviceName_U((WCHAR*)name);
600 if (dosdev)
601 {
602 DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
603 DWORD sz = LOWORD(dosdev); /* in bytes */
604
605 if (8 + sz + 2 > size) return sz + 10;
606 wcscpy(buffer, DeviceRootW);
607 memmove(buffer + 4, name + offset, sz);
608 buffer[4 + sz / sizeof(WCHAR)] = '\0';
609 /* file_part isn't set in this case */
610 return sz + 8;
611 }
612
613 reqsize = get_full_path_helper(name, buffer, size);
614 if (!reqsize) return 0;
615 if (reqsize > size)
616 {
617 LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize);
618 if (tmp == NULL)
619 return 0;
620 reqsize = get_full_path_helper(name, tmp, reqsize);
621 if (reqsize > size) /* it may have worked the second time */
622 {
623 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
624 return reqsize + sizeof(WCHAR);
625 }
626 memcpy( buffer, tmp, reqsize + sizeof(WCHAR) );
627 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
628 }
629
630 /* find file part */
631 if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr)
632 *file_part = ptr;
633 return reqsize;
634 }
635
636
637 /*
638 * @implemented
639 */
640 BOOLEAN NTAPI
641 RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName,
642 OUT PUNICODE_STRING NtPathName,
643 OUT PCWSTR *NtFileNamePart,
644 OUT CURDIR *DirectoryInfo)
645 {
646 UNICODE_STRING us;
647 PCURDIR cd;
648 ULONG Type;
649 ULONG Size;
650 ULONG Length;
651 ULONG tmpLength;
652 ULONG Offset;
653 WCHAR fullname[MAX_PATH + 1];
654 PWSTR Buffer = NULL;
655
656 RtlInitUnicodeString (&us, DosPathName);
657 if (us.Length > 8)
658 {
659 Buffer = us.Buffer;
660 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
661 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
662 Buffer[2] == L'?' && Buffer[3] == L'\\')
663 {
664 /* allocate the new string and simply copy it */
665 NtPathName->Length = us.Length;
666 NtPathName->MaximumLength = us.Length + sizeof(WCHAR);
667 NtPathName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
668 0,
669 NtPathName->MaximumLength);
670 if (NtPathName->Buffer == NULL)
671 {
672 return FALSE;
673 }
674
675 /* copy the string */
676 RtlCopyMemory(NtPathName->Buffer,
677 us.Buffer,
678 NtPathName->Length);
679 NtPathName->Buffer[us.Length / sizeof(WCHAR)] = L'\0';
680
681 /* change the \\?\ prefix to \??\ */
682 NtPathName->Buffer[1] = L'?';
683
684 if (NtFileNamePart != NULL)
685 {
686 PWSTR FilePart = NULL;
687 PWSTR s;
688
689 /* try to find the last separator */
690 s = NtPathName->Buffer + (NtPathName->Length / sizeof(WCHAR));
691 while (s != NtPathName->Buffer)
692 {
693 if (*s == L'\\')
694 {
695 FilePart = s + 1;
696 break;
697 }
698 s--;
699 }
700
701 *NtFileNamePart = FilePart;
702 }
703
704 if (DirectoryInfo != NULL)
705 {
706 DirectoryInfo->DosPath.Length = 0;
707 DirectoryInfo->DosPath.MaximumLength = 0;
708 DirectoryInfo->DosPath.Buffer = NULL;
709 DirectoryInfo->Handle = NULL;
710 }
711
712 return TRUE;
713 }
714 }
715
716 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
717 0,
718 sizeof( fullname ) + MAX_PFX_SIZE);
719 if (Buffer == NULL)
720 {
721 return FALSE;
722 }
723
724 RtlAcquirePebLock ();
725
726 Size = RtlGetFullPathName_U (DosPathName,
727 sizeof(fullname),
728 fullname,
729 (PWSTR*)NtFileNamePart);
730 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
731 {
732 RtlFreeHeap (RtlGetProcessHeap (),
733 0,
734 Buffer);
735 RtlReleasePebLock ();
736 return FALSE;
737 }
738
739 /* Set NT prefix */
740 Offset = 0;
741 memcpy (Buffer, L"\\??\\", 4 * sizeof(WCHAR));
742 tmpLength = 4;
743
744 Type = RtlDetermineDosPathNameType_U (fullname);
745 switch (Type)
746 {
747 case 1:
748 memcpy (Buffer + tmpLength, L"UNC\\", 4 * sizeof(WCHAR));
749 tmpLength += 4;
750 Offset = 2;
751 break; /* \\xxx */
752
753 case 6:
754 Offset = 4;
755 break; /* \\.\xxx */
756 }
757 Length = wcslen(fullname + Offset);
758 memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
759 Length += tmpLength;
760 if (Type == RtlPathTypeDriveAbsolute ||
761 Type == RtlPathTypeDriveRelative)
762 {
763 /* make the drive letter to uppercase */
764 Buffer[tmpLength] = towupper(Buffer[tmpLength]);
765 }
766
767 /* set NT filename */
768 NtPathName->Length = Length * sizeof(WCHAR);
769 NtPathName->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
770 NtPathName->Buffer = Buffer;
771
772 /* set pointer to file part if possible */
773 if (NtFileNamePart && *NtFileNamePart)
774 *NtFileNamePart = Buffer + Length - wcslen (*NtFileNamePart);
775
776 /* Set name and handle structure if possible */
777 if (DirectoryInfo)
778 {
779 memset (DirectoryInfo, 0, sizeof(CURDIR));
780 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath);
781 if (Type == 5 && cd->Handle)
782 {
783 RtlInitUnicodeString(&us, fullname);
784 if (RtlEqualUnicodeString(&us, &cd->DosPath, TRUE))
785 {
786 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
787 DirectoryInfo->DosPath.Buffer = Buffer + Length;
788 DirectoryInfo->DosPath.Length = NtPathName->Length - (Length * sizeof(WCHAR));
789 DirectoryInfo->DosPath.MaximumLength = DirectoryInfo->DosPath.Length;
790 DirectoryInfo->Handle = cd->Handle;
791 }
792 }
793 }
794
795 RtlReleasePebLock();
796 return TRUE;
797 }
798
799
800 /*
801 * @implemented
802 */
803 ULONG
804 NTAPI
805 RtlDosSearchPath_U (
806 PCWSTR sp,
807 PCWSTR name,
808 PCWSTR ext,
809 ULONG buf_sz,
810 WCHAR *buffer,
811 PWSTR *FilePart
812 )
813 {
814 ULONG Type;
815 ULONG Length = 0;
816 PWSTR full_name;
817 PWSTR wcs;
818 PCWSTR path;
819
820 Type = RtlDetermineDosPathNameType_U (name);
821
822 if (Type == 5)
823 {
824 Length = wcslen (sp);
825 Length += wcslen (name);
826 if (wcschr (name, L'.'))
827 ext = NULL;
828 if (ext != NULL)
829 Length += wcslen (ext);
830
831 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
832 0,
833 (Length + 1) * sizeof(WCHAR));
834 Length = 0;
835 if (full_name != NULL)
836 {
837 path = sp;
838 while (*path)
839 {
840 wcs = full_name;
841 while (*path && *path != L';')
842 *wcs++ = *path++;
843 if (*path)
844 path++;
845 if (wcs != full_name && *(wcs - 1) != L'\\')
846 *wcs++ = L'\\';
847 wcscpy (wcs, name);
848 if (ext)
849 wcscat (wcs, ext);
850 if (RtlDoesFileExists_U (full_name))
851 {
852 Length = RtlGetFullPathName_U (full_name,
853 buf_sz,
854 buffer,
855 FilePart);
856 break;
857 }
858 }
859
860 RtlFreeHeap (RtlGetProcessHeap (),
861 0,
862 full_name);
863 }
864 }
865 else if (RtlDoesFileExists_U (name))
866 {
867 Length = RtlGetFullPathName_U (name,
868 buf_sz,
869 buffer,
870 FilePart);
871 }
872
873 return Length;
874 }
875
876
877 /*
878 * @implemented
879 */
880 BOOLEAN NTAPI
881 RtlDoesFileExists_U(IN PCWSTR FileName)
882 {
883 UNICODE_STRING NtFileName;
884 OBJECT_ATTRIBUTES Attr;
885 FILE_BASIC_INFORMATION Info;
886 NTSTATUS Status;
887 CURDIR CurDir;
888
889
890 if (!RtlDosPathNameToNtPathName_U (FileName,
891 &NtFileName,
892 NULL,
893 &CurDir))
894 return FALSE;
895
896 if (CurDir.DosPath.Length)
897 NtFileName = CurDir.DosPath;
898 else
899 CurDir.Handle = 0;
900
901 InitializeObjectAttributes (&Attr,
902 &NtFileName,
903 OBJ_CASE_INSENSITIVE,
904 CurDir.Handle,
905 NULL);
906
907 Status = ZwQueryAttributesFile (&Attr, &Info);
908
909 RtlFreeUnicodeString(&NtFileName);
910
911
912 if (NT_SUCCESS(Status) ||
913 Status == STATUS_SHARING_VIOLATION ||
914 Status == STATUS_ACCESS_DENIED)
915 return TRUE;
916
917 return FALSE;
918 }
919
920
921 /*
922 * @unimplemented
923 */
924 BOOLEAN NTAPI
925 RtlDosPathNameToRelativeNtPathName_U(PVOID Unknown1,
926 PVOID Unknown2,
927 PVOID Unknown3,
928 PVOID Unknown4)
929 {
930 DPRINT1("RtlDosPathNameToRelativeNtPathName_U(0x%p, 0x%p, 0x%p, 0x%p) UNIMPLEMENTED!\n",
931 Unknown1, Unknown2, Unknown3, Unknown4);
932 return FALSE;
933 }
934
935
936 /*
937 * @unimplemented
938 */
939 VOID NTAPI
940 RtlReleaseRelativeName(PVOID Unknown)
941 {
942 DPRINT1("RtlReleaseRelativeName(0x%p) UNIMPLEMENTED\n", Unknown);
943 }
944
945 NTSTATUS NTAPI
946 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
947 {
948 DPRINT1("RtlpEnsureBufferSize: stub\n");
949 return STATUS_NOT_IMPLEMENTED;
950 }
951
952 NTSTATUS NTAPI
953 RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
954 {
955 DPRINT1("RtlNtPathNameToDosPathName: stub\n");
956 return STATUS_NOT_IMPLEMENTED;
957 }
958
959 /* EOF */