3 * Copyright (C) 2002, 2003, 2014 ReactOS Team
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/dirctl.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Pierre Schweitzer (pierre@reactos.org)
25 * Hervé Poussineau (hpoussin@reactos.org)
28 /* INCLUDES *****************************************************************/
35 /* FUNCTIONS ****************************************************************/
38 * @name NtfsAddFilenameToDirectory
41 * Adds a $FILE_NAME attribute to a given directory index.
44 * Points to the target disk's DEVICE_EXTENSION.
46 * @param DirectoryMftIndex
47 * Mft index of the parent directory which will receive the file.
49 * @param FileReferenceNumber
50 * File reference of the file to be added to the directory. This is a combination of the
51 * Mft index and sequence number.
53 * @param FilenameAttribute
54 * Pointer to the FILENAME_ATTRIBUTE of the file being added to the directory.
56 * @param CaseSensitive
57 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
58 * if an application created the file with the FILE_FLAG_POSIX_SEMANTICS flag.
61 * STATUS_SUCCESS on success.
62 * STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
63 * STATUS_NOT_IMPLEMENTED if target address isn't at the end of the given file record.
66 * WIP - Can only support a few files in a directory.
67 * One FILENAME_ATTRIBUTE is added to the directory's index for each link to that file. So, each
68 * file which contains one FILENAME_ATTRIBUTE for a long name and another for the 8.3 name, will
69 * get both attributes added to its parent directory.
72 NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt
,
73 ULONGLONG DirectoryMftIndex
,
74 ULONGLONG FileReferenceNumber
,
75 PFILENAME_ATTRIBUTE FilenameAttribute
,
76 BOOLEAN CaseSensitive
)
78 NTSTATUS Status
= STATUS_SUCCESS
;
79 PFILE_RECORD_HEADER ParentFileRecord
;
80 PNTFS_ATTR_CONTEXT IndexRootContext
;
81 PINDEX_ROOT_ATTRIBUTE I30IndexRoot
;
82 ULONG IndexRootOffset
;
83 ULONGLONG I30IndexRootLength
;
85 PNTFS_ATTR_RECORD DestinationAttribute
;
86 PINDEX_ROOT_ATTRIBUTE NewIndexRoot
;
87 ULONG AttributeLength
;
88 PNTFS_ATTR_RECORD NextAttribute
;
90 ULONG BtreeIndexLength
;
93 // Allocate memory for the parent directory
94 ParentFileRecord
= ExAllocatePoolWithTag(NonPagedPool
,
95 DeviceExt
->NtfsInfo
.BytesPerFileRecord
,
97 if (!ParentFileRecord
)
99 DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
100 return STATUS_INSUFFICIENT_RESOURCES
;
103 // Open the parent directory
104 Status
= ReadFileRecord(DeviceExt
, DirectoryMftIndex
, ParentFileRecord
);
105 if (!NT_SUCCESS(Status
))
107 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
108 DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
113 DPRINT1("Dumping old parent file record:\n");
114 NtfsDumpFileRecord(DeviceExt
, ParentFileRecord
);
116 // Find the index root attribute for the directory
117 Status
= FindAttribute(DeviceExt
,
124 if (!NT_SUCCESS(Status
))
126 DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
128 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
132 // Find the maximum index size given what the file record can hold
133 MaxIndexSize
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
135 - IndexRootContext
->Record
.Resident
.ValueOffset
136 - FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE
, Header
)
137 - (sizeof(ULONG
) * 2);
139 // Allocate memory for the index root data
140 I30IndexRootLength
= AttributeDataLength(&IndexRootContext
->Record
);
141 I30IndexRoot
= ExAllocatePoolWithTag(NonPagedPool
, I30IndexRootLength
, TAG_NTFS
);
144 DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
145 ReleaseAttributeContext(IndexRootContext
);
146 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
147 return STATUS_INSUFFICIENT_RESOURCES
;
150 // Read the Index Root
151 Status
= ReadAttribute(DeviceExt
, IndexRootContext
, 0, (PCHAR
)I30IndexRoot
, I30IndexRootLength
);
152 if (!NT_SUCCESS(Status
))
154 DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex
);
155 ReleaseAttributeContext(IndexRootContext
);
156 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
157 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
161 // Convert the index to a B*Tree
162 Status
= CreateBTreeFromIndex(IndexRootContext
, I30IndexRoot
, &NewTree
);
163 if (!NT_SUCCESS(Status
))
165 DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
166 ReleaseAttributeContext(IndexRootContext
);
167 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
168 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
174 // Insert the key for the file we're adding
175 Status
= NtfsInsertKey(FileReferenceNumber
, FilenameAttribute
, NewTree
->RootNode
, CaseSensitive
);
176 if (!NT_SUCCESS(Status
))
178 DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
179 DestroyBTree(NewTree
);
180 ReleaseAttributeContext(IndexRootContext
);
181 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
182 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
188 // Convert B*Tree back to Index Root
189 Status
= CreateIndexRootFromBTree(DeviceExt
, NewTree
, MaxIndexSize
, &NewIndexRoot
, &BtreeIndexLength
);
190 if (!NT_SUCCESS(Status
))
192 DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
193 DestroyBTree(NewTree
);
194 ReleaseAttributeContext(IndexRootContext
);
195 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
196 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
200 // We're done with the B-Tree now
201 DestroyBTree(NewTree
);
203 // Write back the new index root attribute to the parent directory file record
205 // First, we need to resize the attribute.
206 // CreateIndexRootFromBTree() should have verified that the index root fits within MaxIndexSize.
207 // We can't set the size as we normally would, because if we extend past the file record,
208 // we must create an index allocation and index bitmap (TODO). Also TODO: support file records with
209 // $ATTRIBUTE_LIST's.
210 AttributeLength
= NewIndexRoot
->Header
.AllocatedSize
+ FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE
, Header
);
211 DestinationAttribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)ParentFileRecord
+ IndexRootOffset
);
213 // Find the attribute (or attribute-end marker) after the index root
214 NextAttribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)DestinationAttribute
+ DestinationAttribute
->Length
);
215 if (NextAttribute
->Type
!= AttributeEnd
)
217 DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n");
218 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
219 ReleaseAttributeContext(IndexRootContext
);
220 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
221 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
222 return STATUS_NOT_IMPLEMENTED
;
225 // Update the length of the attribute in the file record of the parent directory
226 InternalSetResidentAttributeLength(IndexRootContext
,
231 NT_ASSERT(ParentFileRecord
->BytesInUse
<= DeviceExt
->NtfsInfo
.BytesPerFileRecord
);
233 Status
= UpdateFileRecord(DeviceExt
, DirectoryMftIndex
, ParentFileRecord
);
234 if (!NT_SUCCESS(Status
))
236 DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex
);
237 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
238 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
239 ReleaseAttributeContext(IndexRootContext
);
240 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
244 // Write the new index root to disk
245 Status
= WriteAttribute(DeviceExt
,
248 (PUCHAR
)NewIndexRoot
,
251 if (!NT_SUCCESS(Status
) )
253 DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
254 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
255 ReleaseAttributeContext(IndexRootContext
);
256 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
257 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
261 // re-read the parent file record, so we can dump it
262 Status
= ReadFileRecord(DeviceExt
, DirectoryMftIndex
, ParentFileRecord
);
263 if (!NT_SUCCESS(Status
))
265 DPRINT1("ERROR: Couldn't read parent directory after messing with it!\n");
269 DPRINT1("Dumping new parent file record:\n");
270 NtfsDumpFileRecord(DeviceExt
, ParentFileRecord
);
274 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
275 ReleaseAttributeContext(IndexRootContext
);
276 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
277 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
283 NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt
,
284 PFILE_RECORD_HEADER FileRecord
,
287 PULONGLONG AllocatedSize
)
289 ULONGLONG Size
= 0ULL;
290 ULONGLONG Allocated
= 0ULL;
292 PNTFS_ATTR_CONTEXT DataContext
;
294 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Stream
, StreamLength
, &DataContext
, NULL
);
295 if (NT_SUCCESS(Status
))
297 Size
= AttributeDataLength(&DataContext
->Record
);
298 Allocated
= AttributeAllocatedLength(&DataContext
->Record
);
299 ReleaseAttributeContext(DataContext
);
302 if (AllocatedSize
!= NULL
) *AllocatedSize
= Allocated
;
309 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt
,
310 PFILE_RECORD_HEADER FileRecord
,
312 PFILE_NAMES_INFORMATION Info
,
316 PFILENAME_ATTRIBUTE FileName
;
318 DPRINT("NtfsGetNameInformation() called\n");
320 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
321 if (FileName
== NULL
)
323 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
324 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
325 return STATUS_OBJECT_NAME_NOT_FOUND
;
328 Length
= FileName
->NameLength
* sizeof (WCHAR
);
329 if ((sizeof(FILE_NAMES_INFORMATION
) + Length
) > BufferLength
)
330 return(STATUS_BUFFER_OVERFLOW
);
332 Info
->FileNameLength
= Length
;
333 Info
->NextEntryOffset
=
334 ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) + Length
, sizeof(ULONG
));
335 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
337 return(STATUS_SUCCESS
);
342 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
343 PFILE_RECORD_HEADER FileRecord
,
345 PFILE_DIRECTORY_INFORMATION Info
,
349 PFILENAME_ATTRIBUTE FileName
;
350 PSTANDARD_INFORMATION StdInfo
;
352 DPRINT("NtfsGetDirectoryInformation() called\n");
354 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
355 if (FileName
== NULL
)
357 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
358 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
359 return STATUS_OBJECT_NAME_NOT_FOUND
;
362 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
363 ASSERT(StdInfo
!= NULL
);
365 Length
= FileName
->NameLength
* sizeof (WCHAR
);
366 if ((sizeof(FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
367 return(STATUS_BUFFER_OVERFLOW
);
369 Info
->FileNameLength
= Length
;
370 Info
->NextEntryOffset
=
371 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
372 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
374 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
375 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
376 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
377 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
379 /* Convert file flags */
380 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
382 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
384 Info
->FileIndex
= MFTIndex
;
386 return STATUS_SUCCESS
;
391 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
392 PFILE_RECORD_HEADER FileRecord
,
394 PFILE_FULL_DIRECTORY_INFORMATION Info
,
398 PFILENAME_ATTRIBUTE FileName
;
399 PSTANDARD_INFORMATION StdInfo
;
401 DPRINT("NtfsGetFullDirectoryInformation() called\n");
403 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
404 if (FileName
== NULL
)
406 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
407 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
408 return STATUS_OBJECT_NAME_NOT_FOUND
;
411 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
412 ASSERT(StdInfo
!= NULL
);
414 Length
= FileName
->NameLength
* sizeof (WCHAR
);
415 if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
416 return(STATUS_BUFFER_OVERFLOW
);
418 Info
->FileNameLength
= Length
;
419 Info
->NextEntryOffset
=
420 ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
421 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
423 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
424 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
425 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
426 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
428 /* Convert file flags */
429 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
431 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
433 Info
->FileIndex
= MFTIndex
;
436 return STATUS_SUCCESS
;
441 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
442 PFILE_RECORD_HEADER FileRecord
,
444 PFILE_BOTH_DIR_INFORMATION Info
,
448 PFILENAME_ATTRIBUTE FileName
, ShortFileName
;
449 PSTANDARD_INFORMATION StdInfo
;
451 DPRINT("NtfsGetBothDirectoryInformation() called\n");
453 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
454 if (FileName
== NULL
)
456 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
457 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
458 return STATUS_OBJECT_NAME_NOT_FOUND
;
460 ShortFileName
= GetFileNameFromRecord(DeviceExt
, FileRecord
, NTFS_FILE_NAME_DOS
);
462 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
463 ASSERT(StdInfo
!= NULL
);
465 Length
= FileName
->NameLength
* sizeof (WCHAR
);
466 if ((sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
) > BufferLength
)
467 return(STATUS_BUFFER_OVERFLOW
);
469 Info
->FileNameLength
= Length
;
470 Info
->NextEntryOffset
=
471 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
, sizeof(ULONG
));
472 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
476 /* Should we upcase the filename? */
477 ASSERT(ShortFileName
->NameLength
<= ARRAYSIZE(Info
->ShortName
));
478 Info
->ShortNameLength
= ShortFileName
->NameLength
* sizeof(WCHAR
);
479 RtlCopyMemory(Info
->ShortName
, ShortFileName
->Name
, Info
->ShortNameLength
);
483 Info
->ShortName
[0] = 0;
484 Info
->ShortNameLength
= 0;
487 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
488 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
489 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
490 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
492 /* Convert file flags */
493 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
495 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
497 Info
->FileIndex
= MFTIndex
;
500 return STATUS_SUCCESS
;
505 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext
)
508 PDEVICE_OBJECT DeviceObject
;
509 PDEVICE_EXTENSION DeviceExtension
;
510 LONG BufferLength
= 0;
511 PUNICODE_STRING SearchPattern
= NULL
;
512 FILE_INFORMATION_CLASS FileInformationClass
;
514 PUCHAR Buffer
= NULL
;
515 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
518 BOOLEAN First
= FALSE
;
519 PIO_STACK_LOCATION Stack
;
520 PFILE_OBJECT FileObject
;
521 NTSTATUS Status
= STATUS_SUCCESS
;
522 PFILE_RECORD_HEADER FileRecord
;
523 ULONGLONG MFTRecord
, OldMFTRecord
= 0;
524 UNICODE_STRING Pattern
;
526 DPRINT1("NtfsQueryDirectory() called\n");
529 Irp
= IrpContext
->Irp
;
530 DeviceObject
= IrpContext
->DeviceObject
;
532 DeviceExtension
= DeviceObject
->DeviceExtension
;
533 Stack
= IoGetCurrentIrpStackLocation(Irp
);
534 FileObject
= Stack
->FileObject
;
536 Ccb
= (PNTFS_CCB
)FileObject
->FsContext2
;
537 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
539 /* Obtain the callers parameters */
540 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
541 SearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
542 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
543 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
545 if (NtfsFCBIsCompressed(Fcb
))
547 DPRINT1("Compressed directory!\n");
549 return STATUS_NOT_IMPLEMENTED
;
552 if (!ExAcquireResourceSharedLite(&Fcb
->MainResource
,
553 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
555 return STATUS_PENDING
;
558 if (SearchPattern
!= NULL
)
560 if (!Ccb
->DirectorySearchPattern
)
564 Pattern
.MaximumLength
= SearchPattern
->Length
+ sizeof(WCHAR
);
565 Ccb
->DirectorySearchPattern
= Pattern
.Buffer
=
566 ExAllocatePoolWithTag(NonPagedPool
, Pattern
.MaximumLength
, TAG_NTFS
);
567 if (!Ccb
->DirectorySearchPattern
)
569 ExReleaseResourceLite(&Fcb
->MainResource
);
570 return STATUS_INSUFFICIENT_RESOURCES
;
573 memcpy(Ccb
->DirectorySearchPattern
, SearchPattern
->Buffer
, SearchPattern
->Length
);
574 Ccb
->DirectorySearchPattern
[SearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
577 else if (!Ccb
->DirectorySearchPattern
)
580 Ccb
->DirectorySearchPattern
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), TAG_NTFS
);
581 if (!Ccb
->DirectorySearchPattern
)
583 ExReleaseResourceLite(&Fcb
->MainResource
);
584 return STATUS_INSUFFICIENT_RESOURCES
;
587 Ccb
->DirectorySearchPattern
[0] = L
'*';
588 Ccb
->DirectorySearchPattern
[1] = 0;
591 RtlInitUnicodeString(&Pattern
, Ccb
->DirectorySearchPattern
);
592 DPRINT("Search pattern '%S'\n", Ccb
->DirectorySearchPattern
);
593 DPRINT("In: '%S'\n", Fcb
->PathName
);
595 /* Determine directory index */
596 if (Stack
->Flags
& SL_INDEX_SPECIFIED
)
598 Ccb
->Entry
= Ccb
->CurrentByteOffset
.u
.LowPart
;
600 else if (First
|| (Stack
->Flags
& SL_RESTART_SCAN
))
605 /* Get Buffer for result */
606 Buffer
= NtfsGetUserBuffer(Irp
, FALSE
);
608 DPRINT("Buffer=%p tofind=%S\n", Buffer
, Ccb
->DirectorySearchPattern
);
610 if (!ExAcquireResourceExclusiveLite(&DeviceExtension
->DirResource
,
611 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
613 ExReleaseResourceLite(&Fcb
->MainResource
);
614 return STATUS_PENDING
;
617 while (Status
== STATUS_SUCCESS
&& BufferLength
> 0)
619 Status
= NtfsFindFileAt(DeviceExtension
,
625 BooleanFlagOn(Stack
->Flags
, SL_CASE_SENSITIVE
));
627 if (NT_SUCCESS(Status
))
629 /* HACK: files with both a short name and a long name are present twice in the index.
630 * Ignore the second entry, if it is immediately following the first one.
632 if (MFTRecord
== OldMFTRecord
)
634 DPRINT1("Ignoring duplicate MFT entry 0x%x\n", MFTRecord
);
636 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
639 OldMFTRecord
= MFTRecord
;
641 switch (FileInformationClass
)
643 case FileNameInformation
:
644 Status
= NtfsGetNameInformation(DeviceExtension
,
647 (PFILE_NAMES_INFORMATION
)Buffer
,
651 case FileDirectoryInformation
:
652 Status
= NtfsGetDirectoryInformation(DeviceExtension
,
655 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
659 case FileFullDirectoryInformation
:
660 Status
= NtfsGetFullDirectoryInformation(DeviceExtension
,
663 (PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,
667 case FileBothDirectoryInformation
:
668 Status
= NtfsGetBothDirectoryInformation(DeviceExtension
,
671 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
676 Status
= STATUS_INVALID_INFO_CLASS
;
679 if (Status
== STATUS_BUFFER_OVERFLOW
)
683 Buffer0
->NextEntryOffset
= 0;
692 Buffer0
->NextEntryOffset
= 0;
697 Status
= STATUS_NO_SUCH_FILE
;
701 Status
= STATUS_NO_MORE_FILES
;
706 Buffer0
= (PFILE_NAMES_INFORMATION
)Buffer
;
707 Buffer0
->FileIndex
= FileIndex
++;
710 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
714 BufferLength
-= Buffer0
->NextEntryOffset
;
715 Buffer
+= Buffer0
->NextEntryOffset
;
716 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
721 Buffer0
->NextEntryOffset
= 0;
724 ExReleaseResourceLite(&DeviceExtension
->DirResource
);
725 ExReleaseResourceLite(&Fcb
->MainResource
);
729 Status
= STATUS_SUCCESS
;
737 NtfsDirectoryControl(PNTFS_IRP_CONTEXT IrpContext
)
739 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
741 DPRINT1("NtfsDirectoryControl() called\n");
743 switch (IrpContext
->MinorFunction
)
745 case IRP_MN_QUERY_DIRECTORY
:
746 Status
= NtfsQueryDirectory(IrpContext
);
749 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
750 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
751 Status
= STATUS_NOT_IMPLEMENTED
;
755 Status
= STATUS_INVALID_DEVICE_REQUEST
;
759 if (Status
== STATUS_PENDING
&& IrpContext
->Flags
& IRPCONTEXT_COMPLETE
)
761 return NtfsMarkIrpContextForQueue(IrpContext
);
764 IrpContext
->Irp
->IoStatus
.Information
= 0;