ReactOS  0.4.14-dev-554-g2f8d847
symlink.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 2011-2012 ReactOS Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * COPYRIGHT: See COPYING in the top level directory
20  * PROJECT: ReactOS kernel
21  * FILE: drivers/filesystem/mountmgr/symlink.c
22  * PURPOSE: Mount Manager - Symbolic links functions
23  * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24  */
25 
26 #include "mntmgr.h"
27 
28 #define NDEBUG
29 #include <debug.h>
30 
32 UNICODE_STRING DosDevicesMount = RTL_CONSTANT_STRING(L"\\DosDevices\\MountPointManager");
38 UNICODE_STRING SafeVolumes = RTL_CONSTANT_STRING(L"\\Device\\VolumesSafeForWriteAccess");
40 UNICODE_STRING ReparseIndex = RTL_CONSTANT_STRING(L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
41 
42 /*
43  * @implemented
44  */
47  OUT PUNICODE_STRING GlobalString)
48 {
49  UNICODE_STRING IntGlobal;
50 
52  {
53  /* DOS device - use DOS global */
55  IntGlobal.MaximumLength = IntGlobal.Length + sizeof(WCHAR);
56  IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
57  if (!IntGlobal.Buffer)
58  {
60  }
61 
63  RtlCopyMemory(IntGlobal.Buffer + (DosGlobal.Length / sizeof(WCHAR)),
64  DosName->Buffer + (DosDevices.Length / sizeof(WCHAR)),
66  IntGlobal.Buffer[IntGlobal.Length / sizeof(WCHAR)] = UNICODE_NULL;
67  }
69  {
70  /* Switch to DOS global */
72  IntGlobal.MaximumLength = IntGlobal.Length + sizeof(WCHAR);
73  IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
74  if (!IntGlobal.Buffer)
75  {
77  }
78 
80  RtlCopyMemory(IntGlobal.Buffer + (DosGlobal.Length / sizeof(WCHAR)),
81  DosName->Buffer + (Global.Length / sizeof(WCHAR)),
83  IntGlobal.Buffer[IntGlobal.Length / sizeof(WCHAR)] = UNICODE_NULL;
84  }
85  else
86  {
87  /* Simply duplicate string */
88  IntGlobal.Length = DosName->Length;
89  IntGlobal.MaximumLength = DosName->MaximumLength;
90  IntGlobal.Buffer = AllocatePool(IntGlobal.MaximumLength);
91  if (!IntGlobal.Buffer)
92  {
94  }
95 
96  RtlCopyMemory(IntGlobal.Buffer, DosName->Buffer, IntGlobal.MaximumLength);
97  }
98 
99  /* Return string */
100  GlobalString->Length = IntGlobal.Length;
101  GlobalString->MaximumLength = IntGlobal.MaximumLength;
102  GlobalString->Buffer = IntGlobal.Buffer;
103 
104  return STATUS_SUCCESS;
105 }
106 
107 /*
108  * @implemented
109  */
110 NTSTATUS
113 {
115  UNICODE_STRING GlobalName;
116 
117  /* First create the global string */
118  Status = CreateStringWithGlobal(DosName, &GlobalName);
119  if (!NT_SUCCESS(Status))
120  {
121  return Status;
122  }
123 
124  /* Then, create the symlink */
125  Status = IoCreateSymbolicLink(&GlobalName, DeviceName);
126 
127  FreePool(GlobalName.Buffer);
128 
129  return Status;
130 }
131 
132 /*
133  * @implemented
134  */
135 NTSTATUS
137 {
139  UNICODE_STRING GlobalName;
140 
141  /* Recreate the string (to find the link) */
142  Status = CreateStringWithGlobal(DosName, &GlobalName);
143  if (!NT_SUCCESS(Status))
144  {
145  return Status;
146  }
147 
148  /* And delete the link */
149  Status = IoDeleteSymbolicLink(&GlobalName);
150 
151  FreePool(GlobalName.Buffer);
152 
153  return Status;
154 }
155 
156 /*
157  * @implemented
158  */
159 VOID
161 {
162  PIRP Irp;
163  KEVENT Event;
164  ULONG NameSize;
167  PIO_STACK_LOCATION Stack;
171 
172  /* Get the device associated with the name */
175  &FileObject,
176  &DeviceObject);
177  if (!NT_SUCCESS(Status))
178  {
179  return;
180  }
181 
182  /* Get attached device (will notify it) */
184 
185  /* NameSize is the size of the whole MOUNTDEV_NAME struct */
186  NameSize = sizeof(USHORT) + SymbolicName->Length;
187  Name = AllocatePool(NameSize);
188  if (!Name)
189  {
190  goto Cleanup;
191  }
192 
193  /* Initialize struct */
194  Name->NameLength = SymbolicName->Length;
196 
198  /* Microsoft does it twice... Once with limited access, second with any
199  * So, first one here
200  */
202  DeviceObject,
203  Name,
204  NameSize,
205  NULL,
206  0,
207  FALSE,
208  &Event,
209  &IoStatusBlock);
210  /* This one can fail, no one matters */
211  if (Irp)
212  {
214  Stack->FileObject = FileObject;
215 
217  if (Status == STATUS_PENDING)
218  {
220  }
221  }
222 
223  /* Then, second one */
226  DeviceObject,
227  Name,
228  NameSize,
229  NULL,
230  0,
231  FALSE,
232  &Event,
233  &IoStatusBlock);
234  if (!Irp)
235  {
236  goto Cleanup;
237  }
238 
240  Stack->FileObject = FileObject;
241 
242  /* Really notify */
244  if (Status == STATUS_PENDING)
245  {
247  }
248 
249 Cleanup:
250  if (Name)
251  {
252  FreePool(Name);
253  }
254 
257 
258  return;
259 }
260 
261 /*
262  * @implemented
263  */
264 VOID
267 {
268  PIRP Irp;
269  KEVENT Event;
270  ULONG NameSize;
273  PIO_STACK_LOCATION Stack;
277 
278  /* Get the device associated with the name */
281  &FileObject,
282  &DeviceObject);
283  if (!NT_SUCCESS(Status))
284  {
285  return;
286  }
287 
288  /* Get attached device (will notify it) */
290 
291  /* NameSize is the size of the whole MOUNTDEV_NAME struct */
292  NameSize = sizeof(USHORT) + SymbolicName->Length;
293  Name = AllocatePool(NameSize);
294  if (!Name)
295  {
296  goto Cleanup;
297  }
298 
299  /* Initialize struct */
300  Name->NameLength = SymbolicName->Length;
302 
304  /* Cf: SendLinkCreated comment */
306  DeviceObject,
307  Name,
308  NameSize,
309  NULL,
310  0,
311  FALSE,
312  &Event,
313  &IoStatusBlock);
314  /* This one can fail, no one matters */
315  if (Irp)
316  {
318  Stack->FileObject = FileObject;
319 
321  if (Status == STATUS_PENDING)
322  {
324  }
325  }
326 
327  /* Then, second one */
330  DeviceObject,
331  Name,
332  NameSize,
333  NULL,
334  0,
335  FALSE,
336  &Event,
337  &IoStatusBlock);
338  if (!Irp)
339  {
340  goto Cleanup;
341  }
342 
344  Stack->FileObject = FileObject;
345 
346  /* Really notify */
348  if (Status == STATUS_PENDING)
349  {
351  }
352 
353 Cleanup:
354  if (Name)
355  {
356  FreePool(Name);
357  }
358 
361 
362  return;
363 }
364 
365 /*
366  * @implemented
367  */
368 NTSTATUS
369 NTAPI
374  IN PVOID Context,
376 {
377  UNICODE_STRING ValueNameString;
378  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
379 
380  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
381  (UniqueId->UniqueIdLength != ValueLength))
382  {
383  return STATUS_SUCCESS;
384  }
385 
387  {
388  return STATUS_SUCCESS;
389  }
390 
391  /* That one matched, increase count */
392  RtlInitUnicodeString(&ValueNameString, ValueName);
393  if (ValueNameString.Length)
394  {
395  (*((PULONG)EntryContext))++;
396  }
397 
398  return STATUS_SUCCESS;
399 }
400 
401 /*
402  * @implemented
403  */
404 NTSTATUS
405 NTAPI
410  IN PVOID Context,
412 {
413  UNICODE_STRING ValueNameString;
414  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
415  /* Unicode strings table */
416  PUNICODE_STRING ReturnString = EntryContext;
417 
418  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
419  (UniqueId->UniqueIdLength != ValueLength))
420  {
421  return STATUS_SUCCESS;
422  }
423 
425  {
426  return STATUS_SUCCESS;
427  }
428 
429  /* Unique ID matches, let's put the symlink */
430  RtlInitUnicodeString(&ValueNameString, ValueName);
431  if (!ValueNameString.Length)
432  {
433  return STATUS_SUCCESS;
434  }
435 
436  /* Allocate string to copy */
437  ValueNameString.Buffer = AllocatePool(ValueNameString.MaximumLength);
438  if (!ValueNameString.Buffer)
439  {
440  return STATUS_SUCCESS;
441  }
442 
443  /* Copy */
444  RtlCopyMemory(ValueNameString.Buffer, ValueName, ValueNameString.Length);
445  ValueNameString.Buffer[ValueNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
446 
447  while (ReturnString->Length)
448  {
449  ReturnString++;
450  }
451 
452  /* And return that string */
453  *ReturnString = ValueNameString;
454 
455  return STATUS_SUCCESS;
456 }
457 
458 /*
459  * @implemented
460  */
461 NTSTATUS
463  IN PGUID VolumeGuid OPTIONAL)
464 {
465  GUID Guid;
468 
469  /* If no GUID was provided, then create one */
470  if (!VolumeGuid)
471  {
473  if (!NT_SUCCESS(Status))
474  {
475  return Status;
476  }
477  }
478  else
479  {
480  RtlCopyMemory(&Guid, VolumeGuid, sizeof(GUID));
481  }
482 
483  /* Convert GUID to string */
485  if (!NT_SUCCESS(Status))
486  {
487  return Status;
488  }
489 
490  /* Size for volume namespace, literal GUID, and null char */
491  VolumeName->MaximumLength = 0x14 + 0x4C + sizeof(UNICODE_NULL);
492  VolumeName->Buffer = AllocatePool(0x14 + 0x4C + sizeof(UNICODE_NULL));
493  if (!VolumeName->Buffer)
494  {
496  }
497  else
498  {
503  }
504 
505  ExFreePoolWithTag(GuidString.Buffer, 0);
506 
507  return Status;
508 }
509 
510 /*
511  * @implemented
512  */
513 NTSTATUS
515  IN PDEVICE_INFORMATION DeviceInformation,
516  IN PUNICODE_STRING SuggestedLinkName,
517  IN BOOLEAN UseOnlyIfThereAreNoOtherLinks,
518  OUT PUNICODE_STRING * SymLinks,
519  OUT PULONG SymLinkCount,
520  IN BOOLEAN HasGuid,
521  IN LPGUID Guid)
522 {
524  BOOLEAN WriteNew;
526 
527  UNREFERENCED_PARAMETER(DeviceExtension);
528 
529  /* First of all, count links */
532  QueryTable[0].EntryContext = SymLinkCount;
533  *SymLinkCount = 0;
534 
536  DatabasePath,
537  QueryTable,
538  DeviceInformation->UniqueId,
539  NULL);
540  if (!NT_SUCCESS(Status))
541  {
542  *SymLinkCount = 0;
543  }
544 
545  /* Check if we have to write a new one first */
546  if (SuggestedLinkName && !IsDriveLetter(SuggestedLinkName) &&
547  UseOnlyIfThereAreNoOtherLinks && *SymLinkCount == 0)
548  {
549  WriteNew = TRUE;
550  }
551  else
552  {
553  WriteNew = FALSE;
554  }
555 
556  /* If has GUID, it makes one more link */
557  if (HasGuid)
558  {
559  (*SymLinkCount)++;
560  }
561 
562  if (WriteNew)
563  {
564  /* Write link */
566  DatabasePath,
567  SuggestedLinkName->Buffer,
568  REG_BINARY,
569  DeviceInformation->UniqueId->UniqueId,
570  DeviceInformation->UniqueId->UniqueIdLength);
571 
572  /* And recount all the needed links */
575  QueryTable[0].EntryContext = SymLinkCount;
576  *SymLinkCount = 0;
577 
579  DatabasePath,
580  QueryTable,
581  DeviceInformation->UniqueId,
582  NULL);
583  if (!NT_SUCCESS(Status))
584  {
585  return STATUS_NOT_FOUND;
586  }
587  }
588 
589  /* Not links found? */
590  if (!*SymLinkCount)
591  {
592  return STATUS_NOT_FOUND;
593  }
594 
595  /* Allocate a buffer big enough to hold symlinks (table of unicode strings) */
596  *SymLinks = AllocatePool(*SymLinkCount * sizeof(UNICODE_STRING));
597  if (!*SymLinks)
598  {
600  }
601 
602  /* Prepare to query links */
603  RtlZeroMemory(*SymLinks, *SymLinkCount * sizeof(UNICODE_STRING));
606 
607  /* No GUID? Keep it that way */
608  if (!HasGuid)
609  {
610  QueryTable[0].EntryContext = *SymLinks;
611  }
612  /* Otherwise, first create volume name */
613  else
614  {
615  Status = CreateNewVolumeName(SymLinks[0], Guid);
616  if (!NT_SUCCESS(Status))
617  {
618  FreePool(*SymLinks);
619  return Status;
620  }
621 
622  /* Skip first link (ours) */
623  QueryTable[0].EntryContext = *SymLinks + 1;
624  }
625 
626  /* Now, query */
628  DatabasePath,
629  QueryTable,
630  DeviceInformation->UniqueId,
631  NULL);
632 
633  return STATUS_SUCCESS;
634 }
635 
636 /*
637  * @implemented
638  */
641  IN PMOUNTDEV_UNIQUE_ID UniqueId)
642 {
643  PLIST_ENTRY NextEntry;
644  PSAVED_LINK_INFORMATION SavedLinkInformation;
645 
646  /* No saved links? Easy! */
647  if (IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
648  {
649  return NULL;
650  }
651 
652  /* Now, browse saved links */
653  for (NextEntry = DeviceExtension->SavedLinksListHead.Flink;
654  NextEntry != &(DeviceExtension->SavedLinksListHead);
655  NextEntry = NextEntry->Flink)
656  {
657  SavedLinkInformation = CONTAINING_RECORD(NextEntry,
659  SavedLinksListEntry);
660 
661  /* Find the one that matches */
662  if (SavedLinkInformation->UniqueId->UniqueIdLength == UniqueId->UniqueIdLength)
663  {
664  if (RtlCompareMemory(SavedLinkInformation->UniqueId->UniqueId,
665  UniqueId->UniqueId,
666  UniqueId->UniqueIdLength) ==
667  UniqueId->UniqueIdLength)
668  {
669  /* Remove it and return it */
670  RemoveEntryList(&(SavedLinkInformation->SavedLinksListEntry));
671  return SavedLinkInformation;
672  }
673  }
674  }
675 
676  /* None found (none removed) */
677  return NULL;
678 }
679 
680 /*
681  * @implemented
682  */
683 NTSTATUS
685  OUT PUNICODE_STRING SuggestedLinkName,
686  OUT PBOOLEAN UseOnlyIfThereAreNoOtherLinks)
687 {
688  PIRP Irp;
689  KEVENT Event;
691  USHORT NameLength;
695  PIO_STACK_LOCATION IoStackLocation;
696  PMOUNTDEV_SUGGESTED_LINK_NAME IoCtlSuggested;
697 
698  /* First, get device */
701  &FileObject,
702  &DeviceObject);
703  if (!NT_SUCCESS(Status))
704  {
705  return Status;
706  }
707 
708  /* Then, get attached device */
710 
711  /* Then, prepare buffer to query suggested name */
712  IoCtlSuggested = AllocatePool(sizeof(MOUNTDEV_SUGGESTED_LINK_NAME));
713  if (!IoCtlSuggested)
714  {
716  goto Dereference;
717  }
718 
719  /* Prepare request */
722  DeviceObject,
723  NULL,
724  0,
725  IoCtlSuggested,
727  FALSE,
728  &Event,
729  &IoStatusBlock);
730  if (!Irp)
731  {
733  goto Release;
734  }
735 
736  IoStackLocation = IoGetNextIrpStackLocation(Irp);
737  IoStackLocation->FileObject = FileObject;
738 
739  /* And ask */
741  if (Status == STATUS_PENDING)
742  {
744  FALSE, NULL);
746  }
747 
748  /* Overflow? Normal */
750  {
751  /* Reallocate big enough buffer */
752  NameLength = IoCtlSuggested->NameLength + sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
753  FreePool(IoCtlSuggested);
754 
755  IoCtlSuggested = AllocatePool(NameLength);
756  if (!IoCtlSuggested)
757  {
759  goto Dereference;
760  }
761 
762  /* And reask */
765  DeviceObject,
766  NULL,
767  0,
768  IoCtlSuggested,
769  NameLength,
770  FALSE,
771  &Event,
772  &IoStatusBlock);
773  if (!Irp)
774  {
776  goto Release;
777  }
778 
779  IoStackLocation = IoGetNextIrpStackLocation(Irp);
780  IoStackLocation->FileObject = FileObject;
781 
783  if (Status == STATUS_PENDING)
784  {
786  FALSE, NULL);
788  }
789  }
790 
791  if (!NT_SUCCESS(Status))
792  {
793  goto Release;
794  }
795 
796  /* Now we have suggested name, copy it */
797  SuggestedLinkName->Length = IoCtlSuggested->NameLength;
798  SuggestedLinkName->MaximumLength = IoCtlSuggested->NameLength + sizeof(UNICODE_NULL);
799  SuggestedLinkName->Buffer = AllocatePool(IoCtlSuggested->NameLength + sizeof(UNICODE_NULL));
800  if (!SuggestedLinkName->Buffer)
801  {
803  }
804  else
805  {
806  RtlCopyMemory(SuggestedLinkName->Buffer, IoCtlSuggested->Name, IoCtlSuggested->NameLength);
807  SuggestedLinkName->Buffer[SuggestedLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
808  }
809 
810  /* Also return its priority */
811  *UseOnlyIfThereAreNoOtherLinks = IoCtlSuggested->UseOnlyIfThereAreNoOtherLinks;
812 
813 Release:
814  FreePool(IoCtlSuggested);
815 
816 Dereference:
819 
820  return Status;
821 }
822 
823 /*
824  * @implemented
825  */
826 BOOLEAN
829  IN PUNICODE_STRING NewLink)
830 {
831  PLIST_ENTRY NextEntry;
832  PSYMLINK_INFORMATION SymlinkInformation;
833 
834  /* Find the link */
835  for (NextEntry = SavedLinkInformation->SymbolicLinksListHead.Flink;
836  NextEntry != &(SavedLinkInformation->SymbolicLinksListHead);
837  NextEntry = NextEntry->Flink)
838  {
839  SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
840 
841  if (!RtlEqualUnicodeString(DosName, &(SymlinkInformation->Name), TRUE))
842  {
843  /* Delete old link */
845  /* Set its new location */
847 
848  /* And remove it from the list (not valid any more) */
849  RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
850  FreePool(SymlinkInformation->Name.Buffer);
851  FreePool(SymlinkInformation);
852 
853  return TRUE;
854  }
855  }
856 
857  return FALSE;
858 }
859 
860 /*
861  * @implemented
862  */
863 VOID
866  IN BOOLEAN MarkOffline)
867 {
868  PLIST_ENTRY DeviceEntry, SymbolEntry;
869  PDEVICE_INFORMATION DeviceInformation;
870  PSYMLINK_INFORMATION SymlinkInformation;
871 
872  /* First of all, ensure we have devices */
873  if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
874  {
875  return;
876  }
877 
878  /* Then, look for the symbolic name */
879  for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
880  DeviceEntry != &(DeviceExtension->DeviceListHead);
881  DeviceEntry = DeviceEntry->Flink)
882  {
883  DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
884 
885  for (SymbolEntry = DeviceInformation->SymbolicLinksListHead.Flink;
886  SymbolEntry != &(DeviceInformation->SymbolicLinksListHead);
887  SymbolEntry = SymbolEntry->Flink)
888  {
889  SymlinkInformation = CONTAINING_RECORD(SymbolEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
890 
891  /* One we have found it */
892  if (RtlCompareUnicodeString(SymbolicLink, &(SymlinkInformation->Name), TRUE) == 0)
893  {
894  /* Check if caller just want it to be offline */
895  if (MarkOffline)
896  {
897  SymlinkInformation->Online = FALSE;
898  }
899  else
900  {
901  /* If not, delete it & notify */
902  SendLinkDeleted(&(DeviceInformation->SymbolicName), SymbolicLink);
903  RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
904 
905  FreePool(SymlinkInformation->Name.Buffer);
906  FreePool(SymlinkInformation);
907  }
908 
909  /* No need to go farther */
910  return;
911  }
912  }
913  }
914 
915  return;
916 }
917 
918 /*
919  * @implemented
920  */
921 BOOLEAN
923 {
924  WCHAR Letter, Colon;
925 
926  /* We must have a precise length */
927  if (SymbolicName->Length != DosDevices.Length + 2 * sizeof(WCHAR))
928  {
929  return FALSE;
930  }
931 
932  /* Must start with the DosDevices prefix */
934  {
935  return FALSE;
936  }
937 
938  /* Check if letter is correct */
940  if ((Letter < L'A' || Letter > L'Z') && Letter != (WCHAR)-1)
941  {
942  return FALSE;
943  }
944 
945  /* And finally it must end with a colon */
946  Colon = SymbolicName->Buffer[DosDevices.Length / sizeof(WCHAR) + 1];
947  if (Colon != L':')
948  {
949  return FALSE;
950  }
951 
952  return TRUE;
953 }
954 
955 /*
956  * @implemented
957  */
958 NTSTATUS
961 {
963  HANDLE LinkHandle;
965 
966  /* Open the symbolic link */
968  SymbolicName,
970  NULL,
971  NULL);
972 
973  Status = ZwOpenSymbolicLinkObject(&LinkHandle,
974  GENERIC_READ,
976  if (!NT_SUCCESS(Status))
977  {
978  return Status;
979  }
980 
981  /* Query its target */
982  Status = ZwQuerySymbolicLinkObject(LinkHandle,
983  LinkTarget,
984  NULL);
985 
986  ZwClose(LinkHandle);
987 
988  if (!NT_SUCCESS(Status))
989  {
990  return Status;
991  }
992 
993  if (LinkTarget->Length <= sizeof(WCHAR))
994  {
995  return Status;
996  }
997 
998  /* If it's not finished by \, just return */
999  if (LinkTarget->Buffer[LinkTarget->Length / sizeof(WCHAR) - 1] != L'\\')
1000  {
1001  return Status;
1002  }
1003 
1004  /* Otherwise, ensure to drop the tailing \ */
1005  LinkTarget->Length -= sizeof(WCHAR);
1007 
1008  return Status;
1009 }
#define FILE_READ_ACCESS
Definition: nt_native.h:610
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
static PWSTR GuidString
Definition: apphelp.c:91
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4004
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ BOOLEAN Release
Definition: classpnp.h:929
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define IOCTL_MOUNTDEV_LINK_DELETED
Definition: imports.h:112
#define REG_BINARY
Definition: nt_native.h:1496
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
uint16_t * PWSTR
Definition: typedefs.h:54
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4016
_In_ PNDIS_STRING _In_ PNDIS_STRING SymbolicName
Definition: ndis.h:4676
LONG NTSTATUS
Definition: precomp.h:26
USHORT UniqueIdLength
Definition: imports.h:138
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
WCHAR DeviceName[]
Definition: adapter.cpp:21
#define FreePool(P)
Definition: mntmgr.h:154
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define MOUNTMGR_DEVICE_NAME
Definition: imports.h:76
UNICODE_STRING SymbolicName
Definition: mntmgr.h:48
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
_Inout_ PUNICODE_STRING LinkTarget
Definition: zwfuncs.h:292
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define UNICODE_NULL
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:435
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4004
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
NTKERNELAPI NTSTATUS ExUuidCreate(OUT UUID *Uuid)
Definition: uuid.c:385
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
PDEVICE_OBJECT NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1406
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#define CTL_CODE(DeviceType, Function, Method, Access)
Definition: nt_native.h:586
#define STATUS_NOT_FOUND
Definition: shellext.h:72
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
LIST_ENTRY SymbolicLinksListHead
Definition: mntmgr.h:45
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
* PFILE_OBJECT
Definition: iotypes.h:1955
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define MOUNTDEVCONTROLTYPE
Definition: imports.h:78
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
char * PBOOLEAN
Definition: retypes.h:11
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
static const WCHAR L[]
Definition: oid.c:1250
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
WCHAR Letter
#define GENERIC_READ
Definition: compat.h:124
Definition: typedefs.h:117
NTSYSAPI NTSTATUS WINAPI RtlStringFromGUID(REFGUID, PUNICODE_STRING)
static const WCHAR Cleanup[]
Definition: register.c:80
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2647
#define AllocatePool(Size)
Definition: mntmgr.h:153
PWSTR DatabasePath
Definition: database.c:31
Status
Definition: gdiplustypes.h:24
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
PFILE_OBJECT FileObject
Definition: iotypes.h:2813
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
struct _MOUNTDEV_SUGGESTED_LINK_NAME MOUNTDEV_SUGGESTED_LINK_NAME
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
unsigned short USHORT
Definition: pedump.c:61
#define IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
Definition: imports.h:99
#define METHOD_BUFFERED
Definition: nt_native.h:594
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
_Out_ PUNICODE_STRING DosName
Definition: rtlfuncs.h:1270
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:881
_Must_inspect_result_ _Inout_opt_ PUNICODE_STRING VolumeName
Definition: fltkernel.h:1117
#define FILE_WRITE_ACCESS
Definition: nt_native.h:611
#define OUT
Definition: typedefs.h:39
struct tagContext Context
Definition: acpixf.h:1030
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2938
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
UCHAR UniqueId[1]
Definition: imports.h:139
NTSYSAPI NTSTATUS NTAPI ZwOpenSymbolicLinkObject(_Out_ PHANDLE SymbolicLinkHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes)
static const WCHAR SymbolicLink[]
Definition: interface.c:31
#define IOCTL_MOUNTDEV_LINK_CREATED
Definition: imports.h:106
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68