ReactOS  0.4.14-dev-583-g2a1ba2c
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 */
37 typedef 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 */
66 typedef 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 */
86 typedef 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 
179 static 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 
277 static ULONG
279  IN PCUNICODE_STRING CandidateToken,
280  IN const PCWSTR* TokenTable)
281 {
282  ULONG Index = 0;
283 #if 0
284  SIZE_T Length;
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 
311 BOOLEAN
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  */
380 static 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);
454  return STATUS_NOT_SUPPORTED;
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 
574 Quit:
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  */
598 static 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  */
688 static 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,
717  &AdapterType,
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);
732  return STATUS_NOT_SUPPORTED;
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  {
809  return STATUS_NAME_TOO_LONG;
810  }
811 
812  NtName->Length = (USHORT)NameLength * sizeof(WCHAR);
813 
814  return STATUS_SUCCESS;
815 }
816 
817 
818 BOOLEAN
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!
916 PWSTR
917 NtPathToArcPath(
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 */
const PCWSTR PeripheralTypes_U[]
Definition: arcname.c:102
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
enum _CONTROLLER_TYPE * PCONTROLLER_TYPE
PDISKENTRY GetDiskBySignature(IN PPARTLIST List, IN ULONG Signature)
Definition: partlist.c:2246
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define IN
Definition: typedefs.h:38
#define isspace(c)
Definition: acclib.h:69
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
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
#define TRUE
Definition: types.h:120
static ULONG ArcMatchToken_UStr(IN PCUNICODE_STRING CandidateToken, IN const PCWSTR *TokenTable)
Definition: arcname.c:278
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
uint16_t * PWSTR
Definition: typedefs.h:54
NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: obdir.c:401
enum _CONTROLLER_TYPE CONTROLLER_TYPE
char CHAR
Definition: xmlstorage.h:175
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
LONG NTSTATUS
Definition: precomp.h:26
_IRQL_requires_same_ _In_ PLSA_STRING _In_ SECURITY_LOGON_TYPE _In_ ULONG _In_ ULONG _In_opt_ PTOKEN_GROUPS _In_ PTOKEN_SOURCE _Out_ PVOID _Out_ PULONG _Inout_ PLUID _Out_ PHANDLE Token
_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)
static HANDLE DirectoryHandle
Definition: ObType.c:48
BOOLEAN ArcPathToNtPath(OUT PUNICODE_STRING NtPath, IN PCWSTR ArcPath, IN PPARTLIST PartList OPTIONAL)
Definition: arcname.c:819
ULONG DiskNumber
Definition: partlist.h:104
NTSTATUS ConcatPaths(IN OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:659
_Check_return_ unsigned long __cdecl wcstoul(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2056
NTSTRSAFEAPI RtlStringCbCatW(_Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:636
static USHORT PathLength
#define UNICODE_STRING_MAX_BYTES
#define _stricmp
Definition: cat.c:22
const PCSTR PeripheralTypes_A[]
Definition: arcname.c:94
static NTSTATUS ResolveArcNameNtSymLink(OUT PUNICODE_STRING NtName, IN PUNICODE_STRING ArcName)
Definition: arcname.c:599
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
uint32_t ULONG_PTR
Definition: typedefs.h:63
PPARTENTRY GetPartition(IN PDISKENTRY DiskEntry, IN ULONG PartitionNumber)
Definition: partlist.c:2272
static NTSTATUS ResolveArcNameManually(OUT PUNICODE_STRING NtName, IN OUT PCWSTR *ArcNamePath, IN PPARTLIST PartList)
Definition: arcname.c:689
#define UNICODE_NULL
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
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
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:484
enum _ADAPTER_TYPE * PADAPTER_TYPE
ULONG ArcMatchTokenA(IN PCSTR CandidateToken, IN const PCSTR *TokenTable)
Definition: arcname.c:248
#define UNICODE_STRING_MAX_CHARS
struct _DISKENTRY * DiskEntry
Definition: partlist.h:39
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
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
static const UCHAR Index[8]
Definition: usbohci.c:18
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
PCHAR Buffer
Definition: ntsecapi.h:174
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
enum _ADAPTER_TYPE ADAPTER_TYPE
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define iswspace(_c)
Definition: ctype.h:669
char * PBOOLEAN
Definition: retypes.h:11
static const WCHAR L[]
Definition: oid.c:1250
ULONG ArcMatchTokenU(IN PCWSTR CandidateToken, IN const PCWSTR *TokenTable)
Definition: arcname.c:263
_PERIPHERAL_TYPE
Definition: arcname.c:86
Status
Definition: gdiplustypes.h:24
ULONG_PTR SIZE_T
Definition: typedefs.h:78
unsigned short USHORT
Definition: pedump.c:61
#define DIRECTORY_ALL_ACCESS
Definition: nt_native.h:1259
signed char * PSTR
Definition: retypes.h:7
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
static PCWSTR ArcGetNextTokenU(IN PCWSTR ArcPath, OUT PUNICODE_STRING TokenSpecifier, OUT PULONG Key)
Definition: arcname.c:180
enum _PERIPHERAL_TYPE PERIPHERAL_TYPE
unsigned int * PULONG
Definition: retypes.h:1
_CONTROLLER_TYPE
Definition: arcname.c:66
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:279
const PCSTR ControllerTypes_A[]
Definition: arcname.c:72
#define MAXUSHORT
Definition: typedefs.h:81
char * strchr(const char *String, int ch)
Definition: utclib.c:501
#define DPRINT1
Definition: precomp.h:8
enum _PERIPHERAL_TYPE * PPERIPHERAL_TYPE
#define OUT
Definition: typedefs.h:39
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:409
unsigned int ULONG
Definition: retypes.h:1
PDISKENTRY GetDiskBySCSI(IN PPARTLIST List, IN USHORT Port, IN USHORT Bus, IN USHORT Id)
Definition: partlist.c:2216
#define SYMBOLIC_LINK_QUERY
Definition: nt_native.h:1265
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define ULONG_PTR
Definition: config.h:101
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
PCSTR ArcGetNextTokenA(IN PCSTR ArcPath, OUT PANSI_STRING TokenSpecifier, OUT PULONG Key)
Definition: arcname.c:115
const PCWSTR ControllerTypes_U[]
Definition: arcname.c:78
const PCSTR AdapterTypes_A[]
Definition: arcname.c:46
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
const char * PCSTR
Definition: typedefs.h:51
GLfloat GLfloat p
Definition: glext.h:8902
#define STATUS_OBJECT_PATH_SYNTAX_BAD
Definition: ntstatus.h:281
return STATUS_SUCCESS
Definition: btrfs.c:2938
_ADAPTER_TYPE
Definition: arcname.c:37
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
const PCWSTR AdapterTypes_U[]
Definition: arcname.c:55
BOOLEAN ArcPathNormalize(OUT PUNICODE_STRING NormalizedArcPath, IN PCWSTR ArcPath)
Definition: arcname.c:312
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68