https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7bea4ec07eadf78e29b1b…
commit 7bea4ec07eadf78e29b1bafda9b20872ebbf60a7
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Jan 6 21:39:25 2018 +0100
[NTFS] Apply fix from 52f0726: allow partial info copy on dir enumeration on first
entry return.
This is assorted with misc fixes to make this code closer to what we currently have in
FastFAT.
This also allows fixing a memory leak in case of single entry return.
CORE-13367
---
drivers/filesystems/ntfs/dirctl.c | 298 +++++++++++++++++++++++++-------------
1 file changed, 198 insertions(+), 100 deletions(-)
diff --git a/drivers/filesystems/ntfs/dirctl.c b/drivers/filesystems/ntfs/dirctl.c
index 3c8d3cdb9a..4ad76fa382 100644
--- a/drivers/filesystems/ntfs/dirctl.c
+++ b/drivers/filesystems/ntfs/dirctl.c
@@ -60,18 +60,32 @@ NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
}
+#define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
+
+
static NTSTATUS
NtfsGetNamesInformation(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
ULONGLONG MFTIndex,
PFILE_NAMES_INFORMATION Info,
- ULONG BufferLength)
+ ULONG BufferLength,
+ PULONG Written,
+ BOOLEAN First)
{
ULONG Length;
+ NTSTATUS Status;
+ ULONG BytesToCopy = 0;
PFILENAME_ATTRIBUTE FileName;
DPRINT("NtfsGetNamesInformation() called\n");
+ *Written = 0;
+ Status = STATUS_BUFFER_OVERFLOW;
+ if (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > BufferLength)
+ {
+ return Status;
+ }
+
FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
if (FileName == NULL)
{
@@ -81,15 +95,28 @@ NtfsGetNamesInformation(PDEVICE_EXTENSION DeviceExt,
}
Length = FileName->NameLength * sizeof (WCHAR);
- if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
- return(STATUS_BUFFER_OVERFLOW);
+ if (First || (BufferLength >= FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) +
Length))
+ {
+ Info->FileNameLength = Length;
- Info->FileNameLength = Length;
- Info->NextEntryOffset =
- ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
- RtlCopyMemory(Info->FileName, FileName->Name, Length);
+ *Written = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
+ Info->NextEntryOffset = 0;
+ if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName))
+ {
+ BytesToCopy = min(Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION,
FileName));
+ RtlCopyMemory(Info->FileName, FileName->Name, BytesToCopy);
+ *Written += BytesToCopy;
- return(STATUS_SUCCESS);
+ if (BytesToCopy == Length)
+ {
+ Info->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION)
+
+ BytesToCopy);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ }
+
+ return Status;
}
@@ -98,14 +125,25 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
ULONGLONG MFTIndex,
PFILE_DIRECTORY_INFORMATION Info,
- ULONG BufferLength)
+ ULONG BufferLength,
+ PULONG Written,
+ BOOLEAN First)
{
ULONG Length;
+ NTSTATUS Status;
+ ULONG BytesToCopy = 0;
PFILENAME_ATTRIBUTE FileName;
PSTANDARD_INFORMATION StdInfo;
DPRINT("NtfsGetDirectoryInformation() called\n");
+ *Written = 0;
+ Status = STATUS_BUFFER_OVERFLOW;
+ if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > BufferLength)
+ {
+ return Status;
+ }
+
FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
if (FileName == NULL)
{
@@ -118,27 +156,40 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
ASSERT(StdInfo != NULL);
Length = FileName->NameLength * sizeof (WCHAR);
- if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
- return(STATUS_BUFFER_OVERFLOW);
+ if (First || (BufferLength >= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) +
Length))
+ {
+ Info->FileNameLength = Length;
- Info->FileNameLength = Length;
- Info->NextEntryOffset =
- ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
- RtlCopyMemory(Info->FileName, FileName->Name, Length);
+ *Written = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
+ Info->NextEntryOffset = 0;
+ if (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName))
+ {
+ BytesToCopy = min(Length, BufferLength -
FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName));
+ RtlCopyMemory(Info->FileName, FileName->Name, BytesToCopy);
+ *Written += BytesToCopy;
- Info->CreationTime.QuadPart = FileName->CreationTime;
- Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
- Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
- Info->ChangeTime.QuadPart = FileName->ChangeTime;
+ if (BytesToCopy == Length)
+ {
+ Info->NextEntryOffset =
ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
+ BytesToCopy);
+ Status = STATUS_SUCCESS;
+ }
+ }
- /* Convert file flags */
- NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute,
&Info->FileAttributes);
+ Info->CreationTime.QuadPart = FileName->CreationTime;
+ Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+ Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+ Info->ChangeTime.QuadPart = FileName->ChangeTime;
- Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"",
0, (PULONGLONG)&Info->AllocationSize.QuadPart);
+ /* Convert file flags */
+ NtfsFileFlagsToAttributes(FileName->FileAttributes |
StdInfo->FileAttribute, &Info->FileAttributes);
- Info->FileIndex = MFTIndex;
+ Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord,
L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
- return STATUS_SUCCESS;
+ Info->FileIndex = MFTIndex;
+ }
+
+ return Status;
}
@@ -147,14 +198,25 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
ULONGLONG MFTIndex,
PFILE_FULL_DIRECTORY_INFORMATION Info,
- ULONG BufferLength)
+ ULONG BufferLength,
+ PULONG Written,
+ BOOLEAN First)
{
ULONG Length;
+ NTSTATUS Status;
+ ULONG BytesToCopy = 0;
PFILENAME_ATTRIBUTE FileName;
PSTANDARD_INFORMATION StdInfo;
DPRINT("NtfsGetFullDirectoryInformation() called\n");
+ *Written = 0;
+ Status = STATUS_BUFFER_OVERFLOW;
+ if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > BufferLength)
+ {
+ return Status;
+ }
+
FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
if (FileName == NULL)
{
@@ -167,28 +229,41 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
ASSERT(StdInfo != NULL);
Length = FileName->NameLength * sizeof (WCHAR);
- if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
- return(STATUS_BUFFER_OVERFLOW);
+ if (First || (BufferLength >= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) +
Length))
+ {
+ Info->FileNameLength = Length;
- Info->FileNameLength = Length;
- Info->NextEntryOffset =
- ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
- RtlCopyMemory(Info->FileName, FileName->Name, Length);
+ *Written = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
+ Info->NextEntryOffset = 0;
+ if (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName))
+ {
+ BytesToCopy = min(Length, BufferLength -
FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName));
+ RtlCopyMemory(Info->FileName, FileName->Name, BytesToCopy);
+ *Written += BytesToCopy;
+
+ if (BytesToCopy == Length)
+ {
+ Info->NextEntryOffset =
ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
+ BytesToCopy);
+ Status = STATUS_SUCCESS;
+ }
+ }
- Info->CreationTime.QuadPart = FileName->CreationTime;
- Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
- Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
- Info->ChangeTime.QuadPart = FileName->ChangeTime;
+ Info->CreationTime.QuadPart = FileName->CreationTime;
+ Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+ Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+ Info->ChangeTime.QuadPart = FileName->ChangeTime;
- /* Convert file flags */
- NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute,
&Info->FileAttributes);
+ /* Convert file flags */
+ NtfsFileFlagsToAttributes(FileName->FileAttributes |
StdInfo->FileAttribute, &Info->FileAttributes);
- Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"",
0, (PULONGLONG)&Info->AllocationSize.QuadPart);
+ Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord,
L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
- Info->FileIndex = MFTIndex;
- Info->EaSize = 0;
+ Info->FileIndex = MFTIndex;
+ Info->EaSize = 0;
+ }
- return STATUS_SUCCESS;
+ return Status;
}
@@ -197,14 +272,25 @@ NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
ULONGLONG MFTIndex,
PFILE_BOTH_DIR_INFORMATION Info,
- ULONG BufferLength)
+ ULONG BufferLength,
+ PULONG Written,
+ BOOLEAN First)
{
ULONG Length;
+ NTSTATUS Status;
+ ULONG BytesToCopy = 0;
PFILENAME_ATTRIBUTE FileName, ShortFileName;
PSTANDARD_INFORMATION StdInfo;
DPRINT("NtfsGetBothDirectoryInformation() called\n");
+ *Written = 0;
+ Status = STATUS_BUFFER_OVERFLOW;
+ if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > BufferLength)
+ {
+ return Status;
+ }
+
FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
if (FileName == NULL)
{
@@ -218,41 +304,54 @@ NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
ASSERT(StdInfo != NULL);
Length = FileName->NameLength * sizeof (WCHAR);
- if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
- return(STATUS_BUFFER_OVERFLOW);
+ if (First || (BufferLength >= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) +
Length))
+ {
+ Info->FileNameLength = Length;
- Info->FileNameLength = Length;
- Info->NextEntryOffset =
- ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
- RtlCopyMemory(Info->FileName, FileName->Name, Length);
+ *Written = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
+ Info->NextEntryOffset = 0;
+ if (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName))
+ {
+ BytesToCopy = min(Length, BufferLength -
FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName));
+ RtlCopyMemory(Info->FileName, FileName->Name, BytesToCopy);
+ *Written += BytesToCopy;
- if (ShortFileName)
- {
- /* Should we upcase the filename? */
- ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
- Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
- RtlCopyMemory(Info->ShortName, ShortFileName->Name,
Info->ShortNameLength);
- }
- else
- {
- Info->ShortName[0] = 0;
- Info->ShortNameLength = 0;
- }
+ if (BytesToCopy == Length)
+ {
+ Info->NextEntryOffset =
ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
+ BytesToCopy);
+ Status = STATUS_SUCCESS;
+ }
+ }
+
+ if (ShortFileName)
+ {
+ /* Should we upcase the filename? */
+ ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
+ Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
+ RtlCopyMemory(Info->ShortName, ShortFileName->Name,
Info->ShortNameLength);
+ }
+ else
+ {
+ Info->ShortName[0] = 0;
+ Info->ShortNameLength = 0;
+ }
- Info->CreationTime.QuadPart = FileName->CreationTime;
- Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
- Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
- Info->ChangeTime.QuadPart = FileName->ChangeTime;
+ Info->CreationTime.QuadPart = FileName->CreationTime;
+ Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+ Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+ Info->ChangeTime.QuadPart = FileName->ChangeTime;
- /* Convert file flags */
- NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute,
&Info->FileAttributes);
+ /* Convert file flags */
+ NtfsFileFlagsToAttributes(FileName->FileAttributes |
StdInfo->FileAttribute, &Info->FileAttributes);
- Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"",
0, (PULONGLONG)&Info->AllocationSize.QuadPart);
+ Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord,
L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
- Info->FileIndex = MFTIndex;
- Info->EaSize = 0;
+ Info->FileIndex = MFTIndex;
+ Info->EaSize = 0;
+ }
- return STATUS_SUCCESS;
+ return Status;
}
@@ -277,6 +376,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
PFILE_RECORD_HEADER FileRecord;
ULONGLONG MFTRecord, OldMFTRecord = 0;
UNICODE_STRING Pattern;
+ ULONG Written;
DPRINT1("NtfsQueryDirectory() called\n");
@@ -350,7 +450,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
/* Determine directory index */
if (Stack->Flags & SL_INDEX_SPECIFIED)
{
- Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
+ Ccb->Entry = FileIndex;
}
else if (First || (Stack->Flags & SL_RESTART_SCAN))
{
@@ -369,6 +469,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
return STATUS_PENDING;
}
+ Written = 0;
while (Status == STATUS_SUCCESS && BufferLength > 0)
{
Status = NtfsFindFileAt(DeviceExtension,
@@ -400,7 +501,9 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
FileRecord,
MFTRecord,
(PFILE_NAMES_INFORMATION)Buffer,
- BufferLength);
+ BufferLength,
+ &Written,
+ Buffer0 == NULL);
break;
case FileDirectoryInformation:
@@ -408,7 +511,9 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
FileRecord,
MFTRecord,
(PFILE_DIRECTORY_INFORMATION)Buffer,
- BufferLength);
+ BufferLength,
+ &Written,
+ Buffer0 == NULL);
break;
case FileFullDirectoryInformation:
@@ -416,7 +521,9 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
FileRecord,
MFTRecord,
(PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
- BufferLength);
+ BufferLength,
+ &Written,
+ Buffer0 == NULL);
break;
case FileBothDirectoryInformation:
@@ -424,66 +531,57 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
FileRecord,
MFTRecord,
(PFILE_BOTH_DIR_INFORMATION)Buffer,
- BufferLength);
+ BufferLength,
+ &Written,
+ Buffer0 == NULL);
break;
default:
Status = STATUS_INVALID_INFO_CLASS;
}
- if (Status == STATUS_BUFFER_OVERFLOW)
+ if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
{
- if (Buffer0)
- {
- Buffer0->NextEntryOffset = 0;
- }
break;
}
}
else
{
- if (Buffer0)
- {
- Buffer0->NextEntryOffset = 0;
- }
-
- if (First)
- {
- Status = STATUS_NO_SUCH_FILE;
- }
- else
- {
- Status = STATUS_NO_MORE_FILES;
- }
+ Status = (First ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
break;
}
Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
Buffer0->FileIndex = FileIndex++;
Ccb->Entry++;
+ BufferLength -= Buffer0->NextEntryOffset;
+
+ ExFreeToNPagedLookasideList(&DeviceExtension->FileRecLookasideList,
FileRecord);
if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
{
break;
}
- BufferLength -= Buffer0->NextEntryOffset;
+
Buffer += Buffer0->NextEntryOffset;
- ExFreeToNPagedLookasideList(&DeviceExtension->FileRecLookasideList,
FileRecord);
}
if (Buffer0)
{
Buffer0->NextEntryOffset = 0;
+ Status = STATUS_SUCCESS;
+ IrpContext->Irp->IoStatus.Information =
Stack->Parameters.QueryDirectory.Length - BufferLength;
+ }
+ else
+ {
+ ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
+ ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
+ IrpContext->Irp->IoStatus.Information = Written;
}
ExReleaseResourceLite(&DeviceExtension->DirResource);
ExReleaseResourceLite(&Fcb->MainResource);
- if (FileIndex > 0)
- {
- Status = STATUS_SUCCESS;
- }
-
return Status;
}