ReactOS 0.4.15-dev-7961-gdcf9eb0
arcname.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: ARC path to-and-from NT path resolver.
5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
6 */
7/*
8 * References:
9 *
10 * - ARC Specification v1.2: http://netbsd.org./docs/Hardware/Machines/ARC/riscspec.pdf
11 * - "Setup and Startup", MSDN article: https://technet.microsoft.com/en-us/library/cc977184.aspx
12 * - Answer for "How do I determine the ARC path for a particular drive letter in Windows?": https://serverfault.com/a/5929
13 * - ARC - LinuxMIPS: https://www.linux-mips.org/wiki/ARC
14 * - ARCLoad - LinuxMIPS: https://www.linux-mips.org/wiki/ARCLoad
15 * - Inside Windows 2000 Server: https://books.google.fr/books?id=kYT7gKnwUQ8C&pg=PA71&lpg=PA71&dq=nt+arc+path&source=bl&ots=K8I1F_KQ_u&sig=EJq5t-v2qQk-QB7gNSREFj7pTVo&hl=en&sa=X&redir_esc=y#v=onepage&q=nt%20arc%20path&f=false
16 * - Inside Windows Server 2003: https://books.google.fr/books?id=zayrcM9ZYdAC&pg=PA61&lpg=PA61&dq=arc+path+to+nt+path&source=bl&ots=x2JSWfp2MA&sig=g9mufN6TCOrPejDov6Rjp0Jrldo&hl=en&sa=X&redir_esc=y#v=onepage&q=arc%20path%20to%20nt%20path&f=false
17 *
18 * Stuff to read: http://www.adminxp.com/windows2000/index.php?aid=46 and http://www.trcb.com/Computers-and-Technology/Windows-XP/Windows-XP-ARC-Naming-Conventions-1432.htm
19 * concerning which values of disk() or rdisk() are valid when either scsi() or multi() adapters are specified.
20 */
21
22/* INCLUDES *****************************************************************/
23
24#include "precomp.h"
25
26#include "filesup.h"
27#include "partlist.h"
28#include "arcname.h"
29
30#define NDEBUG
31#include <debug.h>
32
33
34/* TYPEDEFS *****************************************************************/
35
36/* Supported adapter types */
37typedef enum _ADAPTER_TYPE
38{
47{
48 "eisa",
49 "scsi",
50 "multi",
51 "net",
52 "ramdisk",
53 NULL
54};
56{
57 L"eisa",
58 L"scsi",
59 L"multi",
60 L"net",
61 L"ramdisk",
62 NULL
63};
64
65/* Supported controller types */
66typedef enum _CONTROLLER_TYPE
67{
73{
74 "disk",
75 "cdrom",
76 NULL
77};
79{
80 L"disk",
81 L"cdrom",
82 NULL
83};
84
85/* Supported peripheral types */
86typedef enum _PERIPHERAL_TYPE
87{
88// VDiskPeripheral,
95{
96// "vdisk", // Enable this when we'll support boot from virtual disks!
97 "rdisk",
98 "fdisk",
99 "cdrom",
100 NULL
101};
103{
104// L"vdisk", // Enable this when we'll support boot from virtual disks!
105 L"rdisk",
106 L"fdisk",
107 L"cdrom",
108 NULL
109};
110
111
112/* FUNCTIONS ****************************************************************/
113
114/* static */ PCSTR
116 IN PCSTR ArcPath,
117 OUT PANSI_STRING TokenSpecifier,
118 OUT PULONG Key)
119{
121 PCSTR p = ArcPath;
122 SIZE_T SpecifierLength;
123 ULONG KeyValue;
124
125 /*
126 * We must have a valid "specifier(key)" string, where 'specifier'
127 * cannot be the empty string, and is followed by '('.
128 */
129 p = strchr(p, '(');
130 if (p == NULL)
131 return NULL; /* No '(' found */
132 if (p == ArcPath)
133 return NULL; /* Path starts with '(' and is thus invalid */
134
135 SpecifierLength = (p - ArcPath) * sizeof(CHAR);
136 if (SpecifierLength > MAXUSHORT)
137 {
138 return NULL;
139 }
140
141 /*
142 * The strtoul function skips any leading whitespace.
143 *
144 * Note that if the token is "specifier()" then strtoul won't perform
145 * any conversion and return 0, therefore effectively making the token
146 * equivalent to "specifier(0)", as it should be.
147 */
148 // KeyValue = atoi(p);
149 KeyValue = strtoul(p, (PSTR*)&p, 10);
150
151 /* Skip any trailing whitespace */
152 while (isspace(*p)) ++p;
153
154 /* The token must terminate with ')' */
155 if (*p != ')')
156 return NULL;
157#if 0
158 p = strchr(p, ')');
159 if (p == NULL)
160 return NULL;
161#endif
162
163 /* We should have succeeded, copy the token specifier in the buffer */
164 Status = RtlStringCbCopyNA(TokenSpecifier->Buffer,
165 TokenSpecifier->MaximumLength,
166 ArcPath, SpecifierLength);
167 if (!NT_SUCCESS(Status))
168 return NULL;
169
170 TokenSpecifier->Length = (USHORT)SpecifierLength;
171
172 /* We succeeded, return the token key value */
173 *Key = KeyValue;
174
175 /* Next token starts just after */
176 return ++p;
177}
178
179static PCWSTR
181 IN PCWSTR ArcPath,
182 OUT PUNICODE_STRING TokenSpecifier,
183 OUT PULONG Key)
184{
186 PCWSTR p = ArcPath;
187 SIZE_T SpecifierLength;
188 ULONG KeyValue;
189
190 /*
191 * We must have a valid "specifier(key)" string, where 'specifier'
192 * cannot be the empty string, and is followed by '('.
193 */
194 p = wcschr(p, L'(');
195 if (p == NULL)
196 return NULL; /* No '(' found */
197 if (p == ArcPath)
198 return NULL; /* Path starts with '(' and is thus invalid */
199
200 SpecifierLength = (p - ArcPath) * sizeof(WCHAR);
201 if (SpecifierLength > UNICODE_STRING_MAX_BYTES)
202 {
203 return NULL;
204 }
205
206 ++p;
207
208 /*
209 * The strtoul function skips any leading whitespace.
210 *
211 * Note that if the token is "specifier()" then strtoul won't perform
212 * any conversion and return 0, therefore effectively making the token
213 * equivalent to "specifier(0)", as it should be.
214 */
215 // KeyValue = _wtoi(p);
216 KeyValue = wcstoul(p, (PWSTR*)&p, 10);
217
218 /* Skip any trailing whitespace */
219 while (iswspace(*p)) ++p;
220
221 /* The token must terminate with ')' */
222 if (*p != L')')
223 return NULL;
224#if 0
225 p = wcschr(p, L')');
226 if (p == NULL)
227 return NULL;
228#endif
229
230 /* We should have succeeded, copy the token specifier in the buffer */
231 Status = RtlStringCbCopyNW(TokenSpecifier->Buffer,
232 TokenSpecifier->MaximumLength,
233 ArcPath, SpecifierLength);
234 if (!NT_SUCCESS(Status))
235 return NULL;
236
237 TokenSpecifier->Length = (USHORT)SpecifierLength;
238
239 /* We succeeded, return the token key value */
240 *Key = KeyValue;
241
242 /* Next token starts just after */
243 return ++p;
244}
245
246
247/* static */ ULONG
249 IN PCSTR CandidateToken,
250 IN const PCSTR* TokenTable)
251{
252 ULONG Index = 0;
253
254 while (TokenTable[Index] && _stricmp(CandidateToken, TokenTable[Index]) != 0)
255 {
256 ++Index;
257 }
258
259 return Index;
260}
261
262/* static */ ULONG
264 IN PCWSTR CandidateToken,
265 IN const PCWSTR* TokenTable)
266{
267 ULONG Index = 0;
268
269 while (TokenTable[Index] && _wcsicmp(CandidateToken, TokenTable[Index]) != 0)
270 {
271 ++Index;
272 }
273
274 return Index;
275}
276
277static ULONG
279 IN PCUNICODE_STRING CandidateToken,
280 IN const PCWSTR* TokenTable)
281{
282 ULONG Index = 0;
283#if 0
285#else
287#endif
288
289 while (TokenTable[Index])
290 {
291#if 0
292 Length = wcslen(TokenTable[Index]);
293 if ((Length == CandidateToken->Length / sizeof(WCHAR)) &&
294 (_wcsnicmp(CandidateToken->Buffer, TokenTable[Index], Length) == 0))
295 {
296 break;
297 }
298#else
299 RtlInitUnicodeString(&Token, TokenTable[Index]);
300 if (RtlEqualUnicodeString(CandidateToken, &Token, TRUE))
301 break;
302#endif
303
304 ++Index;
305 }
306
307 return Index;
308}
309
310
313 OUT PUNICODE_STRING NormalizedArcPath,
314 IN PCWSTR ArcPath)
315{
317 PCWSTR EndOfArcName;
318 PCWSTR p;
320
321 if (NormalizedArcPath->MaximumLength < sizeof(UNICODE_NULL))
322 return FALSE;
323
324 *NormalizedArcPath->Buffer = UNICODE_NULL;
325 NormalizedArcPath->Length = 0;
326
327 EndOfArcName = wcschr(ArcPath, OBJ_NAME_PATH_SEPARATOR);
328 if (!EndOfArcName)
329 EndOfArcName = ArcPath + wcslen(ArcPath);
330
331 while ((p = wcsstr(ArcPath, L"()")) && (p < EndOfArcName))
332 {
333#if 0
334 Status = RtlStringCbCopyNW(NormalizedArcPath->Buffer,
335 NormalizedArcPath->MaximumLength,
336 ArcPath, (p - ArcPath) * sizeof(WCHAR));
337#else
338 Status = RtlStringCbCatNW(NormalizedArcPath->Buffer,
339 NormalizedArcPath->MaximumLength,
340 ArcPath, (p - ArcPath) * sizeof(WCHAR));
341#endif
342 if (!NT_SUCCESS(Status))
343 return FALSE;
344
345 Status = RtlStringCbCatW(NormalizedArcPath->Buffer,
346 NormalizedArcPath->MaximumLength,
347 L"(0)");
348 if (!NT_SUCCESS(Status))
349 return FALSE;
350#if 0
351 NormalizedArcPath->Buffer += wcslen(NormalizedArcPath->Buffer);
352#endif
353 ArcPath = p + 2;
354 }
355
356 Status = RtlStringCbCatW(NormalizedArcPath->Buffer,
357 NormalizedArcPath->MaximumLength,
358 ArcPath);
359 if (!NT_SUCCESS(Status))
360 return FALSE;
361
362 PathLength = wcslen(NormalizedArcPath->Buffer);
364 {
365 return FALSE;
366 }
367
368 NormalizedArcPath->Length = (USHORT)PathLength * sizeof(WCHAR);
369 return TRUE;
370}
371
372
373/*
374 * ArcNamePath:
375 * In input, pointer to an ARC path (NULL-terminated) starting by an
376 * ARC name to be parsed into its different components.
377 * In output, ArcNamePath points to the beginning of the path after
378 * the ARC name part.
379 */
380static NTSTATUS
382 IN OUT PCWSTR* ArcNamePath,
383 OUT PULONG pAdapterKey,
384 OUT PULONG pControllerKey,
385 OUT PULONG pPeripheralKey,
386 OUT PULONG pPartitionNumber,
387 OUT PADAPTER_TYPE pAdapterType,
388 OUT PCONTROLLER_TYPE pControllerType,
389 OUT PPERIPHERAL_TYPE pPeripheralType,
390 OUT PBOOLEAN pUseSignature)
391{
392 // NTSTATUS Status;
393 WCHAR TokenBuffer[50];
395 PCWSTR p, q;
396 ULONG AdapterKey = 0;
397 ULONG ControllerKey = 0;
398 ULONG PeripheralKey = 0;
401 CONTROLLER_TYPE ControllerType = ControllerTypeMax;
402 PERIPHERAL_TYPE PeripheralType = PeripheralTypeMax;
403 BOOLEAN UseSignature = FALSE;
404
405 /*
406 * The format of ArcName is:
407 * adapter(www)[controller(xxx)peripheral(yyy)[partition(zzz)][filepath]] ,
408 * where the [filepath] part is not being parsed.
409 */
410
411 RtlInitEmptyUnicodeString(&Token, TokenBuffer, sizeof(TokenBuffer));
412
413 p = *ArcNamePath;
414
415 /* Retrieve the adapter */
416 p = ArcGetNextTokenU(p, &Token, &AdapterKey);
417 if (!p)
418 {
419 DPRINT1("No adapter specified!\n");
421 }
422
423 /* Check for the 'signature()' pseudo-adapter, introduced in Windows 2000 */
424 if (_wcsicmp(Token.Buffer, L"signature") == 0)
425 {
426 /*
427 * We've got a signature! Remember this for later, and set the adapter type to SCSI.
428 * We however check that the rest of the ARC path is valid by parsing the other tokens.
429 * AdapterKey stores the disk signature value (that holds in a ULONG).
430 */
431 UseSignature = TRUE;
433 }
434 else
435 {
436 /* Check for regular adapters */
437 // ArcMatchTokenU(Token.Buffer, AdapterTypes_U);
440 {
441 DPRINT1("Invalid adapter type %wZ\n", &Token);
443 }
444
445 /* Check for adapters that don't take any extra controller or peripheral nodes */
447 {
448 // if (*p)
449 // return STATUS_OBJECT_PATH_SYNTAX_BAD;
450
451 if (AdapterType == NetAdapter)
452 {
453 DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U[AdapterType], AdapterKey);
455 }
456
457 goto Quit;
458 }
459 }
460
461 /* Here, we have either an 'eisa', a 'scsi/signature', or a 'multi' adapter */
462
463 /* Check for a valid controller */
464 p = ArcGetNextTokenU(p, &Token, &ControllerKey);
465 if (!p)
466 {
467 DPRINT1("%S(%lu) adapter doesn't have a controller!\n", AdapterTypes_U[AdapterType], AdapterKey);
469 }
470 // ArcMatchTokenU(Token.Buffer, ControllerTypes_U);
472 if (ControllerType >= ControllerTypeMax)
473 {
474 DPRINT1("Invalid controller type %wZ\n", &Token);
476 }
477
478 /* Here the controller can only be either a disk or a CDROM */
479
480 /*
481 * Ignore the controller in case we have a 'multi' adapter.
482 * I guess a similar condition holds for the 'eisa' adapter too...
483 *
484 * For SignatureAdapter, as similar for ScsiAdapter, the controller key corresponds
485 * to the disk target ID. Note that actually, the implementation just ignores the
486 * target ID, as well as the LUN, and just loops over all the available disks and
487 * searches for the one having the correct signature.
488 */
489 if ((AdapterType == MultiAdapter /* || AdapterType == EisaAdapter */) && ControllerKey != 0)
490 {
491 DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
492 AdapterTypes_U[AdapterType], AdapterKey,
493 ControllerTypes_U[ControllerType], ControllerKey);
494 ControllerKey = 0;
495 }
496
497 /*
498 * Only the 'scsi' adapter supports a direct 'cdrom' controller.
499 * For the others, we need a 'disk' controller to which a 'cdrom' peripheral can talk to.
500 */
501 if ((AdapterType != ScsiAdapter) && (ControllerType == CdRomController))
502 {
503 DPRINT1("%S(%lu) adapter cannot have a CDROM controller!\n", AdapterTypes_U[AdapterType], AdapterKey);
505 }
506
507 /* Check for a valid peripheral */
508 p = ArcGetNextTokenU(p, &Token, &PeripheralKey);
509 if (!p)
510 {
511 DPRINT1("%S(%lu)%S(%lu) adapter-controller doesn't have a peripheral!\n",
512 AdapterTypes_U[AdapterType], AdapterKey,
513 ControllerTypes_U[ControllerType], ControllerKey);
515 }
516 // ArcMatchTokenU(Token.Buffer, PeripheralTypes_U);
518 if (PeripheralType >= PeripheralTypeMax)
519 {
520 DPRINT1("Invalid peripheral type %wZ\n", &Token);
522 }
523
524 /*
525 * If we had a 'cdrom' controller already, the corresponding peripheral can only be 'fdisk'
526 * (see for example the ARC syntax for SCSI CD-ROMs: scsi(x)cdrom(y)fdisk(z) where z == 0).
527 */
528 if ((ControllerType == CdRomController) && (PeripheralType != FDiskPeripheral))
529 {
530 DPRINT1("%S(%lu) controller cannot have a %S(%lu) peripheral! (note that we haven't check whether the adapter was SCSI or not)\n",
531 ControllerTypes_U[ControllerType], ControllerKey,
532 PeripheralTypes_U[PeripheralType], PeripheralKey);
534 }
535
536 /* For a 'scsi' adapter, the possible peripherals are only 'rdisk' or 'fdisk' */
537 if (AdapterType == ScsiAdapter && !(PeripheralType == RDiskPeripheral || PeripheralType == FDiskPeripheral))
538 {
539 DPRINT1("%S(%lu)%S(%lu) SCSI adapter-controller has an invalid peripheral %S(%lu) !\n",
540 AdapterTypes_U[AdapterType], AdapterKey,
541 ControllerTypes_U[ControllerType], ControllerKey,
542 PeripheralTypes_U[PeripheralType], PeripheralKey);
544 }
545
546#if 0
547 if (AdapterType == SignatureAdapter && PeripheralKey != 0)
548 {
549 DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
550 AdapterTypes_U[AdapterType], AdapterKey,
551 PeripheralTypes_U[PeripheralType], PeripheralKey);
552 PeripheralKey = 0;
553 }
554#endif
555
556 /* Check for the optional 'partition' specifier */
558 if (q && _wcsicmp(Token.Buffer, L"partition") == 0)
559 {
560 /* We've got a partition! */
561 p = q;
562 }
563 else
564 {
565 /*
566 * Either no other ARC token was found, or we've got something else
567 * (possibly invalid or not)...
568 */
569 PartitionNumber = 0;
570 }
571
572 // TODO: Check the partition number in case of fdisks and cdroms??
573
574Quit:
575 /* Return the results */
576 *ArcNamePath = p;
577 *pAdapterKey = AdapterKey;
578 *pControllerKey = ControllerKey;
579 *pPeripheralKey = PeripheralKey;
580 *pPartitionNumber = PartitionNumber;
581 *pAdapterType = AdapterType;
582 *pControllerType = ControllerType;
583 *pPeripheralType = PeripheralType;
584 *pUseSignature = UseSignature;
585
586 return STATUS_SUCCESS;
587}
588
589/*
590 * ArcName:
591 * ARC name (counted string) to be resolved into a NT device name.
592 * The caller should have already delimited it from within an ARC path
593 * (usually by finding where the first path separator appears in the path).
594 *
595 * NtName:
596 * Receives the resolved NT name. The buffer is NULL-terminated.
597 */
598static NTSTATUS
600 OUT PUNICODE_STRING NtName,
601 IN PUNICODE_STRING ArcName)
602{
605 HANDLE DirectoryHandle, LinkHandle;
606 UNICODE_STRING ArcNameDir;
607
608 if (NtName->MaximumLength < sizeof(UNICODE_NULL))
610
611 /* Open the \ArcName object directory */
612 RtlInitUnicodeString(&ArcNameDir, L"\\ArcName");
614 &ArcNameDir,
616 NULL,
617 NULL);
621 if (!NT_SUCCESS(Status))
622 {
623 DPRINT1("NtOpenDirectoryObject(%wZ) failed, Status 0x%08lx\n", &ArcNameDir, Status);
624 return Status;
625 }
626
627 /* Open the ARC name link */
629 ArcName,
632 NULL);
633 Status = NtOpenSymbolicLinkObject(&LinkHandle,
636
637 /* Close the \ArcName object directory handle */
639
640 /* Check for success */
641 if (!NT_SUCCESS(Status))
642 {
643 DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName, Status);
644 return Status;
645 }
646
647 /* Reserve one WCHAR for the NULL-termination */
648 NtName->MaximumLength -= sizeof(UNICODE_NULL);
649
650 /* Resolve the link and close its handle */
651 Status = NtQuerySymbolicLinkObject(LinkHandle, NtName, NULL);
652 NtClose(LinkHandle);
653
654 /* Restore the NULL-termination */
655 NtName->MaximumLength += sizeof(UNICODE_NULL);
656
657 /* Check for success */
658 if (!NT_SUCCESS(Status))
659 {
660 /* We failed, don't touch NtName */
661 DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName, Status);
662 }
663 else
664 {
665 /* We succeeded, NULL-terminate NtName */
666 NtName->Buffer[NtName->Length / sizeof(WCHAR)] = UNICODE_NULL;
667 }
668
669 return Status;
670}
671
672/*
673 * ArcNamePath:
674 * In input, pointer to an ARC path (NULL-terminated) starting by an
675 * ARC name to be resolved into a NT device name.
676 * In opposition to ResolveArcNameNtSymLink(), the caller does not have
677 * to delimit the ARC name from within an ARC path. The real ARC name is
678 * deduced after parsing the ARC path, and, in output, ArcNamePath points
679 * to the beginning of the path after the ARC name part.
680 *
681 * NtName:
682 * Receives the resolved NT name. The buffer is NULL-terminated.
683 *
684 * PartList:
685 * (Optional) partition list that helps in resolving the paths pointing
686 * to hard disks.
687 */
688static NTSTATUS
690 OUT PUNICODE_STRING NtName,
691 IN OUT PCWSTR* ArcNamePath,
692 IN PPARTLIST PartList)
693{
695 ULONG AdapterKey;
696 ULONG ControllerKey;
697 ULONG PeripheralKey;
700 CONTROLLER_TYPE ControllerType;
701 PERIPHERAL_TYPE PeripheralType;
702 BOOLEAN UseSignature;
703 SIZE_T NameLength;
704
705 PDISKENTRY DiskEntry;
706 PPARTENTRY PartEntry = NULL;
707
708 if (NtName->MaximumLength < sizeof(UNICODE_NULL))
710
711 /* Parse the ARC path */
712 Status = ParseArcName(ArcNamePath,
713 &AdapterKey,
714 &ControllerKey,
715 &PeripheralKey,
718 &ControllerType,
719 &PeripheralType,
720 &UseSignature);
721 if (!NT_SUCCESS(Status))
722 return Status;
723
724 // TODO: Check the partition number in case of fdisks and cdroms??
725
726 /* Check for adapters that don't take any extra controller or peripheral node */
728 {
729 if (AdapterType == NetAdapter)
730 {
731 DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U[AdapterType], AdapterKey);
733 }
734
735 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
736 L"\\Device\\Ramdisk%lu", AdapterKey);
737 }
738 else
739 if (ControllerType == CdRomController) // and so, AdapterType == ScsiAdapter and PeripheralType == FDiskPeripheral
740 {
741 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
742 L"\\Device\\Scsi\\CdRom%lu", ControllerKey);
743 }
744 else
745 /* Now, ControllerType == DiskController */
746 if (PeripheralType == CdRomPeripheral)
747 {
748 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
749 L"\\Device\\CdRom%lu", PeripheralKey);
750 }
751 else
752 if (PeripheralType == FDiskPeripheral)
753 {
754 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
755 L"\\Device\\Floppy%lu", PeripheralKey);
756 }
757 else
758 if (PeripheralType == RDiskPeripheral)
759 {
760 if (UseSignature)
761 {
762 /* The disk signature is stored in AdapterKey */
763 DiskEntry = GetDiskBySignature(PartList, AdapterKey);
764 }
765 else
766 {
767 DiskEntry = GetDiskBySCSI(PartList, AdapterKey,
768 ControllerKey, PeripheralKey);
769 }
770 if (!DiskEntry)
771 return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_NOT_FOUND;
772
773 if (PartitionNumber != 0)
774 {
775 PartEntry = GetPartition(DiskEntry, PartitionNumber);
776 if (!PartEntry)
777 return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_DEVICE_NOT_PARTITIONED;
778 ASSERT(PartEntry->DiskEntry == DiskEntry);
779 }
780
781 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
782 L"\\Device\\Harddisk%lu\\Partition%lu",
783 DiskEntry->DiskNumber, PartitionNumber);
784 }
785#if 0 // FIXME: Not implemented yet!
786 else
787 if (PeripheralType == VDiskPeripheral)
788 {
789 // TODO: Check how Win 7+ deals with virtual disks.
790 Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
791 L"\\Device\\VirtualHarddisk%lu\\Partition%lu",
792 PeripheralKey, PartitionNumber);
793 }
794#endif
795
796 if (!NT_SUCCESS(Status))
797 {
798 /* Returned NtName is invalid, so zero it out */
799 *NtName->Buffer = UNICODE_NULL;
800 NtName->Length = 0;
801
802 return Status;
803 }
804
805 /* Update NtName length */
806 NameLength = wcslen(NtName->Buffer);
807 if (NameLength > UNICODE_STRING_MAX_CHARS)
808 {
810 }
811
812 NtName->Length = (USHORT)NameLength * sizeof(WCHAR);
813
814 return STATUS_SUCCESS;
815}
816
817
820 OUT PUNICODE_STRING NtPath,
821 IN PCWSTR ArcPath,
822 IN PPARTLIST PartList OPTIONAL)
823{
825 PCWSTR BeginOfPath;
826 UNICODE_STRING ArcName;
828
829 /* TODO: We should "normalize" the path, i.e. expand all the xxx() into xxx(0) */
830
831 if (NtPath->MaximumLength < sizeof(UNICODE_NULL))
832 return FALSE;
833
834 *NtPath->Buffer = UNICODE_NULL;
835 NtPath->Length = 0;
836
837 /*
838 * - First, check whether the ARC path is already inside \\ArcName
839 * and if so, map it to the corresponding NT path.
840 * - Only then, if we haven't found any ArcName, try to build a
841 * NT path by deconstructing the ARC path, using its disk and
842 * partition numbers. We may use here our disk/partition list.
843 *
844 * See also freeldr/arcname.c
845 *
846 * Note that it would be nice to maintain a cache of these mappings.
847 */
848
849 /*
850 * Initialize the ARC name to resolve, by cutting the ARC path at the first
851 * NT path separator. The ARC name therefore ends where the NT path part starts.
852 */
853 RtlInitUnicodeString(&ArcName, ArcPath);
854 BeginOfPath = wcschr(ArcName.Buffer, OBJ_NAME_PATH_SEPARATOR);
855 if (BeginOfPath)
856 ArcName.Length = (ULONG_PTR)BeginOfPath - (ULONG_PTR)ArcName.Buffer;
857
858 /* Resolve the ARC name via NT SymLinks. Note that NtPath is returned NULL-terminated. */
859 Status = ResolveArcNameNtSymLink(NtPath, &ArcName);
860 if (!NT_SUCCESS(Status))
861 {
862 /* We failed, attempt a manual resolution */
863 DPRINT1("ResolveArcNameNtSymLink(ArcName = '%wZ') for ArcPath = '%S' failed, Status 0x%08lx\n", &ArcName, ArcPath, Status);
864
865 /*
866 * We failed at directly resolving the ARC path, and we cannot perform
867 * a manual resolution because we don't have any disk/partition list,
868 * we therefore fail here.
869 */
870 if (!PartList)
871 {
872 DPRINT1("PartList == NULL, cannot perform a manual resolution\n");
873 return FALSE;
874 }
875
876 *NtPath->Buffer = UNICODE_NULL;
877 NtPath->Length = 0;
878
879 BeginOfPath = ArcPath;
880 Status = ResolveArcNameManually(NtPath, &BeginOfPath, PartList);
881 if (!NT_SUCCESS(Status))
882 {
883 /* We really failed this time, bail out */
884 DPRINT1("ResolveArcNameManually(ArcPath = '%S') failed, Status 0x%08lx\n", ArcPath, Status);
885 return FALSE;
886 }
887 }
888
889 /*
890 * We succeeded. Concatenate the rest of the system-specific path. We know the path is going
891 * to be inside the NT namespace, therefore we can use the path string concatenation function
892 * that uses '\\' as the path separator.
893 */
894 if (BeginOfPath && *BeginOfPath)
895 {
896 Status = ConcatPaths(NtPath->Buffer, NtPath->MaximumLength / sizeof(WCHAR), 1, BeginOfPath);
897 if (!NT_SUCCESS(Status))
898 {
899 /* Buffer not large enough, or whatever...: just bail out */
900 return FALSE;
901 }
902 }
903
904 PathLength = wcslen(NtPath->Buffer);
906 {
907 return FALSE;
908 }
909
910 NtPath->Length = (USHORT)PathLength * sizeof(WCHAR);
911
912 return TRUE;
913}
914
915#if 0 // FIXME: Not implemented yet!
916PWSTR
917NtPathToArcPath(
918 IN PWSTR NtPath)
919{
920 /*
921 * - First, check whether any of the ARC paths inside \\ArcName
922 * map to the corresponding NT path. If so, we are OK.
923 * - Only then, if we haven't found any ArcName, try to build an
924 * ARC path by deconstructing the NT path, using its disk and
925 * partition numbers. We may use here our disk/partition list.
926 *
927 * See also freeldr/arcname.c
928 *
929 * Note that it would be nice to maintain a cache of these mappings.
930 */
931}
932#endif
933
934/* EOF */
static USHORT PathLength
static HANDLE DirectoryHandle
Definition: ObType.c:48
unsigned char BOOLEAN
#define isspace(c)
Definition: acclib.h:69
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
static ULONG ArcMatchToken_UStr(IN PCUNICODE_STRING CandidateToken, IN const PCWSTR *TokenTable)
Definition: arcname.c:278
const PCWSTR PeripheralTypes_U[]
Definition: arcname.c:102
ULONG ArcMatchTokenA(IN PCSTR CandidateToken, IN const PCSTR *TokenTable)
Definition: arcname.c:248
enum _ADAPTER_TYPE ADAPTER_TYPE
static PCWSTR ArcGetNextTokenU(IN PCWSTR ArcPath, OUT PUNICODE_STRING TokenSpecifier, OUT PULONG Key)
Definition: arcname.c:180
static NTSTATUS ResolveArcNameManually(OUT PUNICODE_STRING NtName, IN OUT PCWSTR *ArcNamePath, IN PPARTLIST PartList)
Definition: arcname.c:689
static NTSTATUS ResolveArcNameNtSymLink(OUT PUNICODE_STRING NtName, IN PUNICODE_STRING ArcName)
Definition: arcname.c:599
const PCSTR AdapterTypes_A[]
Definition: arcname.c:46
const PCWSTR AdapterTypes_U[]
Definition: arcname.c:55
_ADAPTER_TYPE
Definition: arcname.c:38
@ AdapterTypeMax
Definition: arcname.c:44
@ RamdiskAdapter
Definition: arcname.c:43
@ ScsiAdapter
Definition: arcname.c:40
@ EisaAdapter
Definition: arcname.c:39
@ MultiAdapter
Definition: arcname.c:41
@ NetAdapter
Definition: arcname.c:42
enum _CONTROLLER_TYPE CONTROLLER_TYPE
BOOLEAN ArcPathNormalize(OUT PUNICODE_STRING NormalizedArcPath, IN PCWSTR ArcPath)
Definition: arcname.c:312
ULONG ArcMatchTokenU(IN PCWSTR CandidateToken, IN const PCWSTR *TokenTable)
Definition: arcname.c:263
const PCWSTR ControllerTypes_U[]
Definition: arcname.c:78
PCSTR ArcGetNextTokenA(IN PCSTR ArcPath, OUT PANSI_STRING TokenSpecifier, OUT PULONG Key)
Definition: arcname.c:115
enum _CONTROLLER_TYPE * PCONTROLLER_TYPE
BOOLEAN ArcPathToNtPath(OUT PUNICODE_STRING NtPath, IN PCWSTR ArcPath, IN PPARTLIST PartList OPTIONAL)
Definition: arcname.c:819
const PCSTR PeripheralTypes_A[]
Definition: arcname.c:94
_PERIPHERAL_TYPE
Definition: arcname.c:87
@ PeripheralTypeMax
Definition: arcname.c:92
@ RDiskPeripheral
Definition: arcname.c:89
@ FDiskPeripheral
Definition: arcname.c:90
@ CdRomPeripheral
Definition: arcname.c:91
const PCSTR ControllerTypes_A[]
Definition: arcname.c:72
enum _ADAPTER_TYPE * PADAPTER_TYPE
enum _PERIPHERAL_TYPE PERIPHERAL_TYPE
_CONTROLLER_TYPE
Definition: arcname.c:67
@ CdRomController
Definition: arcname.c:69
@ ControllerTypeMax
Definition: arcname.c:70
@ DiskController
Definition: arcname.c:68
static NTSTATUS ParseArcName(IN OUT PCWSTR *ArcNamePath, OUT PULONG pAdapterKey, OUT PULONG pControllerKey, OUT PULONG pPeripheralKey, OUT PULONG pPartitionNumber, OUT PADAPTER_TYPE pAdapterType, OUT PCONTROLLER_TYPE pControllerType, OUT PPERIPHERAL_TYPE pPeripheralType, OUT PBOOLEAN pUseSignature)
Definition: arcname.c:381
enum _PERIPHERAL_TYPE * PPERIPHERAL_TYPE
#define _stricmp
Definition: cat.c:22
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define wcschr
Definition: compat.h:17
#define ULONG_PTR
Definition: config.h:101
NTSTATUS ConcatPaths(IN OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:659
Status
Definition: gdiplustypes.h:25
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLfloat GLfloat p
Definition: glext.h:8902
#define iswspace(_c)
Definition: ctype.h:669
_Check_return_ unsigned long __cdecl wcstoul(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define ASSERT(a)
Definition: mode.c:44
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define DIRECTORY_ALL_ACCESS
Definition: nt_native.h:1259
#define UNICODE_NULL
#define UNICODE_STRING_MAX_CHARS
#define UNICODE_STRING_MAX_BYTES
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_OBJECT_PATH_SYNTAX_BAD
Definition: ntstatus.h:295
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:293
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:498
NTSTRSAFEAPI RtlStringCbCatW(_Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:636
NTSTRSAFEVAPI RtlStringCbPrintfW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1173
NTSTRSAFEAPI RtlStringCbCopyNA(_Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToCopy) STRSAFE_LPCSTR pszSrc, _In_ size_t cbToCopy)
Definition: ntstrsafe.h:395
NTSTRSAFEAPI RtlStringCbCatNW(_Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToAppend) STRSAFE_LPCWSTR pszSrc, _In_ size_t cbToAppend)
Definition: ntstrsafe.h:832
NTSTRSAFEAPI RtlStringCbCopyNW(_Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cbToCopy)
Definition: ntstrsafe.h:416
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: obdir.c:393
unsigned short USHORT
Definition: pedump.c:61
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
PPARTENTRY GetPartition(IN PDISKENTRY DiskEntry, IN ULONG PartitionNumber)
Definition: partlist.c:2116
PDISKENTRY GetDiskBySignature(IN PPARTLIST List, IN ULONG Signature)
Definition: partlist.c:2090
PDISKENTRY GetDiskBySCSI(IN PPARTLIST List, IN USHORT Port, IN USHORT Bus, IN USHORT Id)
Definition: partlist.c:2060
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG DiskNumber
Definition: partlist.h:108
struct _DISKENTRY * DiskEntry
Definition: partlist.h:46
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
char * PSTR
Definition: typedefs.h:51
const uint16_t * PCWSTR
Definition: typedefs.h:57
unsigned char * PBOOLEAN
Definition: typedefs.h:53
ULONG_PTR SIZE_T
Definition: typedefs.h:80
const char * PCSTR
Definition: typedefs.h:52
#define MAXUSHORT
Definition: typedefs.h:83
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
_In_ WDFCOLLECTION _In_ ULONG Index
@ AdapterType
Definition: cmtypes.h:991
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175