[FASTFAT][CDFS]
[reactos.git] / reactos / drivers / filesystems / cdfs / dirctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/cdfs/dirctl.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Art Yerkes
25 * Eric Kohl
26 * UPDATE HISTORY:
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include "cdfs.h"
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* FUNCTIONS ****************************************************************/
37
38 #define ROUND_DOWN(N, S) (((N) / (S)) * (S))
39 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
40
41 /* FUNCTIONS ****************************************************************/
42
43 /*
44 * FUNCTION: Retrieves the file name, be it in short or long file name format
45 */
46 static NTSTATUS
47 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
48 PVOID *Context,
49 PVOID *Block,
50 PLARGE_INTEGER StreamOffset,
51 ULONG DirLength,
52 PVOID *Ptr,
53 PWSTR Name,
54 PULONG pIndex,
55 PULONG CurrentOffset)
56 {
57 PDIR_RECORD Record = *Ptr;
58 ULONG Index;
59
60 if (*CurrentOffset >= DirLength)
61 return(STATUS_NO_MORE_ENTRIES);
62
63 if (*CurrentOffset == 0)
64 {
65 Index = 0;
66 Record = (PDIR_RECORD)*Block;
67 while (Index < *pIndex)
68 {
69 (*Ptr) = (PVOID)((ULONG_PTR)(*Ptr) + Record->RecordLength);
70 (*CurrentOffset) += Record->RecordLength;
71 Record = *Ptr;
72 if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0)
73 {
74 DPRINT("Map next sector\n");
75 CcUnpinData(*Context);
76 StreamOffset->QuadPart += BLOCKSIZE;
77 *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
78 _SEH2_TRY
79 {
80 CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block);
81 }
82 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
83 {
84 DPRINT("CcMapData() failed\n");
85 _SEH2_YIELD(return _SEH2_GetExceptionCode());
86 }
87 _SEH2_END;
88 *Ptr = *Block;
89 Record = (PDIR_RECORD)*Ptr;
90 }
91 if (*CurrentOffset >= DirLength)
92 return(STATUS_NO_MORE_ENTRIES);
93
94 Index++;
95 }
96 }
97
98 if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0)
99 {
100 DPRINT("Map next sector\n");
101 CcUnpinData(*Context);
102 StreamOffset->QuadPart += BLOCKSIZE;
103 *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
104 _SEH2_TRY
105 {
106 CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block);
107 }
108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
109 {
110 DPRINT("CcMapData() failed\n");
111 _SEH2_YIELD(return _SEH2_GetExceptionCode());
112 }
113 _SEH2_END;
114 *Ptr = *Block;
115 Record = (PDIR_RECORD)*Ptr;
116 }
117
118 if (*CurrentOffset >= DirLength)
119 return STATUS_NO_MORE_ENTRIES;
120
121 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
122 *pIndex, Record->RecordLength, *CurrentOffset);
123
124 if (!CdfsIsRecordValid(DeviceExt, Record))
125 {
126 CcUnpinData(*Context);
127 return STATUS_DISK_CORRUPT_ERROR;
128 }
129
130 CdfsGetDirEntryName(DeviceExt, Record, Name);
131
132 *Ptr = Record;
133
134 return(STATUS_SUCCESS);
135 }
136
137
138 /*
139 * FUNCTION: Find a file
140 */
141 static NTSTATUS
142 CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
143 PFCB Fcb,
144 PFCB Parent,
145 PUNICODE_STRING FileToFind,
146 PULONG pDirIndex,
147 PULONG pOffset)
148 {
149 WCHAR name[256];
150 WCHAR ShortNameBuffer[13];
151 UNICODE_STRING TempString;
152 UNICODE_STRING ShortName;
153 UNICODE_STRING LongName;
154 UNICODE_STRING FileToFindUpcase;
155 PVOID Block;
156 NTSTATUS Status;
157 ULONG len;
158 ULONG DirIndex;
159 ULONG Offset = 0;
160 BOOLEAN IsRoot;
161 PVOID Context = NULL;
162 ULONG DirSize;
163 PDIR_RECORD Record;
164 LARGE_INTEGER StreamOffset, OffsetOfEntry;
165
166 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
167 Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
168 DPRINT("FindFile: old Pathname %p, old Objectname %p)\n",
169 Fcb->PathName, Fcb->ObjectName);
170
171 IsRoot = FALSE;
172 DirIndex = 0;
173
174 if (FileToFind == NULL || FileToFind->Length == 0)
175 {
176 RtlInitUnicodeString(&TempString, L".");
177 FileToFind = &TempString;
178 }
179
180 if (Parent)
181 {
182 if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
183 {
184 IsRoot = TRUE;
185 }
186 }
187 else
188 {
189 IsRoot = TRUE;
190 }
191
192 if (IsRoot == TRUE)
193 {
194 StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
195 DirSize = DeviceExt->CdInfo.RootSize;
196
197
198 if (FileToFind->Buffer[0] == 0 ||
199 (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) ||
200 (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0))
201 {
202 /* it's root : complete essentials fields then return ok */
203 RtlZeroMemory(Fcb, sizeof(FCB));
204 RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer));
205
206 Fcb->PathNameBuffer[0] = '\\';
207 Fcb->PathName.Length = sizeof(WCHAR);
208 Fcb->ObjectName = &Fcb->PathNameBuffer[1];
209 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
210 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
211 Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
212
213 if (pDirIndex)
214 *pDirIndex = 0;
215 if (pOffset)
216 *pOffset = 0;
217 DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb->PathName, Fcb->ObjectName);
218 return STATUS_SUCCESS;
219 }
220 }
221 else
222 {
223 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
224 DirSize = Parent->Entry.DataLengthL;
225 }
226
227 DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset.QuadPart, DirSize);
228
229 if (pDirIndex && (*pDirIndex))
230 DirIndex = *pDirIndex;
231
232 if (pOffset && (*pOffset))
233 {
234 Offset = *pOffset;
235 StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE);
236 }
237
238 _SEH2_TRY
239 {
240 CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block);
241 }
242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
243 {
244 DPRINT("CcMapData() failed\n");
245 _SEH2_YIELD(return _SEH2_GetExceptionCode());
246 }
247 _SEH2_END;
248
249 Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE);
250 if (Offset)
251 {
252 Offset += Record->RecordLength;
253 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
254 }
255
256 /* Upper case the expression for FsRtlIsNameInExpression */
257 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
258 if (!NT_SUCCESS(Status))
259 {
260 return Status;
261 }
262
263 while(TRUE)
264 {
265 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
266 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
267
268 Status = CdfsGetEntryName
269 (DeviceExt, &Context, &Block, &StreamOffset,
270 DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
271
272 if (Status == STATUS_NO_MORE_ENTRIES)
273 {
274 break;
275 }
276 else if (Status == STATUS_UNSUCCESSFUL || Status == STATUS_DISK_CORRUPT_ERROR)
277 {
278 /* Note: the directory cache has already been unpinned */
279 RtlFreeUnicodeString(&FileToFindUpcase);
280 return Status;
281 }
282
283 DPRINT("Name '%S'\n", name);
284
285 RtlInitUnicodeString(&LongName, name);
286
287 ShortName.Length = 0;
288 ShortName.MaximumLength = 26;
289 ShortName.Buffer = ShortNameBuffer;
290
291 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
292 CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);
293
294 DPRINT("ShortName '%wZ'\n", &ShortName);
295
296 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
297 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
298 {
299 if (Parent->PathName.Buffer[0])
300 {
301 RtlCopyUnicodeString(&Fcb->PathName, &Parent->PathName);
302 len = Parent->PathName.Length / sizeof(WCHAR);
303 Fcb->ObjectName=&Fcb->PathName.Buffer[len];
304 if (len != 1 || Fcb->PathName.Buffer[0] != '\\')
305 {
306 Fcb->ObjectName[0] = '\\';
307 Fcb->ObjectName = &Fcb->ObjectName[1];
308 }
309 }
310 else
311 {
312 Fcb->ObjectName=Fcb->PathName.Buffer;
313 Fcb->ObjectName[0]='\\';
314 Fcb->ObjectName=&Fcb->ObjectName[1];
315 }
316
317 DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName);
318
319 memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
320 wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1,
321 MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName)));
322
323 /* Copy short name */
324 Fcb->ShortNameU.Length = ShortName.Length;
325 Fcb->ShortNameU.MaximumLength = ShortName.Length;
326 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
327 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
328
329 if (pDirIndex)
330 *pDirIndex = DirIndex;
331 if (pOffset)
332 *pOffset = Offset;
333
334 DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n",
335 &Fcb->PathName, Fcb->ObjectName, DirIndex);
336
337 RtlFreeUnicodeString(&FileToFindUpcase);
338 CcUnpinData(Context);
339
340 return STATUS_SUCCESS;
341 }
342
343 Offset += Record->RecordLength;
344 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
345 DirIndex++;
346 }
347
348 RtlFreeUnicodeString(&FileToFindUpcase);
349 CcUnpinData(Context);
350
351 if (pDirIndex)
352 *pDirIndex = DirIndex;
353
354 if (pOffset)
355 *pOffset = Offset;
356
357 return STATUS_UNSUCCESSFUL;
358 }
359
360
361 static NTSTATUS
362 CdfsGetNameInformation(PFCB Fcb,
363 PDEVICE_EXTENSION DeviceExt,
364 PFILE_NAMES_INFORMATION Info,
365 ULONG BufferLength)
366 {
367 ULONG Length;
368
369 DPRINT("CdfsGetNameInformation() called\n");
370
371 UNREFERENCED_PARAMETER(DeviceExt);
372
373 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
374 if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
375 return(STATUS_BUFFER_OVERFLOW);
376
377 Info->FileNameLength = Length;
378 Info->NextEntryOffset =
379 ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
380 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
381
382 // Info->FileIndex=;
383
384 return(STATUS_SUCCESS);
385 }
386
387
388 static NTSTATUS
389 CdfsGetDirectoryInformation(PFCB Fcb,
390 PDEVICE_EXTENSION DeviceExt,
391 PFILE_DIRECTORY_INFORMATION Info,
392 ULONG BufferLength)
393 {
394 ULONG Length;
395
396 DPRINT("CdfsGetDirectoryInformation() called\n");
397
398 UNREFERENCED_PARAMETER(DeviceExt);
399
400 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
401 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
402 return(STATUS_BUFFER_OVERFLOW);
403
404 Info->FileNameLength = Length;
405 Info->NextEntryOffset =
406 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
407 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
408
409 /* Convert file times */
410 CdfsDateTimeToSystemTime(Fcb,
411 &Info->CreationTime);
412 Info->LastWriteTime = Info->CreationTime;
413 Info->ChangeTime = Info->CreationTime;
414
415 /* Convert file flags */
416 CdfsFileFlagsToAttributes(Fcb,
417 &Info->FileAttributes);
418 if (CdfsFCBIsDirectory(Fcb))
419 {
420 Info->EndOfFile.QuadPart = 0;
421 Info->AllocationSize.QuadPart = 0;
422 }
423 else
424 {
425 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
426
427 /* Make AllocSize a rounded up multiple of the sector size */
428 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
429 }
430
431 // Info->FileIndex=;
432
433 return(STATUS_SUCCESS);
434 }
435
436
437 static NTSTATUS
438 CdfsGetFullDirectoryInformation(PFCB Fcb,
439 PDEVICE_EXTENSION DeviceExt,
440 PFILE_FULL_DIR_INFORMATION Info,
441 ULONG BufferLength)
442 {
443 ULONG Length;
444
445 DPRINT("CdfsGetFullDirectoryInformation() called\n");
446
447 UNREFERENCED_PARAMETER(DeviceExt);
448
449 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
450 if ((sizeof (FILE_FULL_DIR_INFORMATION) + Length) > BufferLength)
451 return(STATUS_BUFFER_OVERFLOW);
452
453 Info->FileNameLength = Length;
454 Info->NextEntryOffset =
455 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + Length, sizeof(ULONG));
456 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
457
458 /* Convert file times */
459 CdfsDateTimeToSystemTime(Fcb,
460 &Info->CreationTime);
461 Info->LastWriteTime = Info->CreationTime;
462 Info->ChangeTime = Info->CreationTime;
463
464 /* Convert file flags */
465 CdfsFileFlagsToAttributes(Fcb,
466 &Info->FileAttributes);
467
468 if (CdfsFCBIsDirectory(Fcb))
469 {
470 Info->EndOfFile.QuadPart = 0;
471 Info->AllocationSize.QuadPart = 0;
472 }
473 else
474 {
475 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
476
477 /* Make AllocSize a rounded up multiple of the sector size */
478 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
479 }
480
481 // Info->FileIndex=;
482 Info->EaSize = 0;
483
484 return(STATUS_SUCCESS);
485 }
486
487
488 static NTSTATUS
489 CdfsGetBothDirectoryInformation(PFCB Fcb,
490 PDEVICE_EXTENSION DeviceExt,
491 PFILE_BOTH_DIR_INFORMATION Info,
492 ULONG BufferLength)
493 {
494 ULONG Length;
495
496 DPRINT("CdfsGetBothDirectoryInformation() called\n");
497
498 UNREFERENCED_PARAMETER(DeviceExt);
499
500 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
501 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
502 return(STATUS_BUFFER_OVERFLOW);
503
504 Info->FileNameLength = Length;
505 Info->NextEntryOffset =
506 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
507 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
508
509 /* Convert file times */
510 CdfsDateTimeToSystemTime(Fcb,
511 &Info->CreationTime);
512 Info->LastWriteTime = Info->CreationTime;
513 Info->ChangeTime = Info->CreationTime;
514
515 /* Convert file flags */
516 CdfsFileFlagsToAttributes(Fcb,
517 &Info->FileAttributes);
518
519 if (CdfsFCBIsDirectory(Fcb))
520 {
521 Info->EndOfFile.QuadPart = 0;
522 Info->AllocationSize.QuadPart = 0;
523 }
524 else
525 {
526 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
527
528 /* Make AllocSize a rounded up multiple of the sector size */
529 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
530 }
531
532 // Info->FileIndex=;
533 Info->EaSize = 0;
534
535 /* Copy short name */
536 ASSERT(Fcb->ShortNameU.Length / sizeof(WCHAR) <= 12);
537 Info->ShortNameLength = (CCHAR)Fcb->ShortNameU.Length;
538 RtlCopyMemory(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
539
540 return(STATUS_SUCCESS);
541 }
542
543
544 static NTSTATUS
545 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
546 PIRP Irp)
547 {
548 PDEVICE_EXTENSION DeviceExtension;
549 LONG BufferLength = 0;
550 PUNICODE_STRING SearchPattern = NULL;
551 FILE_INFORMATION_CLASS FileInformationClass;
552 ULONG FileIndex = 0;
553 PUCHAR Buffer = NULL;
554 PFILE_NAMES_INFORMATION Buffer0 = NULL;
555 PFCB Fcb;
556 PCCB Ccb;
557 FCB TempFcb;
558 BOOLEAN First = FALSE;
559 PIO_STACK_LOCATION Stack;
560 PFILE_OBJECT FileObject;
561 NTSTATUS Status = STATUS_SUCCESS;
562
563 DPRINT("CdfsQueryDirectory() called\n");
564
565 DeviceExtension = DeviceObject->DeviceExtension;
566 Stack = IoGetCurrentIrpStackLocation(Irp);
567 FileObject = Stack->FileObject;
568 RtlInitEmptyUnicodeString(&TempFcb.PathName, TempFcb.PathNameBuffer, sizeof(TempFcb.PathNameBuffer));
569
570 Ccb = (PCCB)FileObject->FsContext2;
571 Fcb = (PFCB)FileObject->FsContext;
572
573 /* Obtain the callers parameters */
574 BufferLength = Stack->Parameters.QueryDirectory.Length;
575 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
576 FileInformationClass =
577 Stack->Parameters.QueryDirectory.FileInformationClass;
578 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
579
580 /* Determine Buffer for result */
581 if (Irp->MdlAddress)
582 {
583 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
584 }
585 else
586 {
587 Buffer = Irp->UserBuffer;
588 }
589
590 /* Allocate search pattern in case:
591 * -> We don't have one already in context
592 * -> We have been given an input pattern
593 * -> The pattern length is not null
594 * -> The pattern buffer is not null
595 * Otherwise, we'll fall later and allocate a match all (*) pattern
596 */
597 if (SearchPattern != NULL &&
598 SearchPattern->Length != 0 && SearchPattern->Buffer != NULL)
599 {
600 if (Ccb->DirectorySearchPattern.Buffer == NULL)
601 {
602 First = TRUE;
603 Ccb->DirectorySearchPattern.Buffer =
604 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), CDFS_SEARCH_PATTERN_TAG);
605 if (Ccb->DirectorySearchPattern.Buffer == NULL)
606 {
607 return STATUS_INSUFFICIENT_RESOURCES;
608 }
609 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
610 RtlCopyUnicodeString(&Ccb->DirectorySearchPattern, SearchPattern);
611 Ccb->DirectorySearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
612 }
613 }
614 else if (Ccb->DirectorySearchPattern.Buffer == NULL)
615 {
616 First = TRUE;
617 Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), CDFS_SEARCH_PATTERN_TAG);
618 if (Ccb->DirectorySearchPattern.Buffer == NULL)
619 {
620 return STATUS_INSUFFICIENT_RESOURCES;
621 }
622
623 Ccb->DirectorySearchPattern.Length = sizeof(WCHAR);
624 Ccb->DirectorySearchPattern.MaximumLength = 2 * sizeof(WCHAR);
625 Ccb->DirectorySearchPattern.Buffer[0] = L'*';
626 Ccb->DirectorySearchPattern.Buffer[1] = 0;
627 }
628 DPRINT("Search pattern '%wZ'\n", &Ccb->DirectorySearchPattern);
629
630 /* Determine directory index */
631 if (Stack->Flags & SL_INDEX_SPECIFIED)
632 {
633 Ccb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
634 Ccb->Offset = Ccb->CurrentByteOffset.u.LowPart;
635 }
636 else if (First || (Stack->Flags & SL_RESTART_SCAN))
637 {
638 Ccb->Entry = 0;
639 Ccb->Offset = 0;
640 }
641 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
642
643 TempFcb.ObjectName = TempFcb.PathName.Buffer;
644 while (Status == STATUS_SUCCESS && BufferLength > 0)
645 {
646 Status = CdfsFindFile(DeviceExtension,
647 &TempFcb,
648 Fcb,
649 &Ccb->DirectorySearchPattern,
650 &Ccb->Entry,
651 &Ccb->Offset);
652 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
653
654 if (NT_SUCCESS(Status))
655 {
656 switch (FileInformationClass)
657 {
658 case FileNameInformation:
659 Status = CdfsGetNameInformation(&TempFcb,
660 DeviceExtension,
661 (PFILE_NAMES_INFORMATION)Buffer,
662 BufferLength);
663 break;
664
665 case FileDirectoryInformation:
666 Status = CdfsGetDirectoryInformation(&TempFcb,
667 DeviceExtension,
668 (PFILE_DIRECTORY_INFORMATION)Buffer,
669 BufferLength);
670 break;
671
672 case FileFullDirectoryInformation:
673 Status = CdfsGetFullDirectoryInformation(&TempFcb,
674 DeviceExtension,
675 (PFILE_FULL_DIR_INFORMATION)Buffer,
676 BufferLength);
677 break;
678
679 case FileBothDirectoryInformation:
680 Status = CdfsGetBothDirectoryInformation(&TempFcb,
681 DeviceExtension,
682 (PFILE_BOTH_DIR_INFORMATION)Buffer,
683 BufferLength);
684 break;
685
686 default:
687 Status = STATUS_INVALID_INFO_CLASS;
688 }
689
690 if (Status == STATUS_BUFFER_OVERFLOW)
691 {
692 if (Buffer0)
693 {
694 Buffer0->NextEntryOffset = 0;
695 }
696 break;
697 }
698 }
699 else
700 {
701 if (Buffer0)
702 {
703 Buffer0->NextEntryOffset = 0;
704 }
705
706 if (First)
707 {
708 Status = STATUS_NO_SUCH_FILE;
709 }
710 else
711 {
712 Status = STATUS_NO_MORE_FILES;
713 }
714 break;
715 }
716
717 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
718 Buffer0->FileIndex = FileIndex++;
719 Ccb->Entry++;
720
721 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
722 {
723 break;
724 }
725 BufferLength -= Buffer0->NextEntryOffset;
726 Buffer += Buffer0->NextEntryOffset;
727 }
728
729 if (Buffer0)
730 {
731 Buffer0->NextEntryOffset = 0;
732 }
733
734 if (FileIndex > 0)
735 {
736 Status = STATUS_SUCCESS;
737 }
738
739 return(Status);
740 }
741
742
743 static NTSTATUS
744 CdfsNotifyChangeDirectory(PDEVICE_OBJECT DeviceObject,
745 PIRP Irp,
746 PCDFS_IRP_CONTEXT IrpContext)
747 {
748 PDEVICE_EXTENSION DeviceExtension;
749 PFCB Fcb;
750 PCCB Ccb;
751 PIO_STACK_LOCATION Stack;
752 PFILE_OBJECT FileObject;
753
754 DPRINT("CdfsNotifyChangeDirectory() called\n");
755
756 DeviceExtension = DeviceObject->DeviceExtension;
757 Stack = IoGetCurrentIrpStackLocation(Irp);
758 FileObject = Stack->FileObject;
759
760 Ccb = (PCCB)FileObject->FsContext2;
761 Fcb = (PFCB)FileObject->FsContext;
762
763 FsRtlNotifyFullChangeDirectory(DeviceExtension->NotifySync,
764 &(DeviceExtension->NotifyList),
765 Ccb,
766 (PSTRING)&(Fcb->PathName),
767 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
768 FALSE,
769 Stack->Parameters.NotifyDirectory.CompletionFilter,
770 Irp,
771 NULL,
772 NULL);
773
774 /* We won't handle IRP completion */
775 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
776
777 return STATUS_PENDING;
778 }
779
780
781 NTSTATUS NTAPI
782 CdfsDirectoryControl(
783 PCDFS_IRP_CONTEXT IrpContext)
784 {
785 PIRP Irp;
786 PDEVICE_OBJECT DeviceObject;
787 NTSTATUS Status;
788
789 DPRINT("CdfsDirectoryControl() called\n");
790
791 ASSERT(IrpContext);
792
793 Irp = IrpContext->Irp;
794 DeviceObject = IrpContext->DeviceObject;
795
796 switch (IrpContext->MinorFunction)
797 {
798 case IRP_MN_QUERY_DIRECTORY:
799 Status = CdfsQueryDirectory(DeviceObject,
800 Irp);
801 break;
802
803 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
804 Status = CdfsNotifyChangeDirectory(DeviceObject,
805 Irp, IrpContext);
806 break;
807
808 default:
809 DPRINT1("CDFS: MinorFunction %u\n", IrpContext->MinorFunction);
810 Status = STATUS_INVALID_DEVICE_REQUEST;
811 break;
812 }
813
814 if (Status != STATUS_PENDING)
815 {
816 Irp->IoStatus.Information = 0;
817 }
818
819 return(Status);
820 }
821
822 /* EOF */