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