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