2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/main.c
5 * PURPOSE: Named Pipe FileSystem Driver Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_MAIN)
16 /* GLOBALS ********************************************************************/
18 PDEVICE_OBJECT NpfsDeviceObject
;
20 PNPFS_ALIAS NpAliasList
;
21 PNPFS_ALIAS NpAliasListByLength
[MAX_INDEXED_LENGTH
+ 1 - MIN_INDEXED_LENGTH
];
23 /* FUNCTIONS ******************************************************************/
35 PNPFS_QUERY_VALUE_CONTEXT QueryContext
= Context
;
38 PNPFS_ALIAS CurrentAlias
;
39 UNICODE_STRING TempString
;
40 PUNICODE_STRING CurrentTargetName
;
42 /* Check if we have the expected type */
43 if (ValueType
!= REG_MULTI_SZ
)
45 return STATUS_INVALID_PARAMETER
;
48 /* Check if only the size is requested */
49 if (QueryContext
->SizeOnly
)
51 /* Count this entry */
52 QueryContext
->NumberOfEntries
++;
54 /* Get the length of the value name (i.e. the target name). */
55 Length
= wcslen(ValueName
) * sizeof(WCHAR
);
57 /* Add the size of the name plus a '\' and a UNICODE_STRING structure */
58 QueryContext
->FullSize
+= Length
+ sizeof(UNICODE_NULL
) +
59 sizeof(OBJ_NAME_PATH_SEPARATOR
) +
60 sizeof(UNICODE_STRING
);
62 /* Loop while we have alias names */
63 CurrentString
= ValueData
;
64 while (*CurrentString
!= UNICODE_NULL
)
66 /* Count this alias */
67 QueryContext
->NumberOfAliases
++;
69 /* Get the length of the current string (i.e. the alias name) */
70 Length
= wcslen(CurrentString
) * sizeof(WCHAR
);
72 /* Count the length plus the size of an NPFS_ALIAS structure */
73 QueryContext
->FullSize
+= Length
+ sizeof(UNICODE_NULL
) + sizeof(NPFS_ALIAS
);
75 /* Go to the next string */
76 CurrentString
+= (Length
+ sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
81 /* Get the next name string pointer */
82 CurrentTargetName
= QueryContext
->CurrentTargetName
++;
84 /* Get the length of the value name (i.e. the target name). */
85 Length
= wcslen(ValueName
) * sizeof(WCHAR
);
87 /* Initialize the current name string (one char more than the name) */
88 CurrentTargetName
->Buffer
= QueryContext
->CurrentStringPointer
;
89 CurrentTargetName
->Length
= Length
+ sizeof(OBJ_NAME_PATH_SEPARATOR
);
90 CurrentTargetName
->MaximumLength
= CurrentTargetName
->Length
+ sizeof(UNICODE_NULL
);
92 /* Update the current string pointer */
93 QueryContext
->CurrentStringPointer
+=
94 CurrentTargetName
->MaximumLength
/ sizeof(WCHAR
);
96 /* Prepend a '\' before the name */
97 CurrentTargetName
->Buffer
[0] = OBJ_NAME_PATH_SEPARATOR
;
99 /* Append the value name (including the NULL termination) */
100 RtlCopyMemory(&CurrentTargetName
->Buffer
[1],
102 Length
+ sizeof(UNICODE_NULL
));
104 /* Upcase the target name */
105 RtlUpcaseUnicodeString(CurrentTargetName
, CurrentTargetName
, 0);
107 /* Loop while we have alias names */
108 CurrentString
= ValueData
;
109 while (*CurrentString
!= UNICODE_NULL
)
111 /* Get the next alias pointer */
112 CurrentAlias
= QueryContext
->CurrentAlias
++;
114 /* Get the length of the current string (i.e. the alias name) */
115 Length
= wcslen(CurrentString
) * sizeof(WCHAR
);
117 /* Setup the alias structure */
118 CurrentAlias
->TargetName
= CurrentTargetName
;
119 CurrentAlias
->Name
.Buffer
= QueryContext
->CurrentStringPointer
;
120 CurrentAlias
->Name
.Length
= Length
;
121 CurrentAlias
->Name
.MaximumLength
= Length
+ sizeof(UNICODE_NULL
);
123 /* Upcase the alias name */
124 TempString
.Buffer
= CurrentString
;
125 TempString
.Length
= Length
;
126 RtlUpcaseUnicodeString(&CurrentAlias
->Name
,
130 /* Update the current string pointer */
131 QueryContext
->CurrentStringPointer
+=
132 CurrentAlias
->Name
.MaximumLength
/ sizeof(WCHAR
);
134 /* Go to the next string */
135 CurrentString
+= (Length
+ sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
139 return STATUS_SUCCESS
;
145 _In_ PCUNICODE_STRING String1
,
146 _In_ PCUNICODE_STRING String2
)
151 /* First check if the string sizes match */
152 if (String1
->Length
!= String2
->Length
)
154 /* They don't, return positive if the first is longer, negative otherwise */
155 return String1
->Length
- String2
->Length
;
158 /* Now loop all characters */
159 Count
= String1
->Length
/ sizeof(WCHAR
);
160 P1
= String1
->Buffer
;
161 P2
= String2
->Buffer
;
164 /* Check if they don't match */
167 /* Return positive if the first char is greater, negative otherwise */
171 /* Go to the next buffer position */
177 /* All characters matched, return 0 */
183 NpInitializeAliases(VOID
)
185 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
186 NPFS_QUERY_VALUE_CONTEXT Context
;
190 PNPFS_ALIAS CurrentAlias
, *AliasPointer
;
192 /* Initialize the query table */
193 QueryTable
[0].QueryRoutine
= NpReadAlias
;
194 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_NOEXPAND
;
195 QueryTable
[0].Name
= NULL
;
196 QueryTable
[0].EntryContext
= NULL
;
197 QueryTable
[0].DefaultType
= REG_NONE
;
198 QueryTable
[0].DefaultData
= NULL
;
199 QueryTable
[0].DefaultLength
= 0;
200 QueryTable
[1].QueryRoutine
= NULL
;
201 QueryTable
[1].Flags
= 0;
202 QueryTable
[1].Name
= NULL
;
204 /* Setup the query context */
205 Context
.SizeOnly
= 1;
206 Context
.FullSize
= 0;
207 Context
.NumberOfAliases
= 0;
208 Context
.NumberOfEntries
= 0;
210 /* Query the registry values (calculate length only) */
211 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
| RTL_REGISTRY_OPTIONAL
,
216 if (!NT_SUCCESS(Status
))
218 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
219 return STATUS_SUCCESS
;
224 /* Check if there is anything */
225 if (Context
.FullSize
== 0)
227 /* Nothing to do, return success */
228 return STATUS_SUCCESS
;
231 /* Allocate a structure large enough to hold all the data */
232 NpAliases
= ExAllocatePoolWithTag(NonPagedPool
, Context
.FullSize
, 'sfpN');
233 if (NpAliases
== NULL
)
234 return STATUS_INSUFFICIENT_RESOURCES
;
236 /* Now setup the actual pointers in the context */
237 Context
.CurrentTargetName
= NpAliases
;
238 CurrentAlias
= (PNPFS_ALIAS
)&Context
.CurrentTargetName
[Context
.NumberOfEntries
];
239 Context
.CurrentAlias
= CurrentAlias
;
240 Context
.CurrentStringPointer
= (PWCHAR
)&CurrentAlias
[Context
.NumberOfAliases
];
242 /* This time query the real data */
243 Context
.SizeOnly
= FALSE
;
244 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
| RTL_REGISTRY_OPTIONAL
,
249 if (!NT_SUCCESS(Status
))
251 ExFreePoolWithTag(NpAliases
, 0);
256 /* Make sure we didn't go past the end of the allocation! */
257 NT_ASSERT((PUCHAR
)Context
.CurrentStringPointer
<=
258 ((PUCHAR
)NpAliases
+ Context
.FullSize
));
260 /* Loop all aliases we got */
261 for (i
= 0; i
< Context
.NumberOfAliases
; i
++)
263 /* Get the length and check what list to use */
264 Length
= CurrentAlias
->Name
.Length
;
265 if ((Length
>= MIN_INDEXED_LENGTH
* sizeof(WCHAR
)) &&
266 (Length
<= MAX_INDEXED_LENGTH
* sizeof(WCHAR
)))
268 /* For this length range, we use an indexed list */
269 AliasPointer
= &NpAliasListByLength
[(Length
/ sizeof(WCHAR
)) - 5];
273 /* Length is outside of the range, use the default list */
274 AliasPointer
= &NpAliasList
;
277 /* Loop through all aliases already in the list until we find one that
278 is greater than our current alias */
279 while ((*AliasPointer
!= NULL
) &&
280 (NpCompareAliasNames(&CurrentAlias
->Name
,
281 &(*AliasPointer
)->Name
) > 0))
283 /* Go to the next alias */
284 AliasPointer
= &(*AliasPointer
)->Next
;
287 /* Insert the alias in the list */
288 CurrentAlias
->Next
= *AliasPointer
;
289 *AliasPointer
= CurrentAlias
;
291 /* Go to the next alias in the array */
295 return STATUS_SUCCESS
;
301 NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject
,
307 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
308 Irp
->IoStatus
.Information
= 0;
310 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
311 return STATUS_NOT_IMPLEMENTED
;
316 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
317 IN PUNICODE_STRING RegistryPath
)
319 PDEVICE_OBJECT DeviceObject
;
320 UNICODE_STRING DeviceName
;
322 UNREFERENCED_PARAMETER(RegistryPath
);
324 DPRINT1("Next-Generation NPFS-Lite\n");
326 Status
= NpInitializeAliases();
327 if (!NT_SUCCESS(Status
))
329 DPRINT1("Failed to initialize aliases!\n");
333 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = NpFsdCreate
;
334 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = NpFsdCreateNamedPipe
;
335 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = NpFsdClose
;
336 DriverObject
->MajorFunction
[IRP_MJ_READ
] = NpFsdRead
;
337 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = NpFsdWrite
;
338 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] = NpFsdQueryInformation
;
339 DriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] = NpFsdSetInformation
;
340 DriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] = NpFsdQueryVolumeInformation
;
341 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = NpFsdCleanup
;
342 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = NpFsdFlushBuffers
;
343 DriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] = NpFsdDirectoryControl
;
344 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = NpFsdFileSystemControl
;
345 DriverObject
->MajorFunction
[IRP_MJ_QUERY_SECURITY
] = NpFsdQuerySecurityInfo
;
346 DriverObject
->MajorFunction
[IRP_MJ_SET_SECURITY
] = NpFsdSetSecurityInfo
;
348 DriverObject
->DriverUnload
= NULL
;
350 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\NamedPipe");
351 Status
= IoCreateDevice(DriverObject
,
354 FILE_DEVICE_NAMED_PIPE
,
358 if (!NT_SUCCESS(Status
))
360 DPRINT1("Failed to create named pipe device! (Status %lx)\n", Status
);
364 /* Initialize the device object */
365 NpfsDeviceObject
= DeviceObject
;
366 DeviceObject
->Flags
|= DO_LONG_TERM_REQUESTS
;
368 /* Initialize the Volume Control Block (VCB) */
369 NpVcb
= DeviceObject
->DeviceExtension
;
371 Status
= NpCreateRootDcb();
372 ASSERT(Status
== STATUS_SUCCESS
);
373 return STATUS_SUCCESS
;