ReactOS 0.4.15-dev-7842-g558ab78
fsrtl.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel - Vista+ APIs
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
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
12typedef struct _ECP_LIST
13{
18
20
21typedef 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
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
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
166{
167 return ((Digit & 1) != 1);
168}
169
172NTAPI
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
272NTAPI
275{
276 /* Call Io */
278}
279
282NTAPI
288{
289 PECP_HEADER CurrentEntry;
290
291 /* If we have no context ... */
292 if (CurrentEcpContext == NULL)
293 {
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) */
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 */
342FailEmpty:
343 if (NextEcpContext != NULL)
344 {
346 }
347
349 {
351 }
352
353 if (NextEcpType != NULL)
354 {
356 }
357
358 /* And return failure */
359 return STATUS_NOT_FOUND;
360}
361
static USHORT PathLength
static USHORT USHORT * NewLength
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1444
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define IsEven(n)
Definition: render.c:183
#define FIELDS_SIZE
FORCEINLINE BOOLEAN IsNullGuid(IN PGUID Guid)
Definition: fsrtl.c:14
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
_In_ PECP_LIST _In_opt_ PVOID CurrentEcpContext
Definition: fltkernel.h:2621
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID _Outptr_opt_ PVOID * NextEcpContext
Definition: fltkernel.h:2623
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID NextEcpType
Definition: fltkernel.h:2622
_Must_inspect_result_ _In_ FSRTL_ALLOCATE_ECPLIST_FLAGS _Outptr_ PECP_LIST * EcpList
Definition: fltkernel.h:2511
_In_ PECP_LIST _In_opt_ PVOID _Out_opt_ LPGUID _Outptr_opt_ PVOID _Out_opt_ ULONG * NextEcpContextSize
Definition: fltkernel.h:2624
VOID(* PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK)(_Inout_ PVOID EcpContext, _In_ LPCGUID EcpType)
Definition: fsrtltypes.h:135
#define REPARSE_DATA_BUFFER_HEADER_SIZE
Definition: vista.c:17
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_IO_REPARSE_TAG_INVALID
Definition: ntstatus.h:754
#define STATUS_IO_REPARSE_DATA_INVALID
Definition: ntstatus.h:756
short SHORT
Definition: pedump.c:59
unsigned short USHORT
Definition: pedump.c:61
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
struct _ECP_LIST * PECP_LIST
struct _ECP_HEADER ECP_HEADER
NTKERNELAPI NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer)
Definition: fsrtl.c:173
struct _ECP_LIST ECP_LIST
NTKERNELAPI NTSTATUS NTAPI FsRtlRemoveDotsFromPath(IN PWSTR OriginalString, IN USHORT PathLength, OUT USHORT *NewLength)
Definition: fsrtl.c:42
#define ECP_CONTEXT_TO_HEADER(C)
Definition: fsrtl.c:37
NTKERNELAPI NTSTATUS NTAPI FsRtlGetEcpListFromIrp(IN PIRP Irp, OUT PECP_LIST *EcpList)
Definition: fsrtl.c:273
struct _ECP_HEADER * PECP_HEADER
ULONG ECP_HEADER_FLAGS
Definition: fsrtl.c:19
#define ECP_HEADER_TO_CONTEXT(H)
Definition: fsrtl.c:36
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
GUID EcpType
Definition: fsrtl.c:26
ECP_HEADER_FLAGS Flags
Definition: fsrtl.c:28
PVOID Filter
Definition: fsrtl.c:31
PVOID ListAllocatedFrom
Definition: fsrtl.c:30
ULONG Signature
Definition: fsrtl.c:23
ULONG Spare
Definition: fsrtl.c:24
PFSRTL_EXTRA_CREATE_PARAMETER_CLEANUP_CALLBACK CleanupCallback
Definition: fsrtl.c:27
ULONG Size
Definition: fsrtl.c:29
LIST_ENTRY ListEntry
Definition: fsrtl.c:25
LIST_ENTRY EcpList
Definition: fsrtl.c:16
ULONG Signature
Definition: fsrtl.c:14
ULONG Flags
Definition: fsrtl.c:15
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
WCHAR PathBuffer[1]
Definition: shellext.h:176
USHORT SubstituteNameOffset
Definition: shellext.h:171
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_Must_inspect_result_ _In_ WDFOBJECT _In_ CONST GUID * Guid
Definition: wdfobject.h:762
#define FORCEINLINE
Definition: wdftypes.h:67
#define NTKERNELAPI
NTKRNLVISTAAPI NTSTATUS NTAPI IoGetIrpExtraCreateParameter(_In_ PIRP Irp, _Outptr_result_maybenull_ struct _ECP_LIST **ExtraCreateParameter)
#define IO_REPARSE_TAG_RESERVED_ONE
Definition: iotypes.h:7217
struct _REPARSE_GUID_DATA_BUFFER * PREPARSE_GUID_DATA_BUFFER
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:7213
#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
Definition: iotypes.h:7211
#define IO_REPARSE_TAG_SYMLINK
Definition: iotypes.h:7240
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:7231
#define IO_REPARSE_TAG_RESERVED_ZERO
Definition: iotypes.h:7216
#define IsReparseTagMicrosoft(_tag)
Definition: iotypes.h:7220
__wchar_t WCHAR
Definition: xmlstorage.h:180