ReactOS  0.4.13-dev-687-g023794c
fsrtl.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel - Vista+ APIs
3  * LICENSE: GPL v2 - See COPYING in the top level directory
4  * FILE: lib/drivers/ntoskrnl_vista/fsrtl.c
5  * PURPOSE: FsRtl functions of Vista+
6  * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
7  */
8 
9 #include <ntdef.h>
10 #include <ntifs.h>
11 
12 typedef struct _ECP_LIST
13 {
18 
20 
21 typedef struct _ECP_HEADER
22 {
33 
34 #define ECP_HEADER_SIZE (sizeof(ECP_HEADER))
35 
36 #define ECP_HEADER_TO_CONTEXT(H) ((PVOID)((ULONG_PTR)H + ECP_HEADER_SIZE))
37 #define ECP_CONTEXT_TO_HEADER(C) ((PECP_HEADER)((ULONG_PTR)C - ECP_HEADER_SIZE))
38 
41 NTAPI
45 {
46  USHORT Length, ReadPos, WritePos;
47 
48  Length = PathLength / sizeof(WCHAR);
49 
50  if (Length == 3 && OriginalString[0] == '\\' && OriginalString[1] == '.' && OriginalString[2] == '.')
51  {
53  }
54 
55  if (Length == 2 && OriginalString[0] == '.' && OriginalString[1] == '.')
56  {
58  }
59 
60  if (Length > 2 && OriginalString[0] == '.' && OriginalString[1] == '.' && OriginalString[2] == '\\')
61  {
63  }
64 
65  for (ReadPos = 0, WritePos = 0; ReadPos < Length; ++WritePos)
66  {
67  for (; ReadPos > 0 && ReadPos < Length; ++ReadPos)
68  {
69  if (ReadPos < Length - 1 && OriginalString[ReadPos] == '\\' && OriginalString[ReadPos + 1] == '\\')
70  {
71  continue;
72  }
73 
74  if (OriginalString[ReadPos] != '.')
75  {
76  break;
77  }
78 
79  if (ReadPos == Length - 1)
80  {
81  if (OriginalString[ReadPos - 1] == '\\')
82  {
83  if (WritePos > 1)
84  {
85  --WritePos;
86  }
87 
88  continue;
89  }
90 
91  OriginalString[WritePos] = '.';
92  ++WritePos;
93  continue;
94  }
95 
96  if (OriginalString[ReadPos + 1] == '\\')
97  {
98  if (OriginalString[ReadPos - 1] != '\\')
99  {
100  OriginalString[WritePos] = '.';
101  ++WritePos;
102  continue;
103  }
104  }
105  else
106  {
107  if (OriginalString[ReadPos + 1] != '.' || OriginalString[ReadPos - 1] != '\\' ||
108  ((ReadPos != Length - 2) && OriginalString[ReadPos + 2] != '\\'))
109  {
110  OriginalString[WritePos] = '.';
111  ++WritePos;
112  continue;
113  }
114 
115  for (WritePos -= 2; (SHORT)WritePos > 0 && OriginalString[WritePos] != '\\'; --WritePos);
116 
117  if ((SHORT)WritePos < 0 || OriginalString[WritePos] != '\\')
118  {
120  }
121 
122  if (WritePos == 0 && ReadPos == Length - 2)
123  {
124  WritePos = 1;
125  }
126  }
127 
128  ++ReadPos;
129  }
130 
131  if (ReadPos >= Length)
132  {
133  break;
134  }
135 
136  OriginalString[WritePos] = OriginalString[ReadPos];
137  ++ReadPos;
138  }
139 
140  *NewLength = WritePos * sizeof(WCHAR);
141 
142  while (WritePos < Length)
143  {
144  OriginalString[WritePos++] = UNICODE_NULL;
145  }
146 
147  return STATUS_SUCCESS;
148 }
149 
151 BOOLEAN
153 {
154  if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 &&
155  ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0)
156  {
157  return TRUE;
158  }
159 
160  return FALSE;
161 }
162 
164 BOOLEAN
166 {
167  return ((Digit & 1) != 1);
168 }
169 
171 NTSTATUS
172 NTAPI
174  IN PREPARSE_DATA_BUFFER ReparseBuffer)
175 {
177  ULONG ReparseTag;
178  PREPARSE_GUID_DATA_BUFFER GuidBuffer;
179 
180  /* Validate data size range */
181  if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
182  {
184  }
185 
186  GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
187  DataLength = ReparseBuffer->ReparseDataLength;
188  ReparseTag = ReparseBuffer->ReparseTag;
189 
190  /* Validate size consistency */
192  {
194  }
195 
196  /* REPARSE_DATA_BUFFER is reserved for MS tags */
198  {
200  }
201 
202  /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */
204  && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK)))
205  {
207  }
208 
209  /* Check the data for MS non reserved tags */
210  if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE)
211  {
212  /* If that's a mount point, validate the MountPointReparseBuffer branch */
213  if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
214  {
215  /* We need information */
217  {
218  /* Substitue must be the first in row */
219  if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset)
220  {
221  /* Substitude must be null-terminated */
222  if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL))
223  {
224  /* There must just be the Offset/Length fields + buffer + 2 null chars */
225  if (DataLength == ReparseBuffer->MountPointReparseBuffer.PrintNameLength + ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.SubstituteNameOffset)) + 2 * sizeof(UNICODE_NULL))
226  {
227  return STATUS_SUCCESS;
228  }
229  }
230  }
231  }
232  }
233  else
234  {
235 #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset))
236 
237  /* If that's not a symlink, accept the MS tag as it */
238  if (ReparseTag != IO_REPARSE_TAG_SYMLINK)
239  {
240  return STATUS_SUCCESS;
241  }
242 
243  /* We need information */
244  if (DataLength >= FIELDS_SIZE)
245  {
246  /* Validate lengths */
247  if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength)
248  {
249  /* Validate unicode strings */
250  if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) &&
251  IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset))
252  {
253  if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)
254  && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE))
255  {
256  return STATUS_SUCCESS;
257  }
258  }
259  }
260  }
261 #undef FIELDS_SIZE
262  }
263 
265  }
266 
268 }
269 
271 NTSTATUS
272 NTAPI
275 {
276  /* Call Io */
278 }
279 
281 NTSTATUS
282 NTAPI
288 {
289  PECP_HEADER CurrentEntry;
290 
291  /* If we have no context ... */
292  if (CurrentEcpContext == NULL)
293  {
294  if (IsListEmpty(&EcpList->EcpList))
295  {
296  goto FailEmpty;
297  }
298 
299  /* Simply consider first entry */
300  CurrentEntry = CONTAINING_RECORD(EcpList->EcpList.Flink, ECP_HEADER, ListEntry);
301  }
302  else
303  {
304  /* Otherwise, consider the entry matching the given context */
306 
307  /* Make sure we didn't reach the end */
308  if (&CurrentEntry->ListEntry == &EcpList->EcpList)
309  {
310  goto FailEmpty;
311  }
312  }
313 
314  /* We must have an entry */
315  if (CurrentEntry == NULL)
316  {
317  goto FailEmpty;
318  }
319 
320  /* If caller wants a context, give it */
321  if (NextEcpContext != NULL)
322  {
323  *NextEcpContext = ECP_HEADER_TO_CONTEXT(CurrentEntry);
324  }
325 
326  /* Same for its size (which the size minus the header overhead) */
327  if (NextEcpContextSize != NULL)
328  {
329  *NextEcpContextSize = CurrentEntry->Size - sizeof(ECP_HEADER);
330  }
331 
332  /* And copy the type if asked to */
333  if (NextEcpType != NULL)
334  {
335  RtlCopyMemory(NextEcpType, &CurrentEntry->EcpType, sizeof(GUID));
336  }
337 
338  /* Job done */
339  return STATUS_SUCCESS;
340 
341  /* Failure case: just zero everything */
342 FailEmpty:
343  if (NextEcpContext != NULL)
344  {
345  *NextEcpContext = NULL;
346  }
347 
348  if (NextEcpContextSize != NULL)
349  {
350  *NextEcpContextSize = 0;
351  }
352 
353  if (NextEcpType != NULL)
354  {
355  RtlZeroMemory(NextEcpType, sizeof(GUID));
356  }
357 
358  /* And return failure */
359  return STATUS_NOT_FOUND;
360 }
361 
_Must_inspect_result_ _In_ FSRTL_ALLOCATE_ECPLIST_FLAGS _Outptr_ PECP_LIST * EcpList
Definition: fltkernel.h:2511
#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)
_In_ PIRP Irp
Definition: csq.h:116
uint16_t * PWSTR
Definition: typedefs.h:54
GUID EcpType
Definition: fsrtl.c:26
LONG NTSTATUS
Definition: precomp.h:26
#define IsReparseTagMicrosoft(_tag)
Definition: iotypes.h:6863
ECP_HEADER_FLAGS Flags
Definition: fsrtl.c:28
#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
Definition: iotypes.h:6854
ULONG Flags
Definition: fsrtl.c:15
#define FIELDS_SIZE
static USHORT PathLength
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define IO_REPARSE_TAG_RESERVED_ZERO
Definition: iotypes.h:6859
static USHORT USHORT * NewLength
PVOID ListAllocatedFrom
Definition: fsrtl.c:30
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:6874
LIST_ENTRY EcpList
Definition: fsrtl.c:16
WCHAR PathBuffer[1]
Definition: shellext.h:152
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define UNICODE_NULL
ULONG Spare
Definition: fsrtl.c:24
_In_ ULONG BufferLength
Definition: usbdlib.h:225
short SHORT
Definition: pedump.c:59
NTKERNELAPI NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer)
Definition: fsrtl.c:173
#define STATUS_IO_REPARSE_DATA_INVALID
Definition: ntstatus.h:742
unsigned char BOOLEAN
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
struct _ECP_LIST ECP_LIST
#define FORCEINLINE
Definition: ntbasedef.h:221
#define NTKERNELAPI
struct _ECP_LIST * PECP_LIST
LIST_ENTRY ListEntry
Definition: fsrtl.c:25
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
struct _ECP_HEADER * PECP_HEADER
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#define STATUS_NOT_FOUND
Definition: shellext.h:67
NTKERNELAPI NTSTATUS NTAPI FsRtlGetEcpListFromIrp(IN PIRP Irp, OUT PECP_LIST *EcpList)
Definition: fsrtl.c:273
__wchar_t WCHAR
Definition: xmlstorage.h:180
NTKERNELAPI NTSTATUS NTAPI FsRtlGetNextExtraCreateParameter(IN PECP_LIST EcpList, IN PVOID CurrentEcpContext, OUT LPGUID NextEcpType OPTIONAL, OUT PVOID *NextEcpContext, OUT PULONG NextEcpContextSize OPTIONAL)
Definition: fsrtl.c:283
#define ECP_CONTEXT_TO_HEADER(C)
Definition: fsrtl.c:37
#define ECP_HEADER_TO_CONTEXT(H)
Definition: fsrtl.c:36
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
struct _REPARSE_GUID_DATA_BUFFER * PREPARSE_GUID_DATA_BUFFER
_In_ PECP_LIST _In_opt_ PVOID CurrentEcpContext
Definition: fltkernel.h:2621
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID _Outptr_opt_ PVOID _Out_opt_ ULONG * NextEcpContextSize
Definition: fltkernel.h:2621
Definition: typedefs.h:117
FORCEINLINE BOOLEAN IsEven(IN USHORT Digit)
Definition: fsrtl.c:165
NTSTATUS NTAPI IoGetIrpExtraCreateParameter(_In_ PIRP Irp, _Outptr_result_maybenull_ struct _ECP_LIST **ExtraCreateParameter)
FORCEINLINE BOOLEAN IsNullGuid(IN PGUID Guid)
Definition: fsrtl.c:152
#define REPARSE_DATA_BUFFER_HEADER_SIZE
Definition: iotypes.h:6842
ULONG Signature
Definition: fsrtl.c:23
unsigned short USHORT
Definition: pedump.c:61
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
unsigned int * PULONG
Definition: retypes.h:1
PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK CleanupCallback
Definition: fsrtl.c:27
#define IO_REPARSE_TAG_RESERVED_ONE
Definition: iotypes.h:6860
#define STATUS_IO_REPARSE_TAG_INVALID
Definition: ntstatus.h:740
ULONG Size
Definition: fsrtl.c:29
#define OUT
Definition: typedefs.h:39
USHORT SubstituteNameOffset
Definition: shellext.h:147
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
VOID(* PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK)(_Inout_ PVOID EcpContext, _In_ LPCGUID EcpType)
Definition: fsrtltypes.h:135
NTKERNELAPI NTSTATUS NTAPI FsRtlRemoveDotsFromPath(IN PWSTR OriginalString, IN USHORT PathLength, OUT USHORT *NewLength)
Definition: fsrtl.c:42
struct _ECP_HEADER ECP_HEADER
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID NextEcpType
Definition: fltkernel.h:2621
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
return STATUS_SUCCESS
Definition: btrfs.c:2777
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:6856
PVOID Filter
Definition: fsrtl.c:31
#define IO_REPARSE_TAG_SYMLINK
Definition: iotypes.h:6883
ULONG Signature
Definition: fsrtl.c:14
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID _Outptr_opt_ PVOID * NextEcpContext
Definition: fltkernel.h:2621
ULONG ECP_HEADER_FLAGS
Definition: fsrtl.c:19
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68