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
= (PINDEX_ROOT_ATTRIBUTE
)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
);
149 // Read the Index Root
150 Status
= ReadAttribute(DeviceExt
, IndexRootContext
, 0, (PCHAR
)I30IndexRoot
, I30IndexRootLength
);
151 if (!NT_SUCCESS(Status
))
153 DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex
);
154 ReleaseAttributeContext(IndexRootContext
);
155 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
156 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
160 // Convert the index to a B*Tree
161 Status
= CreateBTreeFromIndex(IndexRootContext
, I30IndexRoot
, &NewTree
);
162 if (!NT_SUCCESS(Status
))
164 DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
165 ReleaseAttributeContext(IndexRootContext
);
166 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
167 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
173 // Insert the key for the file we're adding
174 Status
= NtfsInsertKey(FileReferenceNumber
, FilenameAttribute
, NewTree
->RootNode
, CaseSensitive
);
175 if (!NT_SUCCESS(Status
))
177 DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
178 DestroyBTree(NewTree
);
179 ReleaseAttributeContext(IndexRootContext
);
180 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
181 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
187 // Convert B*Tree back to Index Root
188 Status
= CreateIndexRootFromBTree(DeviceExt
, NewTree
, MaxIndexSize
, &NewIndexRoot
, &BtreeIndexLength
);
189 if (!NT_SUCCESS(Status
))
191 DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
192 DestroyBTree(NewTree
);
193 ReleaseAttributeContext(IndexRootContext
);
194 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
195 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
199 // We're done with the B-Tree now
200 DestroyBTree(NewTree
);
202 // Write back the new index root attribute to the parent directory file record
204 // First, we need to resize the attribute.
205 // CreateIndexRootFromBTree() should have verified that the index root fits within MaxIndexSize.
206 // We can't set the size as we normally would, because if we extend past the file record,
207 // we must create an index allocation and index bitmap (TODO). Also TODO: support file records with
208 // $ATTRIBUTE_LIST's.
209 AttributeLength
= NewIndexRoot
->Header
.AllocatedSize
+ FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE
, Header
);
210 DestinationAttribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)ParentFileRecord
+ IndexRootOffset
);
212 // Find the attribute (or attribute-end marker) after the index root
213 NextAttribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)DestinationAttribute
+ DestinationAttribute
->Length
);
214 if (NextAttribute
->Type
!= AttributeEnd
)
216 DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n");
217 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
218 ReleaseAttributeContext(IndexRootContext
);
219 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
220 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
221 return STATUS_NOT_IMPLEMENTED
;
224 // Update the length of the attribute in the file record of the parent directory
225 InternalSetResidentAttributeLength(IndexRootContext
,
230 NT_ASSERT(ParentFileRecord
->BytesInUse
<= DeviceExt
->NtfsInfo
.BytesPerFileRecord
);
232 Status
= UpdateFileRecord(DeviceExt
, DirectoryMftIndex
, ParentFileRecord
);
233 if (!NT_SUCCESS(Status
))
235 DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex
);
236 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
237 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
238 ReleaseAttributeContext(IndexRootContext
);
239 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
243 // Write the new index root to disk
244 Status
= WriteAttribute(DeviceExt
,
247 (PUCHAR
)NewIndexRoot
,
250 if (!NT_SUCCESS(Status
) )
252 DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
253 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
254 ReleaseAttributeContext(IndexRootContext
);
255 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
256 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
260 // re-read the parent file record, so we can dump it
261 Status
= ReadFileRecord(DeviceExt
, DirectoryMftIndex
, ParentFileRecord
);
262 if (!NT_SUCCESS(Status
))
264 DPRINT1("ERROR: Couldn't read parent directory after messing with it!\n");
268 DPRINT1("Dumping new parent file record:\n");
269 NtfsDumpFileRecord(DeviceExt
, ParentFileRecord
);
273 ExFreePoolWithTag(NewIndexRoot
, TAG_NTFS
);
274 ReleaseAttributeContext(IndexRootContext
);
275 ExFreePoolWithTag(I30IndexRoot
, TAG_NTFS
);
276 ExFreePoolWithTag(ParentFileRecord
, TAG_NTFS
);
282 NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt
,
283 PFILE_RECORD_HEADER FileRecord
,
286 PULONGLONG AllocatedSize
)
288 ULONGLONG Size
= 0ULL;
289 ULONGLONG Allocated
= 0ULL;
291 PNTFS_ATTR_CONTEXT DataContext
;
293 Status
= FindAttribute(DeviceExt
, FileRecord
, AttributeData
, Stream
, StreamLength
, &DataContext
, NULL
);
294 if (NT_SUCCESS(Status
))
296 Size
= AttributeDataLength(&DataContext
->Record
);
297 Allocated
= AttributeAllocatedLength(&DataContext
->Record
);
298 ReleaseAttributeContext(DataContext
);
301 if (AllocatedSize
!= NULL
) *AllocatedSize
= Allocated
;
308 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt
,
309 PFILE_RECORD_HEADER FileRecord
,
311 PFILE_NAMES_INFORMATION Info
,
315 PFILENAME_ATTRIBUTE FileName
;
317 DPRINT("NtfsGetNameInformation() called\n");
319 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
320 if (FileName
== NULL
)
322 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
323 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
324 return STATUS_OBJECT_NAME_NOT_FOUND
;
327 Length
= FileName
->NameLength
* sizeof (WCHAR
);
328 if ((sizeof(FILE_NAMES_INFORMATION
) + Length
) > BufferLength
)
329 return(STATUS_BUFFER_OVERFLOW
);
331 Info
->FileNameLength
= Length
;
332 Info
->NextEntryOffset
=
333 ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) + Length
, sizeof(ULONG
));
334 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
336 return(STATUS_SUCCESS
);
341 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
342 PFILE_RECORD_HEADER FileRecord
,
344 PFILE_DIRECTORY_INFORMATION Info
,
348 PFILENAME_ATTRIBUTE FileName
;
349 PSTANDARD_INFORMATION StdInfo
;
351 DPRINT("NtfsGetDirectoryInformation() called\n");
353 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
354 if (FileName
== NULL
)
356 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
357 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
358 return STATUS_OBJECT_NAME_NOT_FOUND
;
361 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
362 ASSERT(StdInfo
!= NULL
);
364 Length
= FileName
->NameLength
* sizeof (WCHAR
);
365 if ((sizeof(FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
366 return(STATUS_BUFFER_OVERFLOW
);
368 Info
->FileNameLength
= Length
;
369 Info
->NextEntryOffset
=
370 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
371 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
373 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
374 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
375 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
376 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
378 /* Convert file flags */
379 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
381 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
383 Info
->FileIndex
= MFTIndex
;
385 return STATUS_SUCCESS
;
390 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
391 PFILE_RECORD_HEADER FileRecord
,
393 PFILE_FULL_DIRECTORY_INFORMATION Info
,
397 PFILENAME_ATTRIBUTE FileName
;
398 PSTANDARD_INFORMATION StdInfo
;
400 DPRINT("NtfsGetFullDirectoryInformation() called\n");
402 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
403 if (FileName
== NULL
)
405 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
406 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
407 return STATUS_OBJECT_NAME_NOT_FOUND
;
410 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
411 ASSERT(StdInfo
!= NULL
);
413 Length
= FileName
->NameLength
* sizeof (WCHAR
);
414 if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
415 return(STATUS_BUFFER_OVERFLOW
);
417 Info
->FileNameLength
= Length
;
418 Info
->NextEntryOffset
=
419 ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
420 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
422 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
423 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
424 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
425 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
427 /* Convert file flags */
428 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
430 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
432 Info
->FileIndex
= MFTIndex
;
435 return STATUS_SUCCESS
;
440 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt
,
441 PFILE_RECORD_HEADER FileRecord
,
443 PFILE_BOTH_DIR_INFORMATION Info
,
447 PFILENAME_ATTRIBUTE FileName
, ShortFileName
;
448 PSTANDARD_INFORMATION StdInfo
;
450 DPRINT("NtfsGetBothDirectoryInformation() called\n");
452 FileName
= GetBestFileNameFromRecord(DeviceExt
, FileRecord
);
453 if (FileName
== NULL
)
455 DPRINT1("No name information for file ID: %#I64x\n", MFTIndex
);
456 NtfsDumpFileAttributes(DeviceExt
, FileRecord
);
457 return STATUS_OBJECT_NAME_NOT_FOUND
;
459 ShortFileName
= GetFileNameFromRecord(DeviceExt
, FileRecord
, NTFS_FILE_NAME_DOS
);
461 StdInfo
= GetStandardInformationFromRecord(DeviceExt
, FileRecord
);
462 ASSERT(StdInfo
!= NULL
);
464 Length
= FileName
->NameLength
* sizeof (WCHAR
);
465 if ((sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
) > BufferLength
)
466 return(STATUS_BUFFER_OVERFLOW
);
468 Info
->FileNameLength
= Length
;
469 Info
->NextEntryOffset
=
470 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) + Length
, sizeof(ULONG
));
471 RtlCopyMemory(Info
->FileName
, FileName
->Name
, Length
);
475 /* Should we upcase the filename? */
476 ASSERT(ShortFileName
->NameLength
<= ARRAYSIZE(Info
->ShortName
));
477 Info
->ShortNameLength
= ShortFileName
->NameLength
* sizeof(WCHAR
);
478 RtlCopyMemory(Info
->ShortName
, ShortFileName
->Name
, Info
->ShortNameLength
);
482 Info
->ShortName
[0] = 0;
483 Info
->ShortNameLength
= 0;
486 Info
->CreationTime
.QuadPart
= FileName
->CreationTime
;
487 Info
->LastAccessTime
.QuadPart
= FileName
->LastAccessTime
;
488 Info
->LastWriteTime
.QuadPart
= FileName
->LastWriteTime
;
489 Info
->ChangeTime
.QuadPart
= FileName
->ChangeTime
;
491 /* Convert file flags */
492 NtfsFileFlagsToAttributes(FileName
->FileAttributes
| StdInfo
->FileAttribute
, &Info
->FileAttributes
);
494 Info
->EndOfFile
.QuadPart
= NtfsGetFileSize(DeviceExt
, FileRecord
, L
"", 0, (PULONGLONG
)&Info
->AllocationSize
.QuadPart
);
496 Info
->FileIndex
= MFTIndex
;
499 return STATUS_SUCCESS
;
504 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext
)
507 PDEVICE_OBJECT DeviceObject
;
508 PDEVICE_EXTENSION DeviceExtension
;
509 LONG BufferLength
= 0;
510 PUNICODE_STRING SearchPattern
= NULL
;
511 FILE_INFORMATION_CLASS FileInformationClass
;
513 PUCHAR Buffer
= NULL
;
514 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
517 BOOLEAN First
= FALSE
;
518 PIO_STACK_LOCATION Stack
;
519 PFILE_OBJECT FileObject
;
520 NTSTATUS Status
= STATUS_SUCCESS
;
521 PFILE_RECORD_HEADER FileRecord
;
522 ULONGLONG MFTRecord
, OldMFTRecord
= 0;
523 UNICODE_STRING Pattern
;
525 DPRINT1("NtfsQueryDirectory() called\n");
528 Irp
= IrpContext
->Irp
;
529 DeviceObject
= IrpContext
->DeviceObject
;
531 DeviceExtension
= DeviceObject
->DeviceExtension
;
532 Stack
= IoGetCurrentIrpStackLocation(Irp
);
533 FileObject
= Stack
->FileObject
;
535 Ccb
= (PNTFS_CCB
)FileObject
->FsContext2
;
536 Fcb
= (PNTFS_FCB
)FileObject
->FsContext
;
538 /* Obtain the callers parameters */
539 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
540 SearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
541 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
542 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
544 if (NtfsFCBIsCompressed(Fcb
))
546 DPRINT1("Compressed directory!\n");
548 return STATUS_NOT_IMPLEMENTED
;
551 if (!ExAcquireResourceSharedLite(&Fcb
->MainResource
,
552 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
554 return STATUS_PENDING
;
557 if (SearchPattern
!= NULL
)
559 if (!Ccb
->DirectorySearchPattern
)
563 Pattern
.MaximumLength
= SearchPattern
->Length
+ sizeof(WCHAR
);
564 Ccb
->DirectorySearchPattern
= Pattern
.Buffer
=
565 ExAllocatePoolWithTag(NonPagedPool
, Pattern
.MaximumLength
, TAG_NTFS
);
566 if (!Ccb
->DirectorySearchPattern
)
568 ExReleaseResourceLite(&Fcb
->MainResource
);
569 return STATUS_INSUFFICIENT_RESOURCES
;
572 memcpy(Ccb
->DirectorySearchPattern
, SearchPattern
->Buffer
, SearchPattern
->Length
);
573 Ccb
->DirectorySearchPattern
[SearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
576 else if (!Ccb
->DirectorySearchPattern
)
579 Ccb
->DirectorySearchPattern
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), TAG_NTFS
);
580 if (!Ccb
->DirectorySearchPattern
)
582 ExReleaseResourceLite(&Fcb
->MainResource
);
583 return STATUS_INSUFFICIENT_RESOURCES
;
586 Ccb
->DirectorySearchPattern
[0] = L
'*';
587 Ccb
->DirectorySearchPattern
[1] = 0;
590 RtlInitUnicodeString(&Pattern
, Ccb
->DirectorySearchPattern
);
591 DPRINT("Search pattern '%S'\n", Ccb
->DirectorySearchPattern
);
592 DPRINT("In: '%S'\n", Fcb
->PathName
);
594 /* Determine directory index */
595 if (Stack
->Flags
& SL_INDEX_SPECIFIED
)
597 Ccb
->Entry
= Ccb
->CurrentByteOffset
.u
.LowPart
;
599 else if (First
|| (Stack
->Flags
& SL_RESTART_SCAN
))
604 /* Get Buffer for result */
605 Buffer
= NtfsGetUserBuffer(Irp
, FALSE
);
607 DPRINT("Buffer=%p tofind=%S\n", Buffer
, Ccb
->DirectorySearchPattern
);
609 if (!ExAcquireResourceExclusiveLite(&DeviceExtension
->DirResource
,
610 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
612 ExReleaseResourceLite(&Fcb
->MainResource
);
613 return STATUS_PENDING
;
616 while (Status
== STATUS_SUCCESS
&& BufferLength
> 0)
618 Status
= NtfsFindFileAt(DeviceExtension
,
624 BooleanFlagOn(Stack
->Flags
, SL_CASE_SENSITIVE
));
626 if (NT_SUCCESS(Status
))
628 /* HACK: files with both a short name and a long name are present twice in the index.
629 * Ignore the second entry, if it is immediately following the first one.
631 if (MFTRecord
== OldMFTRecord
)
633 DPRINT1("Ignoring duplicate MFT entry 0x%x\n", MFTRecord
);
635 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
638 OldMFTRecord
= MFTRecord
;
640 switch (FileInformationClass
)
642 case FileNameInformation
:
643 Status
= NtfsGetNameInformation(DeviceExtension
,
646 (PFILE_NAMES_INFORMATION
)Buffer
,
650 case FileDirectoryInformation
:
651 Status
= NtfsGetDirectoryInformation(DeviceExtension
,
654 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
658 case FileFullDirectoryInformation
:
659 Status
= NtfsGetFullDirectoryInformation(DeviceExtension
,
662 (PFILE_FULL_DIRECTORY_INFORMATION
)Buffer
,
666 case FileBothDirectoryInformation
:
667 Status
= NtfsGetBothDirectoryInformation(DeviceExtension
,
670 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
675 Status
= STATUS_INVALID_INFO_CLASS
;
678 if (Status
== STATUS_BUFFER_OVERFLOW
)
682 Buffer0
->NextEntryOffset
= 0;
691 Buffer0
->NextEntryOffset
= 0;
696 Status
= STATUS_NO_SUCH_FILE
;
700 Status
= STATUS_NO_MORE_FILES
;
705 Buffer0
= (PFILE_NAMES_INFORMATION
)Buffer
;
706 Buffer0
->FileIndex
= FileIndex
++;
709 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
713 BufferLength
-= Buffer0
->NextEntryOffset
;
714 Buffer
+= Buffer0
->NextEntryOffset
;
715 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
720 Buffer0
->NextEntryOffset
= 0;
723 ExReleaseResourceLite(&DeviceExtension
->DirResource
);
724 ExReleaseResourceLite(&Fcb
->MainResource
);
728 Status
= STATUS_SUCCESS
;
736 NtfsDirectoryControl(PNTFS_IRP_CONTEXT IrpContext
)
738 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
740 DPRINT1("NtfsDirectoryControl() called\n");
742 switch (IrpContext
->MinorFunction
)
744 case IRP_MN_QUERY_DIRECTORY
:
745 Status
= NtfsQueryDirectory(IrpContext
);
748 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
749 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
750 Status
= STATUS_NOT_IMPLEMENTED
;
754 Status
= STATUS_INVALID_DEVICE_REQUEST
;
758 if (Status
== STATUS_PENDING
&& IrpContext
->Flags
& IRPCONTEXT_COMPLETE
)
760 return NtfsMarkIrpContextForQueue(IrpContext
);
763 IrpContext
->Irp
->IoStatus
.Information
= 0;