2002-06-25 22:23:06 +00:00
|
|
|
/*
|
|
|
|
* ReactOS kernel
|
2014-11-02 21:50:40 +00:00
|
|
|
* Copyright (C) 2002, 2014 ReactOS Team
|
2002-06-25 22:23:06 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2008-03-08 21:45:51 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-06-25 22:23:06 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
2008-02-10 11:20:29 +00:00
|
|
|
* FILE: drivers/filesystem/ntfs/fcb.c
|
2002-06-25 22:23:06 +00:00
|
|
|
* PURPOSE: NTFS filesystem driver
|
2014-11-02 21:50:40 +00:00
|
|
|
* PROGRAMMERS: Eric Kohl
|
|
|
|
* Pierre Schweitzer (pierre@reactos.org)
|
2014-11-02 22:56:38 +00:00
|
|
|
* Hervé Poussineau (hpoussin@reactos.org)
|
2002-06-25 22:23:06 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-01-28 20:55:50 +00:00
|
|
|
#include "ntfs.h"
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2004-06-05 08:28:37 +00:00
|
|
|
#define NDEBUG
|
2002-06-25 22:23:06 +00:00
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
2017-07-04 22:34:17 +00:00
|
|
|
PCWSTR
|
|
|
|
NtfsGetNextPathElement(PCWSTR FileName)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
if (*FileName == L'\0')
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
while (*FileName != L'\0' && *FileName != L'\\')
|
|
|
|
{
|
|
|
|
FileName++;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return FileName;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
|
|
|
VOID
|
|
|
|
NtfsWSubString(PWCHAR pTarget,
|
2017-07-04 22:34:17 +00:00
|
|
|
PCWSTR pSource,
|
2013-06-16 12:15:06 +00:00
|
|
|
size_t pLength)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
wcsncpy(pTarget, pSource, pLength);
|
|
|
|
pTarget[pLength] = L'\0';
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 08:51:47 +00:00
|
|
|
PNTFS_FCB
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsCreateFCB(PCWSTR FileName,
|
2015-06-28 13:14:07 +00:00
|
|
|
PCWSTR Stream,
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_VCB Vcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_FCB Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
ASSERT(Vcb);
|
|
|
|
ASSERT(Vcb->Identifier.Type == NTFS_TYPE_VCB);
|
2008-06-21 10:04:14 +00:00
|
|
|
|
2015-06-11 20:54:01 +00:00
|
|
|
Fcb = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->FcbLookasideList);
|
2022-11-14 22:28:33 +00:00
|
|
|
if (Fcb == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
RtlZeroMemory(Fcb, sizeof(NTFS_FCB));
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb->Identifier.Type = NTFS_TYPE_FCB;
|
|
|
|
Fcb->Identifier.Size = sizeof(NTFS_TYPE_FCB);
|
2008-03-15 09:47:00 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb->Vcb = Vcb;
|
|
|
|
|
|
|
|
if (FileName)
|
2008-03-15 09:25:09 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
wcscpy(Fcb->PathName, FileName);
|
|
|
|
if (wcsrchr(Fcb->PathName, '\\') != 0)
|
|
|
|
{
|
|
|
|
Fcb->ObjectName = wcsrchr(Fcb->PathName, '\\');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Fcb->ObjectName = Fcb->PathName;
|
|
|
|
}
|
2008-03-15 09:25:09 +00:00
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
if (Stream)
|
|
|
|
{
|
|
|
|
wcscpy(Fcb->Stream, Stream);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Fcb->Stream[0] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
ExInitializeResourceLite(&Fcb->MainResource);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb->RFCB.Resource = &(Fcb->MainResource);
|
|
|
|
|
|
|
|
return Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsDestroyFCB(PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
ASSERT(Fcb);
|
|
|
|
ASSERT(Fcb->Identifier.Type == NTFS_TYPE_FCB);
|
2008-06-21 11:20:48 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
ExDeleteResourceLite(&Fcb->MainResource);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2015-06-11 20:54:01 +00:00
|
|
|
ExFreeToNPagedLookasideList(&NtfsGlobalData->FcbLookasideList, Fcb);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsFCBIsDirectory(PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-10-08 19:45:33 +00:00
|
|
|
return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_DIRECTORY) == NTFS_FILE_TYPE_DIRECTORY);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-07 13:30:13 +00:00
|
|
|
BOOLEAN
|
|
|
|
NtfsFCBIsReparsePoint(PNTFS_FCB Fcb)
|
|
|
|
{
|
|
|
|
return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_REPARSE) == NTFS_FILE_TYPE_REPARSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-14 22:44:54 +00:00
|
|
|
BOOLEAN
|
|
|
|
NtfsFCBIsCompressed(PNTFS_FCB Fcb)
|
|
|
|
{
|
2021-06-11 12:29:21 +00:00
|
|
|
return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_COMPRESSED) == NTFS_FILE_TYPE_COMPRESSED);
|
2016-02-14 22:44:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-04 06:03:39 +00:00
|
|
|
BOOLEAN
|
|
|
|
NtfsFCBIsEncrypted(PNTFS_FCB Fcb)
|
|
|
|
{
|
|
|
|
return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_ENCRYPTED) == NTFS_FILE_TYPE_ENCRYPTED);
|
|
|
|
}
|
|
|
|
|
2002-06-25 22:23:06 +00:00
|
|
|
BOOLEAN
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsFCBIsRoot(PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
return (wcscmp(Fcb->PathName, L"\\") == 0);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsGrabFCB(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
KIRQL oldIrql;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DPRINT("grabbing FCB at %p: %S, refCount:%d\n",
|
|
|
|
Fcb,
|
|
|
|
Fcb->PathName,
|
|
|
|
Fcb->RefCount);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
|
|
Fcb->RefCount++;
|
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsReleaseFCB(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
KIRQL oldIrql;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DPRINT("releasing FCB at %p: %S, refCount:%d\n",
|
|
|
|
Fcb,
|
|
|
|
Fcb->PathName,
|
|
|
|
Fcb->RefCount);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
|
|
Fcb->RefCount--;
|
|
|
|
if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb))
|
|
|
|
{
|
|
|
|
RemoveEntryList(&Fcb->FcbListEntry);
|
2014-11-02 19:27:58 +00:00
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
2013-06-16 12:15:06 +00:00
|
|
|
CcUninitializeCacheMap(Fcb->FileObject, NULL, NULL);
|
|
|
|
NtfsDestroyFCB(Fcb);
|
|
|
|
}
|
2014-11-02 19:27:58 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsAddFCBToTable(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
KIRQL oldIrql;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
|
|
Fcb->Vcb = Vcb;
|
|
|
|
InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
|
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 08:51:47 +00:00
|
|
|
PNTFS_FCB
|
|
|
|
NtfsGrabFCBFromTable(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PCWSTR FileName)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
PNTFS_FCB Fcb;
|
|
|
|
PLIST_ENTRY current_entry;
|
2008-03-15 09:25:09 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
2008-03-15 09:25:09 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
if (FileName == NULL || *FileName == 0)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
DPRINT("Return FCB for stream file object\n");
|
|
|
|
Fcb = Vcb->StreamFileObject->FsContext;
|
|
|
|
Fcb->RefCount++;
|
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
|
|
return Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
current_entry = Vcb->FcbListHead.Flink;
|
|
|
|
while (current_entry != &Vcb->FcbListHead)
|
|
|
|
{
|
|
|
|
Fcb = CONTAINING_RECORD(current_entry, NTFS_FCB, FcbListEntry);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName);
|
2015-02-14 15:35:35 +00:00
|
|
|
if (_wcsicmp(FileName, Fcb->PathName) == 0)
|
2013-06-16 12:15:06 +00:00
|
|
|
{
|
|
|
|
Fcb->RefCount++;
|
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
|
|
return Fcb;
|
|
|
|
}
|
|
|
|
|
|
|
|
//FIXME: need to compare against short name in FCB here
|
|
|
|
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
|
|
|
|
|
|
return NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsFCBInitializeCache(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB Fcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PNTFS_CCB newCCB;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
|
|
|
|
if (newCCB == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
newCCB->Identifier.Type = NTFS_TYPE_CCB;
|
|
|
|
newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
|
2008-03-15 09:47:00 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
|
|
|
|
FileObject->FsContext = Fcb;
|
|
|
|
FileObject->FsContext2 = newCCB;
|
|
|
|
newCCB->PtrFileObject = FileObject;
|
|
|
|
Fcb->FileObject = FileObject;
|
|
|
|
Fcb->Vcb = Vcb;
|
2008-03-08 12:14:41 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Status = STATUS_SUCCESS;
|
2015-06-21 09:26:15 +00:00
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
CcInitializeCacheMap(FileObject,
|
|
|
|
(PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
|
|
|
|
FALSE,
|
|
|
|
&(NtfsGlobalData->CacheMgrCallbacks),
|
|
|
|
Fcb);
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
FileObject->FsContext2 = NULL;
|
|
|
|
ExFreePoolWithTag(newCCB, TAG_CCB);
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
Fcb->FileObject = NULL;
|
|
|
|
return _SEH2_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
2008-03-08 12:14:41 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
Fcb->Flags |= FCB_CACHE_INITIALIZED;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return Status;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 08:51:47 +00:00
|
|
|
PNTFS_FCB
|
|
|
|
NtfsMakeRootFCB(PNTFS_VCB Vcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_FCB Fcb;
|
2014-10-08 19:32:21 +00:00
|
|
|
PFILE_RECORD_HEADER MftRecord;
|
|
|
|
PFILENAME_ATTRIBUTE FileName;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2017-12-31 13:14:24 +00:00
|
|
|
MftRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
|
2014-10-08 19:32:21 +00:00
|
|
|
if (MftRecord == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
|
2014-10-08 19:32:21 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
[NTFS]
Totally rewrite the way MFT records attributes are handled.
Up to now, we were having really similar loops, only looking at the resident part of the attribute list, not really caring about how the loop was going.
This was leading to some issues:
- In case the attribute we were looking for was stored in the non-resident part of the attribute list, we would miss it (excepted in the case of FindAttribute() which was properly browsing the whole attribute list).
- In the specific case of FindAttribute(), one would have been able to setup a broken MFT record with the resident attribute list pointing on the non resident attribute list which itself would point to the resident attribute list. In such case, the driver would loop forever caught on the loop, allocating tones of memory. It was possible to trigger this by user space, from a non-privileged user, just by browsing the right directory entry.
- In the case of the other loops (non FindAttribute()), another issue (other than missing attributes) was present, one would have been able to setup a broken MFT record with an attribute of null-length. This would have caused the driver to loop forever on the attribute list. This could be triggered from usermode too. And could be triggered by a non-privileged user.
This commit introduces a new set of functions for attributes browsing: FindFirstAttribute(), FindNextAttribute(), FindCloseAttribute(). It allows safely browsing attributes and handles broken cases. It also performs reading of the attribute list when present and makes sure there's only one read. This method should be the only one to use to browse the attributes.
The whole NTFS code base has been converted to use this newly set of functions. This really simplifies the implementation of FindAttribute(), and prevent unsafe code duplication.
CORE-10037 #resolve #comment Fixed with r68829
svn path=/trunk/; revision=68829
2015-08-26 18:20:04 +00:00
|
|
|
FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
|
2014-10-08 19:32:21 +00:00
|
|
|
if (!FileName)
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
|
2014-10-08 19:32:21 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
|
2014-10-08 19:32:21 +00:00
|
|
|
if (!Fcb)
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
|
2014-10-08 19:32:21 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2014-10-08 19:32:21 +00:00
|
|
|
memcpy(&Fcb->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
|
|
|
|
Fcb->Entry.NameType = FileName->NameType;
|
|
|
|
Fcb->Entry.NameLength = 0;
|
|
|
|
Fcb->Entry.Name[0] = UNICODE_NULL;
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb->RefCount = 1;
|
|
|
|
Fcb->DirIndex = 0;
|
2014-10-08 19:32:21 +00:00
|
|
|
Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
|
|
|
|
Fcb->RFCB.ValidDataLength.QuadPart = FileName->DataSize;
|
|
|
|
Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
|
2014-09-26 17:49:05 +00:00
|
|
|
Fcb->MFTIndex = NTFS_FILE_ROOT;
|
2014-12-15 21:28:06 +00:00
|
|
|
Fcb->LinkCount = MftRecord->LinkCount;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsFCBInitializeCache(Vcb, Fcb);
|
|
|
|
NtfsAddFCBToTable(Vcb, Fcb);
|
|
|
|
NtfsGrabFCB(Vcb, Fcb);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, MftRecord);
|
2014-10-08 20:02:09 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 08:51:47 +00:00
|
|
|
PNTFS_FCB
|
|
|
|
NtfsOpenRootFCB(PNTFS_VCB Vcb)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_FCB Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb = NtfsGrabFCBFromTable(Vcb, L"\\");
|
|
|
|
if (Fcb == NULL)
|
|
|
|
{
|
|
|
|
Fcb = NtfsMakeRootFCB(Vcb);
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return Fcb;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2014-10-06 20:51:41 +00:00
|
|
|
NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
|
2015-06-28 13:14:07 +00:00
|
|
|
PNTFS_FCB DirectoryFCB,
|
|
|
|
PUNICODE_STRING Name,
|
|
|
|
PCWSTR Stream,
|
|
|
|
PFILE_RECORD_HEADER Record,
|
2014-10-08 19:12:48 +00:00
|
|
|
ULONGLONG MFTIndex,
|
2015-06-28 13:14:07 +00:00
|
|
|
PNTFS_FCB * fileFCB)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-10-08 19:12:48 +00:00
|
|
|
WCHAR pathName[MAX_PATH];
|
|
|
|
PFILENAME_ATTRIBUTE FileName;
|
2014-12-08 19:36:40 +00:00
|
|
|
PSTANDARD_INFORMATION StdInfo;
|
2014-10-08 19:12:48 +00:00
|
|
|
PNTFS_FCB rcFCB;
|
2015-07-05 19:04:05 +00:00
|
|
|
ULONGLONG Size, AllocatedSize;
|
2014-10-08 19:12:48 +00:00
|
|
|
|
2019-06-15 16:24:27 +00:00
|
|
|
DPRINT("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
[NTFS]
Totally rewrite the way MFT records attributes are handled.
Up to now, we were having really similar loops, only looking at the resident part of the attribute list, not really caring about how the loop was going.
This was leading to some issues:
- In case the attribute we were looking for was stored in the non-resident part of the attribute list, we would miss it (excepted in the case of FindAttribute() which was properly browsing the whole attribute list).
- In the specific case of FindAttribute(), one would have been able to setup a broken MFT record with the resident attribute list pointing on the non resident attribute list which itself would point to the resident attribute list. In such case, the driver would loop forever caught on the loop, allocating tones of memory. It was possible to trigger this by user space, from a non-privileged user, just by browsing the right directory entry.
- In the case of the other loops (non FindAttribute()), another issue (other than missing attributes) was present, one would have been able to setup a broken MFT record with an attribute of null-length. This would have caused the driver to loop forever on the attribute list. This could be triggered from usermode too. And could be triggered by a non-privileged user.
This commit introduces a new set of functions for attributes browsing: FindFirstAttribute(), FindNextAttribute(), FindCloseAttribute(). It allows safely browsing attributes and handles broken cases. It also performs reading of the attribute list when present and makes sure there's only one read. This method should be the only one to use to browse the attributes.
The whole NTFS code base has been converted to use this newly set of functions. This really simplifies the implementation of FindAttribute(), and prevent unsafe code duplication.
CORE-10037 #resolve #comment Fixed with r68829
svn path=/trunk/; revision=68829
2015-08-26 18:20:04 +00:00
|
|
|
FileName = GetBestFileNameFromRecord(Vcb, Record);
|
2014-10-08 19:12:48 +00:00
|
|
|
if (!FileName)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-10-08 19:12:48 +00:00
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2014-12-14 21:18:47 +00:00
|
|
|
if (DirectoryFCB && Name)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-12-14 21:18:47 +00:00
|
|
|
if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
|
|
|
|
sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2014-12-14 21:18:47 +00:00
|
|
|
wcscpy(pathName, DirectoryFCB->PathName);
|
|
|
|
if (!NtfsFCBIsRoot(DirectoryFCB))
|
|
|
|
{
|
|
|
|
wcscat(pathName, L"\\");
|
|
|
|
}
|
|
|
|
wcscat(pathName, Name->Buffer);
|
|
|
|
}
|
|
|
|
else
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-12-14 21:18:47 +00:00
|
|
|
RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
|
|
|
|
pathName[FileName->NameLength] = UNICODE_NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2015-09-04 15:37:15 +00:00
|
|
|
Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
|
2015-07-05 19:04:05 +00:00
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
|
2014-10-08 19:12:48 +00:00
|
|
|
if (!rcFCB)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 19:32:21 +00:00
|
|
|
memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
|
|
|
|
rcFCB->Entry.NameType = FileName->NameType;
|
2015-07-05 19:04:05 +00:00
|
|
|
rcFCB->RFCB.FileSize.QuadPart = Size;
|
|
|
|
rcFCB->RFCB.ValidDataLength.QuadPart = Size;
|
|
|
|
rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
[NTFS]
Totally rewrite the way MFT records attributes are handled.
Up to now, we were having really similar loops, only looking at the resident part of the attribute list, not really caring about how the loop was going.
This was leading to some issues:
- In case the attribute we were looking for was stored in the non-resident part of the attribute list, we would miss it (excepted in the case of FindAttribute() which was properly browsing the whole attribute list).
- In the specific case of FindAttribute(), one would have been able to setup a broken MFT record with the resident attribute list pointing on the non resident attribute list which itself would point to the resident attribute list. In such case, the driver would loop forever caught on the loop, allocating tones of memory. It was possible to trigger this by user space, from a non-privileged user, just by browsing the right directory entry.
- In the case of the other loops (non FindAttribute()), another issue (other than missing attributes) was present, one would have been able to setup a broken MFT record with an attribute of null-length. This would have caused the driver to loop forever on the attribute list. This could be triggered from usermode too. And could be triggered by a non-privileged user.
This commit introduces a new set of functions for attributes browsing: FindFirstAttribute(), FindNextAttribute(), FindCloseAttribute(). It allows safely browsing attributes and handles broken cases. It also performs reading of the attribute list when present and makes sure there's only one read. This method should be the only one to use to browse the attributes.
The whole NTFS code base has been converted to use this newly set of functions. This really simplifies the implementation of FindAttribute(), and prevent unsafe code duplication.
CORE-10037 #resolve #comment Fixed with r68829
svn path=/trunk/; revision=68829
2015-08-26 18:20:04 +00:00
|
|
|
StdInfo = GetStandardInformationFromRecord(Vcb, Record);
|
2014-12-08 19:36:40 +00:00
|
|
|
if (StdInfo != NULL)
|
|
|
|
{
|
|
|
|
rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
|
|
|
|
}
|
|
|
|
|
2014-10-08 19:12:48 +00:00
|
|
|
NtfsFCBInitializeCache(Vcb, rcFCB);
|
|
|
|
rcFCB->RefCount = 1;
|
|
|
|
rcFCB->MFTIndex = MFTIndex;
|
2014-12-15 21:28:06 +00:00
|
|
|
rcFCB->LinkCount = Record->LinkCount;
|
2014-10-08 19:12:48 +00:00
|
|
|
NtfsAddFCBToTable(Vcb, rcFCB);
|
|
|
|
*fileFCB = rcFCB;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2014-10-08 19:12:48 +00:00
|
|
|
return STATUS_SUCCESS;
|
2014-10-06 20:51:41 +00:00
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsAttachFCBToFileObject(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB Fcb,
|
|
|
|
PFILE_OBJECT FileObject)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_CCB newCCB;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
|
|
|
|
if (newCCB == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
2008-03-15 09:47:00 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
newCCB->Identifier.Type = NTFS_TYPE_CCB;
|
|
|
|
newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
|
|
|
|
FileObject->FsContext = Fcb;
|
|
|
|
FileObject->FsContext2 = newCCB;
|
|
|
|
newCCB->PtrFileObject = FileObject;
|
|
|
|
Fcb->Vcb = Vcb;
|
2008-03-08 12:14:41 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
if (!(Fcb->Flags & FCB_CACHE_INITIALIZED))
|
|
|
|
{
|
2015-06-21 09:26:15 +00:00
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
CcInitializeCacheMap(FileObject,
|
|
|
|
(PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
|
|
|
|
FALSE,
|
|
|
|
&(NtfsGlobalData->CacheMgrCallbacks),
|
|
|
|
Fcb);
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
FileObject->FsContext2 = NULL;
|
|
|
|
ExFreePoolWithTag(newCCB, TAG_CCB);
|
|
|
|
return _SEH2_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
Fcb->Flags |= FCB_CACHE_INITIALIZED;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
//DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-06 21:39:18 +00:00
|
|
|
static NTSTATUS
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsDirFindFile(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB DirectoryFcb,
|
|
|
|
PWSTR FileToFind,
|
2017-06-24 04:36:28 +00:00
|
|
|
BOOLEAN CaseSensitive,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB *FoundFCB)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-10-06 20:51:41 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONGLONG CurrentDir;
|
|
|
|
UNICODE_STRING File;
|
|
|
|
PFILE_RECORD_HEADER FileRecord;
|
2014-10-08 19:12:48 +00:00
|
|
|
ULONGLONG MFTIndex;
|
2015-08-24 09:52:30 +00:00
|
|
|
PWSTR Colon, OldColon;
|
2015-06-28 21:16:03 +00:00
|
|
|
PNTFS_ATTR_CONTEXT DataContext;
|
2015-06-28 13:14:07 +00:00
|
|
|
USHORT Length = 0;
|
2014-10-08 19:12:48 +00:00
|
|
|
|
2019-06-15 16:24:27 +00:00
|
|
|
DPRINT("NtfsDirFindFile(%p, %p, %S, %s, %p)\n",
|
|
|
|
Vcb,
|
|
|
|
DirectoryFcb,
|
|
|
|
FileToFind,
|
|
|
|
CaseSensitive ? "TRUE" : "FALSE",
|
|
|
|
FoundFCB);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2014-10-06 20:51:41 +00:00
|
|
|
*FoundFCB = NULL;
|
|
|
|
RtlInitUnicodeString(&File, FileToFind);
|
|
|
|
CurrentDir = DirectoryFcb->MFTIndex;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
Colon = wcsrchr(FileToFind, L':');
|
|
|
|
if (Colon != NULL)
|
|
|
|
{
|
|
|
|
Length = File.Length;
|
|
|
|
File.Length = (Colon - FileToFind) * sizeof(WCHAR);
|
|
|
|
|
2015-08-24 09:52:30 +00:00
|
|
|
if (_wcsicmp(Colon + 1, L"$DATA") == 0)
|
|
|
|
{
|
|
|
|
OldColon = Colon;
|
|
|
|
Colon[0] = UNICODE_NULL;
|
|
|
|
Colon = wcsrchr(FileToFind, L':');
|
|
|
|
if (Colon != NULL)
|
|
|
|
{
|
|
|
|
Length = File.Length;
|
|
|
|
File.Length = (Colon - FileToFind) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Colon = OldColon;
|
|
|
|
Colon[0] = L':';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
/* Skip colon */
|
|
|
|
++Colon;
|
|
|
|
DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon);
|
|
|
|
}
|
|
|
|
|
2017-06-25 02:38:15 +00:00
|
|
|
Status = NtfsLookupFileAt(Vcb, &File, CaseSensitive, &FileRecord, &MFTIndex, CurrentDir);
|
2014-10-06 20:51:41 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2014-10-06 20:51:41 +00:00
|
|
|
return Status;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
if (Length != 0)
|
|
|
|
{
|
|
|
|
File.Length = Length;
|
|
|
|
}
|
|
|
|
|
2015-06-28 21:16:03 +00:00
|
|
|
if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0)
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2015-06-28 21:16:03 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
else if (Colon != 0)
|
|
|
|
{
|
2016-06-22 21:20:50 +00:00
|
|
|
Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL);
|
2015-06-28 21:16:03 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
}
|
|
|
|
ReleaseAttributeContext(DataContext);
|
|
|
|
}
|
|
|
|
|
2015-06-28 13:14:07 +00:00
|
|
|
Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB);
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2014-10-06 20:51:41 +00:00
|
|
|
|
|
|
|
return Status;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
2003-07-17 13:31:39 +00:00
|
|
|
|
2002-06-25 22:23:06 +00:00
|
|
|
|
|
|
|
NTSTATUS
|
2008-03-15 08:51:47 +00:00
|
|
|
NtfsGetFCBForFile(PNTFS_VCB Vcb,
|
2008-03-15 09:25:09 +00:00
|
|
|
PNTFS_FCB *pParentFCB,
|
|
|
|
PNTFS_FCB *pFCB,
|
2017-07-04 22:34:17 +00:00
|
|
|
PCWSTR pFileName,
|
2017-06-24 04:36:28 +00:00
|
|
|
BOOLEAN CaseSensitive)
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
WCHAR pathName [MAX_PATH];
|
|
|
|
WCHAR elementName [MAX_PATH];
|
2017-07-04 22:34:17 +00:00
|
|
|
PCWSTR currentElement;
|
2013-06-16 12:15:06 +00:00
|
|
|
PNTFS_FCB FCB;
|
|
|
|
PNTFS_FCB parentFCB;
|
|
|
|
|
2017-06-24 04:36:28 +00:00
|
|
|
DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n",
|
2013-06-16 12:15:06 +00:00
|
|
|
Vcb,
|
|
|
|
pParentFCB,
|
|
|
|
pFCB,
|
2017-06-24 04:36:28 +00:00
|
|
|
pFileName,
|
|
|
|
CaseSensitive ? "TRUE" : "FALSE");
|
2013-06-16 12:15:06 +00:00
|
|
|
|
|
|
|
/* Dummy code */
|
2003-07-17 13:31:39 +00:00
|
|
|
// FCB = NtfsOpenRootFCB(Vcb);
|
|
|
|
// *pFCB = FCB;
|
|
|
|
// *pParentFCB = NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2003-07-17 13:31:39 +00:00
|
|
|
#if 1
|
2013-06-16 12:15:06 +00:00
|
|
|
/* Trivial case, open of the root directory on volume */
|
2017-07-05 22:10:22 +00:00
|
|
|
if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
|
2013-06-16 12:15:06 +00:00
|
|
|
{
|
|
|
|
DPRINT("returning root FCB\n");
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
FCB = NtfsOpenRootFCB(Vcb);
|
|
|
|
*pFCB = FCB;
|
|
|
|
*pParentFCB = NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
|
|
|
|
}
|
|
|
|
else
|
2002-06-25 22:23:06 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
currentElement = pFileName + 1;
|
|
|
|
wcscpy (pathName, L"\\");
|
|
|
|
FCB = NtfsOpenRootFCB (Vcb);
|
2008-03-15 09:25:09 +00:00
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
parentFCB = NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
/* Parse filename and check each path element for existence and access */
|
2013-06-16 12:15:06 +00:00
|
|
|
while (NtfsGetNextPathElement(currentElement) != 0)
|
2008-03-15 09:25:09 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
/* Skip blank directory levels */
|
|
|
|
if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
|
|
|
|
{
|
|
|
|
currentElement++;
|
|
|
|
continue;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DPRINT("Parsing, currentElement:%S\n", currentElement);
|
|
|
|
DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
/* Descend to next directory level */
|
|
|
|
if (parentFCB)
|
|
|
|
{
|
|
|
|
NtfsReleaseFCB(Vcb, parentFCB);
|
|
|
|
parentFCB = NULL;
|
|
|
|
}
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
/* fail if element in FCB is not a directory */
|
|
|
|
if (!NtfsFCBIsDirectory(FCB))
|
|
|
|
{
|
|
|
|
DPRINT("Element in requested path is not a directory\n");
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsReleaseFCB(Vcb, FCB);
|
|
|
|
FCB = 0;
|
|
|
|
*pParentFCB = NULL;
|
|
|
|
*pFCB = NULL;
|
2002-06-25 22:23:06 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
2008-03-15 09:25:09 +00:00
|
|
|
}
|
2013-06-16 12:15:06 +00:00
|
|
|
|
|
|
|
parentFCB = FCB;
|
|
|
|
|
|
|
|
/* Extract next directory level into dirName */
|
|
|
|
NtfsWSubString(pathName,
|
|
|
|
pFileName,
|
|
|
|
NtfsGetNextPathElement(currentElement) - pFileName);
|
|
|
|
DPRINT(" pathName:%S\n", pathName);
|
|
|
|
|
|
|
|
FCB = NtfsGrabFCBFromTable(Vcb, pathName);
|
|
|
|
if (FCB == NULL)
|
2008-03-15 09:25:09 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsWSubString(elementName,
|
|
|
|
currentElement,
|
|
|
|
NtfsGetNextPathElement(currentElement) - currentElement);
|
|
|
|
DPRINT(" elementName:%S\n", elementName);
|
|
|
|
|
2017-06-24 04:36:28 +00:00
|
|
|
Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB);
|
2013-06-16 12:15:06 +00:00
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
|
|
{
|
|
|
|
*pParentFCB = parentFCB;
|
|
|
|
*pFCB = NULL;
|
|
|
|
currentElement = NtfsGetNextPathElement(currentElement);
|
|
|
|
if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
NtfsReleaseFCB(Vcb, parentFCB);
|
|
|
|
*pParentFCB = NULL;
|
|
|
|
*pFCB = NULL;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
2008-03-15 09:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
currentElement = NtfsGetNextPathElement(currentElement);
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
*pParentFCB = parentFCB;
|
|
|
|
*pFCB = FCB;
|
2002-06-25 22:23:06 +00:00
|
|
|
#endif
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
return STATUS_SUCCESS;
|
2002-06-25 22:23:06 +00:00
|
|
|
}
|
|
|
|
|
2014-12-07 20:59:45 +00:00
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NtfsReadFCBAttribute(PNTFS_VCB Vcb,
|
|
|
|
PNTFS_FCB pFCB,
|
2021-06-11 12:29:21 +00:00
|
|
|
ULONG Type,
|
2014-12-07 20:59:45 +00:00
|
|
|
PCWSTR Name,
|
|
|
|
ULONG NameLength,
|
|
|
|
PVOID * Data)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_RECORD_HEADER FileRecord;
|
|
|
|
PNTFS_ATTR_CONTEXT AttrCtxt;
|
|
|
|
ULONGLONG AttrLength;
|
|
|
|
|
2017-12-31 13:14:24 +00:00
|
|
|
FileRecord = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList);
|
2014-12-07 20:59:45 +00:00
|
|
|
if (FileRecord == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
2014-12-08 19:51:55 +00:00
|
|
|
Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2016-06-22 21:20:50 +00:00
|
|
|
Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
|
2014-12-07 20:59:45 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2017-08-06 02:54:15 +00:00
|
|
|
AttrLength = AttributeDataLength(AttrCtxt->pRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
*Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
|
|
|
|
if (*Data == NULL)
|
|
|
|
{
|
|
|
|
ReleaseAttributeContext(AttrCtxt);
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
|
|
|
|
|
|
|
|
ReleaseAttributeContext(AttrCtxt);
|
2017-12-31 13:14:24 +00:00
|
|
|
ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, FileRecord);
|
2014-12-07 20:59:45 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-06-25 22:23:06 +00:00
|
|
|
/* EOF */
|