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