- Remove deprecated CHECKPOINT/CHECKPOINT1 macros which basically translated into...
[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[1] || 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 UNICODE_STRING envvar;
211 FILE_FS_DEVICE_INFORMATION device_info;
212 OBJECT_ATTRIBUTES Attr;
213 IO_STATUS_BLOCK iosb;
214 PCURDIR cd;
215 NTSTATUS Status;
216 ULONG size;
217 HANDLE handle = NULL;
218 WCHAR var[4];
219 PWSTR ptr;
220
221 DPRINT("RtlSetCurrentDirectory %wZ\n", dir);
222
223 RtlAcquirePebLock ();
224
225 cd = (PCURDIR)&NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath;
226
227 if (!RtlDosPathNameToNtPathName_U (dir->Buffer, &full, 0, 0))
228 {
229 RtlReleasePebLock ();
230 return STATUS_OBJECT_NAME_INVALID;
231 }
232
233 DPRINT("RtlSetCurrentDirectory: full %wZ\n",&full);
234
235 InitializeObjectAttributes (&Attr,
236 &full,
237 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
238 NULL,
239 NULL);
240
241 Status = ZwOpenFile (&handle,
242 SYNCHRONIZE | FILE_TRAVERSE,
243 &Attr,
244 &iosb,
245 FILE_SHARE_READ | FILE_SHARE_WRITE,
246 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
247
248 if (!NT_SUCCESS(Status))
249 {
250 RtlFreeUnicodeString( &full);
251 RtlReleasePebLock ();
252 return Status;
253 }
254
255 /* don't keep the directory handle open on removable media */
256 if (NT_SUCCESS(ZwQueryVolumeInformationFile( handle, &iosb, &device_info,
257 sizeof(device_info), FileFsDeviceInformation )) &&
258 (device_info.Characteristics & FILE_REMOVABLE_MEDIA))
259 {
260 DPRINT1("don't keep the directory handle open on removable media\n");
261 ZwClose( handle );
262 handle = 0;
263 }
264
265 if (cd->Handle)
266 ZwClose(cd->Handle);
267 cd->Handle = handle;
268
269 /* append trailing \ if missing */
270 size = full.Length / sizeof(WCHAR);
271 ptr = full.Buffer;
272 ptr += 4; /* skip \??\ prefix */
273 size -= 4;
274
275 /* This is ok because RtlDosPathNameToNtPathName_U returns a nullterminated string.
276 * So the nullterm is replaced with \
277 * -Gunnar
278 */
279 if (size && ptr[size - 1] != '\\') ptr[size++] = '\\';
280
281 memcpy( cd->DosPath.Buffer, ptr, size * sizeof(WCHAR));
282 cd->DosPath.Buffer[size] = 0;
283 cd->DosPath.Length = size * sizeof(WCHAR);
284
285
286 /* FIXME: whats this all about??? Wine doesnt have this. -Gunnar */
287 if (cd->DosPath.Buffer[1]==':')
288 {
289 envvar.Length = 2 * swprintf (var, L"=%c:", cd->DosPath.Buffer[0]);
290 envvar.MaximumLength = 8;
291 envvar.Buffer = var;
292
293 RtlSetEnvironmentVariable(NULL,
294 &envvar,
295 &cd->DosPath);
296 }
297
298 RtlFreeUnicodeString( &full);
299 RtlReleasePebLock();
300
301 return STATUS_SUCCESS;
302 }
303
304
305
306 /******************************************************************
307 * collapse_path
308 *
309 * Helper for RtlGetFullPathName_U.
310 * 1) Convert slashes into backslashes
311 * 2) Get rid of duplicate backslashes
312 * 3) Get rid of . and .. components in the path.
313 */
314 static __inline void collapse_path( WCHAR *path, UINT mark )
315 {
316 WCHAR *p, *next;
317
318 /* convert every / into a \ */
319 for (p = path; *p; p++) if (*p == '/') *p = '\\';
320
321 /* collapse duplicate backslashes */
322 next = path + max( 1, mark );
323 for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p;
324 *next = 0;
325
326 p = path + mark;
327 while (*p)
328 {
329 if (*p == '.')
330 {
331 switch(p[1])
332 {
333 case '\\': /* .\ component */
334 next = p + 2;
335 memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
336 continue;
337 case 0: /* final . */
338 if (p > path + mark) p--;
339 *p = 0;
340 continue;
341 case '.':
342 if (p[2] == '\\') /* ..\ component */
343 {
344 next = p + 3;
345 if (p > path + mark)
346 {
347 p--;
348 while (p > path + mark && p[-1] != '\\') p--;
349 }
350 memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) );
351 continue;
352 }
353 else if (!p[2]) /* final .. */
354 {
355 if (p > path + mark)
356 {
357 p--;
358 while (p > path + mark && p[-1] != '\\') p--;
359 if (p > path + mark) p--;
360 }
361 *p = 0;
362 continue;
363 }
364 break;
365 }
366 }
367 /* skip to the next component */
368 while (*p && *p != '\\') p++;
369 if (*p == '\\')
370 {
371 /* remove last dot in previous dir name */
372 if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) );
373 else p++;
374 }
375 }
376
377 /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */
378 while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--;
379 *p = 0;
380 }
381
382
383
384 /******************************************************************
385 * skip_unc_prefix
386 *
387 * Skip the \\share\dir\ part of a file name. Helper for RtlGetFullPathName_U.
388 */
389 static const WCHAR *skip_unc_prefix( const WCHAR *ptr )
390 {
391 ptr += 2;
392 while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* share name */
393 while (IS_PATH_SEPARATOR(*ptr)) ptr++;
394 while (*ptr && !IS_PATH_SEPARATOR(*ptr)) ptr++; /* dir name */
395 while (IS_PATH_SEPARATOR(*ptr)) ptr++;
396 return ptr;
397 }
398
399
400 /******************************************************************
401 * get_full_path_helper
402 *
403 * Helper for RtlGetFullPathName_U
404 * Note: name and buffer are allowed to point to the same memory spot
405 */
406 static ULONG get_full_path_helper(
407 LPCWSTR name,
408 LPWSTR buffer,
409 ULONG size)
410 {
411 ULONG reqsize = 0, mark = 0, dep = 0, deplen;
412 RTL_PATH_TYPE type;
413 LPWSTR ins_str = NULL;
414 LPCWSTR ptr;
415 const UNICODE_STRING* cd;
416 WCHAR tmp[4];
417
418 /* return error if name only consists of spaces */
419 for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break;
420 if (!*ptr) return 0;
421
422 RtlAcquirePebLock();
423
424 //cd = &((PCURDIR)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath)->DosPath;
425 cd = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CurrentDirectory.DosPath;
426
427 switch (type = RtlDetermineDosPathNameType_U(name))
428 {
429 case RtlPathTypeUncAbsolute: /* \\foo */
430 ptr = skip_unc_prefix( name );
431 mark = (ptr - name);
432 break;
433
434 case RtlPathTypeLocalDevice: /* \\.\foo */
435 mark = 4;
436 break;
437
438 case RtlPathTypeDriveAbsolute: /* c:\foo */
439 reqsize = sizeof(WCHAR);
440 tmp[0] = towupper(name[0]);
441 ins_str = tmp;
442 dep = 1;
443 mark = 3;
444 break;
445
446 case RtlPathTypeDriveRelative: /* c:foo */
447 dep = 2;
448 if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':')
449 {
450 UNICODE_STRING var, val;
451
452 tmp[0] = '=';
453 tmp[1] = name[0];
454 tmp[2] = ':';
455 tmp[3] = '\0';
456 var.Length = 3 * sizeof(WCHAR);
457 var.MaximumLength = 4 * sizeof(WCHAR);
458 var.Buffer = tmp;
459 val.Length = 0;
460 val.MaximumLength = size;
461 val.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, size);
462 if (val.Buffer == NULL)
463 {
464 reqsize = 0;
465 goto done;
466 }
467
468 switch (RtlQueryEnvironmentVariable_U(NULL, &var, &val))
469 {
470 case STATUS_SUCCESS:
471 /* FIXME: Win2k seems to check that the environment variable actually points
472 * to an existing directory. If not, root of the drive is used
473 * (this seems also to be the only spot in RtlGetFullPathName that the
474 * existence of a part of a path is checked)
475 */
476 /* fall thru */
477 case STATUS_BUFFER_TOO_SMALL:
478 reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */
479 val.Buffer[val.Length / sizeof(WCHAR)] = '\\';
480 ins_str = val.Buffer;
481 break;
482 case STATUS_VARIABLE_NOT_FOUND:
483 reqsize = 3 * sizeof(WCHAR);
484 tmp[0] = name[0];
485 tmp[1] = ':';
486 tmp[2] = '\\';
487 ins_str = tmp;
488 break;
489 default:
490 DPRINT1("Unsupported status code\n");
491 break;
492 }
493 mark = 3;
494 break;
495 }
496 /* fall through */
497
498 case RtlPathTypeRelative: /* foo */
499 reqsize = cd->Length;
500 ins_str = cd->Buffer;
501 if (cd->Buffer[1] != ':')
502 {
503 ptr = skip_unc_prefix( cd->Buffer );
504 mark = ptr - cd->Buffer;
505 }
506 else mark = 3;
507 break;
508
509 case RtlPathTypeRooted: /* \xxx */
510 #ifdef __WINE__
511 if (name[0] == '/') /* may be a Unix path */
512 {
513 const WCHAR *ptr = name;
514 int drive = find_drive_root( &ptr );
515 if (drive != -1)
516 {
517 reqsize = 3 * sizeof(WCHAR);
518 tmp[0] = 'A' + drive;
519 tmp[1] = ':';
520 tmp[2] = '\\';
521 ins_str = tmp;
522 mark = 3;
523 dep = ptr - name;
524 break;
525 }
526 }
527 #endif
528 if (cd->Buffer[1] == ':')
529 {
530 reqsize = 2 * sizeof(WCHAR);
531 tmp[0] = cd->Buffer[0];
532 tmp[1] = ':';
533 ins_str = tmp;
534 mark = 3;
535 }
536 else
537 {
538 ptr = skip_unc_prefix( cd->Buffer );
539 reqsize = (ptr - cd->Buffer) * sizeof(WCHAR);
540 mark = reqsize / sizeof(WCHAR);
541 ins_str = cd->Buffer;
542 }
543 break;
544
545 case RtlPathTypeRootLocalDevice: /* \\. */
546 reqsize = 4 * sizeof(WCHAR);
547 dep = 3;
548 tmp[0] = '\\';
549 tmp[1] = '\\';
550 tmp[2] = '.';
551 tmp[3] = '\\';
552 ins_str = tmp;
553 mark = 4;
554 break;
555
556 case RtlPathTypeUnknown:
557 goto done;
558 }
559
560 /* enough space ? */
561 deplen = wcslen(name + dep) * sizeof(WCHAR);
562 if (reqsize + deplen + sizeof(WCHAR) > size)
563 {
564 /* not enough space, return need size (including terminating '\0') */
565 reqsize += deplen + sizeof(WCHAR);
566 goto done;
567 }
568
569 memmove(buffer + reqsize / sizeof(WCHAR), name + dep, deplen + sizeof(WCHAR));
570 if (reqsize) memcpy(buffer, ins_str, reqsize);
571 reqsize += deplen;
572
573 if (ins_str && ins_str != tmp && ins_str != cd->Buffer)
574 RtlFreeHeap(RtlGetProcessHeap(), 0, ins_str);
575
576 collapse_path( buffer, mark );
577 reqsize = wcslen(buffer) * sizeof(WCHAR);
578
579 done:
580 RtlReleasePebLock();
581 return reqsize;
582 }
583
584
585 /******************************************************************
586 * RtlGetFullPathName_U (NTDLL.@)
587 *
588 * Returns the number of bytes written to buffer (not including the
589 * terminating NULL) if the function succeeds, or the required number of bytes
590 * (including the terminating NULL) if the buffer is too small.
591 *
592 * file_part will point to the filename part inside buffer (except if we use
593 * DOS device name, in which case file_in_buf is NULL)
594 *
595 * @implemented
596 */
597 ULONG NTAPI RtlGetFullPathName_U(
598 const WCHAR* name,
599 ULONG size,
600 WCHAR* buffer,
601 WCHAR** file_part)
602 {
603 WCHAR* ptr;
604 ULONG dosdev;
605 ULONG reqsize;
606
607 DPRINT("RtlGetFullPathName_U(%S %lu %p %p)\n", name, size, buffer, file_part);
608
609 if (!name || !*name) return 0;
610
611 if (file_part) *file_part = NULL;
612
613 /* check for DOS device name */
614 dosdev = RtlIsDosDeviceName_U((WCHAR*)name);
615 if (dosdev)
616 {
617 DWORD offset = HIWORD(dosdev) / sizeof(WCHAR); /* get it in WCHARs, not bytes */
618 DWORD sz = LOWORD(dosdev); /* in bytes */
619
620 if (8 + sz + 2 > size) return sz + 10;
621 wcscpy(buffer, DeviceRootW);
622 memmove(buffer + 4, name + offset, sz);
623 buffer[4 + sz / sizeof(WCHAR)] = '\0';
624 /* file_part isn't set in this case */
625 return sz + 8;
626 }
627
628 reqsize = get_full_path_helper(name, buffer, size);
629 if (!reqsize) return 0;
630 if (reqsize > size)
631 {
632 LPWSTR tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, reqsize);
633 if (tmp == NULL)
634 return 0;
635 reqsize = get_full_path_helper(name, tmp, reqsize);
636 if (reqsize > size) /* it may have worked the second time */
637 {
638 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
639 return reqsize + sizeof(WCHAR);
640 }
641 memcpy( buffer, tmp, reqsize + sizeof(WCHAR) );
642 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp);
643 }
644
645 /* find file part */
646 if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr)
647 *file_part = ptr;
648 return reqsize;
649 }
650
651
652 /*
653 * @implemented
654 */
655 BOOLEAN NTAPI
656 RtlDosPathNameToNtPathName_U(IN PCWSTR DosPathName,
657 OUT PUNICODE_STRING NtPathName,
658 OUT PCWSTR *NtFileNamePart,
659 OUT CURDIR *DirectoryInfo)
660 {
661 UNICODE_STRING us;
662 PCURDIR cd;
663 ULONG Type;
664 ULONG Size;
665 ULONG Length;
666 ULONG tmpLength;
667 ULONG Offset;
668 WCHAR fullname[MAX_PATH + 1];
669 PWSTR Buffer = NULL;
670
671 RtlInitUnicodeString (&us, DosPathName);
672 if (us.Length > 8)
673 {
674 Buffer = us.Buffer;
675 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
676 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
677 Buffer[2] == L'?' && Buffer[3] == L'\\')
678 {
679 /* allocate the new string and simply copy it */
680 NtPathName->Length = us.Length;
681 NtPathName->MaximumLength = us.Length + sizeof(WCHAR);
682 NtPathName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
683 0,
684 NtPathName->MaximumLength);
685 if (NtPathName->Buffer == NULL)
686 {
687 return FALSE;
688 }
689
690 /* copy the string */
691 RtlCopyMemory(NtPathName->Buffer,
692 us.Buffer,
693 NtPathName->Length);
694 NtPathName->Buffer[us.Length / sizeof(WCHAR)] = L'\0';
695
696 /* change the \\?\ prefix to \??\ */
697 NtPathName->Buffer[1] = L'?';
698
699 if (NtFileNamePart != NULL)
700 {
701 PWSTR FilePart = NULL;
702 PWSTR s;
703
704 /* try to find the last separator */
705 s = NtPathName->Buffer + (NtPathName->Length / sizeof(WCHAR));
706 while (s != NtPathName->Buffer)
707 {
708 if (*s == L'\\')
709 {
710 FilePart = s + 1;
711 break;
712 }
713 s--;
714 }
715
716 *NtFileNamePart = FilePart;
717 }
718
719 if (DirectoryInfo != NULL)
720 {
721 DirectoryInfo->DosPath.Length = 0;
722 DirectoryInfo->DosPath.MaximumLength = 0;
723 DirectoryInfo->DosPath.Buffer = NULL;
724 DirectoryInfo->Handle = NULL;
725 }
726
727 return TRUE;
728 }
729 }
730
731 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
732 0,
733 sizeof( fullname ) + MAX_PFX_SIZE);
734 if (Buffer == NULL)
735 {
736 return FALSE;
737 }
738
739 RtlAcquirePebLock ();
740
741 Size = RtlGetFullPathName_U (DosPathName,
742 sizeof(fullname),
743 fullname,
744 (PWSTR*)NtFileNamePart);
745 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
746 {
747 RtlFreeHeap (RtlGetProcessHeap (),
748 0,
749 Buffer);
750 RtlReleasePebLock ();
751 return FALSE;
752 }
753
754 /* Set NT prefix */
755 Offset = 0;
756 memcpy (Buffer, L"\\??\\", 4 * sizeof(WCHAR));
757 tmpLength = 4;
758
759 Type = RtlDetermineDosPathNameType_U (fullname);
760 switch (Type)
761 {
762 case 1:
763 memcpy (Buffer + tmpLength, L"UNC\\", 4 * sizeof(WCHAR));
764 tmpLength += 4;
765 Offset = 2;
766 break; /* \\xxx */
767
768 case 6:
769 Offset = 4;
770 break; /* \\.\xxx */
771 }
772 Length = wcslen(fullname + Offset);
773 memcpy (Buffer + tmpLength, fullname + Offset, (Length + 1) * sizeof(WCHAR));
774 Length += tmpLength;
775 if (Type == RtlPathTypeDriveAbsolute ||
776 Type == RtlPathTypeDriveRelative)
777 {
778 /* make the drive letter to uppercase */
779 Buffer[tmpLength] = towupper(Buffer[tmpLength]);
780 }
781
782 /* set NT filename */
783 NtPathName->Length = Length * sizeof(WCHAR);
784 NtPathName->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
785 NtPathName->Buffer = Buffer;
786
787 /* set pointer to file part if possible */
788 if (NtFileNamePart && *NtFileNamePart)
789 *NtFileNamePart = Buffer + Length - wcslen (*NtFileNamePart);
790
791 /* Set name and handle structure if possible */
792 if (DirectoryInfo)
793 {
794 memset (DirectoryInfo, 0, sizeof(CURDIR));
795 cd = (PCURDIR)&(NtCurrentPeb ()->ProcessParameters->CurrentDirectory.DosPath);
796 if (Type == 5 && cd->Handle)
797 {
798 RtlInitUnicodeString(&us, fullname);
799 if (RtlEqualUnicodeString(&us, &cd->DosPath, TRUE))
800 {
801 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
802 DirectoryInfo->DosPath.Buffer = Buffer + Length;
803 DirectoryInfo->DosPath.Length = NtPathName->Length - (Length * sizeof(WCHAR));
804 DirectoryInfo->DosPath.MaximumLength = DirectoryInfo->DosPath.Length;
805 DirectoryInfo->Handle = cd->Handle;
806 }
807 }
808 }
809
810 RtlReleasePebLock();
811 return TRUE;
812 }
813
814
815 /*
816 * @implemented
817 */
818 ULONG
819 NTAPI
820 RtlDosSearchPath_U (
821 PCWSTR sp,
822 PCWSTR name,
823 PCWSTR ext,
824 ULONG buf_sz,
825 WCHAR *buffer,
826 PWSTR *FilePart
827 )
828 {
829 ULONG Type;
830 ULONG Length = 0;
831 PWSTR full_name;
832 PWSTR wcs;
833 PCWSTR path;
834
835 Type = RtlDetermineDosPathNameType_U (name);
836
837 if (Type == 5)
838 {
839 Length = wcslen (sp);
840 Length += wcslen (name);
841 if (wcschr (name, L'.'))
842 ext = NULL;
843 if (ext != NULL)
844 Length += wcslen (ext);
845
846 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
847 0,
848 (Length + 1) * sizeof(WCHAR));
849 Length = 0;
850 if (full_name != NULL)
851 {
852 path = sp;
853 while (*path)
854 {
855 wcs = full_name;
856 while (*path && *path != L';')
857 *wcs++ = *path++;
858 if (*path)
859 path++;
860 if (wcs != full_name && *(wcs - 1) != L'\\')
861 *wcs++ = L'\\';
862 wcscpy (wcs, name);
863 if (ext)
864 wcscat (wcs, ext);
865 if (RtlDoesFileExists_U (full_name))
866 {
867 Length = RtlGetFullPathName_U (full_name,
868 buf_sz,
869 buffer,
870 FilePart);
871 break;
872 }
873 }
874
875 RtlFreeHeap (RtlGetProcessHeap (),
876 0,
877 full_name);
878 }
879 }
880 else if (RtlDoesFileExists_U (name))
881 {
882 Length = RtlGetFullPathName_U (name,
883 buf_sz,
884 buffer,
885 FilePart);
886 }
887
888 return Length;
889 }
890
891
892 /*
893 * @implemented
894 */
895 BOOLEAN NTAPI
896 RtlDoesFileExists_U(IN PCWSTR FileName)
897 {
898 UNICODE_STRING NtFileName;
899 OBJECT_ATTRIBUTES Attr;
900 FILE_BASIC_INFORMATION Info;
901 NTSTATUS Status;
902 CURDIR CurDir;
903
904
905 if (!RtlDosPathNameToNtPathName_U (FileName,
906 &NtFileName,
907 NULL,
908 &CurDir))
909 return FALSE;
910
911 if (CurDir.DosPath.Length)
912 NtFileName = CurDir.DosPath;
913 else
914 CurDir.Handle = 0;
915
916 InitializeObjectAttributes (&Attr,
917 &NtFileName,
918 OBJ_CASE_INSENSITIVE,
919 CurDir.Handle,
920 NULL);
921
922 Status = ZwQueryAttributesFile (&Attr, &Info);
923
924 RtlFreeUnicodeString(&NtFileName);
925
926
927 if (NT_SUCCESS(Status) ||
928 Status == STATUS_SHARING_VIOLATION ||
929 Status == STATUS_ACCESS_DENIED)
930 return TRUE;
931
932 return FALSE;
933 }
934
935
936 /*
937 * @unimplemented
938 */
939 BOOLEAN NTAPI
940 RtlDosPathNameToRelativeNtPathName_U(PVOID Unknown1,
941 PVOID Unknown2,
942 PVOID Unknown3,
943 PVOID Unknown4)
944 {
945 DPRINT1("RtlDosPathNameToRelativeNtPathName_U(0x%p, 0x%p, 0x%p, 0x%p) UNIMPLEMENTED!\n",
946 Unknown1, Unknown2, Unknown3, Unknown4);
947 return FALSE;
948 }
949
950
951 /*
952 * @unimplemented
953 */
954 VOID NTAPI
955 RtlReleaseRelativeName(PVOID Unknown)
956 {
957 DPRINT1("RtlReleaseRelativeName(0x%p) UNIMPLEMENTED\n", Unknown);
958 }
959
960 NTSTATUS NTAPI
961 RtlpEnsureBufferSize(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
962 {
963 DPRINT1("RtlpEnsureBufferSize: stub\n");
964 return STATUS_NOT_IMPLEMENTED;
965 }
966
967 NTSTATUS NTAPI
968 RtlNtPathNameToDosPathName(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
969 {
970 DPRINT1("RtlNtPathNameToDosPathName: stub\n");
971 return STATUS_NOT_IMPLEMENTED;
972 }
973
974 /* EOF */