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>
15 FsRtlRemoveDotsFromPath(IN PWSTR OriginalString
,
17 OUT USHORT
*NewLength
)
19 USHORT Length
, ReadPos
, WritePos
;
21 Length
= PathLength
/ sizeof(WCHAR
);
23 if (Length
== 3 && OriginalString
[0] == '\\' && OriginalString
[1] == '.' && OriginalString
[2] == '.')
25 return STATUS_IO_REPARSE_DATA_INVALID
;
28 if (Length
== 2 && OriginalString
[0] == '.' && OriginalString
[1] == '.')
30 return STATUS_IO_REPARSE_DATA_INVALID
;
33 if (Length
> 2 && OriginalString
[0] == '.' && OriginalString
[1] == '.' && OriginalString
[2] == '\\')
35 return STATUS_IO_REPARSE_DATA_INVALID
;
38 for (ReadPos
= 0, WritePos
= 0; ReadPos
< Length
; ++WritePos
)
40 for (; ReadPos
> 0 && ReadPos
< Length
; ++ReadPos
)
42 if (ReadPos
< Length
- 1 && OriginalString
[ReadPos
] == '\\' && OriginalString
[ReadPos
+ 1] == '\\')
47 if (OriginalString
[ReadPos
] != '.')
52 if (ReadPos
== Length
- 1)
54 if (OriginalString
[ReadPos
- 1] == '\\')
64 OriginalString
[WritePos
] = '.';
69 if (OriginalString
[ReadPos
+ 1] == '\\')
71 if (OriginalString
[ReadPos
- 1] != '\\')
73 OriginalString
[WritePos
] = '.';
80 if (OriginalString
[ReadPos
+ 1] != '.' || OriginalString
[ReadPos
- 1] != '\\' ||
81 ((ReadPos
!= Length
- 2) && OriginalString
[ReadPos
+ 2] != '\\'))
83 OriginalString
[WritePos
] = '.';
88 for (WritePos
-= 2; (SHORT
)WritePos
> 0 && OriginalString
[WritePos
] != '\\'; --WritePos
);
90 if ((SHORT
)WritePos
< 0 || OriginalString
[WritePos
] != '\\')
92 return STATUS_IO_REPARSE_DATA_INVALID
;
95 if (WritePos
== 0 && ReadPos
== Length
- 2)
104 if (ReadPos
>= Length
)
109 OriginalString
[WritePos
] = OriginalString
[ReadPos
];
113 *NewLength
= WritePos
* sizeof(WCHAR
);
115 while (WritePos
< Length
)
117 OriginalString
[WritePos
++] = UNICODE_NULL
;
120 return STATUS_SUCCESS
;
125 IsNullGuid(IN PGUID Guid
)
127 if (Guid
->Data1
== 0 && Guid
->Data2
== 0 && Guid
->Data3
== 0 &&
128 ((ULONG
*)Guid
->Data4
)[0] == 0 && ((ULONG
*)Guid
->Data4
)[1] == 0)
138 IsEven(IN USHORT Digit
)
140 return ((Digit
& 1) != 1);
146 FsRtlValidateReparsePointBuffer(IN ULONG BufferLength
,
147 IN PREPARSE_DATA_BUFFER ReparseBuffer
)
151 PREPARSE_GUID_DATA_BUFFER GuidBuffer
;
153 /* Validate data size range */
154 if (BufferLength
< REPARSE_DATA_BUFFER_HEADER_SIZE
|| BufferLength
> MAXIMUM_REPARSE_DATA_BUFFER_SIZE
)
156 return STATUS_IO_REPARSE_DATA_INVALID
;
159 GuidBuffer
= (PREPARSE_GUID_DATA_BUFFER
)ReparseBuffer
;
160 DataLength
= ReparseBuffer
->ReparseDataLength
;
161 ReparseTag
= ReparseBuffer
->ReparseTag
;
163 /* Validate size consistency */
164 if (DataLength
+ REPARSE_DATA_BUFFER_HEADER_SIZE
!= BufferLength
&& DataLength
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
!= BufferLength
)
166 return STATUS_IO_REPARSE_DATA_INVALID
;
169 /* REPARSE_DATA_BUFFER is reserved for MS tags */
170 if (DataLength
+ REPARSE_DATA_BUFFER_HEADER_SIZE
== BufferLength
&& !IsReparseTagMicrosoft(ReparseTag
))
172 return STATUS_IO_REPARSE_DATA_INVALID
;
175 /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */
176 if (DataLength
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE
== BufferLength
&& ((!IsReparseTagMicrosoft(ReparseTag
)
177 && IsNullGuid(&GuidBuffer
->ReparseGuid
)) || (ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
|| ReparseTag
== IO_REPARSE_TAG_SYMLINK
)))
179 return STATUS_IO_REPARSE_DATA_INVALID
;
182 /* Check the data for MS non reserved tags */
183 if (!(ReparseTag
& 0xFFF0000) && ReparseTag
!= IO_REPARSE_TAG_RESERVED_ZERO
&& ReparseTag
!= IO_REPARSE_TAG_RESERVED_ONE
)
185 /* If that's a mount point, validate the MountPointReparseBuffer branch */
186 if (ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
)
188 /* We need information */
189 if (DataLength
>= REPARSE_DATA_BUFFER_HEADER_SIZE
)
191 /* Substitue must be the first in row */
192 if (!ReparseBuffer
->MountPointReparseBuffer
.SubstituteNameOffset
)
194 /* Substitude must be null-terminated */
195 if (ReparseBuffer
->MountPointReparseBuffer
.PrintNameOffset
== ReparseBuffer
->MountPointReparseBuffer
.SubstituteNameLength
+ sizeof(UNICODE_NULL
))
197 /* There must just be the Offset/Length fields + buffer + 2 null chars */
198 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
))
200 return STATUS_SUCCESS
;
208 #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset))
210 /* If that's not a symlink, accept the MS tag as it */
211 if (ReparseTag
!= IO_REPARSE_TAG_SYMLINK
)
213 return STATUS_SUCCESS
;
216 /* We need information */
217 if (DataLength
>= FIELDS_SIZE
)
219 /* Validate lengths */
220 if (ReparseBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameLength
&& ReparseBuffer
->SymbolicLinkReparseBuffer
.PrintNameLength
)
222 /* Validate unicode strings */
223 if (IsEven(ReparseBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameLength
) && IsEven(ReparseBuffer
->SymbolicLinkReparseBuffer
.PrintNameLength
) &&
224 IsEven(ReparseBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
) && IsEven(ReparseBuffer
->SymbolicLinkReparseBuffer
.PrintNameOffset
))
226 if ((DataLength
+ REPARSE_DATA_BUFFER_HEADER_SIZE
>= ReparseBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
+ ReparseBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameLength
+ FIELDS_SIZE
+ REPARSE_DATA_BUFFER_HEADER_SIZE
)
227 && (DataLength
+ REPARSE_DATA_BUFFER_HEADER_SIZE
>= ReparseBuffer
->SymbolicLinkReparseBuffer
.PrintNameLength
+ ReparseBuffer
->SymbolicLinkReparseBuffer
.PrintNameOffset
+ FIELDS_SIZE
+ REPARSE_DATA_BUFFER_HEADER_SIZE
))
229 return STATUS_SUCCESS
;
237 return STATUS_IO_REPARSE_DATA_INVALID
;
240 return STATUS_IO_REPARSE_TAG_INVALID
;