1 /* 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 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "npfs.h" 12 13 // File ID number for NPFS bugchecking support 14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_MAIN) 15 16 /* GLOBALS ********************************************************************/ 17 18 PDEVICE_OBJECT NpfsDeviceObject; 19 PVOID NpAliases; 20 PNPFS_ALIAS NpAliasList; 21 PNPFS_ALIAS NpAliasListByLength[MAX_INDEXED_LENGTH + 1 - MIN_INDEXED_LENGTH]; 22 23 FAST_IO_DISPATCH NpFastIoDispatch = 24 { 25 sizeof(FAST_IO_DISPATCH), 26 NULL, 27 NpFastRead, 28 NpFastWrite, 29 }; 30 31 /* FUNCTIONS ******************************************************************/ 32 33 NTSTATUS 34 NTAPI 35 NpReadAlias( 36 PWSTR ValueName, 37 ULONG ValueType, 38 PVOID ValueData, 39 ULONG ValueLength, 40 PVOID Context, 41 PVOID EntryContext) 42 { 43 PNPFS_QUERY_VALUE_CONTEXT QueryContext = Context; 44 PWSTR CurrentString; 45 USHORT Length; 46 PNPFS_ALIAS CurrentAlias; 47 UNICODE_STRING TempString; 48 PUNICODE_STRING CurrentTargetName; 49 50 /* Check if we have the expected type */ 51 if (ValueType != REG_MULTI_SZ) 52 { 53 return STATUS_INVALID_PARAMETER; 54 } 55 56 /* Check if only the size is requested */ 57 if (QueryContext->SizeOnly) 58 { 59 /* Count this entry */ 60 QueryContext->NumberOfEntries++; 61 62 /* Get the length of the value name (i.e. the target name). */ 63 Length = wcslen(ValueName) * sizeof(WCHAR); 64 65 /* Add the size of the name plus a '\' and a UNICODE_STRING structure */ 66 QueryContext->FullSize += Length + sizeof(UNICODE_NULL) + 67 sizeof(OBJ_NAME_PATH_SEPARATOR) + 68 sizeof(UNICODE_STRING); 69 70 /* Loop while we have alias names */ 71 CurrentString = ValueData; 72 while (*CurrentString != UNICODE_NULL) 73 { 74 /* Count this alias */ 75 QueryContext->NumberOfAliases++; 76 77 /* Get the length of the current string (i.e. the alias name) */ 78 Length = wcslen(CurrentString) * sizeof(WCHAR); 79 80 /* Count the length plus the size of an NPFS_ALIAS structure */ 81 QueryContext->FullSize += Length + sizeof(UNICODE_NULL) + sizeof(NPFS_ALIAS); 82 83 /* Go to the next string */ 84 CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); 85 } 86 } 87 else 88 { 89 /* Get the next name string pointer */ 90 CurrentTargetName = QueryContext->CurrentTargetName++; 91 92 /* Get the length of the value name (i.e. the target name). */ 93 Length = wcslen(ValueName) * sizeof(WCHAR); 94 95 /* Initialize the current name string (one char more than the name) */ 96 CurrentTargetName->Buffer = QueryContext->CurrentStringPointer; 97 CurrentTargetName->Length = Length + sizeof(OBJ_NAME_PATH_SEPARATOR); 98 CurrentTargetName->MaximumLength = CurrentTargetName->Length + sizeof(UNICODE_NULL); 99 100 /* Update the current string pointer */ 101 QueryContext->CurrentStringPointer += 102 CurrentTargetName->MaximumLength / sizeof(WCHAR); 103 104 /* Prepend a '\' before the name */ 105 CurrentTargetName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR; 106 107 /* Append the value name (including the NULL termination) */ 108 RtlCopyMemory(&CurrentTargetName->Buffer[1], 109 ValueName, 110 Length + sizeof(UNICODE_NULL)); 111 112 /* Upcase the target name */ 113 RtlUpcaseUnicodeString(CurrentTargetName, CurrentTargetName, 0); 114 115 /* Loop while we have alias names */ 116 CurrentString = ValueData; 117 while (*CurrentString != UNICODE_NULL) 118 { 119 /* Get the next alias pointer */ 120 CurrentAlias = QueryContext->CurrentAlias++; 121 122 /* Get the length of the current string (i.e. the alias name) */ 123 Length = wcslen(CurrentString) * sizeof(WCHAR); 124 125 /* Setup the alias structure */ 126 CurrentAlias->TargetName = CurrentTargetName; 127 CurrentAlias->Name.Buffer = QueryContext->CurrentStringPointer; 128 CurrentAlias->Name.Length = Length; 129 CurrentAlias->Name.MaximumLength = Length + sizeof(UNICODE_NULL); 130 131 /* Upcase the alias name */ 132 TempString.Buffer = CurrentString; 133 TempString.Length = Length; 134 RtlUpcaseUnicodeString(&CurrentAlias->Name, 135 &TempString, 136 FALSE); 137 138 /* Update the current string pointer */ 139 QueryContext->CurrentStringPointer += 140 CurrentAlias->Name.MaximumLength / sizeof(WCHAR); 141 142 /* Go to the next string */ 143 CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); 144 } 145 } 146 147 return STATUS_SUCCESS; 148 } 149 150 LONG 151 NTAPI 152 NpCompareAliasNames( 153 _In_ PCUNICODE_STRING String1, 154 _In_ PCUNICODE_STRING String2) 155 { 156 ULONG Count; 157 PWCHAR P1, P2; 158 159 /* First check if the string sizes match */ 160 if (String1->Length != String2->Length) 161 { 162 /* They don't, return positive if the first is longer, negative otherwise */ 163 return String1->Length - String2->Length; 164 } 165 166 /* Now loop all characters */ 167 Count = String1->Length / sizeof(WCHAR); 168 P1 = String1->Buffer; 169 P2 = String2->Buffer; 170 while (Count) 171 { 172 /* Check if they don't match */ 173 if (*P1 != *P2) 174 { 175 /* Return positive if the first char is greater, negative otherwise */ 176 return *P1 - *P2; 177 } 178 179 /* Go to the next buffer position */ 180 P1++; 181 P2++; 182 Count--; 183 } 184 185 /* All characters matched, return 0 */ 186 return 0; 187 } 188 189 NTSTATUS 190 NTAPI 191 NpInitializeAliases(VOID) 192 { 193 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 194 NPFS_QUERY_VALUE_CONTEXT Context; 195 NTSTATUS Status; 196 USHORT Length; 197 ULONG i; 198 PNPFS_ALIAS CurrentAlias, *AliasPointer; 199 200 /* Initialize the query table */ 201 QueryTable[0].QueryRoutine = NpReadAlias; 202 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND; 203 QueryTable[0].Name = NULL; 204 QueryTable[0].EntryContext = NULL; 205 QueryTable[0].DefaultType = REG_NONE; 206 QueryTable[0].DefaultData = NULL; 207 QueryTable[0].DefaultLength = 0; 208 QueryTable[1].QueryRoutine = NULL; 209 QueryTable[1].Flags = 0; 210 QueryTable[1].Name = NULL; 211 212 /* Setup the query context */ 213 Context.SizeOnly = 1; 214 Context.FullSize = 0; 215 Context.NumberOfAliases = 0; 216 Context.NumberOfEntries = 0; 217 218 /* Query the registry values (calculate length only) */ 219 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL, 220 L"Npfs\\Aliases", 221 QueryTable, 222 &Context, 223 NULL); 224 if (!NT_SUCCESS(Status)) 225 { 226 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 227 return STATUS_SUCCESS; 228 229 return Status; 230 } 231 232 /* Check if there is anything */ 233 if (Context.FullSize == 0) 234 { 235 /* Nothing to do, return success */ 236 return STATUS_SUCCESS; 237 } 238 239 /* Allocate a structure large enough to hold all the data */ 240 NpAliases = ExAllocatePoolWithTag(NonPagedPool, Context.FullSize, 'sfpN'); 241 if (NpAliases == NULL) 242 return STATUS_INSUFFICIENT_RESOURCES; 243 244 /* Now setup the actual pointers in the context */ 245 Context.CurrentTargetName = NpAliases; 246 CurrentAlias = (PNPFS_ALIAS)&Context.CurrentTargetName[Context.NumberOfEntries]; 247 Context.CurrentAlias = CurrentAlias; 248 Context.CurrentStringPointer = (PWCHAR)&CurrentAlias[Context.NumberOfAliases]; 249 250 /* This time query the real data */ 251 Context.SizeOnly = FALSE; 252 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL, 253 L"Npfs\\Aliases", 254 QueryTable, 255 &Context, 256 NULL); 257 if (!NT_SUCCESS(Status)) 258 { 259 ExFreePoolWithTag(NpAliases, 0); 260 NpAliases = NULL; 261 return Status; 262 } 263 264 /* Make sure we didn't go past the end of the allocation! */ 265 NT_ASSERT((PUCHAR)Context.CurrentStringPointer <= 266 ((PUCHAR)NpAliases + Context.FullSize)); 267 268 /* Loop all aliases we got */ 269 for (i = 0; i < Context.NumberOfAliases; i++) 270 { 271 /* Get the length and check what list to use */ 272 Length = CurrentAlias->Name.Length; 273 if ((Length >= MIN_INDEXED_LENGTH * sizeof(WCHAR)) && 274 (Length <= MAX_INDEXED_LENGTH * sizeof(WCHAR))) 275 { 276 /* For this length range, we use an indexed list */ 277 AliasPointer = &NpAliasListByLength[(Length / sizeof(WCHAR)) - 5]; 278 } 279 else 280 { 281 /* Length is outside of the range, use the default list */ 282 AliasPointer = &NpAliasList; 283 } 284 285 /* Loop through all aliases already in the list until we find one that 286 is greater than our current alias */ 287 while ((*AliasPointer != NULL) && 288 (NpCompareAliasNames(&CurrentAlias->Name, 289 &(*AliasPointer)->Name) > 0)) 290 { 291 /* Go to the next alias */ 292 AliasPointer = &(*AliasPointer)->Next; 293 } 294 295 /* Insert the alias in the list */ 296 CurrentAlias->Next = *AliasPointer; 297 *AliasPointer = CurrentAlias; 298 299 /* Go to the next alias in the array */ 300 CurrentAlias++; 301 } 302 303 return STATUS_SUCCESS; 304 } 305 306 307 NTSTATUS 308 NTAPI 309 NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject, 310 IN PIRP Irp) 311 { 312 TRACE("Entered\n"); 313 UNIMPLEMENTED; 314 315 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 316 Irp->IoStatus.Information = 0; 317 318 IoCompleteRequest(Irp, IO_NO_INCREMENT); 319 return STATUS_NOT_IMPLEMENTED; 320 } 321 322 323 NTSTATUS 324 NTAPI 325 DriverEntry(IN PDRIVER_OBJECT DriverObject, 326 IN PUNICODE_STRING RegistryPath) 327 { 328 PDEVICE_OBJECT DeviceObject; 329 UNICODE_STRING DeviceName; 330 NTSTATUS Status; 331 UNREFERENCED_PARAMETER(RegistryPath); 332 333 DPRINT("Next-Generation NPFS-Advanced\n"); 334 335 Status = NpInitializeAliases(); 336 if (!NT_SUCCESS(Status)) 337 { 338 DPRINT1("Failed to initialize aliases!\n"); 339 return Status; 340 } 341 342 DriverObject->MajorFunction[IRP_MJ_CREATE] = NpFsdCreate; 343 DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = NpFsdCreateNamedPipe; 344 DriverObject->MajorFunction[IRP_MJ_CLOSE] = NpFsdClose; 345 DriverObject->MajorFunction[IRP_MJ_READ] = NpFsdRead; 346 DriverObject->MajorFunction[IRP_MJ_WRITE] = NpFsdWrite; 347 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = NpFsdQueryInformation; 348 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = NpFsdSetInformation; 349 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = NpFsdQueryVolumeInformation; 350 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NpFsdCleanup; 351 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = NpFsdFlushBuffers; 352 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = NpFsdDirectoryControl; 353 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = NpFsdFileSystemControl; 354 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = NpFsdQuerySecurityInfo; 355 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = NpFsdSetSecurityInfo; 356 357 DriverObject->DriverUnload = NULL; 358 359 DriverObject->FastIoDispatch = &NpFastIoDispatch; 360 361 RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe"); 362 Status = IoCreateDevice(DriverObject, 363 sizeof(NP_VCB), 364 &DeviceName, 365 FILE_DEVICE_NAMED_PIPE, 366 0, 367 FALSE, 368 &DeviceObject); 369 if (!NT_SUCCESS(Status)) 370 { 371 DPRINT1("Failed to create named pipe device! (Status %lx)\n", Status); 372 return Status; 373 } 374 375 /* Initialize the device object */ 376 NpfsDeviceObject = DeviceObject; 377 DeviceObject->Flags |= DO_LONG_TERM_REQUESTS; 378 379 /* Initialize the Volume Control Block (VCB) */ 380 NpVcb = DeviceObject->DeviceExtension; 381 NpInitializeVcb(); 382 Status = NpCreateRootDcb(); 383 ASSERT(Status == STATUS_SUCCESS); 384 return STATUS_SUCCESS; 385 } 386 387 /* EOF */ 388