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