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