[NTFS]
[reactos.git] / drivers / filesystems / ffs / src / dirctl.c
1 /*
2 * FFS File System Driver for Windows
3 *
4 * dirctl.c
5 *
6 * 2004.5.6 ~
7 *
8 * Lee Jae-Hong, http://www.pyrasis.com
9 *
10 * See License.txt
11 *
12 */
13
14 #include "ntifs.h"
15 #include "ffsdrv.h"
16
17 /* Globals */
18
19 extern PFFS_GLOBAL FFSGlobal;
20
21
22 /* Definitions */
23
24 #ifdef ALLOC_PRAGMA
25 #pragma alloc_text(PAGE, FFSGetInfoLength)
26 #pragma alloc_text(PAGE, FFSProcessDirEntry)
27 #pragma alloc_text(PAGE, FFSQueryDirectory)
28 #pragma alloc_text(PAGE, FFSNotifyChangeDirectory)
29 #pragma alloc_text(PAGE, FFSDirectoryControl)
30 #pragma alloc_text(PAGE, FFSIsDirectoryEmpty)
31 #endif
32
33 ULONG
34 FFSGetInfoLength(
35 IN FILE_INFORMATION_CLASS FileInformationClass)
36 {
37 PAGED_CODE();
38
39 switch (FileInformationClass)
40 {
41 case FileDirectoryInformation:
42 return sizeof(FILE_DIRECTORY_INFORMATION);
43 break;
44
45 case FileFullDirectoryInformation:
46 return sizeof(FILE_FULL_DIR_INFORMATION);
47 break;
48
49 case FileBothDirectoryInformation:
50 return sizeof(FILE_BOTH_DIR_INFORMATION);
51 break;
52
53 case FileNamesInformation:
54 return sizeof(FILE_NAMES_INFORMATION);
55 break;
56
57 default:
58 break;
59 }
60
61 return 0;
62 }
63
64
65 ULONG
66 FFSProcessDirEntry(
67 IN PFFS_VCB Vcb,
68 IN FILE_INFORMATION_CLASS FileInformationClass,
69 IN ULONG in,
70 IN PVOID Buffer,
71 IN ULONG UsedLength,
72 IN ULONG Length,
73 IN ULONG FileIndex,
74 IN PUNICODE_STRING pName,
75 IN BOOLEAN Single)
76 {
77 FFSv1_INODE dinode1;
78 FFSv2_INODE dinode2;
79 PFILE_DIRECTORY_INFORMATION FDI;
80 PFILE_FULL_DIR_INFORMATION FFI;
81 PFILE_BOTH_DIR_INFORMATION FBI;
82 PFILE_NAMES_INFORMATION FNI;
83
84 ULONG InfoLength = 0;
85 ULONG NameLength = 0;
86 ULONG dwBytes = 0;
87
88 PAGED_CODE();
89
90 NameLength = pName->Length;
91
92 if (!in)
93 {
94 FFSPrint((DBG_ERROR, "FFSPricessDirEntry: ffs_dir_entry is empty.\n"));
95 return 0;
96 }
97
98 InfoLength = FFSGetInfoLength(FileInformationClass);
99
100 if (!InfoLength || InfoLength + NameLength - sizeof(WCHAR) > Length)
101 {
102 FFSPrint((DBG_INFO, "FFSPricessDirEntry: Buffer is not enough.\n"));
103 return 0;
104 }
105
106 if (FS_VERSION == 1)
107 {
108 if(!FFSv1LoadInode(Vcb, in, &dinode1))
109 {
110 FFSPrint((DBG_ERROR, "FFSPricessDirEntry: Loading inode %xh error.\n", in));
111
112 FFSBreakPoint();
113
114 return 0;
115 }
116 }
117 else
118 {
119 if(!FFSv2LoadInode(Vcb, in, &dinode2))
120 {
121 FFSPrint((DBG_ERROR, "FFSPricessDirEntry: Loading inode %xh error.\n", in));
122
123 FFSBreakPoint();
124
125 return 0;
126 }
127 }
128
129 switch(FileInformationClass)
130 {
131 case FileDirectoryInformation:
132 FDI = (PFILE_DIRECTORY_INFORMATION) ((PUCHAR)Buffer + UsedLength);
133 if (!Single)
134 FDI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR);
135 else
136 FDI->NextEntryOffset = 0;
137 FDI->FileIndex = FileIndex;
138
139 if (FS_VERSION == 1)
140 {
141 FDI->CreationTime = FFSSysTime(dinode1.di_ctime);
142 FDI->LastAccessTime = FFSSysTime(dinode1.di_atime);
143 FDI->LastWriteTime = FFSSysTime(dinode1.di_mtime);
144 FDI->ChangeTime = FFSSysTime(dinode1.di_mtime);
145 FDI->EndOfFile.QuadPart = dinode1.di_size;
146 FDI->AllocationSize.QuadPart = dinode1.di_size;
147 FDI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
148
149 if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode))
150 {
151 SetFlag(FDI->FileAttributes, FILE_ATTRIBUTE_READONLY);
152 }
153
154 if ((dinode1.di_mode & IFMT) == IFDIR)
155 FDI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
156
157 FDI->FileNameLength = NameLength;
158 RtlCopyMemory(FDI->FileName, pName->Buffer, NameLength);
159 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
160 break;
161 }
162 else
163 {
164 FDI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime);
165 FDI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime);
166 FDI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime);
167 FDI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime);
168 FDI->EndOfFile.QuadPart = dinode2.di_size;
169 FDI->AllocationSize.QuadPart = dinode2.di_size;
170 FDI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
171
172 if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode))
173 {
174 SetFlag(FDI->FileAttributes, FILE_ATTRIBUTE_READONLY);
175 }
176
177 if ((dinode2.di_mode & IFMT) == IFDIR)
178 FDI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
179
180 FDI->FileNameLength = NameLength;
181 RtlCopyMemory(FDI->FileName, pName->Buffer, NameLength);
182 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
183 break;
184 }
185
186 case FileFullDirectoryInformation:
187 FFI = (PFILE_FULL_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength);
188 if (!Single)
189 FFI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR);
190 else
191 FFI->NextEntryOffset = 0;
192 FFI->FileIndex = FileIndex;
193
194 if (FS_VERSION == 1)
195 {
196 FFI->CreationTime = FFSSysTime(dinode1.di_ctime);
197 FFI->LastAccessTime = FFSSysTime(dinode1.di_atime);
198 FFI->LastWriteTime = FFSSysTime(dinode1.di_mtime);
199 FFI->ChangeTime = FFSSysTime(dinode1.di_mtime);
200 FFI->EndOfFile.QuadPart = dinode1.di_size;
201 FFI->AllocationSize.QuadPart = dinode1.di_size;
202 FFI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
203
204 if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode))
205 {
206 SetFlag(FFI->FileAttributes, FILE_ATTRIBUTE_READONLY);
207 }
208
209 if ((dinode1.di_mode & IFMT) == IFDIR)
210 FFI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
211
212 FFI->FileNameLength = NameLength;
213 RtlCopyMemory(FFI->FileName, pName->Buffer, NameLength);
214 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
215
216 break;
217 }
218 else
219 {
220 FFI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime);
221 FFI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime);
222 FFI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime);
223 FFI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime);
224 FFI->EndOfFile.QuadPart = dinode2.di_size;
225 FFI->AllocationSize.QuadPart = dinode2.di_size;
226 FFI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
227
228 if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode))
229 {
230 SetFlag(FFI->FileAttributes, FILE_ATTRIBUTE_READONLY);
231 }
232
233 if ((dinode2.di_mode & IFMT) == IFDIR)
234 FFI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
235
236 FFI->FileNameLength = NameLength;
237 RtlCopyMemory(FFI->FileName, pName->Buffer, NameLength);
238 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
239
240 break;
241 }
242
243 case FileBothDirectoryInformation:
244 FBI = (PFILE_BOTH_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength);
245 if (!Single)
246 FBI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR);
247 else
248 FBI->NextEntryOffset = 0;
249
250 if (FS_VERSION == 1)
251 {
252 FBI->CreationTime = FFSSysTime(dinode1.di_ctime);
253 FBI->LastAccessTime = FFSSysTime(dinode1.di_atime);
254 FBI->LastWriteTime = FFSSysTime(dinode1.di_mtime);
255 FBI->ChangeTime = FFSSysTime(dinode1.di_mtime);
256
257 FBI->FileIndex = FileIndex;
258 FBI->EndOfFile.QuadPart = dinode1.di_size;
259 FBI->AllocationSize.QuadPart = dinode1.di_size;
260 FBI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
261
262 if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode))
263 {
264 SetFlag(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY);
265 }
266
267 if ((dinode1.di_mode & IFMT) == IFDIR)
268 FBI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
269 FBI->FileNameLength = NameLength;
270 RtlCopyMemory(FBI->FileName, pName->Buffer, NameLength);
271 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
272
273 break;
274 }
275 else
276 {
277 FBI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime);
278 FBI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime);
279 FBI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime);
280 FBI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime);
281
282 FBI->FileIndex = FileIndex;
283 FBI->EndOfFile.QuadPart = dinode2.di_size;
284 FBI->AllocationSize.QuadPart = dinode2.di_size;
285 FBI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
286
287 if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode))
288 {
289 SetFlag(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY);
290 }
291
292 if ((dinode2.di_mode & IFMT) == IFDIR)
293 FBI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
294 FBI->FileNameLength = NameLength;
295 RtlCopyMemory(FBI->FileName, pName->Buffer, NameLength);
296 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
297
298 break;
299 }
300
301 case FileNamesInformation:
302 FNI = (PFILE_NAMES_INFORMATION) ((PUCHAR)Buffer + UsedLength);
303 if (!Single)
304 FNI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR);
305 else
306 FNI->NextEntryOffset = 0;
307 FNI->FileNameLength = NameLength;
308 RtlCopyMemory(FNI->FileName, pName->Buffer, NameLength);
309 dwBytes = InfoLength + NameLength - sizeof(WCHAR);
310
311 break;
312
313 default:
314 break;
315 }
316
317 return dwBytes;
318 }
319
320
321 __drv_mustHoldCriticalRegion
322 NTSTATUS
323 FFSQueryDirectory(
324 IN PFFS_IRP_CONTEXT IrpContext)
325 {
326 PDEVICE_OBJECT DeviceObject;
327 NTSTATUS Status = STATUS_UNSUCCESSFUL;
328 PFFS_VCB Vcb = 0;
329 PFILE_OBJECT FileObject;
330 PFFS_FCB Fcb = 0;
331 PFFS_CCB Ccb;
332 PIRP Irp;
333 PIO_STACK_LOCATION IoStackLocation;
334 FILE_INFORMATION_CLASS FileInformationClass;
335 ULONG Length;
336 PUNICODE_STRING FileName;
337 ULONG FileIndex;
338 BOOLEAN RestartScan;
339 BOOLEAN ReturnSingleEntry;
340 BOOLEAN IndexSpecified;
341 PUCHAR Buffer;
342 BOOLEAN FirstQuery;
343 PFFSv1_INODE dinode1 = NULL;
344 PFFSv2_INODE dinode2 = NULL;
345 BOOLEAN FcbResourceAcquired = FALSE;
346 ULONG UsedLength = 0;
347 USHORT InodeFileNameLength;
348 UNICODE_STRING InodeFileName;
349 PFFS_DIR_ENTRY pDir = NULL;
350 ULONG dwBytes;
351 ULONG dwTemp = 0;
352 ULONG dwSize = 0;
353 ULONG dwReturn = 0;
354 BOOLEAN bRun = TRUE;
355 ULONG ByteOffset;
356
357 PAGED_CODE();
358
359 InodeFileName.Buffer = NULL;
360
361 _SEH2_TRY
362 {
363 ASSERT(IrpContext);
364
365 ASSERT((IrpContext->Identifier.Type == FFSICX) &&
366 (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
367
368 DeviceObject = IrpContext->DeviceObject;
369
370 //
371 // This request is not allowed on the main device object
372 //
373 if (DeviceObject == FFSGlobal->DeviceObject)
374 {
375 Status = STATUS_INVALID_DEVICE_REQUEST;
376 _SEH2_LEAVE;
377 }
378
379 Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
380
381 ASSERT(Vcb != NULL);
382
383 ASSERT((Vcb->Identifier.Type == FFSVCB) &&
384 (Vcb->Identifier.Size == sizeof(FFS_VCB)));
385
386 ASSERT(IsMounted(Vcb));
387
388 FileObject = IrpContext->FileObject;
389
390 Fcb = (PFFS_FCB)FileObject->FsContext;
391
392 ASSERT(Fcb);
393
394 //
395 // This request is not allowed on volumes
396 //
397 if (Fcb->Identifier.Type == FFSVCB)
398 {
399 Status = STATUS_INVALID_PARAMETER;
400 _SEH2_LEAVE;
401 }
402
403 ASSERT((Fcb->Identifier.Type == FFSFCB) &&
404 (Fcb->Identifier.Size == sizeof(FFS_FCB)));
405
406 if (!IsDirectory(Fcb))
407 {
408 Status = STATUS_INVALID_PARAMETER;
409 _SEH2_LEAVE;
410 }
411
412 Ccb = (PFFS_CCB)FileObject->FsContext2;
413
414 ASSERT(Ccb);
415
416 ASSERT((Ccb->Identifier.Type == FFSCCB) &&
417 (Ccb->Identifier.Size == sizeof(FFS_CCB)));
418
419 Irp = IrpContext->Irp;
420
421 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
422
423 #if !defined(_GNU_NTIFS_) || defined(__REACTOS__)
424
425 FileInformationClass =
426 IoStackLocation->Parameters.QueryDirectory.FileInformationClass;
427
428 Length = IoStackLocation->Parameters.QueryDirectory.Length;
429
430 FileName = IoStackLocation->Parameters.QueryDirectory.FileName;
431
432 FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex;
433
434 #else // _GNU_NTIFS_
435
436 FileInformationClass = ((PEXTENDED_IO_STACK_LOCATION)
437 IoStackLocation)->Parameters.QueryDirectory.FileInformationClass;
438
439 Length = ((PEXTENDED_IO_STACK_LOCATION)
440 IoStackLocation)->Parameters.QueryDirectory.Length;
441
442 FileName = ((PEXTENDED_IO_STACK_LOCATION)
443 IoStackLocation)->Parameters.QueryDirectory.FileName;
444
445 FileIndex = ((PEXTENDED_IO_STACK_LOCATION)
446 IoStackLocation)->Parameters.QueryDirectory.FileIndex;
447
448 #endif // _GNU_NTIFS_
449
450 RestartScan = FlagOn(IoStackLocation->Flags, SL_RESTART_SCAN);
451 ReturnSingleEntry = FlagOn(IoStackLocation->Flags, SL_RETURN_SINGLE_ENTRY);
452 IndexSpecified = FlagOn(IoStackLocation->Flags, SL_INDEX_SPECIFIED);
453 /*
454 if (!Irp->MdlAddress && Irp->UserBuffer)
455 {
456 ProbeForWrite(Irp->UserBuffer, Length, 1);
457 }
458 */
459 Buffer = FFSGetUserBuffer(Irp);
460
461 if (Buffer == NULL)
462 {
463 FFSBreakPoint();
464 Status = STATUS_INVALID_USER_BUFFER;
465 _SEH2_LEAVE;
466 }
467
468 if (!IrpContext->IsSynchronous)
469 {
470 Status = STATUS_PENDING;
471 _SEH2_LEAVE;
472 }
473
474 if (!ExAcquireResourceSharedLite(
475 &Fcb->MainResource,
476 IrpContext->IsSynchronous))
477 {
478 Status = STATUS_PENDING;
479 _SEH2_LEAVE;
480 }
481
482 FcbResourceAcquired = TRUE;
483
484 if (FileName != NULL)
485 {
486 if (Ccb->DirectorySearchPattern.Buffer != NULL)
487 {
488 FirstQuery = FALSE;
489 }
490 else
491 {
492 FirstQuery = TRUE;
493
494 Ccb->DirectorySearchPattern.Length =
495 Ccb->DirectorySearchPattern.MaximumLength =
496 FileName->Length;
497
498 Ccb->DirectorySearchPattern.Buffer =
499 ExAllocatePoolWithTag(PagedPool, FileName->Length, FFS_POOL_TAG);
500
501 if (Ccb->DirectorySearchPattern.Buffer == NULL)
502 {
503 Status = STATUS_INSUFFICIENT_RESOURCES;
504 _SEH2_LEAVE;
505 }
506
507 Status = RtlUpcaseUnicodeString(
508 &(Ccb->DirectorySearchPattern),
509 FileName,
510 FALSE);
511
512 if (!NT_SUCCESS(Status))
513 _SEH2_LEAVE;
514 }
515 }
516 else if (Ccb->DirectorySearchPattern.Buffer != NULL)
517 {
518 FirstQuery = FALSE;
519 FileName = &Ccb->DirectorySearchPattern;
520 }
521 else
522 {
523 FirstQuery = TRUE;
524
525 Ccb->DirectorySearchPattern.Length =
526 Ccb->DirectorySearchPattern.MaximumLength = 2;
527
528 Ccb->DirectorySearchPattern.Buffer =
529 ExAllocatePoolWithTag(PagedPool, 2, FFS_POOL_TAG);
530
531 if (Ccb->DirectorySearchPattern.Buffer == NULL)
532 {
533 Status = STATUS_INSUFFICIENT_RESOURCES;
534 _SEH2_LEAVE;
535 }
536
537 RtlCopyMemory(
538 Ccb->DirectorySearchPattern.Buffer,
539 L"*\0", 2);
540 }
541
542 if (!IndexSpecified)
543 {
544 if (RestartScan || FirstQuery)
545 {
546 FileIndex = Fcb->FFSMcb->DeOffset = 0;
547 }
548 else
549 {
550 FileIndex = Ccb->CurrentByteOffset;
551 }
552 }
553
554 if (FS_VERSION == 1)
555 {
556 dinode1 = (PFFSv1_INODE)ExAllocatePoolWithTag(
557 PagedPool,
558 DINODE1_SIZE, FFS_POOL_TAG);
559
560 if (dinode1 == NULL)
561 {
562 Status = STATUS_INSUFFICIENT_RESOURCES;
563 _SEH2_LEAVE;
564 }
565
566 RtlZeroMemory(Buffer, Length);
567
568 if (Fcb->dinode1->di_size <= FileIndex)
569 {
570 Status = STATUS_NO_MORE_FILES;
571 _SEH2_LEAVE;
572 }
573 }
574 else
575 {
576 dinode2 = (PFFSv2_INODE)ExAllocatePoolWithTag(
577 PagedPool,
578 DINODE2_SIZE, FFS_POOL_TAG);
579
580 if (dinode2 == NULL)
581 {
582 Status = STATUS_INSUFFICIENT_RESOURCES;
583 _SEH2_LEAVE;
584 }
585
586 RtlZeroMemory(Buffer, Length);
587
588 if (Fcb->dinode2->di_size <= FileIndex)
589 {
590 Status = STATUS_NO_MORE_FILES;
591 _SEH2_LEAVE;
592 }
593 }
594
595 pDir = ExAllocatePoolWithTag(PagedPool,
596 sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG);
597 if (!pDir)
598 {
599 Status = STATUS_INSUFFICIENT_RESOURCES;
600 _SEH2_LEAVE;
601 }
602
603
604 if (FS_VERSION == 1)
605 {
606 dwBytes = 0;
607 dwSize = (ULONG)Fcb->dinode1->di_size - FileIndex -
608 (sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);
609
610 ByteOffset = FileIndex;
611
612 dwTemp = 0;
613
614 while (bRun && UsedLength < Length && dwBytes < dwSize)
615 {
616 OEM_STRING OemName;
617
618 RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));
619
620 Status = FFSv1ReadInode(
621 NULL,
622 Vcb,
623 Fcb->dinode1,
624 ByteOffset,
625 (PVOID)pDir,
626 sizeof(FFS_DIR_ENTRY),
627 &dwReturn);
628
629 if (!NT_SUCCESS(Status))
630 {
631 _SEH2_LEAVE;
632 }
633
634 if (!pDir->d_ino)
635 {
636 if (pDir->d_reclen == 0)
637 {
638 FFSBreakPoint();
639 _SEH2_LEAVE;
640 }
641
642 goto ProcessNextEntryv1;
643 }
644
645 OemName.Buffer = pDir->d_name;
646 OemName.Length = (pDir->d_namlen & 0xff);
647 OemName.MaximumLength = OemName.Length;
648
649 #if 0
650 /*
651 //
652 // We could not filter the files: "." and ".."
653 //
654
655 if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
656 {
657 if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
658 {
659 }
660 else
661 {
662 goto ProcessNextEntry1;
663 }
664 }
665 */
666 #endif
667
668 InodeFileNameLength = (USHORT)
669 RtlOemStringToUnicodeSize(&OemName);
670
671 InodeFileName.Length = 0;
672 InodeFileName.MaximumLength = InodeFileNameLength + 2;
673
674 if (InodeFileNameLength <= 0)
675 {
676 break;
677 }
678
679 InodeFileName.Buffer = ExAllocatePoolWithTag(
680 PagedPool,
681 InodeFileNameLength + 2, FFS_POOL_TAG);
682
683 if (!InodeFileName.Buffer)
684 {
685 Status = STATUS_INSUFFICIENT_RESOURCES;
686 _SEH2_LEAVE;
687 }
688
689 RtlZeroMemory(
690 InodeFileName.Buffer,
691 InodeFileNameLength + 2);
692
693 Status = FFSOEMToUnicode(&InodeFileName,
694 &OemName);
695
696 if (!NT_SUCCESS(Status))
697 {
698 _SEH2_LEAVE;
699 }
700
701 if (FsRtlDoesNameContainWildCards(
702 &(Ccb->DirectorySearchPattern)) ?
703 FsRtlIsNameInExpression(
704 &(Ccb->DirectorySearchPattern),
705 &InodeFileName,
706 TRUE,
707 NULL) :
708 !RtlCompareUnicodeString(
709 &(Ccb->DirectorySearchPattern),
710 &InodeFileName,
711 TRUE))
712 {
713 dwReturn = FFSProcessDirEntry(
714 Vcb, FileInformationClass,
715 pDir->d_ino,
716 Buffer,
717 UsedLength,
718 Length - UsedLength,
719 (FileIndex + dwBytes),
720 &InodeFileName,
721 ReturnSingleEntry);
722
723 if (dwReturn <= 0)
724 {
725 bRun = FALSE;
726 }
727 else
728 {
729 dwTemp = UsedLength;
730 UsedLength += dwReturn;
731 }
732 }
733
734 if (InodeFileName.Buffer != NULL)
735 {
736 ExFreePool(InodeFileName.Buffer);
737 InodeFileName.Buffer = NULL;
738 }
739
740 ProcessNextEntryv1:
741
742 if (bRun)
743 {
744 dwBytes +=pDir->d_reclen;
745 Ccb->CurrentByteOffset = FileIndex + dwBytes;
746 }
747
748 if (UsedLength && ReturnSingleEntry)
749 {
750 Status = STATUS_SUCCESS;
751 _SEH2_LEAVE;
752 }
753
754 ByteOffset = FileIndex + dwBytes;
755 }
756 }
757 else
758 {
759 dwBytes = 0;
760 dwSize = (ULONG)Fcb->dinode2->di_size - FileIndex -
761 (sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);
762
763 ByteOffset = FileIndex;
764
765 dwTemp = 0;
766
767 while (bRun && UsedLength < Length && dwBytes < dwSize)
768 {
769 OEM_STRING OemName;
770
771 RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));
772
773 Status = FFSv2ReadInode(
774 NULL,
775 Vcb,
776 Fcb->dinode2,
777 ByteOffset,
778 (PVOID)pDir,
779 sizeof(FFS_DIR_ENTRY),
780 &dwReturn);
781
782 if (!NT_SUCCESS(Status))
783 {
784 _SEH2_LEAVE;
785 }
786
787 if (!pDir->d_ino)
788 {
789 if (pDir->d_reclen == 0)
790 {
791 FFSBreakPoint();
792 _SEH2_LEAVE;
793 }
794
795 goto ProcessNextEntryv2;
796 }
797
798 OemName.Buffer = pDir->d_name;
799 OemName.Length = (pDir->d_namlen & 0xff);
800 OemName.MaximumLength = OemName.Length;
801 #if 0
802 /*
803 //
804 // We could not filter the files: "." and ".."
805 //
806
807 if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
808 {
809 if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
810 {
811 }
812 else
813 {
814 goto ProcessNextEntry2;
815 }
816 }
817 */
818 #endif
819
820 InodeFileNameLength = (USHORT)
821 RtlOemStringToUnicodeSize(&OemName);
822
823 InodeFileName.Length = 0;
824 InodeFileName.MaximumLength = InodeFileNameLength + 2;
825
826 if (InodeFileNameLength <= 0)
827 {
828 break;
829 }
830
831 InodeFileName.Buffer = ExAllocatePoolWithTag(
832 PagedPool,
833 InodeFileNameLength + 2, FFS_POOL_TAG);
834
835 if (!InodeFileName.Buffer)
836 {
837 Status = STATUS_INSUFFICIENT_RESOURCES;
838 _SEH2_LEAVE;
839 }
840
841 RtlZeroMemory(
842 InodeFileName.Buffer,
843 InodeFileNameLength + 2);
844
845 Status = FFSOEMToUnicode(&InodeFileName,
846 &OemName);
847
848 if (!NT_SUCCESS(Status))
849 {
850 _SEH2_LEAVE;
851 }
852
853 if (FsRtlDoesNameContainWildCards(
854 &(Ccb->DirectorySearchPattern)) ?
855 FsRtlIsNameInExpression(
856 &(Ccb->DirectorySearchPattern),
857 &InodeFileName,
858 TRUE,
859 NULL) :
860 !RtlCompareUnicodeString(
861 &(Ccb->DirectorySearchPattern),
862 &InodeFileName,
863 TRUE))
864 {
865 dwReturn = FFSProcessDirEntry(
866 Vcb, FileInformationClass,
867 pDir->d_ino,
868 Buffer,
869 UsedLength,
870 Length - UsedLength,
871 (FileIndex + dwBytes),
872 &InodeFileName,
873 ReturnSingleEntry);
874
875 if (dwReturn <= 0)
876 {
877 bRun = FALSE;
878 }
879 else
880 {
881 dwTemp = UsedLength;
882 UsedLength += dwReturn;
883 }
884 }
885
886 if (InodeFileName.Buffer != NULL)
887 {
888 ExFreePool(InodeFileName.Buffer);
889 InodeFileName.Buffer = NULL;
890 }
891
892 ProcessNextEntryv2:
893
894 if (bRun)
895 {
896 dwBytes +=pDir->d_reclen;
897 Ccb->CurrentByteOffset = FileIndex + dwBytes;
898 }
899
900 if (UsedLength && ReturnSingleEntry)
901 {
902 Status = STATUS_SUCCESS;
903 _SEH2_LEAVE;
904 }
905
906 ByteOffset = FileIndex + dwBytes;
907 }
908 }
909
910 FileIndex += dwBytes;
911
912 ((PULONG)((PUCHAR)Buffer + dwTemp)) [0] = 0;
913
914 if (!UsedLength)
915 {
916 if (FirstQuery)
917 {
918 Status = STATUS_NO_SUCH_FILE;
919 }
920 else
921 {
922 Status = STATUS_NO_MORE_FILES;
923 }
924 }
925 else
926 {
927 Status = STATUS_SUCCESS;
928 }
929 }
930
931 _SEH2_FINALLY
932 {
933
934 if (FcbResourceAcquired)
935 {
936 ExReleaseResourceForThreadLite(
937 &Fcb->MainResource,
938 ExGetCurrentResourceThread());
939 }
940
941 if (FS_VERSION == 1)
942 {
943 if (dinode1 != NULL)
944 {
945 ExFreePool(dinode1);
946 }
947 }
948 else
949 {
950 if (dinode2 != NULL)
951 {
952 ExFreePool(dinode2);
953 }
954 }
955
956 if (pDir != NULL)
957 {
958 ExFreePool(pDir);
959 pDir = NULL;
960 }
961
962 if (InodeFileName.Buffer != NULL)
963 {
964 ExFreePool(InodeFileName.Buffer);
965 }
966
967 if (!IrpContext->ExceptionInProgress)
968 {
969 if (Status == STATUS_PENDING)
970 {
971 Status = FFSLockUserBuffer(
972 IrpContext->Irp,
973 Length,
974 IoWriteAccess);
975
976 if (NT_SUCCESS(Status))
977 {
978 Status = FFSQueueRequest(IrpContext);
979 }
980 else
981 {
982 FFSCompleteIrpContext(IrpContext, Status);
983 }
984 }
985 else
986 {
987 IrpContext->Irp->IoStatus.Information = UsedLength;
988 FFSCompleteIrpContext(IrpContext, Status);
989 }
990 }
991 } _SEH2_END;
992
993 return Status;
994 }
995
996
997 __drv_mustHoldCriticalRegion
998 NTSTATUS
999 FFSNotifyChangeDirectory(
1000 IN PFFS_IRP_CONTEXT IrpContext)
1001 {
1002 PDEVICE_OBJECT DeviceObject;
1003 BOOLEAN CompleteRequest;
1004 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1005 PFFS_VCB Vcb;
1006 PFILE_OBJECT FileObject;
1007 PFFS_FCB Fcb = 0;
1008 PIRP Irp;
1009 PIO_STACK_LOCATION IrpSp;
1010 ULONG CompletionFilter;
1011 BOOLEAN WatchTree;
1012
1013 BOOLEAN bFcbAcquired = FALSE;
1014
1015 PUNICODE_STRING FullName;
1016
1017 PAGED_CODE();
1018
1019 _SEH2_TRY
1020 {
1021 ASSERT(IrpContext);
1022
1023 ASSERT((IrpContext->Identifier.Type == FFSICX) &&
1024 (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
1025
1026 //
1027 // Always set the wait flag in the Irp context for the original request.
1028 //
1029
1030 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1031
1032 DeviceObject = IrpContext->DeviceObject;
1033
1034 if (DeviceObject == FFSGlobal->DeviceObject)
1035 {
1036 CompleteRequest = TRUE;
1037 Status = STATUS_INVALID_DEVICE_REQUEST;
1038 _SEH2_LEAVE;
1039 }
1040
1041 Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
1042
1043 ASSERT(Vcb != NULL);
1044
1045 ASSERT((Vcb->Identifier.Type == FFSVCB) &&
1046 (Vcb->Identifier.Size == sizeof(FFS_VCB)));
1047
1048 ASSERT(IsMounted(Vcb));
1049
1050 FileObject = IrpContext->FileObject;
1051
1052 Fcb = (PFFS_FCB)FileObject->FsContext;
1053
1054 ASSERT(Fcb);
1055
1056 if (Fcb->Identifier.Type == FFSVCB)
1057 {
1058 FFSBreakPoint();
1059 CompleteRequest = TRUE;
1060 Status = STATUS_INVALID_PARAMETER;
1061 _SEH2_LEAVE;
1062 }
1063
1064 ASSERT((Fcb->Identifier.Type == FFSFCB) &&
1065 (Fcb->Identifier.Size == sizeof(FFS_FCB)));
1066
1067 if (!IsDirectory(Fcb))
1068 {
1069 FFSBreakPoint();
1070 CompleteRequest = TRUE;
1071 Status = STATUS_INVALID_PARAMETER;
1072 _SEH2_LEAVE;
1073 }
1074
1075 if (ExAcquireResourceExclusiveLite(
1076 &Fcb->MainResource,
1077 TRUE))
1078 {
1079 bFcbAcquired = TRUE;
1080 }
1081 else
1082 {
1083 Status = STATUS_PENDING;
1084 _SEH2_LEAVE;
1085 }
1086
1087 Irp = IrpContext->Irp;
1088
1089 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1090
1091 #if !defined(_GNU_NTIFS_) || defined(__REACTOS__)
1092
1093 CompletionFilter =
1094 IrpSp->Parameters.NotifyDirectory.CompletionFilter;
1095
1096 #else // _GNU_NTIFS_
1097
1098 CompletionFilter = ((PEXTENDED_IO_STACK_LOCATION)
1099 IrpSp)->Parameters.NotifyDirectory.CompletionFilter;
1100
1101 #endif // _GNU_NTIFS_
1102
1103 WatchTree = IsFlagOn(IrpSp->Flags, SL_WATCH_TREE);
1104
1105 if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING))
1106 {
1107 Status = STATUS_DELETE_PENDING;
1108 _SEH2_LEAVE;
1109 }
1110
1111 FullName = &Fcb->LongName;
1112
1113 if (FullName->Buffer == NULL)
1114 {
1115 if (!FFSGetFullFileName(Fcb->FFSMcb, FullName))
1116 {
1117 Status = STATUS_INSUFFICIENT_RESOURCES;
1118 _SEH2_LEAVE;
1119 }
1120 }
1121
1122 FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
1123 &Vcb->NotifyList,
1124 FileObject->FsContext2,
1125 (PSTRING)FullName,
1126 WatchTree,
1127 FALSE,
1128 CompletionFilter,
1129 Irp,
1130 NULL,
1131 NULL);
1132
1133 CompleteRequest = FALSE;
1134
1135 Status = STATUS_PENDING;
1136
1137 /*
1138 Currently the driver is read-only but here is an example on how to use the
1139 FsRtl-functions to report a change:
1140
1141 ANSI_STRING TestString;
1142 USHORT FileNamePartLength;
1143
1144 RtlInitAnsiString(&TestString, "\\ntifs.h");
1145
1146 FileNamePartLength = 7;
1147
1148 FsRtlNotifyReportChange(
1149 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1150 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1151 &TestString, // PSTRING FullTargetName
1152 &FileNamePartLength, // PUSHORT FileNamePartLength
1153 FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch
1154 );
1155
1156 or
1157
1158 ANSI_STRING TestString;
1159
1160 RtlInitAnsiString(&TestString, "\\ntifs.h");
1161
1162 FsRtlNotifyFullReportChange(
1163 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1164 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1165 &TestString, // PSTRING FullTargetName
1166 1, // USHORT TargetNameOffset
1167 NULL, // PSTRING StreamName OPTIONAL
1168 NULL, // PSTRING NormalizedParentName OPTIONAL
1169 FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch
1170 0, // ULONG Action
1171 NULL // PVOID TargetContext
1172 );
1173 */
1174
1175 }
1176 _SEH2_FINALLY
1177 {
1178 if (bFcbAcquired)
1179 {
1180 ExReleaseResourceForThreadLite(
1181 &Fcb->MainResource,
1182 ExGetCurrentResourceThread());
1183 }
1184
1185 if (!IrpContext->ExceptionInProgress)
1186 {
1187 if (!CompleteRequest)
1188 {
1189 IrpContext->Irp = NULL;
1190 }
1191
1192 FFSCompleteIrpContext(IrpContext, Status);
1193 }
1194 } _SEH2_END;
1195
1196 return Status;
1197 }
1198
1199
1200 VOID
1201 FFSNotifyReportChange(
1202 IN PFFS_IRP_CONTEXT IrpContext,
1203 IN PFFS_VCB Vcb,
1204 IN PFFS_FCB Fcb,
1205 IN ULONG Filter,
1206 IN ULONG Action)
1207 {
1208 PUNICODE_STRING FullName;
1209 USHORT Offset;
1210
1211 FullName = &Fcb->LongName;
1212
1213 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
1214
1215 if (FullName->Buffer == NULL)
1216 {
1217 if (!FFSGetFullFileName(Fcb->FFSMcb, FullName))
1218 {
1219 /*Status = STATUS_INSUFFICIENT_RESOURCES;*/
1220 return;
1221 }
1222 }
1223
1224 Offset = (USHORT)(FullName->Length -
1225 Fcb->FFSMcb->ShortName.Length);
1226
1227 FsRtlNotifyFullReportChange(Vcb->NotifySync,
1228 &(Vcb->NotifyList),
1229 (PSTRING)(FullName),
1230 (USHORT)Offset,
1231 (PSTRING)NULL,
1232 (PSTRING)NULL,
1233 (ULONG)Filter,
1234 (ULONG)Action,
1235 (PVOID)NULL);
1236
1237 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
1238 }
1239
1240
1241 __drv_mustHoldCriticalRegion
1242 NTSTATUS
1243 FFSDirectoryControl(
1244 IN PFFS_IRP_CONTEXT IrpContext)
1245 {
1246 NTSTATUS Status;
1247
1248 PAGED_CODE();
1249
1250 ASSERT(IrpContext);
1251
1252 ASSERT((IrpContext->Identifier.Type == FFSICX) &&
1253 (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));
1254
1255 switch (IrpContext->MinorFunction)
1256 {
1257 case IRP_MN_QUERY_DIRECTORY:
1258 Status = FFSQueryDirectory(IrpContext);
1259 break;
1260
1261 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
1262 Status = FFSNotifyChangeDirectory(IrpContext);
1263 break;
1264
1265 default:
1266 Status = STATUS_INVALID_DEVICE_REQUEST;
1267 FFSCompleteIrpContext(IrpContext, Status);
1268 }
1269
1270 return Status;
1271 }
1272
1273
1274 BOOLEAN
1275 FFSIsDirectoryEmpty(
1276 PFFS_VCB Vcb,
1277 PFFS_FCB Dcb)
1278 {
1279 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1280
1281 PFFS_DIR_ENTRY pTarget = NULL;
1282
1283 ULONG dwBytes = 0;
1284 ULONG dwRet;
1285
1286 BOOLEAN bRet = TRUE;
1287
1288 PAGED_CODE();
1289
1290 if (!IsFlagOn(Dcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
1291 return TRUE;
1292
1293 _SEH2_TRY
1294 {
1295 pTarget = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
1296 FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG);
1297 if (!pTarget)
1298 {
1299 Status = STATUS_INSUFFICIENT_RESOURCES;
1300 _SEH2_LEAVE;
1301 }
1302
1303 dwBytes = 0;
1304
1305
1306 while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart)
1307 {
1308 RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));
1309
1310 if (FS_VERSION == 1)
1311 {
1312 Status = FFSv1ReadInode(
1313 NULL,
1314 Vcb,
1315 Dcb->dinode1,
1316 dwBytes,
1317 (PVOID)pTarget,
1318 FFS_DIR_REC_LEN(FFS_NAME_LEN),
1319 &dwRet);
1320 }
1321 else
1322 {
1323 Status = FFSv2ReadInode(
1324 NULL,
1325 Vcb,
1326 Dcb->dinode2,
1327 dwBytes,
1328 (PVOID)pTarget,
1329 FFS_DIR_REC_LEN(FFS_NAME_LEN),
1330 &dwRet);
1331 }
1332
1333 if (!NT_SUCCESS(Status))
1334 {
1335 FFSPrint((DBG_ERROR, "FFSRemoveEntry: Reading Directory Content error.\n"));
1336 _SEH2_LEAVE;
1337 }
1338
1339 if (pTarget->d_ino)
1340 {
1341 if (pTarget->d_namlen == 1 && pTarget->d_name[0] == '.')
1342 {
1343 }
1344 else if (pTarget->d_namlen == 2 && pTarget->d_name[0] == '.' &&
1345 pTarget->d_name[1] == '.')
1346 {
1347 }
1348 else
1349 {
1350 bRet = FALSE;
1351 break;
1352 }
1353 }
1354 else
1355 {
1356 break;
1357 }
1358
1359 dwBytes += pTarget->d_reclen;
1360 }
1361 }
1362
1363 _SEH2_FINALLY
1364 {
1365 if (pTarget != NULL)
1366 {
1367 ExFreePool(pTarget);
1368 }
1369 } _SEH2_END;
1370
1371 return bRet;
1372 }