[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: services/fs/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 DPRINT("Name '%S'\n", name);
294
295 RtlInitUnicodeString(&LongName, name);
296 ShortName.Length = 0;
297 ShortName.MaximumLength = 26;
298 ShortName.Buffer = ShortNameBuffer;
299
300 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
301 CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);
302
303 DPRINT("ShortName '%wZ'\n", &ShortName);
304
305 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
306 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
307 {
308 if (Parent->PathName.Buffer[0])
309 {
310 RtlCopyUnicodeString(&Fcb->PathName, &Parent->PathName);
311 len = Parent->PathName.Length / sizeof(WCHAR);
312 Fcb->ObjectName=&Fcb->PathName.Buffer[len];
313 if (len != 1 || Fcb->PathName.Buffer[0] != '\\')
314 {
315 Fcb->ObjectName[0] = '\\';
316 Fcb->ObjectName = &Fcb->ObjectName[1];
317 }
318 }
319 else
320 {
321 Fcb->ObjectName=Fcb->PathName.Buffer;
322 Fcb->ObjectName[0]='\\';
323 Fcb->ObjectName=&Fcb->ObjectName[1];
324 }
325
326 DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName);
327
328 memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
329 wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1,
330 MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName)));
331
332 /* Copy short name */
333 Fcb->ShortNameU.Length = ShortName.Length;
334 Fcb->ShortNameU.MaximumLength = ShortName.Length;
335 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
336 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
337
338 if (pDirIndex)
339 *pDirIndex = DirIndex;
340 if (pOffset)
341 *pOffset = Offset;
342
343 DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n",
344 &Fcb->PathName, Fcb->ObjectName, DirIndex);
345
346 RtlFreeUnicodeString(&FileToFindUpcase);
347 CcUnpinData(Context);
348
349 return STATUS_SUCCESS;
350 }
351
352 Offset += Record->RecordLength;
353 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
354 DirIndex++;
355 }
356
357 RtlFreeUnicodeString(&FileToFindUpcase);
358 CcUnpinData(Context);
359
360 if (pDirIndex)
361 *pDirIndex = DirIndex;
362
363 if (pOffset)
364 *pOffset = Offset;
365
366 return STATUS_UNSUCCESSFUL;
367 }
368
369
370 static NTSTATUS
371 CdfsGetNameInformation(PFCB Fcb,
372 PDEVICE_EXTENSION DeviceExt,
373 PFILE_NAMES_INFORMATION Info,
374 ULONG BufferLength)
375 {
376 ULONG Length;
377
378 DPRINT("CdfsGetNameInformation() called\n");
379
380 UNREFERENCED_PARAMETER(DeviceExt);
381
382 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
383 if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
384 return(STATUS_BUFFER_OVERFLOW);
385
386 Info->FileNameLength = Length;
387 Info->NextEntryOffset =
388 ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
389 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
390
391 // Info->FileIndex=;
392
393 return(STATUS_SUCCESS);
394 }
395
396
397 static NTSTATUS
398 CdfsGetDirectoryInformation(PFCB Fcb,
399 PDEVICE_EXTENSION DeviceExt,
400 PFILE_DIRECTORY_INFORMATION Info,
401 ULONG BufferLength)
402 {
403 ULONG Length;
404
405 DPRINT("CdfsGetDirectoryInformation() called\n");
406
407 UNREFERENCED_PARAMETER(DeviceExt);
408
409 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
410 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
411 return(STATUS_BUFFER_OVERFLOW);
412
413 Info->FileNameLength = Length;
414 Info->NextEntryOffset =
415 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
416 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
417
418 /* Convert file times */
419 CdfsDateTimeToSystemTime(Fcb,
420 &Info->CreationTime);
421 Info->LastWriteTime = Info->CreationTime;
422 Info->ChangeTime = Info->CreationTime;
423
424 /* Convert file flags */
425 CdfsFileFlagsToAttributes(Fcb,
426 &Info->FileAttributes);
427 if (CdfsFCBIsDirectory(Fcb))
428 {
429 Info->EndOfFile.QuadPart = 0;
430 Info->AllocationSize.QuadPart = 0;
431 }
432 else
433 {
434 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
435
436 /* Make AllocSize a rounded up multiple of the sector size */
437 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
438 }
439
440 // Info->FileIndex=;
441
442 return(STATUS_SUCCESS);
443 }
444
445
446 static NTSTATUS
447 CdfsGetFullDirectoryInformation(PFCB Fcb,
448 PDEVICE_EXTENSION DeviceExt,
449 PFILE_FULL_DIR_INFORMATION Info,
450 ULONG BufferLength)
451 {
452 ULONG Length;
453
454 DPRINT("CdfsGetFullDirectoryInformation() called\n");
455
456 UNREFERENCED_PARAMETER(DeviceExt);
457
458 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
459 if ((sizeof (FILE_FULL_DIR_INFORMATION) + Length) > BufferLength)
460 return(STATUS_BUFFER_OVERFLOW);
461
462 Info->FileNameLength = Length;
463 Info->NextEntryOffset =
464 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + Length, sizeof(ULONG));
465 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
466
467 /* Convert file times */
468 CdfsDateTimeToSystemTime(Fcb,
469 &Info->CreationTime);
470 Info->LastWriteTime = Info->CreationTime;
471 Info->ChangeTime = Info->CreationTime;
472
473 /* Convert file flags */
474 CdfsFileFlagsToAttributes(Fcb,
475 &Info->FileAttributes);
476
477 if (CdfsFCBIsDirectory(Fcb))
478 {
479 Info->EndOfFile.QuadPart = 0;
480 Info->AllocationSize.QuadPart = 0;
481 }
482 else
483 {
484 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
485
486 /* Make AllocSize a rounded up multiple of the sector size */
487 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
488 }
489
490 // Info->FileIndex=;
491 Info->EaSize = 0;
492
493 return(STATUS_SUCCESS);
494 }
495
496
497 static NTSTATUS
498 CdfsGetBothDirectoryInformation(PFCB Fcb,
499 PDEVICE_EXTENSION DeviceExt,
500 PFILE_BOTH_DIR_INFORMATION Info,
501 ULONG BufferLength)
502 {
503 ULONG Length;
504
505 DPRINT("CdfsGetBothDirectoryInformation() called\n");
506
507 UNREFERENCED_PARAMETER(DeviceExt);
508
509 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
510 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
511 return(STATUS_BUFFER_OVERFLOW);
512
513 Info->FileNameLength = Length;
514 Info->NextEntryOffset =
515 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
516 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
517
518 /* Convert file times */
519 CdfsDateTimeToSystemTime(Fcb,
520 &Info->CreationTime);
521 Info->LastWriteTime = Info->CreationTime;
522 Info->ChangeTime = Info->CreationTime;
523
524 /* Convert file flags */
525 CdfsFileFlagsToAttributes(Fcb,
526 &Info->FileAttributes);
527
528 if (CdfsFCBIsDirectory(Fcb))
529 {
530 Info->EndOfFile.QuadPart = 0;
531 Info->AllocationSize.QuadPart = 0;
532 }
533 else
534 {
535 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
536
537 /* Make AllocSize a rounded up multiple of the sector size */
538 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
539 }
540
541 // Info->FileIndex=;
542 Info->EaSize = 0;
543
544 /* Copy short name */
545 ASSERT(Fcb->ShortNameU.Length / sizeof(WCHAR) <= 12);
546 Info->ShortNameLength = (CCHAR)Fcb->ShortNameU.Length;
547 RtlCopyMemory(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
548
549 return(STATUS_SUCCESS);
550 }
551
552
553 static NTSTATUS
554 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
555 PIRP Irp)
556 {
557 PDEVICE_EXTENSION DeviceExtension;
558 LONG BufferLength = 0;
559 PUNICODE_STRING SearchPattern = NULL;
560 FILE_INFORMATION_CLASS FileInformationClass;
561 ULONG FileIndex = 0;
562 PUCHAR Buffer = NULL;
563 PFILE_NAMES_INFORMATION Buffer0 = NULL;
564 PFCB Fcb;
565 PCCB Ccb;
566 FCB TempFcb;
567 BOOLEAN First = FALSE;
568 PIO_STACK_LOCATION Stack;
569 PFILE_OBJECT FileObject;
570 NTSTATUS Status = STATUS_SUCCESS;
571
572 DPRINT("CdfsQueryDirectory() called\n");
573
574 DeviceExtension = DeviceObject->DeviceExtension;
575 Stack = IoGetCurrentIrpStackLocation(Irp);
576 FileObject = Stack->FileObject;
577 RtlInitEmptyUnicodeString(&TempFcb.PathName, TempFcb.PathNameBuffer, sizeof(TempFcb.PathNameBuffer));
578
579 Ccb = (PCCB)FileObject->FsContext2;
580 Fcb = (PFCB)FileObject->FsContext;
581
582 /* Obtain the callers parameters */
583 BufferLength = Stack->Parameters.QueryDirectory.Length;
584 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
585 FileInformationClass =
586 Stack->Parameters.QueryDirectory.FileInformationClass;
587 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
588
589 /* Determine Buffer for result */
590 if (Irp->MdlAddress)
591 {
592 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
593 }
594 else
595 {
596 Buffer = Irp->UserBuffer;
597 }
598
599 /* Allocate search pattern in case:
600 * -> We don't have one already in context
601 * -> We have been given an input pattern
602 * -> The pattern length is not null
603 * -> The pattern buffer is not null
604 * Otherwise, we'll fall later and allocate a match all (*) pattern
605 */
606 if (SearchPattern != NULL &&
607 SearchPattern->Length != 0 && SearchPattern->Buffer != NULL)
608 {
609 if (Ccb->DirectorySearchPattern.Buffer == NULL)
610 {
611 First = TRUE;
612 Ccb->DirectorySearchPattern.Buffer =
613 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_CCB);
614 if (Ccb->DirectorySearchPattern.Buffer == NULL)
615 {
616 return STATUS_INSUFFICIENT_RESOURCES;
617 }
618 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
619 RtlCopyUnicodeString(&Ccb->DirectorySearchPattern, SearchPattern);
620 Ccb->DirectorySearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
621 }
622 }
623 else if (Ccb->DirectorySearchPattern.Buffer == NULL)
624 {
625 First = TRUE;
626 Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_CCB);
627 if (Ccb->DirectorySearchPattern.Buffer == NULL)
628 {
629 return STATUS_INSUFFICIENT_RESOURCES;
630 }
631
632 Ccb->DirectorySearchPattern.Length = sizeof(WCHAR);
633 Ccb->DirectorySearchPattern.MaximumLength = 2 * sizeof(WCHAR);
634 Ccb->DirectorySearchPattern.Buffer[0] = L'*';
635 Ccb->DirectorySearchPattern.Buffer[1] = 0;
636 }
637 DPRINT("Search pattern '%wZ'\n", &Ccb->DirectorySearchPattern);
638
639 /* Determine directory index */
640 if (Stack->Flags & SL_INDEX_SPECIFIED)
641 {
642 Ccb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
643 Ccb->Offset = Ccb->CurrentByteOffset.u.LowPart;
644 }
645 else if (First || (Stack->Flags & SL_RESTART_SCAN))
646 {
647 Ccb->Entry = 0;
648 Ccb->Offset = 0;
649 }
650 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
651
652 TempFcb.ObjectName = TempFcb.PathName.Buffer;
653 while (Status == STATUS_SUCCESS && BufferLength > 0)
654 {
655 Status = CdfsFindFile(DeviceExtension,
656 &TempFcb,
657 Fcb,
658 &Ccb->DirectorySearchPattern,
659 &Ccb->Entry,
660 &Ccb->Offset);
661 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
662
663 if (NT_SUCCESS(Status))
664 {
665 switch (FileInformationClass)
666 {
667 case FileNameInformation:
668 Status = CdfsGetNameInformation(&TempFcb,
669 DeviceExtension,
670 (PFILE_NAMES_INFORMATION)Buffer,
671 BufferLength);
672 break;
673
674 case FileDirectoryInformation:
675 Status = CdfsGetDirectoryInformation(&TempFcb,
676 DeviceExtension,
677 (PFILE_DIRECTORY_INFORMATION)Buffer,
678 BufferLength);
679 break;
680
681 case FileFullDirectoryInformation:
682 Status = CdfsGetFullDirectoryInformation(&TempFcb,
683 DeviceExtension,
684 (PFILE_FULL_DIR_INFORMATION)Buffer,
685 BufferLength);
686 break;
687
688 case FileBothDirectoryInformation:
689 Status = CdfsGetBothDirectoryInformation(&TempFcb,
690 DeviceExtension,
691 (PFILE_BOTH_DIR_INFORMATION)Buffer,
692 BufferLength);
693 break;
694
695 default:
696 Status = STATUS_INVALID_INFO_CLASS;
697 }
698
699 if (Status == STATUS_BUFFER_OVERFLOW)
700 {
701 if (Buffer0)
702 {
703 Buffer0->NextEntryOffset = 0;
704 }
705 break;
706 }
707 }
708 else
709 {
710 if (Buffer0)
711 {
712 Buffer0->NextEntryOffset = 0;
713 }
714
715 if (First)
716 {
717 Status = STATUS_NO_SUCH_FILE;
718 }
719 else
720 {
721 Status = STATUS_NO_MORE_FILES;
722 }
723 break;
724 }
725
726 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
727 Buffer0->FileIndex = FileIndex++;
728 Ccb->Entry++;
729
730 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
731 {
732 break;
733 }
734 BufferLength -= Buffer0->NextEntryOffset;
735 Buffer += Buffer0->NextEntryOffset;
736 }
737
738 if (Buffer0)
739 {
740 Buffer0->NextEntryOffset = 0;
741 }
742
743 if (FileIndex > 0)
744 {
745 Status = STATUS_SUCCESS;
746 }
747
748 return(Status);
749 }
750
751
752 static NTSTATUS
753 CdfsNotifyChangeDirectory(PDEVICE_OBJECT DeviceObject,
754 PIRP Irp)
755 {
756 PDEVICE_EXTENSION DeviceExtension;
757 PFCB Fcb;
758 PCCB Ccb;
759 PIO_STACK_LOCATION Stack;
760 PFILE_OBJECT FileObject;
761
762 DPRINT("CdfsNotifyChangeDirectory() called\n");
763
764 DeviceExtension = DeviceObject->DeviceExtension;
765 Stack = IoGetCurrentIrpStackLocation(Irp);
766 FileObject = Stack->FileObject;
767
768 Ccb = (PCCB)FileObject->FsContext2;
769 Fcb = (PFCB)FileObject->FsContext;
770
771 FsRtlNotifyFullChangeDirectory(DeviceExtension->NotifySync,
772 &(DeviceExtension->NotifyList),
773 Ccb,
774 (PSTRING)&(Fcb->PathName),
775 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
776 FALSE,
777 Stack->Parameters.NotifyDirectory.CompletionFilter,
778 Irp,
779 NULL,
780 NULL);
781
782 return STATUS_PENDING;
783 }
784
785
786 NTSTATUS NTAPI
787 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
788 PIRP Irp)
789 {
790 PIO_STACK_LOCATION Stack;
791 NTSTATUS Status;
792
793 DPRINT("CdfsDirectoryControl() called\n");
794 FsRtlEnterFileSystem();
795
796 Stack = IoGetCurrentIrpStackLocation(Irp);
797
798 switch (Stack->MinorFunction)
799 {
800 case IRP_MN_QUERY_DIRECTORY:
801 Status = CdfsQueryDirectory(DeviceObject,
802 Irp);
803 break;
804
805 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
806 Status = CdfsNotifyChangeDirectory(DeviceObject,
807 Irp);
808 break;
809
810 default:
811 DPRINT1("CDFS: MinorFunction %u\n", Stack->MinorFunction);
812 Status = STATUS_INVALID_DEVICE_REQUEST;
813 break;
814 }
815
816 if (Status != STATUS_PENDING)
817 {
818 Irp->IoStatus.Status = Status;
819 Irp->IoStatus.Information = 0;
820 IoCompleteRequest(Irp, IO_NO_INCREMENT);
821 }
822 FsRtlExitFileSystem();
823
824 return(Status);
825 }
826
827 /* EOF */