ReactOS  0.4.13-dev-455-g28ed234
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 
118 
119  /* First create the global string */
120  Status = CreateStringWithGlobal(DosName, &GlobalName);
121  if (!NT_SUCCESS(Status))
122  {
123  return Status;
124  }
125 
126  /* Then, create the symlink */
127  Status = IoCreateSymbolicLink(&GlobalName, DosName);
128 
129  FreePool(GlobalName.Buffer);
130 
131  return Status;
132 }
133 
134 /*
135  * @implemented
136  */
137 NTSTATUS
139 {
141  UNICODE_STRING GlobalName;
142 
143  /* Recreate the string (to find the link) */
144  Status = CreateStringWithGlobal(DosName, &GlobalName);
145  if (!NT_SUCCESS(Status))
146  {
147  return Status;
148  }
149 
150  /* And delete the link */
151  Status = IoDeleteSymbolicLink(&GlobalName);
152 
153  FreePool(GlobalName.Buffer);
154 
155  return Status;
156 }
157 
158 /*
159  * @implemented
160  */
161 VOID
163 {
164  PIRP Irp;
165  KEVENT Event;
166  ULONG NameSize;
169  PIO_STACK_LOCATION Stack;
173 
174  /* Get the device associated with the name */
177  &FileObject,
178  &DeviceObject);
179  if (!NT_SUCCESS(Status))
180  {
181  return;
182  }
183 
184  /* Get attached device (will notify it) */
186 
187  /* NameSize is the size of the whole MOUNTDEV_NAME struct */
188  NameSize = sizeof(USHORT) + SymbolicName->Length;
189  Name = AllocatePool(NameSize);
190  if (!Name)
191  {
192  goto Cleanup;
193  }
194 
195  /* Initialize struct */
196  Name->NameLength = SymbolicName->Length;
198 
200  /* Microsoft does it twice... Once with limited access, second with any
201  * So, first one here
202  */
204  DeviceObject,
205  Name,
206  NameSize,
207  NULL,
208  0,
209  FALSE,
210  &Event,
211  &IoStatusBlock);
212  /* This one can fail, no one matters */
213  if (Irp)
214  {
216  Stack->FileObject = FileObject;
217 
219  if (Status == STATUS_PENDING)
220  {
222  }
223  }
224 
225  /* Then, second one */
228  DeviceObject,
229  Name,
230  NameSize,
231  NULL,
232  0,
233  FALSE,
234  &Event,
235  &IoStatusBlock);
236  if (!Irp)
237  {
238  goto Cleanup;
239  }
240 
242  Stack->FileObject = FileObject;
243 
244  /* Really notify */
246  if (Status == STATUS_PENDING)
247  {
249  }
250 
251 Cleanup:
252  if (Name)
253  {
254  FreePool(Name);
255  }
256 
259 
260  return;
261 }
262 
263 /*
264  * @implemented
265  */
266 VOID
269 {
270  PIRP Irp;
271  KEVENT Event;
272  ULONG NameSize;
275  PIO_STACK_LOCATION Stack;
279 
280  /* Get the device associated with the name */
283  &FileObject,
284  &DeviceObject);
285  if (!NT_SUCCESS(Status))
286  {
287  return;
288  }
289 
290  /* Get attached device (will notify it) */
292 
293  /* NameSize is the size of the whole MOUNTDEV_NAME struct */
294  NameSize = sizeof(USHORT) + SymbolicName->Length;
295  Name = AllocatePool(NameSize);
296  if (!Name)
297  {
298  goto Cleanup;
299  }
300 
301  /* Initialize struct */
302  Name->NameLength = SymbolicName->Length;
304 
306  /* Cf: SendLinkCreated comment */
308  DeviceObject,
309  Name,
310  NameSize,
311  NULL,
312  0,
313  FALSE,
314  &Event,
315  &IoStatusBlock);
316  /* This one can fail, no one matters */
317  if (Irp)
318  {
320  Stack->FileObject = FileObject;
321 
323  if (Status == STATUS_PENDING)
324  {
326  }
327  }
328 
329  /* Then, second one */
332  DeviceObject,
333  Name,
334  NameSize,
335  NULL,
336  0,
337  FALSE,
338  &Event,
339  &IoStatusBlock);
340  if (!Irp)
341  {
342  goto Cleanup;
343  }
344 
346  Stack->FileObject = FileObject;
347 
348  /* Really notify */
350  if (Status == STATUS_PENDING)
351  {
353  }
354 
355 Cleanup:
356  if (Name)
357  {
358  FreePool(Name);
359  }
360 
363 
364  return;
365 }
366 
367 /*
368  * @implemented
369  */
370 NTSTATUS
371 NTAPI
376  IN PVOID Context,
378 {
379  UNICODE_STRING ValueNameString;
380  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
381 
382  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
383  (UniqueId->UniqueIdLength != ValueLength))
384  {
385  return STATUS_SUCCESS;
386  }
387 
389  {
390  return STATUS_SUCCESS;
391  }
392 
393  /* That one matched, increase count */
394  RtlInitUnicodeString(&ValueNameString, ValueName);
395  if (ValueNameString.Length)
396  {
397  (*((PULONG)EntryContext))++;
398  }
399 
400  return STATUS_SUCCESS;
401 }
402 
403 /*
404  * @implemented
405  */
406 NTSTATUS
407 NTAPI
412  IN PVOID Context,
414 {
415  UNICODE_STRING ValueNameString;
416  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
417  /* Unicode strings table */
418  PUNICODE_STRING ReturnString = EntryContext;
419 
420  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
421  (UniqueId->UniqueIdLength != ValueLength))
422  {
423  return STATUS_SUCCESS;
424  }
425 
427  {
428  return STATUS_SUCCESS;
429  }
430 
431  /* Unique ID matches, let's put the symlink */
432  RtlInitUnicodeString(&ValueNameString, ValueName);
433  if (!ValueNameString.Length)
434  {
435  return STATUS_SUCCESS;
436  }
437 
438  /* Allocate string to copy */
439  ValueNameString.Buffer = AllocatePool(ValueNameString.MaximumLength);
440  if (!ValueNameString.Buffer)
441  {
442  return STATUS_SUCCESS;
443  }
444 
445  /* Copy */
446  RtlCopyMemory(ValueNameString.Buffer, ValueName, ValueNameString.Length);
447  ValueNameString.Buffer[ValueNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
448 
449  while (ReturnString->Length)
450  {
451  ReturnString++;
452  }
453 
454  /* And return that string */
455  *ReturnString = ValueNameString;
456 
457  return STATUS_SUCCESS;
458 }
459 
460 /*
461  * @implemented
462  */
463 NTSTATUS
465  IN PGUID VolumeGuid OPTIONAL)
466 {
467  GUID Guid;
470 
471  /* If no GUID was provided, then create one */
472  if (!VolumeGuid)
473  {
475  if (!NT_SUCCESS(Status))
476  {
477  return Status;
478  }
479  }
480  else
481  {
482  RtlCopyMemory(&Guid, VolumeGuid, sizeof(GUID));
483  }
484 
485  /* Convert GUID to string */
487  if (!NT_SUCCESS(Status))
488  {
489  return Status;
490  }
491 
492  /* Size for volume namespace, literal GUID, and null char */
493  VolumeName->MaximumLength = 0x14 + 0x4C + sizeof(UNICODE_NULL);
494  VolumeName->Buffer = AllocatePool(0x14 + 0x4C + sizeof(UNICODE_NULL));
495  if (!VolumeName->Buffer)
496  {
498  }
499  else
500  {
505  }
506 
507  ExFreePoolWithTag(GuidString.Buffer, 0);
508 
509  return Status;
510 }
511 
512 /*
513  * @implemented
514  */
515 NTSTATUS
517  IN PDEVICE_INFORMATION DeviceInformation,
518  IN PUNICODE_STRING SuggestedLinkName,
519  IN BOOLEAN UseOnlyIfThereAreNoOtherLinks,
520  OUT PUNICODE_STRING * SymLinks,
521  OUT PULONG SymLinkCount,
522  IN BOOLEAN HasGuid,
523  IN LPGUID Guid)
524 {
526  BOOLEAN WriteNew;
528 
529  UNREFERENCED_PARAMETER(DeviceExtension);
530 
531  /* First of all, count links */
534  QueryTable[0].EntryContext = SymLinkCount;
535  *SymLinkCount = 0;
536 
538  DatabasePath,
539  QueryTable,
540  DeviceInformation->UniqueId,
541  NULL);
542  if (!NT_SUCCESS(Status))
543  {
544  *SymLinkCount = 0;
545  }
546 
547  /* Check if we have to write a new one first */
548  if (SuggestedLinkName && !IsDriveLetter(SuggestedLinkName) &&
549  UseOnlyIfThereAreNoOtherLinks && *SymLinkCount == 0)
550  {
551  WriteNew = TRUE;
552  }
553  else
554  {
555  WriteNew = FALSE;
556  }
557 
558  /* If has GUID, it makes one more link */
559  if (HasGuid)
560  {
561  (*SymLinkCount)++;
562  }
563 
564  if (WriteNew)
565  {
566  /* Write link */
568  DatabasePath,
569  SuggestedLinkName->Buffer,
570  REG_BINARY,
571  DeviceInformation->UniqueId->UniqueId,
572  DeviceInformation->UniqueId->UniqueIdLength);
573 
574  /* And recount all the needed links */
577  QueryTable[0].EntryContext = SymLinkCount;
578  *SymLinkCount = 0;
579 
581  DatabasePath,
582  QueryTable,
583  DeviceInformation->UniqueId,
584  NULL);
585  if (!NT_SUCCESS(Status))
586  {
587  return STATUS_NOT_FOUND;
588  }
589  }
590 
591  /* Not links found? */
592  if (!*SymLinkCount)
593  {
594  return STATUS_NOT_FOUND;
595  }
596 
597  /* Allocate a buffer big enough to hold symlinks (table of unicode strings) */
598  *SymLinks = AllocatePool(*SymLinkCount * sizeof(UNICODE_STRING));
599  if (!*SymLinks)
600  {
602  }
603 
604  /* Prepare to query links */
605  RtlZeroMemory(*SymLinks, *SymLinkCount * sizeof(UNICODE_STRING));
608 
609  /* No GUID? Keep it that way */
610  if (!HasGuid)
611  {
612  QueryTable[0].EntryContext = *SymLinks;
613  }
614  /* Otherwise, first create volume name */
615  else
616  {
617  Status = CreateNewVolumeName(SymLinks[0], Guid);
618  if (!NT_SUCCESS(Status))
619  {
620  FreePool(*SymLinks);
621  return Status;
622  }
623 
624  /* Skip first link (ours) */
625  QueryTable[0].EntryContext = *SymLinks + 1;
626  }
627 
628  /* Now, query */
630  DatabasePath,
631  QueryTable,
632  DeviceInformation->UniqueId,
633  NULL);
634 
635  return STATUS_SUCCESS;
636 }
637 
638 /*
639  * @implemented
640  */
643  IN PMOUNTDEV_UNIQUE_ID UniqueId)
644 {
645  PLIST_ENTRY NextEntry;
646  PSAVED_LINK_INFORMATION SavedLinkInformation;
647 
648  /* No saved links? Easy! */
649  if (IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
650  {
651  return NULL;
652  }
653 
654  /* Now, browse saved links */
655  for (NextEntry = DeviceExtension->SavedLinksListHead.Flink;
656  NextEntry != &(DeviceExtension->SavedLinksListHead);
657  NextEntry = NextEntry->Flink)
658  {
659  SavedLinkInformation = CONTAINING_RECORD(NextEntry,
661  SavedLinksListEntry);
662 
663  /* Find the one that matches */
664  if (SavedLinkInformation->UniqueId->UniqueIdLength == UniqueId->UniqueIdLength)
665  {
666  if (RtlCompareMemory(SavedLinkInformation->UniqueId->UniqueId,
667  UniqueId->UniqueId,
668  UniqueId->UniqueIdLength) ==
669  UniqueId->UniqueIdLength)
670  {
671  /* Remove it and return it */
672  RemoveEntryList(&(SavedLinkInformation->SavedLinksListEntry));
673  return SavedLinkInformation;
674  }
675  }
676  }
677 
678  /* None found (none removed) */
679  return NULL;
680 }
681 
682 /*
683  * @implemented
684  */
685 NTSTATUS
687  OUT PUNICODE_STRING SuggestedLinkName,
688  OUT PBOOLEAN UseOnlyIfThereAreNoOtherLinks)
689 {
690  PIRP Irp;
691  KEVENT Event;
693  USHORT NameLength;
697  PIO_STACK_LOCATION IoStackLocation;
698  PMOUNTDEV_SUGGESTED_LINK_NAME IoCtlSuggested;
699 
700  /* First, get device */
703  &FileObject,
704  &DeviceObject);
705  if (!NT_SUCCESS(Status))
706  {
707  return Status;
708  }
709 
710  /* Then, get attached device */
712 
713  /* Then, prepare buffer to query suggested name */
714  IoCtlSuggested = AllocatePool(sizeof(MOUNTDEV_SUGGESTED_LINK_NAME));
715  if (!IoCtlSuggested)
716  {
718  goto Dereference;
719  }
720 
721  /* Prepare request */
724  DeviceObject,
725  NULL,
726  0,
727  IoCtlSuggested,
729  FALSE,
730  &Event,
731  &IoStatusBlock);
732  if (!Irp)
733  {
735  goto Release;
736  }
737 
738  IoStackLocation = IoGetNextIrpStackLocation(Irp);
739  IoStackLocation->FileObject = FileObject;
740 
741  /* And ask */
743  if (Status == STATUS_PENDING)
744  {
746  FALSE, NULL);
748  }
749 
750  /* Overflow? Normal */
752  {
753  /* Reallocate big enough buffer */
754  NameLength = IoCtlSuggested->NameLength + sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
755  FreePool(IoCtlSuggested);
756 
757  IoCtlSuggested = AllocatePool(NameLength);
758  if (!IoCtlSuggested)
759  {
761  goto Dereference;
762  }
763 
764  /* And reask */
767  DeviceObject,
768  NULL,
769  0,
770  IoCtlSuggested,
771  NameLength,
772  FALSE,
773  &Event,
774  &IoStatusBlock);
775  if (!Irp)
776  {
778  goto Release;
779  }
780 
781  IoStackLocation = IoGetNextIrpStackLocation(Irp);
782  IoStackLocation->FileObject = FileObject;
783 
785  if (Status == STATUS_PENDING)
786  {
788  FALSE, NULL);
790  }
791  }
792 
793  if (!NT_SUCCESS(Status))
794  {
795  goto Release;
796  }
797 
798  /* Now we have suggested name, copy it */
799  SuggestedLinkName->Length = IoCtlSuggested->NameLength;
800  SuggestedLinkName->MaximumLength = IoCtlSuggested->NameLength + sizeof(UNICODE_NULL);
801  SuggestedLinkName->Buffer = AllocatePool(IoCtlSuggested->NameLength + sizeof(UNICODE_NULL));
802  if (!SuggestedLinkName->Buffer)
803  {
805  }
806  else
807  {
808  RtlCopyMemory(SuggestedLinkName->Buffer, IoCtlSuggested->Name, IoCtlSuggested->NameLength);
809  SuggestedLinkName->Buffer[SuggestedLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
810  }
811 
812  /* Also return its priority */
813  *UseOnlyIfThereAreNoOtherLinks = IoCtlSuggested->UseOnlyIfThereAreNoOtherLinks;
814 
815 Release:
816  FreePool(IoCtlSuggested);
817 
818 Dereference:
821 
822  return Status;
823 }
824 
825 /*
826  * @implemented
827  */
828 BOOLEAN
831  IN PUNICODE_STRING NewLink)
832 {
833  PLIST_ENTRY NextEntry;
834  PSYMLINK_INFORMATION SymlinkInformation;
835 
836  /* Find the link */
837  for (NextEntry = SavedLinkInformation->SymbolicLinksListHead.Flink;
838  NextEntry != &(SavedLinkInformation->SymbolicLinksListHead);
839  NextEntry = NextEntry->Flink)
840  {
841  SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
842 
843  if (!RtlEqualUnicodeString(DosName, &(SymlinkInformation->Name), TRUE))
844  {
845  /* Delete old link */
847  /* Set its new location */
849 
850  /* And remove it from the list (not valid any more) */
851  RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
852  FreePool(SymlinkInformation->Name.Buffer);
853  FreePool(SymlinkInformation);
854 
855  return TRUE;
856  }
857  }
858 
859  return FALSE;
860 }
861 
862 /*
863  * @implemented
864  */
865 VOID
868  IN BOOLEAN MarkOffline)
869 {
870  PLIST_ENTRY DeviceEntry, SymbolEntry;
871  PDEVICE_INFORMATION DeviceInformation;
872  PSYMLINK_INFORMATION SymlinkInformation;
873 
874  /* First of all, ensure we have devices */
875  if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
876  {
877  return;
878  }
879 
880  /* Then, look for the symbolic name */
881  for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
882  DeviceEntry != &(DeviceExtension->DeviceListHead);
883  DeviceEntry = DeviceEntry->Flink)
884  {
885  DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
886 
887  for (SymbolEntry = DeviceInformation->SymbolicLinksListHead.Flink;
888  SymbolEntry != &(DeviceInformation->SymbolicLinksListHead);
889  SymbolEntry = SymbolEntry->Flink)
890  {
891  SymlinkInformation = CONTAINING_RECORD(SymbolEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
892 
893  /* One we have found it */
894  if (RtlCompareUnicodeString(SymbolicLink, &(SymlinkInformation->Name), TRUE) == 0)
895  {
896  /* Check if caller just want it to be offline */
897  if (MarkOffline)
898  {
899  SymlinkInformation->Online = FALSE;
900  }
901  else
902  {
903  /* If not, delete it & notify */
904  SendLinkDeleted(&(DeviceInformation->SymbolicName), SymbolicLink);
905  RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry));
906 
907  FreePool(SymlinkInformation->Name.Buffer);
908  FreePool(SymlinkInformation);
909  }
910 
911  /* No need to go farther */
912  return;
913  }
914  }
915  }
916 
917  return;
918 }
919 
920 /*
921  * @implemented
922  */
923 BOOLEAN
925 {
926  WCHAR Letter, Colon;
927 
928  /* We must have a precise length */
929  if (SymbolicName->Length != DosDevices.Length + 2 * sizeof(WCHAR))
930  {
931  return FALSE;
932  }
933 
934  /* Must start with the DosDevices prefix */
936  {
937  return FALSE;
938  }
939 
940  /* Check if letter is correct */
942  if ((Letter < L'A' || Letter > L'Z') && Letter != (WCHAR)-1)
943  {
944  return FALSE;
945  }
946 
947  /* And finally it must end with a colon */
948  Colon = SymbolicName->Buffer[DosDevices.Length / sizeof(WCHAR) + 1];
949  if (Colon != L':')
950  {
951  return FALSE;
952  }
953 
954  return TRUE;
955 }
956 
957 /*
958  * @implemented
959  */
960 NTSTATUS
963 {
965  HANDLE LinkHandle;
967 
968  /* Open the symbolic link */
970  SymbolicName,
972  NULL,
973  NULL);
974 
975  Status = ZwOpenSymbolicLinkObject(&LinkHandle,
976  GENERIC_READ,
978  if (!NT_SUCCESS(Status))
979  {
980  return Status;
981  }
982 
983  /* Query its target */
984  Status = ZwQuerySymbolicLinkObject(LinkHandle,
985  LinkTarget,
986  NULL);
987 
988  ZwClose(LinkHandle);
989 
990  if (!NT_SUCCESS(Status))
991  {
992  return Status;
993  }
994 
995  if (LinkTarget->Length <= sizeof(WCHAR))
996  {
997  return Status;
998  }
999 
1000  /* If it's not finished by \, just return */
1001  if (LinkTarget->Buffer[LinkTarget->Length / sizeof(WCHAR) - 1] != L'\\')
1002  {
1003  return Status;
1004  }
1005 
1006  /* Otherwise, ensure to drop the tailing \ */
1007  LinkTarget->Length -= sizeof(WCHAR);
1009 
1010  return Status;
1011 }
#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:3988
#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:4000
_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:1434
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:434
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:3988
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
NTKERNELAPI NTSTATUS ExUuidCreate(OUT UUID *Uuid)
Definition: uuid.c:403
_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:1405
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:67
__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:1954
#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:2812
#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:61
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:1012
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:2777
#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