From 24c84ca4b7cce1031314ea8284fe043a3513e26a Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Tue, 25 Jun 2002 22:23:06 +0000 Subject: [PATCH] Added NTFS driver stub. svn path=/trunk/; revision=3146 --- reactos/drivers/fs/ntfs/.cvsignore | 6 + reactos/drivers/fs/ntfs/blockdev.c | 255 +++++++++++ reactos/drivers/fs/ntfs/create.c | 243 ++++++++++ reactos/drivers/fs/ntfs/dirctl.c | 709 +++++++++++++++++++++++++++++ reactos/drivers/fs/ntfs/fcb.c | 674 +++++++++++++++++++++++++++ reactos/drivers/fs/ntfs/finfo.c | 268 +++++++++++ reactos/drivers/fs/ntfs/fsctl.c | 476 +++++++++++++++++++ reactos/drivers/fs/ntfs/makefile | 16 + reactos/drivers/fs/ntfs/ntfs.c | 106 +++++ reactos/drivers/fs/ntfs/ntfs.h | 295 ++++++++++++ reactos/drivers/fs/ntfs/ntfs.rc | 39 ++ reactos/drivers/fs/ntfs/volinfo.c | 242 ++++++++++ 12 files changed, 3329 insertions(+) create mode 100644 reactos/drivers/fs/ntfs/.cvsignore create mode 100644 reactos/drivers/fs/ntfs/blockdev.c create mode 100644 reactos/drivers/fs/ntfs/create.c create mode 100644 reactos/drivers/fs/ntfs/dirctl.c create mode 100644 reactos/drivers/fs/ntfs/fcb.c create mode 100644 reactos/drivers/fs/ntfs/finfo.c create mode 100644 reactos/drivers/fs/ntfs/fsctl.c create mode 100644 reactos/drivers/fs/ntfs/makefile create mode 100644 reactos/drivers/fs/ntfs/ntfs.c create mode 100644 reactos/drivers/fs/ntfs/ntfs.h create mode 100644 reactos/drivers/fs/ntfs/ntfs.rc create mode 100644 reactos/drivers/fs/ntfs/volinfo.c diff --git a/reactos/drivers/fs/ntfs/.cvsignore b/reactos/drivers/fs/ntfs/.cvsignore new file mode 100644 index 00000000000..56392de7463 --- /dev/null +++ b/reactos/drivers/fs/ntfs/.cvsignore @@ -0,0 +1,6 @@ +base.tmp +junk.tmp +temp.exp +ntfs.coff +ntfs.sys.unstripped +*.d \ No newline at end of file diff --git a/reactos/drivers/fs/ntfs/blockdev.c b/reactos/drivers/fs/ntfs/blockdev.c new file mode 100644 index 00000000000..72986ebbc28 --- /dev/null +++ b/reactos/drivers/fs/ntfs/blockdev.c @@ -0,0 +1,255 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: blockdev.c,v 1.1 2002/06/25 22:23:05 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/blockdev.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include "ntfs.h" + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS +NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject, + IN ULONG DiskSector, + IN ULONG SectorCount, + IN ULONG SectorSize, + IN OUT PUCHAR Buffer) +{ + IO_STATUS_BLOCK IoStatus; + LARGE_INTEGER Offset; + ULONG BlockSize; + KEVENT Event; + PIRP Irp; + NTSTATUS Status; + + KeInitializeEvent(&Event, + NotificationEvent, + FALSE); + + Offset.QuadPart = (LONGLONG)DiskSector * (LONGLONG)SectorSize; + BlockSize = SectorCount * SectorSize; + + DPRINT("NtfsReadSectors(DeviceObject %x, DiskSector %d, Buffer %x)\n", + DeviceObject, DiskSector, Buffer); + DPRINT("Offset %I64x BlockSize %ld\n", + Offset.QuadPart, + BlockSize); + + DPRINT("Building synchronous FSD Request...\n"); + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, + DeviceObject, + Buffer, + BlockSize, + &Offset, + &Event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildSynchronousFsdRequest failed\n"); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + DPRINT("Calling IO Driver... with irp %x\n", Irp); + Status = IoCallDriver(DeviceObject, Irp); + + DPRINT("Waiting for IO Operation for %x\n", Irp); + if (Status == STATUS_PENDING) + { + DPRINT("Operation pending\n"); + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + DPRINT("Getting IO Status... for %x\n", Irp); + Status = IoStatus.Status; + } + + if (!NT_SUCCESS(Status)) + { + if (Status == STATUS_VERIFY_REQUIRED) + { + PDEVICE_OBJECT DeviceToVerify; + NTSTATUS NewStatus; + + DPRINT1("STATUS_VERIFY_REQUIRED\n"); + DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread()); + IoSetDeviceToVerify(PsGetCurrentThread(), NULL); + + NewStatus = IoVerifyVolume(DeviceToVerify, FALSE); + DPRINT1("IoVerifyVolume() retuned (Status %lx)\n", NewStatus); + } + + DPRINT("NtfsReadSectors() failed (Status %x)\n", Status); + DPRINT("(DeviceObject %x, DiskSector %x, Buffer %x, Offset 0x%I64x)\n", + DeviceObject, DiskSector, Buffer, + Offset.QuadPart); + return(Status); + } + + DPRINT("Block request succeeded for %x\n", Irp); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +NtfsReadRawSectors(IN PDEVICE_OBJECT DeviceObject, + IN ULONG DiskSector, + IN ULONG SectorCount, + IN ULONG SectorSize, + IN OUT PUCHAR Buffer) +{ + PIO_STACK_LOCATION Stack; + IO_STATUS_BLOCK IoStatus; + LARGE_INTEGER Offset; + ULONG BlockSize; + KEVENT Event; + PIRP Irp; + NTSTATUS Status; + + KeInitializeEvent(&Event, + NotificationEvent, + FALSE); + + Offset.QuadPart = (LONGLONG)DiskSector * (LONGLONG)SectorSize; + BlockSize = SectorCount * SectorSize; + + DPRINT("NtfsReadSectors(DeviceObject %x, DiskSector %d, Buffer %x)\n", + DeviceObject, DiskSector, Buffer); + DPRINT("Offset %I64x BlockSize %ld\n", + Offset.QuadPart, + BlockSize); + + DPRINT("Building synchronous FSD Request...\n"); + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, + DeviceObject, + Buffer, + BlockSize, + &Offset, + &Event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildSynchronousFsdRequest failed\n"); + return(STATUS_INSUFFICIENT_RESOURCES); + } + +// Stack = IoGetCurrentIrpStackLocation(Irp); +// Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + + DPRINT("Calling IO Driver... with irp %x\n", Irp); + Status = IoCallDriver(DeviceObject, Irp); + + DPRINT("Waiting for IO Operation for %x\n", Irp); + if (Status == STATUS_PENDING) + { + DPRINT("Operation pending\n"); + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + DPRINT("Getting IO Status... for %x\n", Irp); + Status = IoStatus.Status; + } + + if (!NT_SUCCESS(Status)) + { + DPRINT("NtfsReadSectors() failed (Status %x)\n", Status); + DPRINT("(DeviceObject %x, DiskSector %x, Buffer %x, Offset 0x%I64x)\n", + DeviceObject, DiskSector, Buffer, + Offset.QuadPart); + return(Status); + } + + DPRINT("Block request succeeded for %x\n", Irp); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +NtfsDeviceIoControl(IN PDEVICE_OBJECT DeviceObject, + IN ULONG ControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + IN OUT PVOID OutputBuffer, + IN OUT PULONG OutputBufferSize) +{ + ULONG BufferSize = 0; + PKEVENT Event; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + if (OutputBufferSize != NULL) + { + BufferSize = *OutputBufferSize; + } + + Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); + if (Event == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + KeInitializeEvent(Event, NotificationEvent, FALSE); + + DPRINT("Building device I/O control request ...\n"); + Irp = IoBuildDeviceIoControlRequest(ControlCode, + DeviceObject, + InputBuffer, + InputBufferSize, + OutputBuffer, + BufferSize, + FALSE, + Event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildDeviceIoControlRequest() failed\n"); + ExFreePool(Event); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + DPRINT("Calling IO Driver... with irp %x\n", Irp); + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(Event, Suspended, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + if (OutputBufferSize) + { + *OutputBufferSize = BufferSize; + } + + ExFreePool(Event); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/create.c b/reactos/drivers/fs/ntfs/create.c new file mode 100644 index 00000000000..3d45e434d94 --- /dev/null +++ b/reactos/drivers/fs/ntfs/create.c @@ -0,0 +1,243 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: create.c,v 1.1 2002/06/25 22:23:05 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/create.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +//#define NDEBUG +#include + +#include "ntfs.h" + + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject, + PWSTR pRelativeFileName, + PWSTR *pAbsoluteFilename) +{ + PWSTR rcName; + PFCB Fcb; + PCCB Ccb; + + DPRINT("try related for %S\n", pRelativeFileName); + Ccb = pFileObject->FsContext2; + assert(Ccb); + Fcb = Ccb->Fcb; + assert(Fcb); + + /* verify related object is a directory and target name + don't start with \. */ + if (NtfsFCBIsDirectory(Fcb) == FALSE || + pRelativeFileName[0] == L'\\') + { + return(STATUS_INVALID_PARAMETER); + } + + /* construct absolute path name */ + assert(wcslen (Fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1 + <= MAX_PATH); + rcName = ExAllocatePool(NonPagedPool, MAX_PATH * sizeof(WCHAR)); + if (!rcName) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + wcscpy(rcName, Fcb->PathName); + if (!NtfsFCBIsRoot(Fcb)) + wcscat (rcName, L"\\"); + wcscat (rcName, pRelativeFileName); + *pAbsoluteFilename = rcName; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsOpenFile(PDEVICE_EXTENSION DeviceExt, + PFILE_OBJECT FileObject, + PWSTR FileName) +/* + * FUNCTION: Opens a file + */ +{ + PFCB ParentFcb; + PFCB Fcb; + NTSTATUS Status; + PWSTR AbsFileName = NULL; + + DPRINT("NtfsOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName); + + if (FileObject->RelatedFileObject) + { + DPRINT("Converting relative filename to absolute filename\n"); + + Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject, + FileName, + &AbsFileName); + FileName = AbsFileName; + if (!NT_SUCCESS(Status)) + { + return(Status); + } + return(STATUS_UNSUCCESSFUL); + } + + //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators) + + DPRINT("PathName to open: %S\n", FileName); + + /* try first to find an existing FCB in memory */ + DPRINT("Checking for existing FCB in memory\n"); + Fcb = NtfsGrabFCBFromTable(DeviceExt, + FileName); + if (Fcb == NULL) + { + DPRINT("No existing FCB found, making a new one if file exists.\n"); + Status = NtfsGetFCBForFile(DeviceExt, + &ParentFcb, + &Fcb, + FileName); + if (ParentFcb != NULL) + { + NtfsReleaseFCB(DeviceExt, + ParentFcb); + } + + if (!NT_SUCCESS (Status)) + { + DPRINT("Could not make a new FCB, status: %x\n", Status); + + if (AbsFileName) + ExFreePool(AbsFileName); + + return(Status); + } + } + + DPRINT("Attaching FCB to fileObject\n"); + Status = NtfsAttachFCBToFileObject(DeviceExt, + Fcb, + FileObject); + + if (AbsFileName) + ExFreePool (AbsFileName); + + return(Status); +} + + +static NTSTATUS +NtfsCreateFile(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: Opens a file + */ +{ + PDEVICE_EXTENSION DeviceExt; + PIO_STACK_LOCATION Stack; + PFILE_OBJECT FileObject; + ULONG RequestedDisposition; + ULONG RequestedOptions; + PFCB Fcb; +// PWSTR FileName; + NTSTATUS Status; + + DPRINT("NtfsCreateFile() called\n"); + + DeviceExt = DeviceObject->DeviceExtension; + assert (DeviceExt); + Stack = IoGetCurrentIrpStackLocation (Irp); + assert (Stack); + + RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); +// RequestedOptions = +// Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; +// PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; +// if ((RequestedOptions & FILE_DIRECTORY_FILE) +// && RequestedDisposition == FILE_SUPERSEDE) +// return STATUS_INVALID_PARAMETER; + + FileObject = Stack->FileObject; + + if (RequestedDisposition == FILE_CREATE || + RequestedDisposition == FILE_OVERWRITE_IF || + RequestedDisposition == FILE_SUPERSEDE) + { + return(STATUS_ACCESS_DENIED); + } + + Status = NtfsOpenFile(DeviceExt, + FileObject, + FileObject->FileName.Buffer); + + /* + * If the directory containing the file to open doesn't exist then + * fail immediately + */ + Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0; + Irp->IoStatus.Status = Status; + + return(Status); +} + + +NTSTATUS STDCALL +NtfsCreate(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PDEVICE_EXTENSION DeviceExt; + NTSTATUS Status; + + if (DeviceObject == NtfsGlobalData->DeviceObject) + { + /* DeviceObject represents FileSystem instead of logical volume */ + DPRINT("Opening file system\n"); + Irp->IoStatus.Information = FILE_OPENED; + Status = STATUS_SUCCESS; + goto ByeBye; + } + + DeviceExt = DeviceObject->DeviceExtension; + + ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, + TRUE); + Status = NtfsCreateFile(DeviceObject, + Irp); + ExReleaseResourceLite(&DeviceExt->DirResource); + +ByeBye: + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, + NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/dirctl.c b/reactos/drivers/fs/ntfs/dirctl.c new file mode 100644 index 00000000000..9db29eec1bd --- /dev/null +++ b/reactos/drivers/fs/ntfs/dirctl.c @@ -0,0 +1,709 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: dirctl.c,v 1.1 2002/06/25 22:23:05 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/dirctl.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +//#define NDEBUG +#include + +#include "ntfs.h" + + +/* FUNCTIONS ****************************************************************/ + +#if 0 +static NTSTATUS +CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt, + PVOID *Context, + PVOID *Block, + PLARGE_INTEGER StreamOffset, + ULONG DirLength, + PVOID *Ptr, + PWSTR Name, + PULONG pIndex, + PULONG pIndex2) +/* + * FUNCTION: Retrieves the file name, be it in short or long file name format + */ +{ + PDIR_RECORD Record; + NTSTATUS Status; + ULONG Index = 0; + ULONG Offset = 0; + ULONG BlockOffset = 0; + + Record = (PDIR_RECORD)*Block; + while(Index < *pIndex) + { + BlockOffset += Record->RecordLength; + Offset += Record->RecordLength; + + Record = (PDIR_RECORD)(*Block + BlockOffset); + if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) + { + DPRINT("Map next sector\n"); + CcUnpinData(*Context); + StreamOffset->QuadPart += BLOCKSIZE; + Offset = ROUND_UP(Offset, BLOCKSIZE); + BlockOffset = 0; + + if (!CcMapData(DeviceExt->StreamFileObject, + StreamOffset, + BLOCKSIZE, TRUE, + Context, Block)) + { + DPRINT("CcMapData() failed\n"); + return(STATUS_UNSUCCESSFUL); + } + Record = (PDIR_RECORD)(*Block + BlockOffset); + } + + if (Offset >= DirLength) + return(STATUS_NO_MORE_ENTRIES); + + Index++; + } + + DPRINT("Index %lu RecordLength %lu Offset %lu\n", + Index, Record->RecordLength, Offset); + + if (Record->FileIdLength == 1 && Record->FileId[0] == 0) + { + wcscpy(Name, L"."); + } + else if (Record->FileIdLength == 1 && Record->FileId[0] == 1) + { + wcscpy(Name, L".."); + } + else + { + if (DeviceExt->CdInfo.JolietLevel == 0) + { + ULONG i; + + for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++) + Name[i] = (WCHAR)Record->FileId[i]; + Name[i] = 0; + } + else + { + CdfsSwapString(Name, Record->FileId, Record->FileIdLength); + } + } + + DPRINT("Name '%S'\n", Name); + + *Ptr = Record; + + *pIndex = Index; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +CdfsFindFile(PDEVICE_EXTENSION DeviceExt, + PFCB Fcb, + PFCB Parent, + PWSTR FileToFind, + PULONG pDirIndex, + PULONG pDirIndex2) +/* + * FUNCTION: Find a file + */ +{ + WCHAR name[256]; + WCHAR TempStr[2]; + PVOID Block; + NTSTATUS Status; + ULONG len; + ULONG DirIndex; + ULONG Offset; + ULONG Read; + BOOLEAN IsRoot; + PVOID Context = NULL; + ULONG DirSize; + PUCHAR Ptr; + PDIR_RECORD Record; + LARGE_INTEGER StreamOffset; + + DPRINT("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", + Parent, FileToFind, pDirIndex ? *pDirIndex : 0); + DPRINT("FindFile: old Pathname %x, old Objectname %x)\n", + Fcb->PathName, Fcb->ObjectName); + + IsRoot = FALSE; + DirIndex = 0; + if (wcslen (FileToFind) == 0) + { + CHECKPOINT; + TempStr[0] = (WCHAR) '.'; + TempStr[1] = 0; + FileToFind = (PWSTR)&TempStr; + } + + if (Parent) + { + if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart) + { + IsRoot = TRUE; + } + } + else + { + IsRoot = TRUE; + } + + if (IsRoot == TRUE) + { + StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE; + DirSize = DeviceExt->CdInfo.RootSize; + + + if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0) + || (FileToFind[0] == '.' && FileToFind[1] == 0)) + { + /* it's root : complete essentials fields then return ok */ + RtlZeroMemory(Fcb, sizeof(FCB)); + + Fcb->PathName[0]='\\'; + Fcb->ObjectName = &Fcb->PathName[1]; + Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart; + Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize; + Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY; + + if (pDirIndex) + *pDirIndex = 0; + if (pDirIndex2) + *pDirIndex2 = 0; + DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName); + return (STATUS_SUCCESS); + } + } + else + { + StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; + DirSize = Parent->Entry.DataLengthL; + } + + DPRINT("StreamOffset %I64u DirSize %lu\n", StreamOffset.QuadPart, DirSize); + + if (pDirIndex && (*pDirIndex)) + DirIndex = *pDirIndex; + + if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, + BLOCKSIZE, TRUE, &Context, &Block)) + { + DPRINT("CcMapData() failed\n"); + return(STATUS_UNSUCCESSFUL); + } + + Ptr = (PUCHAR)Block; + while(TRUE) + { + Record = (PDIR_RECORD)Ptr; + if (Record->RecordLength == 0) + { + DPRINT1("Stopped!\n"); + break; + } + + DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", + Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); + + Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset, + DirSize, (PVOID*)&Ptr, name, &DirIndex, pDirIndex2); + if (Status == STATUS_NO_MORE_ENTRIES) + { + break; + } + else if (Status == STATUS_UNSUCCESSFUL) + { + /* Note: the directory cache has already been unpinned */ + return(Status); + } + + DPRINT("Name '%S'\n", name); + + if (wstrcmpjoki(name, FileToFind)) /* || wstrcmpjoki (name2, FileToFind)) */ + { + if (Parent && Parent->PathName) + { + len = wcslen(Parent->PathName); + memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR)); + Fcb->ObjectName=&Fcb->PathName[len]; + if (len != 1 || Fcb->PathName[0] != '\\') + { + Fcb->ObjectName[0] = '\\'; + Fcb->ObjectName = &Fcb->ObjectName[1]; + } + } + else + { + Fcb->ObjectName=Fcb->PathName; + Fcb->ObjectName[0]='\\'; + Fcb->ObjectName=&Fcb->ObjectName[1]; + } + + DPRINT("PathName '%S' ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName); + + memcpy(&Fcb->Entry, Ptr, sizeof(DIR_RECORD)); + wcsncpy(Fcb->ObjectName, name, MAX_PATH); + if (pDirIndex) + *pDirIndex = DirIndex; + + DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n", + Fcb->PathName, Fcb->ObjectName, DirIndex); + + CcUnpinData(Context); + + return(STATUS_SUCCESS); + } + + + Ptr = Ptr + Record->RecordLength; + DirIndex++; + + if (((ULONG)Ptr - (ULONG)Block) >= DirSize) + { + DPRINT("Stopped!\n"); + break; + } + } + + CcUnpinData(Context); + + if (pDirIndex) + *pDirIndex = DirIndex; + + return(STATUS_UNSUCCESSFUL); +} + + +static NTSTATUS +CdfsGetNameInformation(PFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PFILE_NAMES_INFORMATION Info, + ULONG BufferLength) +{ + ULONG Length; + + DPRINT("CdfsGetNameInformation() called\n"); + + Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR); + if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength) + return(STATUS_BUFFER_OVERFLOW); + + Info->FileNameLength = Length; + Info->NextEntryOffset = + ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4); + memcpy(Info->FileName, Fcb->ObjectName, Length); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +CdfsGetDirectoryInformation(PFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PFILE_DIRECTORY_INFORMATION Info, + ULONG BufferLength) +{ + ULONG Length; + + DPRINT("CdfsGetDirectoryInformation() called\n"); + + Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR); + if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength) + return(STATUS_BUFFER_OVERFLOW); + + Info->FileNameLength = Length; + Info->NextEntryOffset = + ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4); + memcpy(Info->FileName, Fcb->ObjectName, Length); + + /* Convert file times */ + CdfsDateTimeToFileTime(Fcb, + &Info->CreationTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastAccessTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastWriteTime); + CdfsDateTimeToFileTime(Fcb, + &Info->ChangeTime); + + /* Convert file flags */ + CdfsFileFlagsToAttributes(Fcb, + &Info->FileAttributes); + + Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL; + + /* Make AllocSize a rounded up multiple of the sector size */ + Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE); + +// Info->FileIndex=; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +CdfsGetFullDirectoryInformation(PFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PFILE_FULL_DIRECTORY_INFORMATION Info, + ULONG BufferLength) +{ + ULONG Length; + + DPRINT("CdfsGetFullDirectoryInformation() called\n"); + + Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR); + if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength) + return(STATUS_BUFFER_OVERFLOW); + + Info->FileNameLength = Length; + Info->NextEntryOffset = + ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4); + memcpy(Info->FileName, Fcb->ObjectName, Length); + + /* Convert file times */ + CdfsDateTimeToFileTime(Fcb, + &Info->CreationTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastAccessTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastWriteTime); + CdfsDateTimeToFileTime(Fcb, + &Info->ChangeTime); + + /* Convert file flags */ + CdfsFileFlagsToAttributes(Fcb, + &Info->FileAttributes); + + Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL; + + /* Make AllocSize a rounded up multiple of the sector size */ + Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE); + +// Info->FileIndex=; + Info->EaSize = 0; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +CdfsGetBothDirectoryInformation(PFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PFILE_BOTH_DIRECTORY_INFORMATION Info, + ULONG BufferLength) +{ + ULONG Length; + + DPRINT("CdfsGetBothDirectoryInformation() called\n"); + + Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR); + if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength) + return(STATUS_BUFFER_OVERFLOW); + + Info->FileNameLength = Length; + Info->NextEntryOffset = + ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4); + memcpy(Info->FileName, Fcb->ObjectName, Length); + + /* Convert file times */ + CdfsDateTimeToFileTime(Fcb, + &Info->CreationTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastAccessTime); + CdfsDateTimeToFileTime(Fcb, + &Info->LastWriteTime); + CdfsDateTimeToFileTime(Fcb, + &Info->ChangeTime); + + /* Convert file flags */ + CdfsFileFlagsToAttributes(Fcb, + &Info->FileAttributes); + + Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL; + + /* Make AllocSize a rounded up multiple of the sector size */ + Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE); + +// Info->FileIndex=; + Info->EaSize = 0; + + if (DeviceExt->CdInfo.JolietLevel == 0) + { + /* Standard ISO-9660 format */ + Info->ShortNameLength = Length; + memcpy(Info->ShortName, Fcb->ObjectName, Length); + } + else + { + /* Joliet extension */ + + /* FIXME: Copy or create a short file name */ + + Info->ShortName[0] = 0; + Info->ShortNameLength = 0; + } + + return(STATUS_SUCCESS); +} +#endif + +static NTSTATUS +NtfsQueryDirectory(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PDEVICE_EXTENSION DeviceExtension; + LONG BufferLength = 0; + PUNICODE_STRING SearchPattern = NULL; + FILE_INFORMATION_CLASS FileInformationClass; + ULONG FileIndex = 0; + PUCHAR Buffer = NULL; + PFILE_NAMES_INFORMATION Buffer0 = NULL; + PFCB Fcb; + PCCB Ccb; + FCB TempFcb; + BOOLEAN First = FALSE; + PIO_STACK_LOCATION Stack; + PFILE_OBJECT FileObject; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT1("NtfsQueryDirectory() called\n"); + + DeviceExtension = DeviceObject->DeviceExtension; + Stack = IoGetCurrentIrpStackLocation(Irp); + FileObject = Stack->FileObject; + + Ccb = (PCCB)FileObject->FsContext2; + Fcb = Ccb->Fcb; + + /* Obtain the callers parameters */ + BufferLength = Stack->Parameters.QueryDirectory.Length; + SearchPattern = Stack->Parameters.QueryDirectory.FileName; + FileInformationClass = + Stack->Parameters.QueryDirectory.FileInformationClass; + FileIndex = Stack->Parameters.QueryDirectory.FileIndex; + + + if (SearchPattern != NULL) + { + if (!Ccb->DirectorySearchPattern) + { + First = TRUE; + Ccb->DirectorySearchPattern = + ExAllocatePool(NonPagedPool, SearchPattern->Length + sizeof(WCHAR)); + if (!Ccb->DirectorySearchPattern) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + memcpy(Ccb->DirectorySearchPattern, + SearchPattern->Buffer, + SearchPattern->Length); + Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0; + } + } + else if (!Ccb->DirectorySearchPattern) + { + First = TRUE; + Ccb->DirectorySearchPattern = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR)); + if (!Ccb->DirectorySearchPattern) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + Ccb->DirectorySearchPattern[0] = L'*'; + Ccb->DirectorySearchPattern[1] = 0; + } + DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern); + + /* Determine directory index */ + if (Stack->Flags & SL_INDEX_SPECIFIED) + { + Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart; + } + else if (First || (Stack->Flags & SL_RESTART_SCAN)) + { + Ccb->Entry = 0; + } + + /* Determine Buffer for result */ + if (Irp->MdlAddress) + { + Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); + } + else + { + Buffer = Irp->UserBuffer; + } + DPRINT("Buffer=%x tofind=%S\n", Buffer, Ccb->DirectorySearchPattern); +#if 0 + TempFcb.ObjectName = TempFcb.PathName; + while (Status == STATUS_SUCCESS && BufferLength > 0) + { + Status = CdfsFindFile(DeviceExtension, + &TempFcb, + Fcb, + Ccb->DirectorySearchPattern, + &Ccb->Entry, + NULL); + DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry); + + if (NT_SUCCESS(Status)) + { + switch (FileInformationClass) + { + case FileNameInformation: + Status = CdfsGetNameInformation(&TempFcb, + DeviceExtension, + (PFILE_NAMES_INFORMATION)Buffer, + BufferLength); + break; + + case FileDirectoryInformation: + Status = CdfsGetDirectoryInformation(&TempFcb, + DeviceExtension, + (PFILE_DIRECTORY_INFORMATION)Buffer, + BufferLength); + break; + + case FileFullDirectoryInformation: + Status = CdfsGetFullDirectoryInformation(&TempFcb, + DeviceExtension, + (PFILE_FULL_DIRECTORY_INFORMATION)Buffer, + BufferLength); + break; + + case FileBothDirectoryInformation: + Status = NtfsGetBothDirectoryInformation(&TempFcb, + DeviceExtension, + (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer, + BufferLength); + break; + + default: + Status = STATUS_INVALID_INFO_CLASS; + } + + if (Status == STATUS_BUFFER_OVERFLOW) + { + 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; + } + break; + } + + Buffer0 = (PFILE_NAMES_INFORMATION)Buffer; + Buffer0->FileIndex = FileIndex++; + Ccb->Entry++; + + if (Stack->Flags & SL_RETURN_SINGLE_ENTRY) + { + break; + } + BufferLength -= Buffer0->NextEntryOffset; + Buffer += Buffer0->NextEntryOffset; + } +#endif + + if (Buffer0) + { + Buffer0->NextEntryOffset = 0; + } + + if (FileIndex > 0) + { + Status = STATUS_SUCCESS; + } + + return(Status); +} + + + +NTSTATUS STDCALL +NtfsDirectoryControl(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + NTSTATUS Status; + + DPRINT1("NtfsDirectoryControl() called\n"); + + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch (Stack->MinorFunction) + { + case IRP_MN_QUERY_DIRECTORY: + Status = NtfsQueryDirectory(DeviceObject, + Irp); + break; + + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + + default: + DPRINT1("NTFS: MinorFunction %d\n", Stack->MinorFunction); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/fcb.c b/reactos/drivers/fs/ntfs/fcb.c new file mode 100644 index 00000000000..26b6171ff65 --- /dev/null +++ b/reactos/drivers/fs/ntfs/fcb.c @@ -0,0 +1,674 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: fcb.c,v 1.1 2002/06/25 22:23:05 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/fcb.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include "ntfs.h" + + +/* MACROS *******************************************************************/ + +#define TAG_FCB TAG('I', 'F', 'C', 'B') + + + +/* FUNCTIONS ****************************************************************/ + +static PWCHAR +NtfsGetNextPathElement(PWCHAR FileName) +{ + if (*FileName == L'\0') + { + return(NULL); + } + + while (*FileName != L'\0' && *FileName != L'\\') + { + FileName++; + } + + return(FileName); +} + + +static VOID +NtfsWSubString(PWCHAR pTarget, const PWCHAR pSource, size_t pLength) +{ + wcsncpy (pTarget, pSource, pLength); + pTarget [pLength] = L'\0'; +} + + +PFCB +NtfsCreateFCB(PWSTR FileName) +{ + PFCB Fcb; + + Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB); + RtlZeroMemory(Fcb, sizeof(FCB)); + + if (FileName) + { + wcscpy(Fcb->PathName, FileName); + if (wcsrchr(Fcb->PathName, '\\') != 0) + { + Fcb->ObjectName = wcsrchr(Fcb->PathName, '\\'); + } + else + { + Fcb->ObjectName = Fcb->PathName; + } + } + + ExInitializeResourceLite(&Fcb->MainResource); + + return(Fcb); +} + + +VOID +NtfsDestroyFCB(PFCB Fcb) +{ + ExDeleteResourceLite(&Fcb->MainResource); + + ExFreePool(Fcb); +} + + +BOOLEAN +NtfsFCBIsDirectory(PFCB Fcb) +{ +// return(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY); +// return(Fcb->Entry.FileFlags & 0x02); + return(TRUE); +} + + +BOOLEAN +NtfsFCBIsRoot(PFCB Fcb) +{ + return(wcscmp(Fcb->PathName, L"\\") == 0); +} + + +VOID +NtfsGrabFCB(PDEVICE_EXTENSION Vcb, + PFCB Fcb) +{ + KIRQL oldIrql; + + DPRINT("grabbing FCB at %x: %S, refCount:%d\n", + Fcb, + Fcb->PathName, + Fcb->RefCount); + + KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql); + Fcb->RefCount++; + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); +} + + +VOID +NtfsReleaseFCB(PDEVICE_EXTENSION Vcb, + PFCB Fcb) +{ + KIRQL oldIrql; + + DPRINT("releasing FCB at %x: %S, refCount:%d\n", + Fcb, + Fcb->PathName, + Fcb->RefCount); + + KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql); + Fcb->RefCount--; + if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb)) + { + RemoveEntryList(&Fcb->FcbListEntry); + CcRosReleaseFileCache(NULL, Fcb->RFCB.Bcb); + NtfsDestroyFCB(Fcb); + } + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); +} + + +VOID +NtfsAddFCBToTable(PDEVICE_EXTENSION Vcb, + PFCB Fcb) +{ + KIRQL oldIrql; + + KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql); + Fcb->DevExt = Vcb; + InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry); + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); +} + + +PFCB +NtfsGrabFCBFromTable(PDEVICE_EXTENSION Vcb, + PWSTR FileName) +{ + KIRQL oldIrql; + PFCB Fcb; + PLIST_ENTRY current_entry; + + KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql); + + if (FileName == NULL || *FileName == 0) + { + DPRINT("Return FCB for stream file object\n"); + Fcb = ((PCCB)Vcb->StreamFileObject->FsContext2)->Fcb; + Fcb->RefCount++; + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); + return(Fcb); + } + + current_entry = Vcb->FcbListHead.Flink; + while (current_entry != &Vcb->FcbListHead) + { + Fcb = CONTAINING_RECORD(current_entry, FCB, FcbListEntry); + + DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName); + if (_wcsicmp(FileName, Fcb->PathName) == 0) + { + Fcb->RefCount++; + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); + return(Fcb); + } + + //FIXME: need to compare against short name in FCB here + + current_entry = current_entry->Flink; + } + KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); + + return(NULL); +} + + +NTSTATUS +NtfsFCBInitializeCache(PVCB Vcb, + PFCB Fcb) +{ + PFILE_OBJECT FileObject; + NTSTATUS Status; + PCCB newCCB; + + FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice); + + newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB); + if (newCCB == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(newCCB, + sizeof(CCB)); + + FileObject->Flags = FileObject->Flags | FO_FCB_IS_VALID | + FO_DIRECT_CACHE_PAGING_READ; + FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers; + FileObject->FsContext = (PVOID) &Fcb->RFCB; + FileObject->FsContext2 = newCCB; + newCCB->Fcb = Fcb; + newCCB->PtrFileObject = FileObject; + Fcb->FileObject = FileObject; + Fcb->DevExt = Vcb; + + Status = CcRosInitializeFileCache(FileObject, + &Fcb->RFCB.Bcb, + CACHEPAGESIZE(Vcb)); + if (!NT_SUCCESS(Status)) + { + DbgPrint("CcRosInitializeFileCache failed\n"); + KeBugCheck(0); + } + + ObDereferenceObject(FileObject); + Fcb->Flags |= FCB_CACHE_INITIALIZED; + + return(Status); +} + + +PFCB +NtfsMakeRootFCB(PDEVICE_EXTENSION Vcb) +{ + PFCB Fcb; + + Fcb = NtfsCreateFCB(L"\\"); + +// memset(Fcb->entry.Filename, ' ', 11); + +// Fcb->Entry.DataLengthL = Vcb->CdInfo.RootSize; +// Fcb->Entry.ExtentLocationL = Vcb->CdInfo.RootStart; +// Fcb->Entry.FileFlags = 0x02; // FILE_ATTRIBUTE_DIRECTORY; + Fcb->RefCount = 1; + Fcb->DirIndex = 0; + Fcb->RFCB.FileSize.QuadPart = PAGESIZE;//Vcb->CdInfo.RootSize; + Fcb->RFCB.ValidDataLength.QuadPart = PAGESIZE;//Vcb->CdInfo.RootSize; + Fcb->RFCB.AllocationSize.QuadPart = PAGESIZE;//Vcb->CdInfo.RootSize; + + NtfsFCBInitializeCache(Vcb, Fcb); + NtfsAddFCBToTable(Vcb, Fcb); + NtfsGrabFCB(Vcb, Fcb); + + return(Fcb); +} + + +PFCB +NtfsOpenRootFCB(PDEVICE_EXTENSION Vcb) +{ + PFCB Fcb; + + Fcb = NtfsGrabFCBFromTable(Vcb, L"\\"); + if (Fcb == NULL) + { + Fcb = NtfsMakeRootFCB(Vcb); + } + + return(Fcb); +} + + +#if 0 +static VOID +NtfsGetDirEntryName(PDEVICE_EXTENSION DeviceExt, + PDIR_RECORD Record, + PWSTR Name) +/* + * FUNCTION: Retrieves the file name, be it in short or long file name format + */ +{ + if (Record->FileIdLength == 1 && Record->FileId[0] == 0) + { + wcscpy(Name, L"."); + } + else if (Record->FileIdLength == 1 && Record->FileId[0] == 1) + { + wcscpy(Name, L".."); + } + else + { + if (DeviceExt->CdInfo.JolietLevel == 0) + { + ULONG i; + + for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++) + Name[i] = (WCHAR)Record->FileId[i]; + Name[i] = 0; + } + else + { + CdfsSwapString(Name, Record->FileId, Record->FileIdLength); + } + } + + DPRINT("Name '%S'\n", Name); +} + + +NTSTATUS +NtfsMakeFCBFromDirEntry(PVCB Vcb, + PFCB DirectoryFCB, + PWSTR Name, + PDIR_RECORD Record, + PFCB * fileFCB) +{ + WCHAR pathName[MAX_PATH]; + PFCB rcFCB; + ULONG Size; + + if (Name [0] != 0 && wcslen (DirectoryFCB->PathName) + + sizeof(WCHAR) + wcslen (Name) > MAX_PATH) + { + return(STATUS_OBJECT_NAME_INVALID); + } + + wcscpy(pathName, DirectoryFCB->PathName); + if (!CdfsFCBIsRoot(DirectoryFCB)) + { + wcscat(pathName, L"\\"); + } + + if (Name[0] != 0) + { + wcscat(pathName, Name); + } + else + { + WCHAR entryName[MAX_PATH]; + + CdfsGetDirEntryName(Vcb, Record, entryName); + wcscat(pathName, entryName); + } + + rcFCB = CdfsCreateFCB(pathName); + memcpy(&rcFCB->Entry, Record, sizeof(DIR_RECORD)); + + Size = rcFCB->Entry.DataLengthL; + + rcFCB->RFCB.FileSize.QuadPart = Size; + rcFCB->RFCB.ValidDataLength.QuadPart = Size; + rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, BLOCKSIZE); +// DPRINT1("%S %d %d\n", longName, Size, (ULONG)rcFCB->RFCB.AllocationSize.QuadPart); + CdfsFCBInitializeCache(Vcb, rcFCB); + rcFCB->RefCount++; + CdfsAddFCBToTable(Vcb, rcFCB); + *fileFCB = rcFCB; + + return(STATUS_SUCCESS); +} +#endif + + +NTSTATUS +NtfsAttachFCBToFileObject(PDEVICE_EXTENSION Vcb, + PFCB Fcb, + PFILE_OBJECT FileObject) +{ + NTSTATUS Status; + PCCB newCCB; + + newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), TAG_CCB); + if (newCCB == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + memset(newCCB, 0, sizeof(CCB)); + + FileObject->Flags = FileObject->Flags | FO_FCB_IS_VALID | + FO_DIRECT_CACHE_PAGING_READ; + FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers; + FileObject->FsContext = (PVOID)&Fcb->RFCB; + FileObject->FsContext2 = newCCB; + newCCB->Fcb = Fcb; + newCCB->PtrFileObject = FileObject; + Fcb->DevExt = Vcb; + + if (!(Fcb->Flags & FCB_CACHE_INITIALIZED)) + { + Status = CcRosInitializeFileCache(FileObject, + &Fcb->RFCB.Bcb, + CACHEPAGESIZE(Vcb)); + if (!NT_SUCCESS(Status)) + { + DbgPrint("CcRosInitializeFileCache failed\n"); + KeBugCheck(0); + } + Fcb->Flags |= FCB_CACHE_INITIALIZED; + } + + DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL); + + return(STATUS_SUCCESS); +} + + +#if 0 +NTSTATUS +NtfsDirFindFile(PDEVICE_EXTENSION DeviceExt, + PFCB DirectoryFcb, + PWSTR FileToFind, + PFCB *FoundFCB) +{ + WCHAR TempName[2]; + WCHAR Name[256]; + PVOID Block; + ULONG FirstSector; + ULONG DirSize; + PDIR_RECORD Record; + ULONG Offset; + ULONG BlockOffset; + NTSTATUS Status; + + LARGE_INTEGER StreamOffset; + PVOID Context; + + assert(DeviceExt); + assert(DirectoryFcb); + assert(FileToFind); + + DPRINT("CdfsDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n", + DeviceExt, + DirectoryFcb, + FileToFind); + DPRINT("Dir Path:%S\n", DirectoryFcb->PathName); + + /* default to '.' if no filename specified */ + if (wcslen(FileToFind) == 0) + { + TempName[0] = L'.'; + TempName[1] = 0; + FileToFind = TempName; + } + + DirSize = DirectoryFcb->Entry.DataLengthL; + StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; + + if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, + BLOCKSIZE, TRUE, &Context, &Block)) + { + DPRINT("CcMapData() failed\n"); + return(STATUS_UNSUCCESSFUL); + } + + Offset = 0; + BlockOffset = 0; + Record = (PDIR_RECORD)Block; + while(TRUE) + { + if (Record->RecordLength == 0) + { + DPRINT("RecordLength == 0 Stopped!\n"); + break; + } + + DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", + Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); + + CdfsGetDirEntryName(DeviceExt, Record, Name); + DPRINT("Name '%S'\n", Name); + + if (wstrcmpjoki(Name, FileToFind)) + { + DPRINT("Match found, %S\n", Name); + Status = CdfsMakeFCBFromDirEntry(DeviceExt, + DirectoryFcb, + Name, + Record, + FoundFCB); + + CcUnpinData(Context); + + return(Status); + } + + Offset += Record->RecordLength; + BlockOffset += Record->RecordLength; + Record = (PDIR_RECORD)(Block + BlockOffset); + if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) + { + DPRINT("Map next sector\n"); + CcUnpinData(Context); + StreamOffset.QuadPart += BLOCKSIZE; + Offset = ROUND_UP(Offset, BLOCKSIZE); + BlockOffset = 0; + + if (!CcMapData(DeviceExt->StreamFileObject, + &StreamOffset, + BLOCKSIZE, TRUE, + &Context, &Block)) + { + DPRINT("CcMapData() failed\n"); + return(STATUS_UNSUCCESSFUL); + } + Record = (PDIR_RECORD)(Block + BlockOffset); + } + + if (Offset >= DirSize) + break; + } + + CcUnpinData(Context); + + return(STATUS_OBJECT_NAME_NOT_FOUND); +} +#endif + +NTSTATUS +NtfsGetFCBForFile(PDEVICE_EXTENSION Vcb, + PFCB *pParentFCB, + PFCB *pFCB, + const PWSTR pFileName) +{ + NTSTATUS Status; + WCHAR pathName [MAX_PATH]; + WCHAR elementName [MAX_PATH]; + PWCHAR currentElement; + PFCB FCB; + PFCB parentFCB; + + DPRINT("NtfsGetFCBForFile(%x, %x, %x, '%S')\n", + Vcb, + pParentFCB, + pFCB, + pFileName); + + /* Dummy code */ + FCB = NtfsOpenRootFCB(Vcb); + *pFCB = FCB; + *pParentFCB = NULL; + +#if 0 + /* Trivial case, open of the root directory on volume */ + if (pFileName [0] == L'\0' || wcscmp(pFileName, L"\\") == 0) + { + DPRINT("returning root FCB\n"); + + FCB = NtfsOpenRootFCB(Vcb); + *pFCB = FCB; + *pParentFCB = NULL; + + return((FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND); + } + else + { + currentElement = pFileName + 1; + wcscpy (pathName, L"\\"); + FCB = CdfsOpenRootFCB (Vcb); + } + parentFCB = NULL; + + /* Parse filename and check each path element for existance and access */ + while (CdfsGetNextPathElement(currentElement) != 0) + { + /* Skip blank directory levels */ + if ((CdfsGetNextPathElement(currentElement) - currentElement) == 0) + { + currentElement++; + continue; + } + + DPRINT("Parsing, currentElement:%S\n", currentElement); + DPRINT(" parentFCB:%x FCB:%x\n", parentFCB, FCB); + + /* Descend to next directory level */ + if (parentFCB) + { + CdfsReleaseFCB(Vcb, parentFCB); + parentFCB = NULL; + } + + /* fail if element in FCB is not a directory */ + if (!CdfsFCBIsDirectory(FCB)) + { + DPRINT("Element in requested path is not a directory\n"); + + CdfsReleaseFCB(Vcb, FCB); + FCB = 0; + *pParentFCB = NULL; + *pFCB = NULL; + + return(STATUS_OBJECT_PATH_NOT_FOUND); + } + parentFCB = FCB; + + /* Extract next directory level into dirName */ + CdfsWSubString(pathName, + pFileName, + CdfsGetNextPathElement(currentElement) - pFileName); + DPRINT(" pathName:%S\n", pathName); + + FCB = CdfsGrabFCBFromTable(Vcb, pathName); + if (FCB == NULL) + { + CdfsWSubString(elementName, + currentElement, + CdfsGetNextPathElement(currentElement) - currentElement); + DPRINT(" elementName:%S\n", elementName); + + Status = CdfsDirFindFile(Vcb, parentFCB, elementName, &FCB); + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + *pParentFCB = parentFCB; + *pFCB = NULL; + currentElement = CdfsGetNextPathElement(currentElement); + if (*currentElement == L'\0' || CdfsGetNextPathElement(currentElement + 1) == 0) + { + return(STATUS_OBJECT_NAME_NOT_FOUND); + } + else + { + return(STATUS_OBJECT_PATH_NOT_FOUND); + } + } + else if (!NT_SUCCESS(Status)) + { + CdfsReleaseFCB(Vcb, parentFCB); + *pParentFCB = NULL; + *pFCB = NULL; + + return(Status); + } + } + currentElement = CdfsGetNextPathElement(currentElement); + } + + *pParentFCB = parentFCB; + *pFCB = FCB; +#endif + + return(STATUS_SUCCESS); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/finfo.c b/reactos/drivers/fs/ntfs/finfo.c new file mode 100644 index 00000000000..91e583513e3 --- /dev/null +++ b/reactos/drivers/fs/ntfs/finfo.c @@ -0,0 +1,268 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: finfo.c,v 1.1 2002/06/25 22:23:05 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/dirctl.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +//#define NDEBUG +#include + +#include "ntfs.h" + + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +NtfsGetStandardInformation(PFCB Fcb, + PDEVICE_OBJECT DeviceObject, + PFILE_STANDARD_INFORMATION StandardInfo, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the standard file information + */ +{ + DPRINT("NtfsGetStandardInformation() called\n"); + + if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + /* PRECONDITION */ + assert(StandardInfo != NULL); + assert(Fcb != NULL); + + RtlZeroMemory(StandardInfo, + sizeof(FILE_STANDARD_INFORMATION)); + + StandardInfo->AllocationSize = Fcb->RFCB.AllocationSize; + StandardInfo->EndOfFile = Fcb->RFCB.FileSize; + StandardInfo->NumberOfLinks = 0; + StandardInfo->DeletePending = FALSE; + StandardInfo->Directory = NtfsFCBIsDirectory(Fcb); + + *BufferLength -= sizeof(FILE_STANDARD_INFORMATION); + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetPositionInformation(PFILE_OBJECT FileObject, + PFILE_POSITION_INFORMATION PositionInfo, + PULONG BufferLength) +{ + DPRINT("NtfsGetPositionInformation() called\n"); + + if (*BufferLength < sizeof(FILE_POSITION_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + PositionInfo->CurrentByteOffset.QuadPart = + 0; +// FileObject->CurrentByteOffset.QuadPart; + + DPRINT("Getting position %I64x\n", + PositionInfo->CurrentByteOffset.QuadPart); + + *BufferLength -= sizeof(FILE_POSITION_INFORMATION); + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetBasicInformation(PFILE_OBJECT FileObject, + PFCB Fcb, + PDEVICE_OBJECT DeviceObject, + PFILE_BASIC_INFORMATION BasicInfo, + PULONG BufferLength) +{ + DPRINT("NtfsGetBasicInformation() called\n"); + + if (*BufferLength < sizeof(FILE_BASIC_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + +#if 0 + CdfsDateTimeToFileTime(Fcb, + &BasicInfo->CreationTime); + CdfsDateTimeToFileTime(Fcb, + &BasicInfo->LastAccessTime); + CdfsDateTimeToFileTime(Fcb, + &BasicInfo->LastWriteTime); + CdfsDateTimeToFileTime(Fcb, + &BasicInfo->ChangeTime); + + CdfsFileFlagsToAttributes(Fcb, + &BasicInfo->FileAttributes); +#endif + + *BufferLength -= sizeof(FILE_BASIC_INFORMATION); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetNameInformation(PFILE_OBJECT FileObject, + PFCB Fcb, + PDEVICE_OBJECT DeviceObject, + PFILE_NAME_INFORMATION NameInfo, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the file name information + */ +{ + ULONG NameLength; + + DPRINT("NtfsGetNameInformation() called\n"); + + assert(NameInfo != NULL); + assert(Fcb != NULL); + +// NameLength = wcslen(Fcb->PathName) * sizeof(WCHAR); + NameLength = 2; + if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength) + return(STATUS_BUFFER_OVERFLOW); + + NameInfo->FileNameLength = NameLength; +// memcpy(NameInfo->FileName, +// Fcb->PathName, +// NameLength + sizeof(WCHAR)); + wcscpy(NameInfo->FileName, L"\\"); + + *BufferLength -= + (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR)); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetInternalInformation(PFCB Fcb, + PFILE_INTERNAL_INFORMATION InternalInfo, + PULONG BufferLength) +{ + DPRINT("NtfsGetInternalInformation() called\n"); + + assert(InternalInfo); + assert(Fcb); + + if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + /* FIXME: get a real index, that can be used in a create operation */ + InternalInfo->IndexNumber.QuadPart = 0; + + *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION); + + return(STATUS_SUCCESS); +} + + +NTSTATUS STDCALL +NtfsQueryInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: Retrieve the specified file information + */ +{ + FILE_INFORMATION_CLASS FileInformationClass; + PIO_STACK_LOCATION Stack; + PFILE_OBJECT FileObject; + PFCB Fcb; + PVOID SystemBuffer; + ULONG BufferLength; + + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("NtfsQueryInformation() called\n"); + + Stack = IoGetCurrentIrpStackLocation(Irp); + FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; + FileObject = Stack->FileObject; + Fcb = FileObject->FsContext; + + SystemBuffer = Irp->AssociatedIrp.SystemBuffer; + BufferLength = Stack->Parameters.QueryFile.Length; + + switch (FileInformationClass) + { + case FileStandardInformation: + Status = NtfsGetStandardInformation(Fcb, + DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FilePositionInformation: + Status = NtfsGetPositionInformation(FileObject, + SystemBuffer, + &BufferLength); + break; + + case FileBasicInformation: + Status = NtfsGetBasicInformation(FileObject, + Fcb, + DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileNameInformation: + Status = NtfsGetNameInformation(FileObject, + Fcb, + DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileInternalInformation: + Status = NtfsGetInternalInformation(Fcb, + SystemBuffer, + &BufferLength); + break; + + case FileAlternateNameInformation: + case FileAllInformation: + Status = STATUS_NOT_IMPLEMENTED; + break; + + default: + DPRINT("Unimplemented information class %u\n", FileInformationClass); + Status = STATUS_NOT_SUPPORTED; + } + + Irp->IoStatus.Status = Status; + if (NT_SUCCESS(Status)) + Irp->IoStatus.Information = + Stack->Parameters.QueryFile.Length - BufferLength; + else + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/fsctl.c b/reactos/drivers/fs/ntfs/fsctl.c new file mode 100644 index 00000000000..2f4d63c434f --- /dev/null +++ b/reactos/drivers/fs/ntfs/fsctl.c @@ -0,0 +1,476 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: fsctl.c,v 1.1 2002/06/25 22:23:06 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/fsctl.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include "ntfs.h" + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount) +/* + * FUNCTION: Tests if the device contains a filesystem that can be mounted + * by this fsd + */ +{ + PARTITION_INFORMATION PartitionInfo; + DISK_GEOMETRY DiskGeometry; + ULONG Size; + PBOOT_SECTOR BootSector; + NTSTATUS Status; + + DPRINT("NtfsHasFileSystem() called\n"); + + Size = sizeof(DISK_GEOMETRY); + Status = NtfsDeviceIoControl(DeviceToMount, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status); + return(Status); + } + + if (DiskGeometry.MediaType == FixedMedia) + { + /* We have found a hard disk */ + Size = sizeof(PARTITION_INFORMATION); + Status = NtfsDeviceIoControl(DeviceToMount, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &PartitionInfo, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status); + return(Status); + } + + if (PartitionInfo.PartitionType != PARTITION_IFS) + { + return(STATUS_UNRECOGNIZED_VOLUME); + } + } + + DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); + BootSector = ExAllocatePool(NonPagedPool, + DiskGeometry.BytesPerSector); + if (BootSector == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + Status = NtfsReadRawSectors(DeviceToMount, + 0, + 1, + DiskGeometry.BytesPerSector, + (PVOID)BootSector); + if (NT_SUCCESS(Status)) + { + DPRINT("NTFS-identifier: [%.8s]\n", BootSector->OemName); + if (strncmp(BootSector->OemName, "NTFS ", 8) != 0) + { + Status = STATUS_UNRECOGNIZED_VOLUME; + } + } + + ExFreePool(BootSector); + + return(Status); +} + + +static NTSTATUS +NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject, + PDEVICE_EXTENSION Vcb) +{ + DISK_GEOMETRY DiskGeometry; + PUCHAR Buffer; + ULONG Size; + NTSTATUS Status; + PBOOT_SECTOR BootSector; + + DPRINT("NtfsGetVolumeData() called\n"); + + Size = sizeof(DISK_GEOMETRY); + Status = NtfsDeviceIoControl(DeviceObject, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status); + return(Status); + } + + DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector); + BootSector = ExAllocatePool(NonPagedPool, + DiskGeometry.BytesPerSector); + if (BootSector == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + Status = NtfsReadRawSectors(DeviceObject, + 0, /* Partition boot sector */ + 1, + DiskGeometry.BytesPerSector, + (PVOID)BootSector); + if (NT_SUCCESS(Status)) + { + /* Read data from the bootsector */ + Vcb->NtfsInfo.BytesPerSector = BootSector->BytesPerSector; + Vcb->NtfsInfo.SectorsPerCluster = BootSector->SectorsPerCluster; + Vcb->NtfsInfo.BytesPerCluster = BootSector->BytesPerSector * BootSector->SectorsPerCluster; + Vcb->NtfsInfo.SectorCount = BootSector->SectorCount; + + Vcb->NtfsInfo.MftStart = BootSector->MftLocation; + Vcb->NtfsInfo.MftMirrStart = BootSector->MftMirrLocation; + Vcb->NtfsInfo.SerialNumber = BootSector->SerialNumber; + +//#indef NDEBUG + DbgPrint("Boot sector information:\n"); + DbgPrint(" BytesPerSector: %hu\n", BootSector->BytesPerSector); + DbgPrint(" SectorsPerCluster: %hu\n", BootSector->SectorsPerCluster); + + DbgPrint(" SectorCount: %I64u\n", BootSector->SectorCount); + + DbgPrint(" MftStart: %I64u\n", BootSector->MftLocation); + DbgPrint(" MftMirrStart: %I64u\n", BootSector->MftMirrLocation); + + DbgPrint(" ClustersPerMftRecord: %lx\n", BootSector->ClustersPerMftRecord); + DbgPrint(" ClustersPerIndexRecord: %lx\n", BootSector->ClustersPerIndexRecord); + + DbgPrint(" SerialNumber: %I64x\n", BootSector->SerialNumber); +//#endif + } + + ExFreePool(Buffer); + + return(Status); +} + + + +static NTSTATUS +NtfsMountVolume(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PDEVICE_EXTENSION DeviceExt = NULL; + PDEVICE_OBJECT NewDeviceObject = NULL; + PDEVICE_OBJECT DeviceToMount; + PIO_STACK_LOCATION Stack; + PFCB Fcb = NULL; + PCCB Ccb = NULL; + PVPB Vpb; + NTSTATUS Status; + + DPRINT("NtfsMountVolume() called\n"); + + if (DeviceObject != NtfsGlobalData->DeviceObject) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + goto ByeBye; + } + + Stack = IoGetCurrentIrpStackLocation(Irp); + DeviceToMount = Stack->Parameters.MountVolume.DeviceObject; + Vpb = Stack->Parameters.MountVolume.Vpb; + + Status = NtfsHasFileSystem(DeviceToMount); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + Status = IoCreateDevice(NtfsGlobalData->DriverObject, + sizeof(DEVICE_EXTENSION), + NULL, + FILE_DEVICE_FILE_SYSTEM, +// FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &NewDeviceObject); + if (!NT_SUCCESS(Status)) + goto ByeBye; + + NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO; + DeviceExt = (PVOID)NewDeviceObject->DeviceExtension; + RtlZeroMemory(DeviceExt, + sizeof(DEVICE_EXTENSION)); + + Status = NtfsGetVolumeData(DeviceToMount, + DeviceExt); + if (!NT_SUCCESS(Status)) + goto ByeBye; + + NewDeviceObject->Vpb = DeviceToMount->Vpb; + + DeviceExt->StorageDevice = DeviceToMount; + DeviceExt->StorageDevice->Vpb->DeviceObject = NewDeviceObject; + DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice; + DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED; + NewDeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1; + NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL, + DeviceExt->StorageDevice); + + + Fcb = NtfsCreateFCB(NULL); + if (Fcb == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + + Ccb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(CCB), + TAG_CCB); + if (Ccb == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + RtlZeroMemory(Ccb, + sizeof(CCB)); + + DeviceExt->StreamFileObject->Flags = DeviceExt->StreamFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ; + DeviceExt->StreamFileObject->FsContext = (PVOID)&Fcb->RFCB; + DeviceExt->StreamFileObject->FsContext2 = Ccb; + DeviceExt->StreamFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers; + DeviceExt->StreamFileObject->PrivateCacheMap = NULL; + DeviceExt->StreamFileObject->Vpb = DeviceExt->Vpb; + Ccb->Fcb = Fcb; + Ccb->PtrFileObject = DeviceExt->StreamFileObject; + Fcb->FileObject = DeviceExt->StreamFileObject; + Fcb->DevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice; + + Fcb->Flags = FCB_IS_VOLUME_STREAM; + + Fcb->RFCB.FileSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector; + Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector; + Fcb->RFCB.AllocationSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector; /* Correct? */ + +// Fcb->Entry.ExtentLocationL = 0; +// Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE; + + Status = CcRosInitializeFileCache(DeviceExt->StreamFileObject, + &Fcb->RFCB.Bcb, + CACHEPAGESIZE(DeviceExt)); + if (!NT_SUCCESS (Status)) + { + DbgPrint("CcRosInitializeFileCache() failed (Status %lx)\n", Status); + goto ByeBye; + } + + ExInitializeResourceLite(&DeviceExt->DirResource); +// ExInitializeResourceLite(&DeviceExt->FatResource); + + KeInitializeSpinLock(&DeviceExt->FcbListLock); + InitializeListHead(&DeviceExt->FcbListHead); + + /* Read serial number */ + NewDeviceObject->Vpb->SerialNumber = DeviceExt->NtfsInfo.SerialNumber; + + /* Read volume label */ +// NtfsReadVolumeLabel(DeviceExt, +// NewDeviceObject->Vpb); + + Status = STATUS_SUCCESS; + +ByeBye: + if (!NT_SUCCESS(Status)) + { + /* Cleanup */ + if (DeviceExt && DeviceExt->StreamFileObject) + ObDereferenceObject(DeviceExt->StreamFileObject); + if (Fcb) + ExFreePool(Fcb); + if (Ccb) + ExFreePool(Ccb); + if (NewDeviceObject) + IoDeleteDevice(NewDeviceObject); + } + + DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status); + + return(Status); +} + + +static NTSTATUS +NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ +#if 0 + PDEVICE_OBJECT DeviceToVerify; + PIO_STACK_LOCATION Stack; + PUCHAR Buffer; + ULONG Sector; + ULONG i; + NTSTATUS Status; + + union + { + ULONG Value; + UCHAR Part[4]; + } Serial; +#endif + + DPRINT1("NtfsVerifyVolume() called\n"); + +#if 0 + Stack = IoGetCurrentIrpStackLocation(Irp); + DeviceToVerify = Stack->Parameters.VerifyVolume.DeviceObject; + + DPRINT("Device object %p Device to verify %p\n", DeviceObject, DeviceToVerify); + + Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION; + + Buffer = ExAllocatePool(NonPagedPool, + CDFS_BASIC_SECTOR); + if (Buffer == NULL) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + do + { + /* Read the Primary Volume Descriptor (PVD) */ + Status = CdfsReadRawSectors(DeviceToVerify, + Sector, + 1, + Buffer); + DPRINT("CdfsReadRawSectors() status %lx\n", Status); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + if (Buffer[0] == 1 && + Buffer[1] == 'C' && + Buffer[2] == 'D' && + Buffer[3] == '0' && + Buffer[4] == '0' && + Buffer[5] == '1') + { + break; + } + + Sector++; + } + while (Buffer[0] != 255); + + if (Buffer[0] == 255) + goto ByeBye; + + Status = STATUS_WRONG_VOLUME; + + /* Calculate the volume serial number */ + Serial.Value = 0; + for (i = 0; i < 2048; i += 4) + { + /* DON'T optimize this to ULONG!!! (breaks overflow) */ + Serial.Part[0] += Buffer[i+3]; + Serial.Part[1] += Buffer[i+2]; + Serial.Part[2] += Buffer[i+1]; + Serial.Part[3] += Buffer[i+0]; + } + + DPRINT("Current serial number %08lx Vpb serial number %08lx\n", + Serial.Value, DeviceToVerify->Vpb->SerialNumber); + + if (Serial.Value == DeviceToVerify->Vpb->SerialNumber) + Status = STATUS_SUCCESS; + +ByeBye: + ExFreePool(Buffer); + + DPRINT("CdfsVerifyVolume() done (Status: %lx)\n", Status); + + return(Status); +#endif + return(STATUS_UNSUCCESSFUL); +} + + +NTSTATUS STDCALL +NtfsFileSystemControl(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + NTSTATUS Status; + + DPRINT("NtfsFileSystemControl() called\n"); + + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch (Stack->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + DPRINT("NTFS: IRP_MN_USER_FS_REQUEST\n"); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + + case IRP_MN_MOUNT_VOLUME: + DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n"); + Status = NtfsMountVolume(DeviceObject, Irp); + break; + + case IRP_MN_VERIFY_VOLUME: + DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n"); + Status = NtfsVerifyVolume(DeviceObject, Irp); + break; + + default: + DPRINT("NTFS FSC: MinorFunction %d\n", Stack->MinorFunction); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/fs/ntfs/makefile b/reactos/drivers/fs/ntfs/makefile new file mode 100644 index 00000000000..70bf698e4fb --- /dev/null +++ b/reactos/drivers/fs/ntfs/makefile @@ -0,0 +1,16 @@ +# $Id: makefile,v 1.1 2002/06/25 22:23:06 ekohl Exp $ + +PATH_TO_TOP = ../../.. + +TARGET_TYPE = driver + +TARGET_NAME = ntfs + +TARGET_OBJECTS = $(TARGET_NAME).o blockdev.o create.o dirctl.o fcb.o finfo.o \ + fsctl.o volinfo.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/reactos/drivers/fs/ntfs/ntfs.c b/reactos/drivers/fs/ntfs/ntfs.c new file mode 100644 index 00000000000..6c2cb331f5f --- /dev/null +++ b/reactos/drivers/fs/ntfs/ntfs.c @@ -0,0 +1,106 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: ntfs.c,v 1.1 2002/06/25 22:23:06 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/ntfs.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include "ntfs.h" + + +/* GLOBALS *****************************************************************/ + +PNTFS_GLOBAL_DATA NtfsGlobalData; + + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS STDCALL +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +/* + * FUNCTION: Called by the system to initalize the driver + * ARGUMENTS: + * DriverObject = object describing this driver + * RegistryPath = path to our configuration entries + * RETURNS: Success or failure + */ +{ + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status; + UNICODE_STRING DeviceName; + + DPRINT("NTFS 0.0.1\n"); + + RtlInitUnicodeString(&DeviceName, + L"\\Ntfs"); + Status = IoCreateDevice(DriverObject, + sizeof(NTFS_GLOBAL_DATA), + &DeviceName, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + /* Initialize global data */ + NtfsGlobalData = DeviceObject->DeviceExtension; + RtlZeroMemory(NtfsGlobalData, + sizeof(NTFS_GLOBAL_DATA)); + NtfsGlobalData->DriverObject = DriverObject; + NtfsGlobalData->DeviceObject = DeviceObject; + + /* Initialize driver data */ + DeviceObject->Flags = DO_DIRECT_IO; +// DriverObject->MajorFunction[IRP_MJ_CLOSE] = NtfsClose; + DriverObject->MajorFunction[IRP_MJ_CREATE] = NtfsCreate; +// DriverObject->MajorFunction[IRP_MJ_READ] = NtfsRead; +// DriverObject->MajorFunction[IRP_MJ_WRITE] = NtfsWrite; + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = + NtfsFileSystemControl; + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = + NtfsDirectoryControl; + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = + NtfsQueryInformation; +// DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = +// NtfsQueryVolumeInformation; +// DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = +// NtfsSetVolumeInformation; + + DriverObject->DriverUnload = NULL; + + IoRegisterFileSystem(DeviceObject); + + return(STATUS_SUCCESS); +} + diff --git a/reactos/drivers/fs/ntfs/ntfs.h b/reactos/drivers/fs/ntfs/ntfs.h new file mode 100644 index 00000000000..8665c72f977 --- /dev/null +++ b/reactos/drivers/fs/ntfs/ntfs.h @@ -0,0 +1,295 @@ +#ifndef NTFS_H +#define NTFS_H + +#include + + +#define CACHEPAGESIZE(pDeviceExt) \ + ((pDeviceExt)->NtfsInfo.BytesPerCluster > PAGESIZE ? \ + (pDeviceExt)->NtfsInfo.BytesPerCluster : PAGESIZE) + +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) + +#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) + + +typedef struct _BOOT_SECTOR +{ + UCHAR Magic[3]; // 0x00 + UCHAR OemName[8]; // 0x03 + USHORT BytesPerSector; // 0x0B + UCHAR SectorsPerCluster; // 0x0D + UCHAR Unused0[7]; // 0x0E + UCHAR MediaId; // 0x15 + UCHAR Unused1[2]; // 0x16 + USHORT SectorsPerTrack; + USHORT Heads; + UCHAR Unused2[8]; + UCHAR Unknown0[4]; /* always 80 00 80 00 */ + ULONGLONG SectorCount; + ULONGLONG MftLocation; + ULONGLONG MftMirrLocation; + ULONG ClustersPerMftRecord; + ULONG ClustersPerIndexRecord; + ULONGLONG SerialNumber; // 0x48 + UCHAR BootCode[432]; // 0x50 +} __attribute__((packed)) BOOT_SECTOR, *PBOOT_SECTOR; + +//typedef struct _BootSector BootSector; + + + + + +typedef struct _NTFS_INFO +{ + ULONG BytesPerSector; + ULONG SectorsPerCluster; + ULONG BytesPerCluster; + ULONGLONG SectorCount; + ULONGLONG MftStart; + ULONGLONG MftMirrStart; + ULONGLONG SerialNumber; + +} NTFS_INFO, *PNTFS_INFO; + + +typedef struct +{ + ERESOURCE DirResource; +// ERESOURCE FatResource; + + KSPIN_LOCK FcbListLock; + LIST_ENTRY FcbListHead; + + PVPB Vpb; + PDEVICE_OBJECT StorageDevice; + PFILE_OBJECT StreamFileObject; + + NTFS_INFO NtfsInfo; + + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION, VCB, *PVCB; + + +#define FCB_CACHE_INITIALIZED 0x0001 +#define FCB_IS_VOLUME_STREAM 0x0002 +#define FCB_IS_VOLUME 0x0004 + +typedef struct _FCB +{ + REACTOS_COMMON_FCB_HEADER RFCB; + SECTION_OBJECT_POINTERS SectionObjectPointers; + + PFILE_OBJECT FileObject; + PDEVICE_EXTENSION DevExt; + + WCHAR *ObjectName; /* point on filename (250 chars max) in PathName */ + WCHAR PathName[MAX_PATH]; /* path+filename 260 max */ + + ERESOURCE PagingIoResource; + ERESOURCE MainResource; + + LIST_ENTRY FcbListEntry; + struct _FCB* ParentFcb; + + ULONG DirIndex; + + LONG RefCount; + ULONG Flags; + +// DIR_RECORD Entry; + + +} FCB, *PFCB; + + +typedef struct _CCB +{ + PFCB Fcb; + LIST_ENTRY NextCCB; + PFILE_OBJECT PtrFileObject; + LARGE_INTEGER CurrentByteOffset; + /* for DirectoryControl */ + ULONG Entry; + /* for DirectoryControl */ + PWCHAR DirectorySearchPattern; + ULONG LastCluster; + ULONG LastOffset; +} CCB, *PCCB; + +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) + +#define TAG_CCB TAG('I', 'C', 'C', 'B') + + + +typedef struct +{ + PDRIVER_OBJECT DriverObject; + PDEVICE_OBJECT DeviceObject; + ULONG Flags; +} NTFS_GLOBAL_DATA, *PNTFS_GLOBAL_DATA; + +extern PNTFS_GLOBAL_DATA NtfsGlobalData; + + + + +//int CdfsStrcmpi( wchar_t *str1, wchar_t *str2 ); +//void CdfsWstrcpy( wchar_t *str1, wchar_t *str2, int max ); + + +/* blockdev.c */ + +NTSTATUS +NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject, + IN ULONG DiskSector, + IN ULONG SectorCount, + IN ULONG SectorSize, + IN OUT PUCHAR Buffer); + +NTSTATUS +NtfsReadRawSectors(IN PDEVICE_OBJECT DeviceObject, + IN ULONG DiskSector, + IN ULONG SectorCount, + IN ULONG SectorSize, + IN OUT PUCHAR Buffer); + +NTSTATUS +NtfsDeviceIoControl(IN PDEVICE_OBJECT DeviceObject, + IN ULONG ControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + IN OUT PVOID OutputBuffer, + IN OUT PULONG OutputBufferSize); + +#if 0 +/* close.c */ + +NTSTATUS STDCALL +CdfsClose(PDEVICE_OBJECT DeviceObject, + PIRP Irp); +#endif + +/* create.c */ + +NTSTATUS STDCALL +NtfsCreate(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + + +/* dirctl.c */ + +NTSTATUS STDCALL +NtfsDirectoryControl(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + + +/* fcb.c */ + +PFCB +NtfsCreateFCB(PWCHAR FileName); + +VOID +NtfsDestroyFCB(PFCB Fcb); + +BOOLEAN +NtfsFCBIsDirectory(PFCB Fcb); + +BOOLEAN +NtfsFCBIsRoot(PFCB Fcb); + +VOID +NtfsGrabFCB(PDEVICE_EXTENSION Vcb, + PFCB Fcb); + +VOID +NtfsReleaseFCB(PDEVICE_EXTENSION Vcb, + PFCB Fcb); + +VOID +NtfsAddFCBToTable(PDEVICE_EXTENSION Vcb, + PFCB Fcb); + +PFCB +NtfsGrabFCBFromTable(PDEVICE_EXTENSION Vcb, + PWSTR FileName); + +NTSTATUS +NtfsFCBInitializeCache(PVCB Vcb, + PFCB Fcb); + +PFCB +NtfsMakeRootFCB(PDEVICE_EXTENSION Vcb); + +PFCB +NtfsOpenRootFCB(PDEVICE_EXTENSION Vcb); + +NTSTATUS +NtfsAttachFCBToFileObject(PDEVICE_EXTENSION Vcb, + PFCB Fcb, + PFILE_OBJECT FileObject); + +NTSTATUS +NtfsGetFCBForFile(PDEVICE_EXTENSION Vcb, + PFCB *pParentFCB, + PFCB *pFCB, + const PWSTR pFileName); + + +/* finfo.c */ + +NTSTATUS STDCALL +NtfsQueryInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + + +/* fsctl.c */ + +NTSTATUS STDCALL +NtfsFileSystemControl(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +#if 0 +/* misc.c */ + +BOOLEAN +wstrcmpjoki(PWSTR s1, PWSTR s2); + +VOID +CdfsSwapString(PWCHAR Out, + PUCHAR In, + ULONG Count); + +VOID +CdfsDateTimeToFileTime(PFCB Fcb, + TIME *FileTime); + +VOID +CdfsFileFlagsToAttributes(PFCB Fcb, + PULONG FileAttributes); + +/* rw.c */ + +NTSTATUS STDCALL +CdfsRead(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +NTSTATUS STDCALL +CdfsWrite(PDEVICE_OBJECT DeviceObject, + PIRP Irp); +#endif + + +/* volinfo.c */ + +NTSTATUS STDCALL +NtfsQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +NTSTATUS STDCALL +NtfsSetVolumeInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +#endif /* NTFS_H */ diff --git a/reactos/drivers/fs/ntfs/ntfs.rc b/reactos/drivers/fs/ntfs/ntfs.rc new file mode 100644 index 00000000000..ab52053d7d0 --- /dev/null +++ b/reactos/drivers/fs/ntfs/ntfs.rc @@ -0,0 +1,39 @@ + +#include +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD + PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", RES_STR_COMPANY_NAME + VALUE "FileDescription", "NTFS Driver\0" + VALUE "FileVersion", "0.0.1\0" + VALUE "InternalName", "ntfs\0" + VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "ntfs.sys\0" + VALUE "ProductName", RES_STR_PRODUCT_NAME + VALUE "ProductVersion", RES_STR_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/reactos/drivers/fs/ntfs/volinfo.c b/reactos/drivers/fs/ntfs/volinfo.c new file mode 100644 index 00000000000..9502fdbcca4 --- /dev/null +++ b/reactos/drivers/fs/ntfs/volinfo.c @@ -0,0 +1,242 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * 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 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: volinfo.c,v 1.1 2002/06/25 22:23:06 ekohl Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/fs/ntfs/volume.c + * PURPOSE: NTFS filesystem driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include "ntfs.h" + + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject, + PFILE_FS_VOLUME_INFORMATION FsVolumeInfo, + PULONG BufferLength) +{ + ULONG LabelLength; + + DPRINT("NtfsGetFsVolumeInformation() called\n"); + DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + + DPRINT("Vpb %p\n", DeviceObject->Vpb); + LabelLength = DeviceObject->Vpb->VolumeLabelLength; + + DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION) + LabelLength*sizeof(WCHAR))); + DPRINT("LabelLength %lu\n", LabelLength); + DPRINT("Label %S\n", DeviceObject->Vpb->VolumeLabel); + + if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION)) + return(STATUS_INFO_LENGTH_MISMATCH); + + if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + LabelLength*sizeof(WCHAR))) + return(STATUS_BUFFER_OVERFLOW); + + /* valid entries */ + FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber; + FsVolumeInfo->VolumeLabelLength = LabelLength * sizeof (WCHAR); + wcscpy(FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel); + + /* dummy entries */ + FsVolumeInfo->VolumeCreationTime.QuadPart = 0; + FsVolumeInfo->SupportsObjects = FALSE; + + *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + LabelLength * sizeof(WCHAR)); + + DPRINT("BufferLength %lu\n", *BufferLength); + DPRINT("NtfsGetFsVolumeInformation() done\n"); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt, + PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo, + PULONG BufferLength) +{ + DPRINT("NtfsGetFsAttributeInformation()\n"); + DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8)); + + if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION)) + return(STATUS_INFO_LENGTH_MISMATCH); + + if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8)) + return(STATUS_BUFFER_OVERFLOW); + + FsAttributeInfo->FileSystemAttributes = + FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK; + FsAttributeInfo->MaximumComponentNameLength = 255; + FsAttributeInfo->FileSystemNameLength = 8; + + memcpy(FsAttributeInfo->FileSystemName, L"NTFS", 8); + + DPRINT("Finished NtfsGetFsAttributeInformation()\n"); + + *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8); + DPRINT("BufferLength %lu\n", *BufferLength); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject, + PFILE_FS_SIZE_INFORMATION FsSizeInfo, + PULONG BufferLength) +{ + PDEVICE_EXTENSION DeviceExt; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("NtfsGetFsSizeInformation()\n"); + DPRINT("FsSizeInfo = %p\n", FsSizeInfo); + + if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + DeviceExt = DeviceObject->DeviceExtension; + + FsSizeInfo->AvailableAllocationUnits.QuadPart = 0; + FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.SectorCount; /* ?? */ + FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster; + FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector; + + DPRINT("Finished NtfsGetFsSizeInformation()\n"); + if (NT_SUCCESS(Status)) + *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION); + + return(Status); +} + + +static NTSTATUS +NtfsGetFsDeviceInformation(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo, + PULONG BufferLength) +{ + DPRINT("NtfsGetFsDeviceInformation()\n"); + DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION)); + + if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + FsDeviceInfo->DeviceType = FILE_DEVICE_DISK; + FsDeviceInfo->Characteristics = 0; /* FIXME: fix this !! */ + + DPRINT("NtfsGetFsDeviceInformation() finished.\n"); + + *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION); + DPRINT("BufferLength %lu\n", *BufferLength); + + return(STATUS_SUCCESS); +} + + + +NTSTATUS STDCALL +NtfsQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + FS_INFORMATION_CLASS FsInformationClass; + PIO_STACK_LOCATION Stack; + NTSTATUS Status = STATUS_SUCCESS; + PVOID SystemBuffer; + ULONG BufferLength; + + DPRINT("NtfsQueryVolumeInformation() called\n"); + + Stack = IoGetCurrentIrpStackLocation(Irp); + FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass; + BufferLength = Stack->Parameters.QueryVolume.Length; + SystemBuffer = Irp->AssociatedIrp.SystemBuffer; + + DPRINT("FsInformationClass %d\n", FsInformationClass); + DPRINT("SystemBuffer %x\n", SystemBuffer); + + switch (FsInformationClass) + { + case FileFsVolumeInformation: + Status = NtfsGetFsVolumeInformation(DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileFsAttributeInformation: + Status = NtfsGetFsAttributeInformation(DeviceObject->DeviceExtension, + SystemBuffer, + &BufferLength); + break; + + case FileFsSizeInformation: + Status = NtfsGetFsSizeInformation(DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileFsDeviceInformation: + Status = NtfsGetFsDeviceInformation(SystemBuffer, + &BufferLength); + break; + + default: + Status = STATUS_NOT_SUPPORTED; + } + + Irp->IoStatus.Status = Status; + if (NT_SUCCESS(Status)) + Irp->IoStatus.Information = + Stack->Parameters.QueryVolume.Length - BufferLength; + else + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(Status); +} + + +NTSTATUS STDCALL +NtfsSetVolumeInformation(PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + DPRINT("NtfsSetVolumeInformation() called\n"); + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(STATUS_NOT_SUPPORTED); +} + +/* EOF */