ReactOS  0.4.13-dev-455-g28ed234
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  ULONG 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 
137  /*
138  * The strtoul function skips any leading whitespace.
139  *
140  * Note that if the token is "specifier()" then strtoul won't perform
141  * any conversion and return 0, therefore effectively making the token
142  * equivalent to "specifier(0)", as it should be.
143  */
144  // KeyValue = atoi(p);
145  KeyValue = strtoul(p, (PSTR*)&p, 10);
146 
147  /* Skip any trailing whitespace */
148  while (isspace(*p)) ++p;
149 
150  /* The token must terminate with ')' */
151  if (*p != ')')
152  return NULL;
153 #if 0
154  p = strchr(p, ')');
155  if (p == NULL)
156  return NULL;
157 #endif
158 
159  /* We should have succeeded, copy the token specifier in the buffer */
160  Status = RtlStringCbCopyNA(TokenSpecifier->Buffer,
161  TokenSpecifier->MaximumLength,
162  ArcPath, SpecifierLength);
163  if (!NT_SUCCESS(Status))
164  return NULL;
165 
166  TokenSpecifier->Length = strlen(TokenSpecifier->Buffer) * sizeof(CHAR);
167 
168  /* We succeeded, return the token key value */
169  *Key = KeyValue;
170 
171  /* Next token starts just after */
172  return ++p;
173 }
174 
175 static PCWSTR
177  IN PCWSTR ArcPath,
178  OUT PUNICODE_STRING TokenSpecifier,
179  OUT PULONG Key)
180 {
182  PCWSTR p = ArcPath;
183  ULONG SpecifierLength;
184  ULONG KeyValue;
185 
186  /*
187  * We must have a valid "specifier(key)" string, where 'specifier'
188  * cannot be the empty string, and is followed by '('.
189  */
190  p = wcschr(p, L'(');
191  if (p == NULL)
192  return NULL; /* No '(' found */
193  if (p == ArcPath)
194  return NULL; /* Path starts with '(' and is thus invalid */
195 
196  SpecifierLength = (p - ArcPath) * sizeof(WCHAR);
197 
198  ++p;
199 
200  /*
201  * The strtoul function skips any leading whitespace.
202  *
203  * Note that if the token is "specifier()" then strtoul won't perform
204  * any conversion and return 0, therefore effectively making the token
205  * equivalent to "specifier(0)", as it should be.
206  */
207  // KeyValue = _wtoi(p);
208  KeyValue = wcstoul(p, (PWSTR*)&p, 10);
209 
210  /* Skip any trailing whitespace */
211  while (iswspace(*p)) ++p;
212 
213  /* The token must terminate with ')' */
214  if (*p != L')')
215  return NULL;
216 #if 0
217  p = wcschr(p, L')');
218  if (p == NULL)
219  return NULL;
220 #endif
221 
222  /* We should have succeeded, copy the token specifier in the buffer */
223  Status = RtlStringCbCopyNW(TokenSpecifier->Buffer,
224  TokenSpecifier->MaximumLength,
225  ArcPath, SpecifierLength);
226  if (!NT_SUCCESS(Status))
227  return NULL;
228 
229  TokenSpecifier->Length = wcslen(TokenSpecifier->Buffer) * sizeof(WCHAR);
230 
231  /* We succeeded, return the token key value */
232  *Key = KeyValue;
233 
234  /* Next token starts just after */
235  return ++p;
236 }
237 
238 
239 /* static */ ULONG
241  IN PCSTR CandidateToken,
242  IN const PCSTR* TokenTable)
243 {
244  ULONG Index = 0;
245 
246  while (TokenTable[Index] && _stricmp(CandidateToken, TokenTable[Index]) != 0)
247  {
248  ++Index;
249  }
250 
251  return Index;
252 }
253 
254 /* static */ ULONG
256  IN PCWSTR CandidateToken,
257  IN const PCWSTR* TokenTable)
258 {
259  ULONG Index = 0;
260 
261  while (TokenTable[Index] && _wcsicmp(CandidateToken, TokenTable[Index]) != 0)
262  {
263  ++Index;
264  }
265 
266  return Index;
267 }
268 
269 static ULONG
271  IN PCUNICODE_STRING CandidateToken,
272  IN const PCWSTR* TokenTable)
273 {
274  ULONG Index = 0;
275 #if 0
276  SIZE_T Length;
277 #else
279 #endif
280 
281  while (TokenTable[Index])
282  {
283 #if 0
284  Length = wcslen(TokenTable[Index]);
285  if ((Length == CandidateToken->Length / sizeof(WCHAR)) &&
286  (_wcsnicmp(CandidateToken->Buffer, TokenTable[Index], Length) == 0))
287  {
288  break;
289  }
290 #else
291  RtlInitUnicodeString(&Token, TokenTable[Index]);
292  if (RtlEqualUnicodeString(CandidateToken, &Token, TRUE))
293  break;
294 #endif
295 
296  ++Index;
297  }
298 
299  return Index;
300 }
301 
302 
303 BOOLEAN
305  OUT PUNICODE_STRING NormalizedArcPath,
306  IN PCWSTR ArcPath)
307 {
309  PCWSTR EndOfArcName;
310  PCWSTR p;
311 
312  if (NormalizedArcPath->MaximumLength < sizeof(UNICODE_NULL))
313  return FALSE;
314 
315  *NormalizedArcPath->Buffer = UNICODE_NULL;
316  NormalizedArcPath->Length = 0;
317 
318  EndOfArcName = wcschr(ArcPath, OBJ_NAME_PATH_SEPARATOR);
319  if (!EndOfArcName)
320  EndOfArcName = ArcPath + wcslen(ArcPath);
321 
322  while ((p = wcsstr(ArcPath, L"()")) && (p < EndOfArcName))
323  {
324 #if 0
325  Status = RtlStringCbCopyNW(NormalizedArcPath->Buffer,
326  NormalizedArcPath->MaximumLength,
327  ArcPath, (p - ArcPath) * sizeof(WCHAR));
328 #else
329  Status = RtlStringCbCatNW(NormalizedArcPath->Buffer,
330  NormalizedArcPath->MaximumLength,
331  ArcPath, (p - ArcPath) * sizeof(WCHAR));
332 #endif
333  if (!NT_SUCCESS(Status))
334  return FALSE;
335 
336  Status = RtlStringCbCatW(NormalizedArcPath->Buffer,
337  NormalizedArcPath->MaximumLength,
338  L"(0)");
339  if (!NT_SUCCESS(Status))
340  return FALSE;
341 #if 0
342  NormalizedArcPath->Buffer += wcslen(NormalizedArcPath->Buffer);
343 #endif
344  ArcPath = p + 2;
345  }
346 
347  Status = RtlStringCbCatW(NormalizedArcPath->Buffer,
348  NormalizedArcPath->MaximumLength,
349  ArcPath);
350  if (!NT_SUCCESS(Status))
351  return FALSE;
352 
353  NormalizedArcPath->Length = wcslen(NormalizedArcPath->Buffer) * sizeof(WCHAR);
354  return TRUE;
355 }
356 
357 
358 /*
359  * ArcNamePath:
360  * In input, pointer to an ARC path (NULL-terminated) starting by an
361  * ARC name to be parsed into its different components.
362  * In output, ArcNamePath points to the beginning of the path after
363  * the ARC name part.
364  */
365 static NTSTATUS
367  IN OUT PCWSTR* ArcNamePath,
368  OUT PULONG pAdapterKey,
369  OUT PULONG pControllerKey,
370  OUT PULONG pPeripheralKey,
371  OUT PULONG pPartitionNumber,
372  OUT PADAPTER_TYPE pAdapterType,
373  OUT PCONTROLLER_TYPE pControllerType,
374  OUT PPERIPHERAL_TYPE pPeripheralType,
375  OUT PBOOLEAN pUseSignature)
376 {
377  // NTSTATUS Status;
378  WCHAR TokenBuffer[50];
380  PCWSTR p, q;
381  ULONG AdapterKey = 0;
382  ULONG ControllerKey = 0;
383  ULONG PeripheralKey = 0;
386  CONTROLLER_TYPE ControllerType = ControllerTypeMax;
387  PERIPHERAL_TYPE PeripheralType = PeripheralTypeMax;
388  BOOLEAN UseSignature = FALSE;
389 
390  /*
391  * The format of ArcName is:
392  * adapter(www)[controller(xxx)peripheral(yyy)[partition(zzz)][filepath]] ,
393  * where the [filepath] part is not being parsed.
394  */
395 
396  RtlInitEmptyUnicodeString(&Token, TokenBuffer, sizeof(TokenBuffer));
397 
398  p = *ArcNamePath;
399 
400  /* Retrieve the adapter */
401  p = ArcGetNextTokenU(p, &Token, &AdapterKey);
402  if (!p)
403  {
404  DPRINT1("No adapter specified!\n");
406  }
407 
408  /* Check for the 'signature()' pseudo-adapter, introduced in Windows 2000 */
409  if (_wcsicmp(Token.Buffer, L"signature") == 0)
410  {
411  /*
412  * We've got a signature! Remember this for later, and set the adapter type to SCSI.
413  * We however check that the rest of the ARC path is valid by parsing the other tokens.
414  * AdapterKey stores the disk signature value (that holds in a ULONG).
415  */
416  UseSignature = TRUE;
418  }
419  else
420  {
421  /* Check for regular adapters */
422  // ArcMatchTokenU(Token.Buffer, AdapterTypes_U);
425  {
426  DPRINT1("Invalid adapter type %wZ\n", &Token);
428  }
429 
430  /* Check for adapters that don't take any extra controller or peripheral nodes */
432  {
433  // if (*p)
434  // return STATUS_OBJECT_PATH_SYNTAX_BAD;
435 
436  if (AdapterType == NetAdapter)
437  {
438  DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U[AdapterType], AdapterKey);
439  return STATUS_NOT_SUPPORTED;
440  }
441 
442  goto Quit;
443  }
444  }
445 
446  /* Here, we have either an 'eisa', a 'scsi/signature', or a 'multi' adapter */
447 
448  /* Check for a valid controller */
449  p = ArcGetNextTokenU(p, &Token, &ControllerKey);
450  if (!p)
451  {
452  DPRINT1("%S(%lu) adapter doesn't have a controller!\n", AdapterTypes_U[AdapterType], AdapterKey);
454  }
455  // ArcMatchTokenU(Token.Buffer, ControllerTypes_U);
457  if (ControllerType >= ControllerTypeMax)
458  {
459  DPRINT1("Invalid controller type %wZ\n", &Token);
461  }
462 
463  /* Here the controller can only be either a disk or a CDROM */
464 
465  /*
466  * Ignore the controller in case we have a 'multi' adapter.
467  * I guess a similar condition holds for the 'eisa' adapter too...
468  *
469  * For SignatureAdapter, as similar for ScsiAdapter, the controller key corresponds
470  * to the disk target ID. Note that actually, the implementation just ignores the
471  * target ID, as well as the LUN, and just loops over all the available disks and
472  * searches for the one having the correct signature.
473  */
474  if ((AdapterType == MultiAdapter /* || AdapterType == EisaAdapter */) && ControllerKey != 0)
475  {
476  DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
477  AdapterTypes_U[AdapterType], AdapterKey,
478  ControllerTypes_U[ControllerType], ControllerKey);
479  ControllerKey = 0;
480  }
481 
482  /*
483  * Only the 'scsi' adapter supports a direct 'cdrom' controller.
484  * For the others, we need a 'disk' controller to which a 'cdrom' peripheral can talk to.
485  */
486  if ((AdapterType != ScsiAdapter) && (ControllerType == CdRomController))
487  {
488  DPRINT1("%S(%lu) adapter cannot have a CDROM controller!\n", AdapterTypes_U[AdapterType], AdapterKey);
490  }
491 
492  /* Check for a valid peripheral */
493  p = ArcGetNextTokenU(p, &Token, &PeripheralKey);
494  if (!p)
495  {
496  DPRINT1("%S(%lu)%S(%lu) adapter-controller doesn't have a peripheral!\n",
497  AdapterTypes_U[AdapterType], AdapterKey,
498  ControllerTypes_U[ControllerType], ControllerKey);
500  }
501  // ArcMatchTokenU(Token.Buffer, PeripheralTypes_U);
503  if (PeripheralType >= PeripheralTypeMax)
504  {
505  DPRINT1("Invalid peripheral type %wZ\n", &Token);
507  }
508 
509  /*
510  * If we had a 'cdrom' controller already, the corresponding peripheral can only be 'fdisk'
511  * (see for example the ARC syntax for SCSI CD-ROMs: scsi(x)cdrom(y)fdisk(z) where z == 0).
512  */
513  if ((ControllerType == CdRomController) && (PeripheralType != FDiskPeripheral))
514  {
515  DPRINT1("%S(%lu) controller cannot have a %S(%lu) peripheral! (note that we haven't check whether the adapter was SCSI or not)\n",
516  ControllerTypes_U[ControllerType], ControllerKey,
517  PeripheralTypes_U[PeripheralType], PeripheralKey);
519  }
520 
521  /* For a 'scsi' adapter, the possible peripherals are only 'rdisk' or 'fdisk' */
522  if (AdapterType == ScsiAdapter && !(PeripheralType == RDiskPeripheral || PeripheralType == FDiskPeripheral))
523  {
524  DPRINT1("%S(%lu)%S(%lu) SCSI adapter-controller has an invalid peripheral %S(%lu) !\n",
525  AdapterTypes_U[AdapterType], AdapterKey,
526  ControllerTypes_U[ControllerType], ControllerKey,
527  PeripheralTypes_U[PeripheralType], PeripheralKey);
529  }
530 
531 #if 0
532  if (AdapterType == SignatureAdapter && PeripheralKey != 0)
533  {
534  DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
535  AdapterTypes_U[AdapterType], AdapterKey,
536  PeripheralTypes_U[PeripheralType], PeripheralKey);
537  PeripheralKey = 0;
538  }
539 #endif
540 
541  /* Check for the optional 'partition' specifier */
543  if (q && _wcsicmp(Token.Buffer, L"partition") == 0)
544  {
545  /* We've got a partition! */
546  p = q;
547  }
548  else
549  {
550  /*
551  * Either no other ARC token was found, or we've got something else
552  * (possibly invalid or not)...
553  */
554  PartitionNumber = 0;
555  }
556 
557  // TODO: Check the partition number in case of fdisks and cdroms??
558 
559 Quit:
560  /* Return the results */
561  *ArcNamePath = p;
562  *pAdapterKey = AdapterKey;
563  *pControllerKey = ControllerKey;
564  *pPeripheralKey = PeripheralKey;
565  *pPartitionNumber = PartitionNumber;
566  *pAdapterType = AdapterType;
567  *pControllerType = ControllerType;
568  *pPeripheralType = PeripheralType;
569  *pUseSignature = UseSignature;
570 
571  return STATUS_SUCCESS;
572 }
573 
574 /*
575  * ArcName:
576  * ARC name (counted string) to be resolved into a NT device name.
577  * The caller should have already delimited it from within an ARC path
578  * (usually by finding where the first path separator appears in the path).
579  *
580  * NtName:
581  * Receives the resolved NT name. The buffer is NULL-terminated.
582  */
583 static NTSTATUS
585  OUT PUNICODE_STRING NtName,
586  IN PUNICODE_STRING ArcName)
587 {
590  HANDLE DirectoryHandle, LinkHandle;
591  UNICODE_STRING ArcNameDir;
592 
593  if (NtName->MaximumLength < sizeof(UNICODE_NULL))
595 
596  /* Open the \ArcName object directory */
597  RtlInitUnicodeString(&ArcNameDir, L"\\ArcName");
599  &ArcNameDir,
601  NULL,
602  NULL);
606  if (!NT_SUCCESS(Status))
607  {
608  DPRINT1("NtOpenDirectoryObject(%wZ) failed, Status 0x%08lx\n", &ArcNameDir, Status);
609  return Status;
610  }
611 
612  /* Open the ARC name link */
614  ArcName,
617  NULL);
618  Status = NtOpenSymbolicLinkObject(&LinkHandle,
621 
622  /* Close the \ArcName object directory handle */
624 
625  /* Check for success */
626  if (!NT_SUCCESS(Status))
627  {
628  DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName, Status);
629  return Status;
630  }
631 
632  /* Reserve one WCHAR for the NULL-termination */
633  NtName->MaximumLength -= sizeof(UNICODE_NULL);
634 
635  /* Resolve the link and close its handle */
636  Status = NtQuerySymbolicLinkObject(LinkHandle, NtName, NULL);
637  NtClose(LinkHandle);
638 
639  /* Restore the NULL-termination */
640  NtName->MaximumLength += sizeof(UNICODE_NULL);
641 
642  /* Check for success */
643  if (!NT_SUCCESS(Status))
644  {
645  /* We failed, don't touch NtName */
646  DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName, Status);
647  }
648  else
649  {
650  /* We succeeded, NULL-terminate NtName */
651  NtName->Buffer[NtName->Length / sizeof(WCHAR)] = UNICODE_NULL;
652  }
653 
654  return Status;
655 }
656 
657 /*
658  * ArcNamePath:
659  * In input, pointer to an ARC path (NULL-terminated) starting by an
660  * ARC name to be resolved into a NT device name.
661  * In opposition to ResolveArcNameNtSymLink(), the caller does not have
662  * to delimit the ARC name from within an ARC path. The real ARC name is
663  * deduced after parsing the ARC path, and, in output, ArcNamePath points
664  * to the beginning of the path after the ARC name part.
665  *
666  * NtName:
667  * Receives the resolved NT name. The buffer is NULL-terminated.
668  *
669  * PartList:
670  * (Optional) partition list that helps in resolving the paths pointing
671  * to hard disks.
672  */
673 static NTSTATUS
675  OUT PUNICODE_STRING NtName,
676  IN OUT PCWSTR* ArcNamePath,
677  IN PPARTLIST PartList)
678 {
680  ULONG AdapterKey;
681  ULONG ControllerKey;
682  ULONG PeripheralKey;
685  CONTROLLER_TYPE ControllerType;
686  PERIPHERAL_TYPE PeripheralType;
687  BOOLEAN UseSignature;
688 
689  PDISKENTRY DiskEntry;
690  PPARTENTRY PartEntry = NULL;
691 
692  if (NtName->MaximumLength < sizeof(UNICODE_NULL))
694 
695  /* Parse the ARC path */
696  Status = ParseArcName(ArcNamePath,
697  &AdapterKey,
698  &ControllerKey,
699  &PeripheralKey,
701  &AdapterType,
702  &ControllerType,
703  &PeripheralType,
704  &UseSignature);
705  if (!NT_SUCCESS(Status))
706  return Status;
707 
708  // TODO: Check the partition number in case of fdisks and cdroms??
709 
710  /* Check for adapters that don't take any extra controller or peripheral node */
712  {
713  if (AdapterType == NetAdapter)
714  {
715  DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U[AdapterType], AdapterKey);
716  return STATUS_NOT_SUPPORTED;
717  }
718 
719  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
720  L"\\Device\\Ramdisk%lu", AdapterKey);
721  }
722  else
723  if (ControllerType == CdRomController) // and so, AdapterType == ScsiAdapter and PeripheralType == FDiskPeripheral
724  {
725  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
726  L"\\Device\\Scsi\\CdRom%lu", ControllerKey);
727  }
728  else
729  /* Now, ControllerType == DiskController */
730  if (PeripheralType == CdRomPeripheral)
731  {
732  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
733  L"\\Device\\CdRom%lu", PeripheralKey);
734  }
735  else
736  if (PeripheralType == FDiskPeripheral)
737  {
738  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
739  L"\\Device\\Floppy%lu", PeripheralKey);
740  }
741  else
742  if (PeripheralType == RDiskPeripheral)
743  {
744  if (UseSignature)
745  {
746  /* The disk signature is stored in AdapterKey */
747  DiskEntry = GetDiskBySignature(PartList, AdapterKey);
748  }
749  else
750  {
751  DiskEntry = GetDiskBySCSI(PartList, AdapterKey,
752  ControllerKey, PeripheralKey);
753  }
754  if (!DiskEntry)
755  return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_NOT_FOUND;
756 
757  if (PartitionNumber != 0)
758  {
759  PartEntry = GetPartition(DiskEntry, PartitionNumber);
760  if (!PartEntry)
761  return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_DEVICE_NOT_PARTITIONED;
762  ASSERT(PartEntry->DiskEntry == DiskEntry);
763  }
764 
765  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
766  L"\\Device\\Harddisk%lu\\Partition%lu",
767  DiskEntry->DiskNumber, PartitionNumber);
768  }
769 #if 0 // FIXME: Not implemented yet!
770  else
771  if (PeripheralType == VDiskPeripheral)
772  {
773  // TODO: Check how Win 7+ deals with virtual disks.
774  Status = RtlStringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
775  L"\\Device\\VirtualHarddisk%lu\\Partition%lu",
776  PeripheralKey, PartitionNumber);
777  }
778 #endif
779 
780  if (!NT_SUCCESS(Status))
781  {
782  /* Returned NtName is invalid, so zero it out */
783  *NtName->Buffer = UNICODE_NULL;
784  NtName->Length = 0;
785 
786  return Status;
787  }
788 
789  /* Update NtName length */
790  NtName->Length = wcslen(NtName->Buffer) * sizeof(WCHAR);
791 
792  return STATUS_SUCCESS;
793 }
794 
795 
796 BOOLEAN
798  OUT PUNICODE_STRING NtPath,
799  IN PCWSTR ArcPath,
800  IN PPARTLIST PartList OPTIONAL)
801 {
803  PCWSTR BeginOfPath;
804  UNICODE_STRING ArcName;
805 
806  /* TODO: We should "normalize" the path, i.e. expand all the xxx() into xxx(0) */
807 
808  if (NtPath->MaximumLength < sizeof(UNICODE_NULL))
809  return FALSE;
810 
811  *NtPath->Buffer = UNICODE_NULL;
812  NtPath->Length = 0;
813 
814  /*
815  * - First, check whether the ARC path is already inside \\ArcName
816  * and if so, map it to the corresponding NT path.
817  * - Only then, if we haven't found any ArcName, try to build a
818  * NT path by deconstructing the ARC path, using its disk and
819  * partition numbers. We may use here our disk/partition list.
820  *
821  * See also freeldr/arcname.c
822  *
823  * Note that it would be nice to maintain a cache of these mappings.
824  */
825 
826  /*
827  * Initialize the ARC name to resolve, by cutting the ARC path at the first
828  * NT path separator. The ARC name therefore ends where the NT path part starts.
829  */
830  RtlInitUnicodeString(&ArcName, ArcPath);
831  BeginOfPath = wcschr(ArcName.Buffer, OBJ_NAME_PATH_SEPARATOR);
832  if (BeginOfPath)
833  ArcName.Length = (ULONG_PTR)BeginOfPath - (ULONG_PTR)ArcName.Buffer;
834 
835  /* Resolve the ARC name via NT SymLinks. Note that NtPath is returned NULL-terminated. */
836  Status = ResolveArcNameNtSymLink(NtPath, &ArcName);
837  if (!NT_SUCCESS(Status))
838  {
839  /* We failed, attempt a manual resolution */
840  DPRINT1("ResolveArcNameNtSymLink(ArcName = '%wZ') for ArcPath = '%S' failed, Status 0x%08lx\n", &ArcName, ArcPath, Status);
841 
842  /*
843  * We failed at directly resolving the ARC path, and we cannot perform
844  * a manual resolution because we don't have any disk/partition list,
845  * we therefore fail here.
846  */
847  if (!PartList)
848  {
849  DPRINT1("PartList == NULL, cannot perform a manual resolution\n");
850  return FALSE;
851  }
852 
853  *NtPath->Buffer = UNICODE_NULL;
854  NtPath->Length = 0;
855 
856  BeginOfPath = ArcPath;
857  Status = ResolveArcNameManually(NtPath, &BeginOfPath, PartList);
858  if (!NT_SUCCESS(Status))
859  {
860  /* We really failed this time, bail out */
861  DPRINT1("ResolveArcNameManually(ArcPath = '%S') failed, Status 0x%08lx\n", ArcPath, Status);
862  return FALSE;
863  }
864  }
865 
866  /*
867  * We succeeded. Concatenate the rest of the system-specific path. We know the path is going
868  * to be inside the NT namespace, therefore we can use the path string concatenation function
869  * that uses '\\' as the path separator.
870  */
871  if (BeginOfPath && *BeginOfPath)
872  {
873  Status = ConcatPaths(NtPath->Buffer, NtPath->MaximumLength / sizeof(WCHAR), 1, BeginOfPath);
874  if (!NT_SUCCESS(Status))
875  {
876  /* Buffer not large enough, or whatever...: just bail out */
877  return FALSE;
878  }
879  }
880  NtPath->Length = wcslen(NtPath->Buffer) * sizeof(WCHAR);
881 
882  return TRUE;
883 }
884 
885 #if 0 // FIXME: Not implemented yet!
886 PWSTR
887 NtPathToArcPath(
888  IN PWSTR NtPath)
889 {
890  /*
891  * - First, check whether any of the ARC paths inside \\ArcName
892  * map to the corresponding NT path. If so, we are OK.
893  * - Only then, if we haven't found any ArcName, try to build an
894  * ARC path by deconstructing the NT path, using its disk and
895  * partition numbers. We may use here our disk/partition list.
896  *
897  * See also freeldr/arcname.c
898  *
899  * Note that it would be nice to maintain a cache of these mappings.
900  */
901 }
902 #endif
903 
904 /* 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:2056
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:391
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:270
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
_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:806
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:797
ULONG DiskNumber
Definition: partlist.h:105
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:623
#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:584
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
uint32_t ULONG_PTR
Definition: typedefs.h:63
PPARTENTRY GetPartition(IN PDISKENTRY DiskEntry, IN ULONG PartitionNumber)
Definition: partlist.c:2082
static NTSTATUS ResolveArcNameManually(OUT PUNICODE_STRING NtName, IN OUT PCWSTR *ArcNamePath, IN PPARTLIST PartList)
Definition: arcname.c:674
#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:411
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
enum _ADAPTER_TYPE * PADAPTER_TYPE
ULONG ArcMatchTokenA(IN PCSTR CandidateToken, IN const PCSTR *TokenTable)
Definition: arcname.c:240
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
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:255
_PERIPHERAL_TYPE
Definition: arcname.c:86
static __inline NTSTATUS 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:1120
Status
Definition: gdiplustypes.h:24
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#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:176
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
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:2026
#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:366
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:2777
_ADAPTER_TYPE
Definition: arcname.c:37
#define CHAR(Char)
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:304
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68