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