Current directory now always with correct casing.
[reactos.git] / reactos / lib / ntdll / rtl / path.c
1 /* $Id: path.c,v 1.7 2001/03/07 22:29:09 cnettel Exp $
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 <string.h>
16 #include <stdio.h>
17 #include <ctype.h>
18
19 #define NDEBUG
20 #include <ntdll/ntdll.h>
21
22 /* DEFINITONS and MACROS ******************************************************/
23
24 #define MAX_PFX_SIZE 16
25
26 #define IS_PATH_SEPARATOR(x) (((x)==L'\\')||((x)==L'/'))
27
28
29 /* FUNCTIONS *****************************************************************/
30
31
32 static ULONG RtlpGetDotSequence (PWSTR p)
33 {
34 ULONG Count = 0;
35
36 for (;;)
37 {
38 if (*p == '.')
39 Count++;
40 else if ((*p == '\\' || *p == '\0') && Count)
41 return Count;
42 else
43 return 0;
44 p++;
45 }
46 return 0;
47 }
48
49
50 static VOID RtlpEatPath (PWSTR Path)
51 {
52 PWSTR p, prev;
53
54 p = Path + 2;
55 prev = p;
56
57 while ((*p) != 0 || ((*p) == L'\\' && (*(p+1)) == 0))
58 {
59 ULONG DotLen;
60
61 DotLen = RtlpGetDotSequence (p+1);
62 DPRINT("DotSequenceLength %u\n", DotLen);
63 DPRINT("prev %S p %S\n",prev,p);
64
65 if (DotLen == 0)
66 {
67 prev = p;
68 do
69 {
70 p++;
71 }
72 while ((*p) != 0 && (*p) != L'\\');
73 }
74 else if (DotLen == 1)
75 {
76 wcscpy (p, p+2);
77 }
78 else
79 {
80 if (DotLen > 2)
81 {
82 int n = DotLen - 2;
83
84 while (n > 0 && prev > (Path + 2))
85 {
86 prev--;
87 if ((*prev) == L'\\')
88 n--;
89 }
90 }
91
92 if (*(p + DotLen + 1) == 0)
93 *(prev + 1) = 0;
94 else
95 wcscpy (prev, p + DotLen + 1);
96 p = prev;
97 if (prev > (Path + 2))
98 {
99 prev--;
100 while ((*prev) != L'\\')
101 {
102 prev--;
103 }
104 }
105 }
106 }
107 }
108
109
110 ULONG STDCALL RtlGetLongestNtPathLength (VOID)
111 {
112 return (MAX_PATH + 9);
113 }
114
115
116 ULONG
117 STDCALL
118 RtlDetermineDosPathNameType_U (
119 PWSTR Path
120 )
121 {
122 // DPRINT ("RtlDetermineDosPathNameType_U %S\n", Path);
123
124 if (Path == NULL)
125 return 0;
126
127 if (IS_PATH_SEPARATOR(Path[0]))
128 {
129 if (!IS_PATH_SEPARATOR(Path[1]))
130 return 4; /* \xxx */
131
132 if (Path[2] != L'.')
133 return 1; /* \\xxx */
134
135 if (IS_PATH_SEPARATOR(Path[3]))
136 return 6; /* \\.\xxx */
137
138 if (Path[3])
139 return 1; /* \\.xxxx */
140
141 return 7; /* \\. */
142 }
143 else
144 {
145 if (Path[1] != L':')
146 return 5; /* xxx */
147
148 if (IS_PATH_SEPARATOR(Path[2]))
149 return 2; /* x:\xxx */
150
151 return 3; /* x:xxx */
152 }
153 }
154
155
156 /* returns 0 if name is not valid DOS device name, or DWORD with
157 * offset in bytes to DOS device name from beginning of buffer in high word
158 * and size in bytes of DOS device name in low word */
159 ULONG
160 STDCALL
161 RtlIsDosDeviceName_U (
162 PWSTR DeviceName
163 )
164 {
165 ULONG Type;
166 ULONG Length = 0;
167 ULONG Offset;
168 PWCHAR wc;
169
170 if (DeviceName == NULL)
171 return 0;
172
173 while (DeviceName[Length])
174 Length++;
175
176 Type = RtlDetermineDosPathNameType_U (DeviceName);
177 if (Type <= 1)
178 return 0;
179 if (Type == 6)
180 {
181 if (Length == 7 &&
182 !_wcsnicmp (DeviceName, L"\\\\.\\CON", 7))
183 return 0x00080006;
184 return 0;
185 }
186
187 /* name can end with ':' */
188 if (Length && DeviceName[Length - 1 ] == L':')
189 Length--;
190
191 /* there can be spaces or points at the end of name */
192 wc = DeviceName + Length - 1;
193 while (Length && (*wc == L'.' || *wc == L' '))
194 {
195 Length--;
196 wc--;
197 }
198
199 /* let's find a beginning of name */
200 wc = DeviceName + Length - 1;
201 while (wc > DeviceName && !IS_PATH_SEPARATOR(*(wc - 1)))
202 wc--;
203 Offset = wc - DeviceName;
204 Length -= Offset;
205
206 /* check for LPTx or COMx */
207 if (Length == 4 && wc[3] >= L'0' && wc[3] <= L'9')
208 {
209 if (wc[3] == L'0')
210 return 0;
211 if (!_wcsnicmp (wc, L"LPT", 3) ||
212 !_wcsnicmp (wc, L"COM", 3))
213 {
214 return ((Offset * 2) << 16 ) | 8;
215 }
216 return 0;
217 }
218
219 /* check for PRN,AUX,NUL or CON */
220 if (Length == 3 &&
221 (!_wcsnicmp (wc, L"PRN", 3) ||
222 !_wcsnicmp (wc, L"AUX", 3) ||
223 !_wcsnicmp (wc, L"NUL", 3) ||
224 !_wcsnicmp (wc, L"CON", 3)))
225 {
226 return ((Offset * 2) << 16) | 6;
227 }
228
229 return 0;
230 }
231
232
233 ULONG
234 STDCALL
235 RtlGetCurrentDirectory_U (
236 ULONG MaximumLength,
237 PWSTR Buffer
238 )
239 {
240 ULONG Length;
241 PCURDIR cd;
242
243 // DPRINT ("RtlGetCurrentDirectory %lu %p\n", MaximumLength, Buffer);
244
245 cd = &(NtCurrentPeb ()->ProcessParameters->CurrentDirectory);
246
247 RtlAcquirePebLock();
248 Length = cd->DosPath.Length / sizeof(WCHAR);
249 if (cd->DosPath.Buffer[Length - 1] == L'\\' &&
250 cd->DosPath.Buffer[Length - 2] != L':')
251 Length--;
252
253 // DPRINT ("cd->DosPath.Buffer %S Length %d\n",
254 // cd->DosPath.Buffer, Length);
255
256 if (MaximumLength / sizeof(WCHAR) > Length)
257 {
258 memcpy (Buffer,
259 cd->DosPath.Buffer,
260 Length * sizeof(WCHAR));
261 Buffer[Length] = 0;
262 }
263 else
264 {
265 Length++;
266 }
267
268 RtlReleasePebLock ();
269
270 DPRINT ("CurrentDirectory %S\n", Buffer);
271
272 return (Length * sizeof(WCHAR));
273 }
274
275
276 NTSTATUS STDCALL RtlSetCurrentDirectory_U (PUNICODE_STRING name)
277 {
278 UNICODE_STRING full;
279 OBJECT_ATTRIBUTES Attr;
280 IO_STATUS_BLOCK iosb;
281 PCURDIR cd;
282 NTSTATUS Status;
283 ULONG size;
284 HANDLE handle = NULL;
285 PWSTR wcs;
286 PWSTR devpathstart, loopvar;
287 PWSTR buf = 0;
288 PFILE_NAME_INFORMATION objnameinfo;
289 ULONG reslength;
290
291 DPRINT ("RtlSetCurrentDirectory %wZ\n", name);
292
293 RtlAcquirePebLock ();
294 cd = &NtCurrentPeb ()->ProcessParameters->CurrentDirectory;
295 size = cd->DosPath.MaximumLength;
296
297 buf = RtlAllocateHeap (RtlGetProcessHeap(),
298 0,
299 size);
300 if (buf == NULL)
301 {
302 RtlReleasePebLock ();
303 return STATUS_NO_MEMORY;
304 }
305
306 size = RtlGetFullPathName_U (name->Buffer, size, buf, 0);
307 if (!size)
308 {
309 RtlFreeHeap (RtlGetProcessHeap (),
310 0,
311 buf);
312 RtlReleasePebLock ();
313 return STATUS_OBJECT_NAME_INVALID;
314 }
315
316 if (!RtlDosPathNameToNtPathName_U (buf, &full, 0, 0))
317 {
318 RtlFreeHeap (RtlGetProcessHeap (),
319 0,
320 buf);
321 RtlFreeHeap (RtlGetProcessHeap (),
322 0,
323 full.Buffer);
324 RtlReleasePebLock ();
325 return STATUS_OBJECT_NAME_INVALID;
326 }
327
328 InitializeObjectAttributes (&Attr,
329 &full,
330 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
331 NULL,
332 NULL);
333
334 Status = NtOpenFile (&handle,
335 SYNCHRONIZE | FILE_TRAVERSE,
336 &Attr,
337 &iosb,
338 FILE_SHARE_READ | FILE_SHARE_WRITE,
339 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
340
341 objnameinfo = RtlAllocateHeap (RtlGetProcessHeap(),
342 0,
343 cd->DosPath.MaximumLength*sizeof(WCHAR)+4); // A little margin, for Length pre-fix
344
345 NtQueryInformationFile(handle,NULL,objnameinfo,sizeof(OBJECT_NAME_INFORMATION),FileNameInformation);
346
347 devpathstart=buf+wcslen(buf);
348
349 for (loopvar=objnameinfo->FileName;(*loopvar);loopvar++)
350 if ((*loopvar)=='\\')
351 {
352 devpathstart--;
353 for (;devpathstart>buf && (*devpathstart)!='\\';devpathstart--) {}
354 }
355
356 wcscpy(devpathstart, objnameinfo->FileName);
357
358
359 RtlFreeHeap (RtlGetProcessHeap (),
360 0,
361 objnameinfo);
362 if (!NT_SUCCESS(Status))
363 {
364 RtlFreeHeap (RtlGetProcessHeap (),
365 0,
366 buf);
367 RtlFreeHeap (RtlGetProcessHeap (),
368 0,
369 full.Buffer);
370 RtlReleasePebLock ();
371 return Status;
372 }
373
374 /* append backslash if missing */
375 wcs = buf + size / sizeof(WCHAR) - 1;
376 if (*wcs != L'\\')
377 {
378 *(++wcs) = L'\\';
379 *(++wcs) = 0;
380 size += sizeof(WCHAR);
381 }
382
383 memmove (cd->DosPath.Buffer,
384 buf,
385 size + sizeof(WCHAR));
386 cd->DosPath.Length = size;
387
388 if (cd->Handle)
389 NtClose (cd->Handle);
390 cd->Handle = handle;
391
392 RtlFreeHeap (RtlGetProcessHeap (),
393 0,
394 buf);
395
396 RtlFreeHeap (RtlGetProcessHeap (),
397 0,
398 full.Buffer);
399
400 RtlReleasePebLock();
401
402 return STATUS_SUCCESS;
403 }
404
405
406 ULONG
407 STDCALL
408 RtlGetFullPathName_U (
409 PWSTR DosName,
410 ULONG size,
411 PWSTR buf,
412 PWSTR *FilePart
413 )
414 {
415 WCHAR *wcs, var[4], drive;
416 int len;
417 DWORD offs, sz, type;
418 UNICODE_STRING usvar, pfx;
419 PCURDIR cd;
420 NTSTATUS Status;
421
422 // DPRINT("RtlGetFullPathName_U %S %ld %p %p\n",
423 // DosName, size, buf, FilePart);
424
425 if (!DosName || !*DosName)
426 return 0;
427
428 len = wcslen (DosName);
429
430 /* strip trailing spaces */
431 while (len && DosName[len - 1] == L' ')
432 len--;
433 if (!len)
434 return 0;
435
436 /* strip trailing path separator (but don't change '\') */
437 if ((len > 1) &&
438 IS_PATH_SEPARATOR(DosName[len - 1]))
439 len--;
440 if (FilePart)
441 *FilePart = L'\0';
442 memset (buf, 0, size);
443
444 CHECKPOINT;
445 /* check for DOS device name */
446 sz = RtlIsDosDeviceName_U (DosName);
447 if (sz)
448 {
449 offs = sz >> 17;
450 sz &= 0x0000FFFF;
451 if (sz + 8 >= size)
452 return sz + 10;
453 wcscpy (buf, L"\\\\.\\");
454 wcsncat (buf, DosName + offs, sz / sizeof(WCHAR));
455 return sz + 8;
456 }
457
458 CHECKPOINT;
459 type = RtlDetermineDosPathNameType_U (DosName);
460
461 RtlAcquirePebLock();
462
463 cd = &(NtCurrentPeb ()->ProcessParameters->CurrentDirectory);
464 //DPRINT("type %ld\n", type);
465 switch (type)
466 {
467 case 1: /* \\xxx or \\.xxx */
468 case 6: /* \\.\xxx */
469 break;
470
471 case 2: /* x:\xxx */
472 *DosName = towupper (*DosName);
473 break;
474
475 case 3: /* x:xxx */
476 drive = towupper (*DosName);
477 DosName += 2;
478 len -= 2;
479 CHECKPOINT;
480 if (drive == towupper (cd->DosPath.Buffer[0]))
481 {
482 CHECKPOINT;
483 wcscpy (buf, cd->DosPath.Buffer);
484 }
485 else
486 {
487 CHECKPOINT;
488 usvar.Length = 2 * swprintf (var, L"=%c:", drive);
489 usvar.MaximumLength = 8;
490 usvar.Buffer = var;
491 pfx.Length = 0;
492 pfx.MaximumLength = size;
493 pfx.Buffer = buf;
494 Status = RtlQueryEnvironmentVariable_U (NULL,
495 &usvar,
496 &pfx);
497 CHECKPOINT;
498 if (!NT_SUCCESS(Status))
499 {
500 CHECKPOINT;
501 if (Status == STATUS_BUFFER_TOO_SMALL)
502 return pfx.Length + len * 2 + 2;
503 swprintf (buf, L"%c:\\", drive);
504 }
505 else
506 {
507 CHECKPOINT;
508 if (pfx.Length > 6)
509 {
510 CHECKPOINT;
511 buf[pfx.Length / 2] = L'\\';
512 pfx.Length += 2;
513 }
514 }
515 }
516 break;
517
518 case 4: /* \xxx */
519 wcsncpy (buf, cd->DosPath.Buffer, 2);
520 break;
521
522 case 5: /* xxx */
523 wcscpy (buf, cd->DosPath.Buffer);
524 break;
525
526 case 7: /* \\. */
527 wcscpy (buf, L"\\\\.\\");
528 len = 0;
529 break;
530
531 default:
532 return 0;
533 }
534
535 // DPRINT("buf \'%S\' DosName \'%S\' len %ld\n", buf, DosName, len);
536 /* add dosname to prefix */
537 wcsncat (buf, DosName, len);
538
539 CHECKPOINT;
540 /* replace slashes */
541 for (wcs = buf; *wcs; wcs++)
542 if (*wcs == L'/')
543 *wcs = L'\\';
544
545 len = wcslen (buf);
546 if (len < 3 && buf[len-1] == L':')
547 wcscat (buf, L"\\");
548
549 // DPRINT("buf \'%S\'\n", buf);
550 RtlpEatPath (buf);
551 // DPRINT("buf \'%S\'\n", buf);
552
553 len = wcslen (buf);
554
555 /* find file part */
556 if (FilePart)
557 {
558 for (wcs = buf + len - 1; wcs >= buf; wcs--)
559 {
560 if (*wcs == L'\\')
561 {
562 *FilePart = wcs + 1;
563 break;
564 }
565 }
566 }
567
568 RtlReleasePebLock();
569
570 return len * sizeof(WCHAR);
571 }
572
573
574 BOOLEAN
575 STDCALL
576 RtlDosPathNameToNtPathName_U (
577 PWSTR dosname,
578 PUNICODE_STRING ntname,
579 PWSTR *FilePart,
580 PCURDIR nah
581 )
582 {
583 UNICODE_STRING us;
584 PCURDIR cd;
585 ULONG Type;
586 ULONG Size;
587 ULONG Length;
588 ULONG Offset;
589 WCHAR fullname[2*MAX_PATH];
590 PWSTR Buffer = NULL;
591
592 RtlAcquirePebLock ();
593
594 RtlInitUnicodeString (&us, dosname);
595 if (us.Length > 8)
596 {
597 Buffer = us.Buffer;
598 /* check for "\\?\" - allows to use very long filenames ( up to 32k ) */
599 if (Buffer[0] == L'\\' && Buffer[1] == L'\\' &&
600 Buffer[2] == L'?' && Buffer[3] == L'\\')
601 {
602 // if( f_77F68606( &us, ntname, shortname, nah ) )
603 // {
604 // RtlReleasePebLock ();
605 // return TRUE;
606 // }
607 Buffer = NULL;
608 RtlReleasePebLock ();
609 return FALSE;
610 }
611 }
612
613 Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
614 0,
615 sizeof( fullname ) + MAX_PFX_SIZE);
616 if (Buffer == NULL)
617 {
618 RtlReleasePebLock ();
619 return FALSE;
620 }
621
622 Size = RtlGetFullPathName_U (dosname,
623 sizeof(fullname),
624 fullname,
625 FilePart);
626 if (Size == 0 || Size > MAX_PATH * sizeof(WCHAR))
627 {
628 RtlFreeHeap (RtlGetProcessHeap (),
629 0,
630 Buffer);
631 RtlReleasePebLock ();
632 return FALSE;
633 }
634
635 /* Set NT prefix */
636 Offset = 0;
637 wcscpy (Buffer, L"\\??\\");
638
639 Type = RtlDetermineDosPathNameType_U (fullname);
640 switch (Type)
641 {
642 case 1:
643 wcscat (Buffer, L"UNC\\");
644 Offset = 2;
645 break; /* \\xxx */
646
647 case 6:
648 Offset = 4;
649 break; /* \\.\xxx */
650 }
651 wcscat (Buffer, fullname + Offset);
652 Length = wcslen (Buffer);
653
654 /* set NT filename */
655 ntname->Length = Length * sizeof(WCHAR);
656 ntname->MaximumLength = sizeof(fullname) + MAX_PFX_SIZE;
657 ntname->Buffer = Buffer;
658
659 /* set pointer to file part if possible */
660 if (FilePart && *FilePart)
661 *FilePart = Buffer + Length - wcslen (*FilePart);
662
663 /* Set name and handle structure if possible */
664 if (nah)
665 {
666 memset (nah, 0, sizeof(CURDIR));
667 cd = &(NtCurrentPeb ()->ProcessParameters->CurrentDirectory);
668 if (Type == 5 && cd->Handle &&
669 !_wcsnicmp (cd->DosPath.Buffer, fullname, cd->DosPath.Length / 2))
670 {
671 Length = ((cd->DosPath.Length / sizeof(WCHAR)) - Offset) + ((Type == 1) ? 8 : 4);
672 nah->DosPath.Buffer = Buffer + Length;
673 nah->DosPath.Length = ntname->Length - (Length * sizeof(WCHAR));
674 nah->DosPath.MaximumLength = nah->DosPath.Length;
675 nah->Handle = cd->Handle;
676 }
677 }
678
679 RtlReleasePebLock();
680
681 return TRUE;
682 }
683
684
685 ULONG
686 STDCALL
687 RtlDosSearchPath_U (
688 WCHAR *sp,
689 WCHAR *name,
690 WCHAR *ext,
691 ULONG buf_sz,
692 WCHAR *buffer,
693 PWSTR *FilePart
694 )
695 {
696 ULONG Type;
697 ULONG Length = 0;
698 PWSTR full_name;
699 PWSTR wcs;
700 PWSTR path;
701
702 Type = RtlDetermineDosPathNameType_U (name);
703
704 if (Type == 5)
705 {
706 Length = wcslen (sp);
707 Length += wcslen (name);
708 if (wcschr (name, L'.'))
709 ext = NULL;
710 if (ext != NULL)
711 Length += wcslen (ext);
712
713 full_name = (WCHAR*)RtlAllocateHeap (RtlGetProcessHeap (),
714 0,
715 (Length + 1) * sizeof(WCHAR));
716 Length = 0;
717 if (full_name != NULL)
718 {
719 path = sp;
720 while (*path)
721 {
722 wcs = full_name;
723 while (*path && *path != L';')
724 *wcs++ = *path++;
725 if (*path)
726 path++;
727 if (wcs != full_name && *(wcs - 1) != L'\\')
728 *wcs++ = L'\\';
729 wcscpy (wcs, name);
730 if (ext)
731 wcscat (wcs, ext);
732 if (RtlDoesFileExists_U (full_name))
733 {
734 Length = RtlGetFullPathName_U (full_name,
735 buf_sz,
736 buffer,
737 FilePart);
738 break;
739 }
740 }
741
742 RtlFreeHeap (RtlGetProcessHeap (),
743 0,
744 full_name);
745 }
746 }
747 else if (RtlDoesFileExists_U (name))
748 {
749 Length = RtlGetFullPathName_U (name,
750 buf_sz,
751 buffer,
752 FilePart);
753 }
754
755 return Length;
756 }
757
758
759 BOOLEAN
760 STDCALL
761 RtlIsNameLegalDOS8Dot3 (
762 PUNICODE_STRING UnicodeName,
763 PANSI_STRING AnsiName,
764 PBOOLEAN SpacesFound
765 )
766 {
767 PANSI_STRING name = AnsiName;
768 ANSI_STRING DummyString;
769 CHAR Buffer[12];
770 char *str;
771 ULONG Length;
772 ULONG i;
773 NTSTATUS Status;
774 BOOLEAN HasSpace = FALSE;
775 BOOLEAN HasDot = FALSE;
776
777 if (UnicodeName->Length > 24)
778 return FALSE; /* name too long */
779
780 if (!name)
781 {
782 name = &DummyString;
783 name->Length = 0;
784 name->MaximumLength = 12;
785 name->Buffer = Buffer;
786 }
787
788 Status = RtlUpcaseUnicodeStringToCountedOemString (name,
789 UnicodeName,
790 FALSE);
791 if (!NT_SUCCESS(Status))
792 return FALSE;
793
794 Length = name->Length;
795 str = name->Buffer;
796
797 if (!(Length == 1 && *str == '.') &&
798 !(Length == 2 && *str == '.' && *(str + 1) == '.'))
799 {
800 for (i = 0; i < Length; i++, str++)
801 {
802 switch (*str)
803 {
804 case ' ':
805 HasSpace = TRUE;
806 break;
807
808 case '.':
809 if ((HasDot) || /* two points */
810 (!i) || /* point is first char */
811 (i + 1 == Length) ||/* point is last char */
812 (Length - i > 4)) /* more than 3 chars of extension */
813 return FALSE;
814 HasDot = TRUE;
815 break;
816 }
817 }
818 }
819
820 if (SpacesFound)
821 *SpacesFound = HasSpace;
822
823 return TRUE;
824 }
825
826
827 BOOLEAN
828 STDCALL
829 RtlDoesFileExists_U (
830 IN PWSTR FileName
831 )
832 {
833 UNICODE_STRING NtFileName;
834 OBJECT_ATTRIBUTES Attr;
835 NTSTATUS Status;
836 CURDIR CurDir;
837 PWSTR Buffer;
838
839 /* only used by replacement code */
840 HANDLE FileHandle;
841 IO_STATUS_BLOCK StatusBlock;
842
843 if (!RtlDosPathNameToNtPathName_U (FileName,
844 &NtFileName,
845 NULL,
846 &CurDir))
847 return FALSE;
848
849 /* don't forget to free it! */
850 Buffer = NtFileName.Buffer;
851
852 if (CurDir.DosPath.Length)
853 NtFileName = CurDir.DosPath;
854 else
855 CurDir.Handle = 0;
856
857 InitializeObjectAttributes (&Attr,
858 &NtFileName,
859 OBJ_CASE_INSENSITIVE,
860 CurDir.Handle,
861 NULL);
862
863 /* FIXME: not implemented yet */
864 // Status = NtQueryAttributesFile (&Attr, NULL);
865
866 /* REPLACEMENT start */
867 Status = NtOpenFile (&FileHandle,
868 0x10001,
869 &Attr,
870 &StatusBlock,
871 1,
872 FILE_SYNCHRONOUS_IO_NONALERT);
873 if (NT_SUCCESS(Status))
874 NtClose (FileHandle);
875 /* REPLACEMENT end */
876
877 RtlFreeHeap (RtlGetProcessHeap (),
878 0,
879 Buffer);
880
881 if (NT_SUCCESS(Status) ||
882 Status == STATUS_SHARING_VIOLATION ||
883 Status == STATUS_ACCESS_DENIED)
884 return TRUE;
885
886 return FALSE;
887 }
888
889 /* EOF */