1 /* 2 * PROJECT: VFAT Filesystem 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Directory control 5 * COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com> 6 * Copyright 2004-2005 Hervé Poussineau <hpoussin@reactos.org> 7 * Copyright 2012-2018 Pierre Schweitzer <pierre@reactos.org> 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "vfat.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 /* FUNCTIONS ****************************************************************/ 18 19 /* Function like DosDateTimeToFileTime */ 20 BOOLEAN 21 FsdDosDateTimeToSystemTime( 22 PDEVICE_EXTENSION DeviceExt, 23 USHORT DosDate, 24 USHORT DosTime, 25 PLARGE_INTEGER SystemTime) 26 { 27 PDOSTIME pdtime = (PDOSTIME)&DosTime; 28 PDOSDATE pddate = (PDOSDATE)&DosDate; 29 TIME_FIELDS TimeFields; 30 LARGE_INTEGER LocalTime; 31 32 if (SystemTime == NULL) 33 return FALSE; 34 35 TimeFields.Milliseconds = 0; 36 TimeFields.Second = pdtime->Second * 2; 37 TimeFields.Minute = pdtime->Minute; 38 TimeFields.Hour = pdtime->Hour; 39 40 TimeFields.Day = pddate->Day; 41 TimeFields.Month = pddate->Month; 42 TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year); 43 44 RtlTimeFieldsToTime(&TimeFields, &LocalTime); 45 ExLocalTimeToSystemTime(&LocalTime, SystemTime); 46 47 return TRUE; 48 } 49 50 /* Function like FileTimeToDosDateTime */ 51 BOOLEAN 52 FsdSystemTimeToDosDateTime( 53 PDEVICE_EXTENSION DeviceExt, 54 PLARGE_INTEGER SystemTime, 55 PUSHORT pDosDate, 56 PUSHORT pDosTime) 57 { 58 PDOSTIME pdtime = (PDOSTIME)pDosTime; 59 PDOSDATE pddate = (PDOSDATE)pDosDate; 60 TIME_FIELDS TimeFields; 61 LARGE_INTEGER LocalTime; 62 63 if (SystemTime == NULL) 64 return FALSE; 65 66 ExSystemTimeToLocalTime(SystemTime, &LocalTime); 67 RtlTimeToTimeFields(&LocalTime, &TimeFields); 68 69 if (pdtime) 70 { 71 pdtime->Second = TimeFields.Second / 2; 72 pdtime->Minute = TimeFields.Minute; 73 pdtime->Hour = TimeFields.Hour; 74 } 75 76 if (pddate) 77 { 78 pddate->Day = TimeFields.Day; 79 pddate->Month = TimeFields.Month; 80 pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear); 81 } 82 83 return TRUE; 84 } 85 86 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG))) 87 88 static 89 NTSTATUS 90 VfatGetFileNamesInformation( 91 PVFAT_DIRENTRY_CONTEXT DirContext, 92 PFILE_NAMES_INFORMATION pInfo, 93 ULONG BufferLength, 94 PULONG Written, 95 BOOLEAN First) 96 { 97 NTSTATUS Status; 98 ULONG BytesToCopy = 0; 99 100 *Written = 0; 101 Status = STATUS_BUFFER_OVERFLOW; 102 103 if (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > BufferLength) 104 return Status; 105 106 if (First || (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) + DirContext->LongNameU.Length)) 107 { 108 pInfo->FileNameLength = DirContext->LongNameU.Length; 109 110 *Written = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName); 111 pInfo->NextEntryOffset = 0; 112 if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName)) 113 { 114 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName)); 115 RtlCopyMemory(pInfo->FileName, 116 DirContext->LongNameU.Buffer, 117 BytesToCopy); 118 *Written += BytesToCopy; 119 120 if (BytesToCopy == DirContext->LongNameU.Length) 121 { 122 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + 123 BytesToCopy); 124 Status = STATUS_SUCCESS; 125 } 126 } 127 } 128 129 return Status; 130 } 131 132 static 133 NTSTATUS 134 VfatGetFileDirectoryInformation( 135 PVFAT_DIRENTRY_CONTEXT DirContext, 136 PDEVICE_EXTENSION DeviceExt, 137 PFILE_DIRECTORY_INFORMATION pInfo, 138 ULONG BufferLength, 139 PULONG Written, 140 BOOLEAN First) 141 { 142 NTSTATUS Status; 143 ULONG BytesToCopy = 0; 144 145 *Written = 0; 146 Status = STATUS_BUFFER_OVERFLOW; 147 148 if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > BufferLength) 149 return Status; 150 151 if (First || (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) + DirContext->LongNameU.Length)) 152 { 153 pInfo->FileNameLength = DirContext->LongNameU.Length; 154 /* pInfo->FileIndex = ; */ 155 156 *Written = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName); 157 pInfo->NextEntryOffset = 0; 158 if (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName)) 159 { 160 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName)); 161 RtlCopyMemory(pInfo->FileName, 162 DirContext->LongNameU.Buffer, 163 BytesToCopy); 164 *Written += BytesToCopy; 165 166 if (BytesToCopy == DirContext->LongNameU.Length) 167 { 168 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + 169 BytesToCopy); 170 Status = STATUS_SUCCESS; 171 } 172 } 173 174 175 176 if (vfatVolumeIsFatX(DeviceExt)) 177 { 178 FsdDosDateTimeToSystemTime(DeviceExt, 179 DirContext->DirEntry.FatX.CreationDate, 180 DirContext->DirEntry.FatX.CreationTime, 181 &pInfo->CreationTime); 182 FsdDosDateTimeToSystemTime(DeviceExt, 183 DirContext->DirEntry.FatX.AccessDate, 184 DirContext->DirEntry.FatX.AccessTime, 185 &pInfo->LastAccessTime); 186 FsdDosDateTimeToSystemTime(DeviceExt, 187 DirContext->DirEntry.FatX.UpdateDate, 188 DirContext->DirEntry.FatX.UpdateTime, 189 &pInfo->LastWriteTime); 190 191 pInfo->ChangeTime = pInfo->LastWriteTime; 192 193 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY)) 194 { 195 pInfo->EndOfFile.QuadPart = 0; 196 pInfo->AllocationSize.QuadPart = 0; 197 } 198 else 199 { 200 pInfo->EndOfFile.u.HighPart = 0; 201 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; 202 /* Make allocsize a rounded up multiple of BytesPerCluster */ 203 pInfo->AllocationSize.u.HighPart = 0; 204 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, 205 DeviceExt->FatInfo.BytesPerCluster); 206 } 207 208 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; 209 } 210 else 211 { 212 FsdDosDateTimeToSystemTime(DeviceExt, 213 DirContext->DirEntry.Fat.CreationDate, 214 DirContext->DirEntry.Fat.CreationTime, 215 &pInfo->CreationTime); 216 FsdDosDateTimeToSystemTime(DeviceExt, 217 DirContext->DirEntry.Fat.AccessDate, 218 0, 219 &pInfo->LastAccessTime); 220 FsdDosDateTimeToSystemTime(DeviceExt, 221 DirContext->DirEntry.Fat.UpdateDate, 222 DirContext->DirEntry.Fat.UpdateTime, 223 &pInfo->LastWriteTime); 224 225 pInfo->ChangeTime = pInfo->LastWriteTime; 226 227 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY)) 228 { 229 pInfo->EndOfFile.QuadPart = 0; 230 pInfo->AllocationSize.QuadPart = 0; 231 } 232 else 233 { 234 pInfo->EndOfFile.u.HighPart = 0; 235 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; 236 /* Make allocsize a rounded up multiple of BytesPerCluster */ 237 pInfo->AllocationSize.u.HighPart = 0; 238 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, 239 DeviceExt->FatInfo.BytesPerCluster); 240 } 241 242 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; 243 } 244 } 245 246 return Status; 247 } 248 249 static 250 NTSTATUS 251 VfatGetFileFullDirectoryInformation( 252 PVFAT_DIRENTRY_CONTEXT DirContext, 253 PDEVICE_EXTENSION DeviceExt, 254 PFILE_FULL_DIR_INFORMATION pInfo, 255 ULONG BufferLength, 256 PULONG Written, 257 BOOLEAN First) 258 { 259 NTSTATUS Status; 260 ULONG BytesToCopy = 0; 261 262 *Written = 0; 263 Status = STATUS_BUFFER_OVERFLOW; 264 265 if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > BufferLength) 266 return Status; 267 268 if (First || (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length)) 269 { 270 pInfo->FileNameLength = DirContext->LongNameU.Length; 271 /* pInfo->FileIndex = ; */ 272 pInfo->EaSize = 0; 273 274 *Written = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName); 275 pInfo->NextEntryOffset = 0; 276 if (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName)) 277 { 278 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName)); 279 RtlCopyMemory(pInfo->FileName, 280 DirContext->LongNameU.Buffer, 281 BytesToCopy); 282 *Written += BytesToCopy; 283 284 if (BytesToCopy == DirContext->LongNameU.Length) 285 { 286 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + 287 BytesToCopy); 288 Status = STATUS_SUCCESS; 289 } 290 } 291 292 if (vfatVolumeIsFatX(DeviceExt)) 293 { 294 FsdDosDateTimeToSystemTime(DeviceExt, 295 DirContext->DirEntry.FatX.CreationDate, 296 DirContext->DirEntry.FatX.CreationTime, 297 &pInfo->CreationTime); 298 FsdDosDateTimeToSystemTime(DeviceExt, 299 DirContext->DirEntry.FatX.AccessDate, 300 DirContext->DirEntry.FatX.AccessTime, 301 &pInfo->LastAccessTime); 302 FsdDosDateTimeToSystemTime(DeviceExt, 303 DirContext->DirEntry.FatX.UpdateDate, 304 DirContext->DirEntry.FatX.UpdateTime, 305 &pInfo->LastWriteTime); 306 307 pInfo->ChangeTime = pInfo->LastWriteTime; 308 pInfo->EndOfFile.u.HighPart = 0; 309 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; 310 /* Make allocsize a rounded up multiple of BytesPerCluster */ 311 pInfo->AllocationSize.u.HighPart = 0; 312 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, 313 DeviceExt->FatInfo.BytesPerCluster); 314 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; 315 } 316 else 317 { 318 FsdDosDateTimeToSystemTime(DeviceExt, 319 DirContext->DirEntry.Fat.CreationDate, 320 DirContext->DirEntry.Fat.CreationTime, 321 &pInfo->CreationTime); 322 FsdDosDateTimeToSystemTime(DeviceExt, 323 DirContext->DirEntry.Fat.AccessDate, 324 0, 325 &pInfo->LastAccessTime); 326 FsdDosDateTimeToSystemTime(DeviceExt, 327 DirContext->DirEntry.Fat.UpdateDate, 328 DirContext->DirEntry.Fat.UpdateTime, 329 &pInfo->LastWriteTime); 330 331 pInfo->ChangeTime = pInfo->LastWriteTime; 332 pInfo->EndOfFile.u.HighPart = 0; 333 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; 334 /* Make allocsize a rounded up multiple of BytesPerCluster */ 335 pInfo->AllocationSize.u.HighPart = 0; 336 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, 337 DeviceExt->FatInfo.BytesPerCluster); 338 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; 339 } 340 } 341 342 return Status; 343 } 344 345 static 346 NTSTATUS 347 VfatGetFileBothInformation( 348 PVFAT_DIRENTRY_CONTEXT DirContext, 349 PDEVICE_EXTENSION DeviceExt, 350 PFILE_BOTH_DIR_INFORMATION pInfo, 351 ULONG BufferLength, 352 PULONG Written, 353 BOOLEAN First) 354 { 355 NTSTATUS Status; 356 ULONG BytesToCopy = 0; 357 358 *Written = 0; 359 Status = STATUS_BUFFER_OVERFLOW; 360 361 if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > BufferLength) 362 return Status; 363 364 if (First || (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length)) 365 { 366 pInfo->FileNameLength = DirContext->LongNameU.Length; 367 pInfo->EaSize = 0; 368 369 *Written = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName); 370 pInfo->NextEntryOffset = 0; 371 if (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName)) 372 { 373 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName)); 374 RtlCopyMemory(pInfo->FileName, 375 DirContext->LongNameU.Buffer, 376 BytesToCopy); 377 *Written += BytesToCopy; 378 379 if (BytesToCopy == DirContext->LongNameU.Length) 380 { 381 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + 382 BytesToCopy); 383 Status = STATUS_SUCCESS; 384 } 385 } 386 387 if (vfatVolumeIsFatX(DeviceExt)) 388 { 389 pInfo->ShortName[0] = 0; 390 pInfo->ShortNameLength = 0; 391 /* pInfo->FileIndex = ; */ 392 393 FsdDosDateTimeToSystemTime(DeviceExt, 394 DirContext->DirEntry.FatX.CreationDate, 395 DirContext->DirEntry.FatX.CreationTime, 396 &pInfo->CreationTime); 397 FsdDosDateTimeToSystemTime(DeviceExt, 398 DirContext->DirEntry.FatX.AccessDate, 399 DirContext->DirEntry.FatX.AccessTime, 400 &pInfo->LastAccessTime); 401 FsdDosDateTimeToSystemTime(DeviceExt, 402 DirContext->DirEntry.FatX.UpdateDate, 403 DirContext->DirEntry.FatX.UpdateTime, 404 &pInfo->LastWriteTime); 405 406 pInfo->ChangeTime = pInfo->LastWriteTime; 407 408 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY)) 409 { 410 pInfo->EndOfFile.QuadPart = 0; 411 pInfo->AllocationSize.QuadPart = 0; 412 } 413 else 414 { 415 pInfo->EndOfFile.u.HighPart = 0; 416 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; 417 /* Make allocsize a rounded up multiple of BytesPerCluster */ 418 pInfo->AllocationSize.u.HighPart = 0; 419 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, 420 DeviceExt->FatInfo.BytesPerCluster); 421 } 422 423 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; 424 } 425 else 426 { 427 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length; 428 429 ASSERT(pInfo->ShortNameLength / sizeof(WCHAR) <= 12); 430 RtlCopyMemory(pInfo->ShortName, 431 DirContext->ShortNameU.Buffer, 432 DirContext->ShortNameU.Length); 433 434 /* pInfo->FileIndex = ; */ 435 436 FsdDosDateTimeToSystemTime(DeviceExt, 437 DirContext->DirEntry.Fat.CreationDate, 438 DirContext->DirEntry.Fat.CreationTime, 439 &pInfo->CreationTime); 440 FsdDosDateTimeToSystemTime(DeviceExt, 441 DirContext->DirEntry.Fat.AccessDate, 442 0, 443 &pInfo->LastAccessTime); 444 FsdDosDateTimeToSystemTime(DeviceExt, 445 DirContext->DirEntry.Fat.UpdateDate, 446 DirContext->DirEntry.Fat.UpdateTime, 447 &pInfo->LastWriteTime); 448 449 pInfo->ChangeTime = pInfo->LastWriteTime; 450 451 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY)) 452 { 453 pInfo->EndOfFile.QuadPart = 0; 454 pInfo->AllocationSize.QuadPart = 0; 455 } 456 else 457 { 458 pInfo->EndOfFile.u.HighPart = 0; 459 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; 460 /* Make allocsize a rounded up multiple of BytesPerCluster */ 461 pInfo->AllocationSize.u.HighPart = 0; 462 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster); 463 } 464 465 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; 466 } 467 } 468 469 return Status; 470 } 471 472 static 473 NTSTATUS 474 DoQuery( 475 PVFAT_IRP_CONTEXT IrpContext) 476 { 477 NTSTATUS Status = STATUS_SUCCESS; 478 LONG BufferLength = 0; 479 PUNICODE_STRING pSearchPattern = NULL; 480 FILE_INFORMATION_CLASS FileInformationClass; 481 PUCHAR Buffer = NULL; 482 PFILE_NAMES_INFORMATION Buffer0 = NULL; 483 PVFATFCB pFcb; 484 PVFATCCB pCcb; 485 BOOLEAN FirstQuery = FALSE; 486 BOOLEAN FirstCall = TRUE; 487 VFAT_DIRENTRY_CONTEXT DirContext; 488 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1]; 489 WCHAR ShortNameBuffer[13]; 490 ULONG Written; 491 492 PIO_STACK_LOCATION Stack = IrpContext->Stack; 493 494 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2; 495 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext; 496 497 /* Determine Buffer for result : */ 498 BufferLength = Stack->Parameters.QueryDirectory.Length; 499 #if 0 500 /* Do not probe the user buffer until SEH is available */ 501 if (IrpContext->Irp->RequestorMode != KernelMode && 502 IrpContext->Irp->MdlAddress == NULL && 503 IrpContext->Irp->UserBuffer != NULL) 504 { 505 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1); 506 } 507 #endif 508 Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE); 509 510 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, 511 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 512 { 513 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess); 514 if (NT_SUCCESS(Status)) 515 Status = STATUS_PENDING; 516 517 return Status; 518 } 519 520 if (!ExAcquireResourceSharedLite(&pFcb->MainResource, 521 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 522 { 523 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 524 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess); 525 if (NT_SUCCESS(Status)) 526 Status = STATUS_PENDING; 527 528 return Status; 529 } 530 531 /* Obtain the callers parameters */ 532 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName; 533 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass; 534 535 /* Allocate search pattern in case: 536 * -> We don't have one already in context 537 * -> We have been given an input pattern 538 * -> The pattern length is not null 539 * -> The pattern buffer is not null 540 * Otherwise, we'll fall later and allocate a match all (*) pattern 541 */ 542 if (pSearchPattern && 543 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL) 544 { 545 if (!pCcb->SearchPattern.Buffer) 546 { 547 FirstQuery = TRUE; 548 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR); 549 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 550 pCcb->SearchPattern.MaximumLength, 551 TAG_SEARCH); 552 if (!pCcb->SearchPattern.Buffer) 553 { 554 ExReleaseResourceLite(&pFcb->MainResource); 555 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 556 return STATUS_INSUFFICIENT_RESOURCES; 557 } 558 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern); 559 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0; 560 } 561 } 562 else if (!pCcb->SearchPattern.Buffer) 563 { 564 FirstQuery = TRUE; 565 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR); 566 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 567 2 * sizeof(WCHAR), 568 TAG_SEARCH); 569 if (!pCcb->SearchPattern.Buffer) 570 { 571 ExReleaseResourceLite(&pFcb->MainResource); 572 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 573 return STATUS_INSUFFICIENT_RESOURCES; 574 } 575 pCcb->SearchPattern.Buffer[0] = L'*'; 576 pCcb->SearchPattern.Buffer[1] = 0; 577 pCcb->SearchPattern.Length = sizeof(WCHAR); 578 } 579 580 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED)) 581 { 582 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex; 583 } 584 else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN)) 585 { 586 DirContext.DirIndex = pCcb->Entry = 0; 587 } 588 else 589 { 590 DirContext.DirIndex = pCcb->Entry; 591 } 592 593 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern); 594 595 DirContext.DeviceExt = IrpContext->DeviceExt; 596 DirContext.LongNameU.Buffer = LongNameBuffer; 597 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); 598 DirContext.ShortNameU.Buffer = ShortNameBuffer; 599 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); 600 601 Written = 0; 602 while ((Status == STATUS_SUCCESS) && (BufferLength > 0)) 603 { 604 Status = FindFile(IrpContext->DeviceExt, 605 pFcb, 606 &pCcb->SearchPattern, 607 &DirContext, 608 FirstCall); 609 pCcb->Entry = DirContext.DirIndex; 610 611 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry); 612 613 FirstCall = FALSE; 614 if (NT_SUCCESS(Status)) 615 { 616 switch (FileInformationClass) 617 { 618 case FileDirectoryInformation: 619 Status = VfatGetFileDirectoryInformation(&DirContext, 620 IrpContext->DeviceExt, 621 (PFILE_DIRECTORY_INFORMATION)Buffer, 622 BufferLength, 623 &Written, 624 Buffer0 == NULL); 625 break; 626 627 case FileFullDirectoryInformation: 628 Status = VfatGetFileFullDirectoryInformation(&DirContext, 629 IrpContext->DeviceExt, 630 (PFILE_FULL_DIR_INFORMATION)Buffer, 631 BufferLength, 632 &Written, 633 Buffer0 == NULL); 634 break; 635 636 case FileBothDirectoryInformation: 637 Status = VfatGetFileBothInformation(&DirContext, 638 IrpContext->DeviceExt, 639 (PFILE_BOTH_DIR_INFORMATION)Buffer, 640 BufferLength, 641 &Written, 642 Buffer0 == NULL); 643 break; 644 645 case FileNamesInformation: 646 Status = VfatGetFileNamesInformation(&DirContext, 647 (PFILE_NAMES_INFORMATION)Buffer, 648 BufferLength, 649 &Written, 650 Buffer0 == NULL); 651 break; 652 653 default: 654 Status = STATUS_INVALID_INFO_CLASS; 655 break; 656 } 657 658 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS) 659 break; 660 } 661 else 662 { 663 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES); 664 break; 665 } 666 667 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer; 668 Buffer0->FileIndex = DirContext.DirIndex; 669 pCcb->Entry = ++DirContext.DirIndex; 670 BufferLength -= Buffer0->NextEntryOffset; 671 672 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY)) 673 break; 674 675 Buffer += Buffer0->NextEntryOffset; 676 } 677 678 if (Buffer0) 679 { 680 Buffer0->NextEntryOffset = 0; 681 Status = STATUS_SUCCESS; 682 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength; 683 } 684 else 685 { 686 ASSERT(Status != STATUS_SUCCESS || BufferLength == 0); 687 ASSERT(Written <= Stack->Parameters.QueryDirectory.Length); 688 IrpContext->Irp->IoStatus.Information = Written; 689 } 690 691 ExReleaseResourceLite(&pFcb->MainResource); 692 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 693 694 return Status; 695 } 696 697 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext) 698 { 699 PVCB pVcb; 700 PVFATFCB pFcb; 701 PIO_STACK_LOCATION Stack; 702 Stack = IrpContext->Stack; 703 pVcb = IrpContext->DeviceExt; 704 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext; 705 706 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync, 707 &(pVcb->NotifyList), 708 IrpContext->FileObject->FsContext2, 709 (PSTRING)&(pFcb->PathNameU), 710 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE), 711 FALSE, 712 Stack->Parameters.NotifyDirectory.CompletionFilter, 713 IrpContext->Irp, 714 NULL, 715 NULL); 716 717 /* We won't handle IRP completion */ 718 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE; 719 720 return STATUS_PENDING; 721 } 722 723 /* 724 * FUNCTION: directory control : read/write directory informations 725 */ 726 NTSTATUS 727 VfatDirectoryControl( 728 PVFAT_IRP_CONTEXT IrpContext) 729 { 730 NTSTATUS Status = STATUS_SUCCESS; 731 732 IrpContext->Irp->IoStatus.Information = 0; 733 734 switch (IrpContext->MinorFunction) 735 { 736 case IRP_MN_QUERY_DIRECTORY: 737 Status = DoQuery (IrpContext); 738 break; 739 740 case IRP_MN_NOTIFY_CHANGE_DIRECTORY: 741 Status = VfatNotifyChangeDirectory(IrpContext); 742 break; 743 744 default: 745 /* Error */ 746 DPRINT("Unexpected minor function %x in VFAT driver\n", 747 IrpContext->MinorFunction); 748 Status = STATUS_INVALID_DEVICE_REQUEST; 749 break; 750 } 751 752 if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE)) 753 { 754 return VfatMarkIrpContextForQueue(IrpContext); 755 } 756 757 return Status; 758 } 759 760 /* EOF */ 761