mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
Added basic iso-9660 file system driver. Thanks to Art Yerkes.
svn path=/trunk/; revision=2842
This commit is contained in:
parent
bb24d01a48
commit
c423031b39
9 changed files with 1127 additions and 1 deletions
|
@ -47,7 +47,7 @@ DEVICE_DRIVERS = vidport vga blue ide null floppy
|
|||
INPUT_DRIVERS = keyboard mouclass psaux
|
||||
|
||||
#FS_DRIVERS = vfat minix ext2 template
|
||||
FS_DRIVERS = vfat ms np
|
||||
FS_DRIVERS = vfat ms np cdfs
|
||||
|
||||
#NET_DRIVERS = ndis tdi tcpip tditest wshtcpip afd
|
||||
NET_DRIVERS = ndis tdi tcpip tditest wshtcpip afd
|
||||
|
|
|
@ -4,5 +4,6 @@ system32\drivers\class2.sys
|
|||
system32\drivers\disk.sys
|
||||
system32\drivers\cdrom.sys
|
||||
system32\drivers\vfatfs.sys
|
||||
system32\drivers\cdfs.sys
|
||||
system32\config\system.hiv
|
||||
*
|
||||
|
|
756
reactos/drivers/fs/cdfs/cdfs.c
Normal file
756
reactos/drivers/fs/cdfs/cdfs.c
Normal file
|
@ -0,0 +1,756 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: services/fs/cdfs/cdfs.c
|
||||
* PURPOSE: CDROM (ISO 9660) filesystem driver
|
||||
* PROGRAMMER: Art Yerkes
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
|
||||
//#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include "cdfs.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PDEVICE_OBJECT StorageDevice;
|
||||
PFILE_OBJECT StreamFileObject;
|
||||
struct _fcb_system *fss;
|
||||
|
||||
PFCB RootFcb;
|
||||
|
||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||||
|
||||
/* GLOBALS *****************************************************************/
|
||||
|
||||
static PDRIVER_OBJECT DriverObject;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
/* DIRECTORY FUNCTIONS ******************************************************/
|
||||
/* Hacked until working directory code... */
|
||||
|
||||
NTSTATUS
|
||||
FsdGetRootDirectoryData(PDEVICE_OBJECT DeviceObject,
|
||||
PFCB RootFcb)
|
||||
{
|
||||
PPVD Buffer;
|
||||
NTSTATUS Status;
|
||||
|
||||
Buffer = ExAllocatePool( NonPagedPool, CDFS_BASIC_SECTOR );
|
||||
if (Buffer == NULL)
|
||||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||||
|
||||
Status = CdfsReadSectors(DeviceObject,
|
||||
CDFS_PRIMARY_DESCRIPTOR_LOCATION,
|
||||
1,
|
||||
Buffer);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
RootFcb->extent_start = Buffer->RootDirRecord.ExtentLocationL;
|
||||
RootFcb->byte_count = Buffer->RootDirRecord.DataLengthL;
|
||||
|
||||
ExFreePool(Buffer);
|
||||
|
||||
DPRINT1("RootFcb->extent_start %lu\n", RootFcb->extent_start);
|
||||
DPRINT1("RootFcb->byte_count %lu\n", RootFcb->byte_count);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* HACK -- NEEDS FIXING */
|
||||
|
||||
int
|
||||
FsdExtractDirectoryEntry(PDEVICE_EXTENSION DeviceExt,
|
||||
FsdFcbEntry *parent,
|
||||
FsdFcbEntry *fill_in,
|
||||
int entry_to_get)
|
||||
{
|
||||
switch( entry_to_get )
|
||||
{
|
||||
case 0:
|
||||
wcscpy( fill_in->name, L"." );
|
||||
fill_in->extent_start = parent->extent_start;
|
||||
fill_in->byte_count = parent->byte_count;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
wcscpy( fill_in->name, L".." );
|
||||
fill_in->extent_start = parent->extent_start;
|
||||
fill_in->byte_count = parent->byte_count;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
wcscpy( fill_in->name, L"readme.txt" );
|
||||
fill_in->extent_start = 0x190;
|
||||
fill_in->byte_count = 0x800;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FsdFcbEntry *FsdSearchDirectoryAt( PDEVICE_EXTENSION DeviceExt,
|
||||
FsdFcbEntry *parent,
|
||||
wchar_t *look_for )
|
||||
{
|
||||
FsdFcbEntry *ent;
|
||||
int i;
|
||||
|
||||
ent = FsdCreateFcb( DeviceExt->fss, parent, look_for );
|
||||
if( ent )
|
||||
return ent;
|
||||
|
||||
for( i = 0; i < parent->byte_count; i++ ) {
|
||||
FsdFcbEntry new_ent;
|
||||
if( FsdExtractDirectoryEntry( DeviceExt, parent, &new_ent, i ) )
|
||||
return NULL;
|
||||
|
||||
if( !_wcsicmp( new_ent.name, look_for ) ) {
|
||||
ent->extent_start = new_ent.extent_start;
|
||||
ent->byte_count = new_ent.byte_count;
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
FsdDelete( ent );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FsdCloseFile(PDEVICE_EXTENSION DeviceExt,
|
||||
PFILE_OBJECT FileObject)
|
||||
/*
|
||||
* FUNCTION: Closes a file
|
||||
*/
|
||||
{
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
/* Should go into a basic library */
|
||||
PFCB
|
||||
FsdSearchDirectory(PDEVICE_EXTENSION DeviceExt,
|
||||
PFCB ParentFcb,
|
||||
PWSTR filename)
|
||||
{
|
||||
wchar_t *string_imed = NULL;
|
||||
wchar_t *string_end = NULL;
|
||||
FsdFcbEntry *this_elt = NULL;
|
||||
|
||||
DPRINT1("FsdSearchDirectory(%S) called\n", filename);
|
||||
|
||||
if (ParentFcb == NULL && *filename == 0)
|
||||
return(DeviceExt->RootFcb);
|
||||
|
||||
CHECKPOINT1;
|
||||
string_imed = ExAllocatePool(NonPagedPool,
|
||||
(wcslen( filename ) + 1) * sizeof( wchar_t ) );
|
||||
|
||||
if (string_imed == NULL)
|
||||
return NULL;
|
||||
|
||||
wcscpy( string_imed, filename );
|
||||
|
||||
|
||||
/* Chop off a component and try it */
|
||||
string_end = wcschr( string_imed, L'\\' );
|
||||
if (string_end != NULL)
|
||||
{
|
||||
*string_end = 0;
|
||||
string_end++;
|
||||
}
|
||||
CHECKPOINT1;
|
||||
|
||||
if (ParentFcb == NULL)
|
||||
this_elt = FsdGetFcbEntry(DeviceExt->fss, NULL, L"\\");
|
||||
else
|
||||
this_elt = FsdGetFcbEntry(DeviceExt->fss, ParentFcb, string_imed);
|
||||
DPRINT1("this_elt %p\n", this_elt);
|
||||
|
||||
if (this_elt)
|
||||
{
|
||||
ExFreePool( string_imed );
|
||||
CHECKPOINT1;
|
||||
return this_elt;
|
||||
}
|
||||
|
||||
CHECKPOINT1;
|
||||
this_elt = FsdSearchDirectoryAt( DeviceExt, ParentFcb, string_imed );
|
||||
CHECKPOINT1;
|
||||
|
||||
/* It's the end if we have nothing more to do */
|
||||
if (string_end != NULL)
|
||||
this_elt = FsdSearchDirectory( DeviceExt, this_elt, string_end );
|
||||
CHECKPOINT1;
|
||||
|
||||
ExFreePool( string_imed );
|
||||
|
||||
DPRINT1("FsdSearchDirectory() done");
|
||||
|
||||
return this_elt;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
FsdOpenFile(PDEVICE_EXTENSION DeviceExt,
|
||||
PFILE_OBJECT FileObject,
|
||||
PWSTR FileName)
|
||||
/*
|
||||
* FUNCTION: Opens a file
|
||||
*/
|
||||
{
|
||||
PFCB Fcb;
|
||||
|
||||
DPRINT1("FsdOpenFile(FileName %S) called\n", FileName);
|
||||
|
||||
/* Just skip leading backslashes... */
|
||||
while (*FileName == L'\\')
|
||||
FileName++;
|
||||
CHECKPOINT1;
|
||||
|
||||
Fcb = FsdSearchDirectory(DeviceExt->fss,
|
||||
NULL,
|
||||
FileName);
|
||||
CHECKPOINT1;
|
||||
if (Fcb == NULL)
|
||||
{
|
||||
DPRINT1("FsdSearchDirectory() failed\n");
|
||||
return(STATUS_OBJECT_PATH_NOT_FOUND);
|
||||
}
|
||||
CHECKPOINT1;
|
||||
|
||||
FileObject->Flags = FileObject->Flags | FO_FCB_IS_VALID |
|
||||
FO_DIRECT_CACHE_PAGING_READ;
|
||||
FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
|
||||
FileObject->FsContext = Fcb;
|
||||
FileObject->FsContext2 = DeviceExt->fss;
|
||||
|
||||
DPRINT1("FsdOpenFile() done\n");
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
|
||||
/*
|
||||
* FUNCTION: Tests if the device contains a filesystem that can be mounted
|
||||
* by this fsd
|
||||
*/
|
||||
{
|
||||
PUCHAR bytebuf; // [CDFS_BASIC_SECTOR];
|
||||
NTSTATUS readstatus;
|
||||
int ret;
|
||||
|
||||
bytebuf = ExAllocatePool( NonPagedPool, CDFS_BASIC_SECTOR );
|
||||
if( !bytebuf ) return FALSE;
|
||||
|
||||
DPRINT1( "CDFS: Checking on mount of device %08x\n", DeviceToMount );
|
||||
|
||||
readstatus = CdfsReadSectors(DeviceToMount,
|
||||
CDFS_PRIMARY_DESCRIPTOR_LOCATION,
|
||||
1,
|
||||
bytebuf);
|
||||
bytebuf[6] = 0;
|
||||
DPRINT1( "CD-identifier: [%.5s]\n", bytebuf + 1 );
|
||||
|
||||
ret =
|
||||
readstatus == STATUS_SUCCESS &&
|
||||
bytebuf[0] == 1 &&
|
||||
bytebuf[1] == 'C' &&
|
||||
bytebuf[2] == 'D' &&
|
||||
bytebuf[3] == '0' &&
|
||||
bytebuf[4] == '0' &&
|
||||
bytebuf[5] == '1';
|
||||
|
||||
ExFreePool( bytebuf );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
|
||||
PDEVICE_OBJECT DeviceToMount)
|
||||
/*
|
||||
* FUNCTION: Mounts the device
|
||||
*/
|
||||
{
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
FsdReadFile(PDEVICE_EXTENSION DeviceExt,
|
||||
PFILE_OBJECT FileObject,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
ULONG Offset)
|
||||
/*
|
||||
* FUNCTION: Reads data from a file
|
||||
*/
|
||||
{
|
||||
PUCHAR bytebuf; // [CDFS_BASIC_SECTOR];
|
||||
NTSTATUS Status;
|
||||
int ret;
|
||||
int sofar = 0;
|
||||
FsdFcbEntry *ffe = FileObject->FsContext;
|
||||
|
||||
if( Length ) return STATUS_SUCCESS;
|
||||
|
||||
bytebuf = ExAllocatePool( NonPagedPool, CDFS_BASIC_SECTOR );
|
||||
if (!bytebuf)
|
||||
return FALSE;
|
||||
|
||||
if (Offset + Length > ffe->byte_count)
|
||||
Length = ffe->byte_count - Offset;
|
||||
|
||||
DPRINT1( "Reading %d bytes at %d\n", Offset, Length );
|
||||
|
||||
if( Length == 0 ) return STATUS_UNSUCCESSFUL;
|
||||
|
||||
while( sofar < Length )
|
||||
{
|
||||
int remains = 0;
|
||||
|
||||
Status = CdfsReadSectors(DeviceExt->StorageDevice,
|
||||
ffe->extent_start + (sofar >> 11),
|
||||
1,
|
||||
bytebuf);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool( bytebuf );
|
||||
return(Status);
|
||||
}
|
||||
|
||||
remains = Length - sofar;
|
||||
if (remains > BLOCKSIZE)
|
||||
remains = BLOCKSIZE;
|
||||
|
||||
memcpy( ((char *)Buffer) + sofar, bytebuf, remains );
|
||||
sofar += remains;
|
||||
}
|
||||
|
||||
ExFreePool( bytebuf );
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdClose(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = Stack->FileObject;
|
||||
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1( "Closing\n" );
|
||||
|
||||
Status = FsdCloseFile(DeviceExtension,FileObject);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdCreate(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = Stack->FileObject;
|
||||
NTSTATUS Status;
|
||||
PDEVICE_EXTENSION DeviceExt;
|
||||
|
||||
DeviceExt = DeviceObject->DeviceExtension;
|
||||
Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
if (Status == STATUS_SUCCESS)
|
||||
Irp->IoStatus.Information = FILE_OPENED;
|
||||
else
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdWrite(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
|
||||
|
||||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||||
Irp->IoStatus.Information = 0;
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdRead(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
ULONG Length;
|
||||
PVOID Buffer;
|
||||
ULONG Offset;
|
||||
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = Stack->FileObject;
|
||||
PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
|
||||
|
||||
Length = Stack->Parameters.Read.Length;
|
||||
Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
||||
Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
|
||||
|
||||
Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
Irp->IoStatus.Information = Length;
|
||||
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
// XXX The VPB in devicetomount may be null for some reason...
|
||||
NTSTATUS
|
||||
FsdMountVolume(PIRP Irp)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject = NULL;
|
||||
PDEVICE_OBJECT DeviceToMount;
|
||||
PDEVICE_EXTENSION DeviceExt = NULL;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1("FsdMountVolume() called\n");
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
|
||||
|
||||
if (FsdHasFileSystem(DeviceToMount) == FALSE)
|
||||
return(STATUS_UNRECOGNIZED_VOLUME);
|
||||
|
||||
Status = IoCreateDevice(DriverObject,
|
||||
sizeof(DEVICE_EXTENSION),
|
||||
NULL,
|
||||
FILE_DEVICE_CD_ROM_FILE_SYSTEM,
|
||||
0,
|
||||
FALSE,
|
||||
&DeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return(Status);
|
||||
|
||||
DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
|
||||
DeviceExt = (PVOID)DeviceObject->DeviceExtension;
|
||||
RtlZeroMemory(DeviceExt,sizeof(DEVICE_EXTENSION));
|
||||
|
||||
DeviceExt->fss = FsdFcbInit();
|
||||
if (!DeviceExt->fss)
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
|
||||
DeviceExt->RootFcb = FsdCreateFcb(DeviceExt->fss, NULL, L"\\");
|
||||
Status = FsdGetRootDirectoryData(DeviceToMount, DeviceExt->RootFcb);
|
||||
|
||||
DeviceObject->Vpb = DeviceToMount->Vpb;
|
||||
if (DeviceObject->Vpb != NULL)
|
||||
DeviceObject->Vpb->Flags |= VPB_MOUNTED;
|
||||
|
||||
#if 0
|
||||
Status = FsdMountDevice(DeviceExt,
|
||||
DeviceToMount);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return(Status);
|
||||
#endif
|
||||
|
||||
DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
|
||||
DeviceToMount);
|
||||
|
||||
DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
|
||||
DeviceExt->StorageDevice);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1("CDFS FsdFileSystemControl() called\n");
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
switch (Stack->MinorFunction)
|
||||
{
|
||||
case IRP_MN_USER_FS_REQUEST:
|
||||
DPRINT("CDFS: IRP_MN_USER_FS_REQUEST\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case IRP_MN_MOUNT_VOLUME:
|
||||
DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
|
||||
Status = FsdMountVolume(Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_VERIFY_VOLUME:
|
||||
DPRINT("CDFS: IRP_MN_VERIFY_VOLUME\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINT("CDFS 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);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1("FsdDirectoryControl() called\n");
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
switch (Stack->MinorFunction)
|
||||
{
|
||||
#if 0
|
||||
case IRP_MN_USER_FS_REQUEST:
|
||||
DPRINT("CDFS: IRP_MN_USER_FS_REQUEST\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case IRP_MN_MOUNT_VOLUME:
|
||||
DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
|
||||
Status = FsdMountVolume(Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_VERIFY_VOLUME:
|
||||
DPRINT("CDFS: IRP_MN_VERIFY_VOLUME\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
DPRINT("CDFS 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);
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS
|
||||
FsdQueryNameInformation(PFILE_OBJECT FileObject,
|
||||
PFCB Fcb,
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PFILE_NAME_INFORMATION NameInfo,
|
||||
PULONG BufferLength)
|
||||
/*
|
||||
* FUNCTION: Retrieve the file name information
|
||||
*/
|
||||
{
|
||||
ULONG NameLength;
|
||||
|
||||
assert (NameInfo != NULL);
|
||||
assert (Fcb != NULL);
|
||||
|
||||
#if 0
|
||||
NameLength = wcslen(FCB->PathName) * sizeof(WCHAR);
|
||||
if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength)
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
|
||||
NameInfo->FileNameLength = NameLength;
|
||||
memcpy(NameInfo->FileName,
|
||||
FCB->PathName,
|
||||
NameLength + sizeof(WCHAR));
|
||||
#endif
|
||||
|
||||
/* Fake name */
|
||||
NameLength = 2;
|
||||
wcscpy(NameInfo->FileName, L"\\");
|
||||
|
||||
*BufferLength -=
|
||||
(sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
FsdQueryInformation(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;
|
||||
|
||||
DPRINT1("FsdQueryInformation() 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)
|
||||
{
|
||||
#if 0
|
||||
case FileStandardInformation:
|
||||
Status = VfatGetStandardInformation(Fcb,
|
||||
IrpContext->DeviceObject,
|
||||
SystemBuffer,
|
||||
&BufferLength);
|
||||
break;
|
||||
case FilePositionInformation:
|
||||
RC = VfatGetPositionInformation(IrpContext->FileObject,
|
||||
FCB,
|
||||
IrpContext->DeviceObject,
|
||||
SystemBuffer,
|
||||
&BufferLength);
|
||||
break;
|
||||
case FileBasicInformation:
|
||||
RC = VfatGetBasicInformation(FileObject,
|
||||
FCB,
|
||||
DeviceObject,
|
||||
SystemBuffer,
|
||||
&BufferLength);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case FileNameInformation:
|
||||
Status = FsdQueryNameInformation(FileObject,
|
||||
Fcb,
|
||||
DeviceObject,
|
||||
SystemBuffer,
|
||||
&BufferLength);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case FileInternalInformation:
|
||||
Status = FsdGetInternalInformation(Fcb,
|
||||
SystemBuffer,
|
||||
&BufferLength);
|
||||
break;
|
||||
|
||||
case FileAlternateNameInformation:
|
||||
case FileAllInformation:
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
DbgPrint("CDFS 0.0.1\n");
|
||||
|
||||
DriverObject = _DriverObject;
|
||||
|
||||
RtlInitUnicodeString(&DeviceName,
|
||||
L"\\Device\\cdfs");
|
||||
Status = IoCreateDevice(DriverObject,
|
||||
0,
|
||||
&DeviceName,
|
||||
FILE_DEVICE_CD_ROM_FILE_SYSTEM,
|
||||
0,
|
||||
FALSE,
|
||||
&DeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
DeviceObject->Flags = DO_DIRECT_IO;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
|
||||
DriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
|
||||
DriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
|
||||
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
|
||||
FsdFileSystemControl;
|
||||
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
|
||||
FsdDirectoryControl;
|
||||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
||||
FsdQueryInformation;
|
||||
DriverObject->DriverUnload = NULL;
|
||||
|
||||
IoRegisterFileSystem(DeviceObject);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
116
reactos/drivers/fs/cdfs/cdfs.h
Normal file
116
reactos/drivers/fs/cdfs/cdfs.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef CDFS_H
|
||||
#define CDFS_H
|
||||
|
||||
#include <ddk/ntifs.h>
|
||||
|
||||
#define CDFS_BASIC_SECTOR 2048
|
||||
#define CDFS_PRIMARY_DESCRIPTOR_LOCATION 16
|
||||
#define BLOCKSIZE CDFS_BASIC_SECTOR
|
||||
#define CDFS_MAX_NAME_LEN 256
|
||||
|
||||
struct _DIR_RECORD
|
||||
{
|
||||
UCHAR RecordLength; // 1
|
||||
UCHAR ExtAttrRecordLength; // 2
|
||||
ULONG ExtentLocationL; // 3-6
|
||||
ULONG ExtentLocationM; // 7-10
|
||||
ULONG DataLengthL; // 11-14
|
||||
ULONG DataLengthM; // 15-18
|
||||
UCHAR Year; // 19
|
||||
UCHAR Month; // 20
|
||||
UCHAR Day; // 21
|
||||
UCHAR Hour; // 22
|
||||
UCHAR Minute; // 23
|
||||
UCHAR Second; // 24
|
||||
UCHAR TimeZone; // 25
|
||||
UCHAR FileFlags; // 26
|
||||
UCHAR FileUnitSize; // 27
|
||||
UCHAR InterleaveGapSize; // 28
|
||||
ULONG VolumeSequenceNumber; // 29-32
|
||||
UCHAR FileIdLength; // 33
|
||||
UCHAR FileId[1]; // 34
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct _DIR_RECORD DIR_RECORD, PDIR_RECORD;
|
||||
|
||||
|
||||
/* Primary Volume Descriptor */
|
||||
struct _PVD
|
||||
{
|
||||
unsigned char VdType; // 1
|
||||
unsigned char StandardId[5]; // 2-6
|
||||
unsigned char VdVersion; // 7
|
||||
unsigned char unused0; // 8
|
||||
unsigned char SystemId[32]; // 9-40
|
||||
unsigned char VolumeId[32]; // 41-72
|
||||
unsigned char unused1[8]; // 73-80
|
||||
unsigned long VolumeSpaceSizeL; // 81-84
|
||||
unsigned long VolumeSpaceSizeM; // 85-88
|
||||
unsigned char unused2[32]; // 89-120
|
||||
unsigned long VolumeSetSize; // 121-124
|
||||
unsigned long VolumeSequenceNumber; // 125-128
|
||||
unsigned long LogicalBlockSize; // 129-132
|
||||
unsigned long PathTableSizeL; // 133-136
|
||||
unsigned long PathTableSizeM; // 137-140
|
||||
ULONG LPathTablePos; // 141-144
|
||||
ULONG LOptPathTablePos; // 145-148
|
||||
ULONG MPathTablePos; // 149-152
|
||||
ULONG MOptPathTablePos; // 153-156
|
||||
DIR_RECORD RootDirRecord; // 157-190
|
||||
|
||||
/* more data ... */
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct _PVD PVD, *PPVD;
|
||||
|
||||
|
||||
|
||||
typedef struct _FCB
|
||||
{
|
||||
REACTOS_COMMON_FCB_HEADER RFCB;
|
||||
SECTION_OBJECT_POINTERS SectionObjectPointers;
|
||||
|
||||
/* CDFS owned elements */
|
||||
|
||||
struct _FCB *next;
|
||||
struct _FCB *parent;
|
||||
|
||||
wchar_t name[CDFS_MAX_NAME_LEN];
|
||||
int hashval;
|
||||
unsigned int extent_start;
|
||||
unsigned int byte_count;
|
||||
unsigned int file_pointer;
|
||||
} FsdFcbEntry, FCB, *PFCB;
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG DiskSector,
|
||||
IN ULONG SectorCount,
|
||||
IN OUT PUCHAR Buffer);
|
||||
|
||||
int CdfsStrcmpi( wchar_t *str1, wchar_t *str2 );
|
||||
void CdfsWstrcpy( wchar_t *str1, wchar_t *str2, int max );
|
||||
|
||||
|
||||
/*
|
||||
CDFS: FCB system (Perhaps there should be a library to make this easier)
|
||||
*/
|
||||
|
||||
typedef struct _fcb_system
|
||||
{
|
||||
int fcbs_in_use;
|
||||
int fcb_table_size;
|
||||
int fcb_table_mask;
|
||||
FsdFcbEntry **fcb_table;
|
||||
FsdFcbEntry *parent;
|
||||
} fcb_system;
|
||||
|
||||
|
||||
PFCB
|
||||
FsdGetFcbEntry(fcb_system *fss,
|
||||
PFCB ParentFcb,
|
||||
PWSTR name);
|
||||
|
||||
#endif//CDFS_H
|
39
reactos/drivers/fs/cdfs/cdfs.rc
Normal file
39
reactos/drivers/fs/cdfs/cdfs.rc
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
#include <defines.h>
|
||||
#include <reactos/resource.h>
|
||||
|
||||
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", "ISO9660 Driver\0"
|
||||
VALUE "FileVersion", "0.0.6\0"
|
||||
VALUE "InternalName", "cdfs\0"
|
||||
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
|
||||
VALUE "OriginalFilename", "cdfs.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
|
||||
|
75
reactos/drivers/fs/cdfs/common.c
Normal file
75
reactos/drivers/fs/cdfs/common.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <ddk/ntddk.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include "cdfs.h"
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG DiskSector,
|
||||
IN ULONG SectorCount,
|
||||
IN OUT PUCHAR Buffer)
|
||||
{
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
LARGE_INTEGER Offset;
|
||||
ULONG BlockSize;
|
||||
KEVENT Event;
|
||||
PIRP Irp;
|
||||
NTSTATUS Status;
|
||||
|
||||
KeInitializeEvent(&Event,
|
||||
NotificationEvent,
|
||||
FALSE);
|
||||
|
||||
Offset.u.LowPart = DiskSector << 11;
|
||||
Offset.u.HighPart = DiskSector >> 21;
|
||||
|
||||
BlockSize = BLOCKSIZE * SectorCount;
|
||||
|
||||
DPRINT("CdfsReadSectors(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))
|
||||
{
|
||||
DPRINT("CdfsReadSectors() 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);
|
||||
}
|
123
reactos/drivers/fs/cdfs/fcb.c
Normal file
123
reactos/drivers/fs/cdfs/fcb.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include <ddk/ntddk.h>
|
||||
#include "cdfs.h"
|
||||
|
||||
/*
|
||||
CDFS: FCB system (Perhaps there should be a library to make this easier)
|
||||
*/
|
||||
#if 0
|
||||
typedef struct _fcb_system {
|
||||
int fcbs_in_use;
|
||||
int fcb_table_size;
|
||||
int fcb_table_mask;
|
||||
FsdFcbEntry **fcb_table;
|
||||
FsdFcbEntry *parent;
|
||||
} fcb_system;
|
||||
#endif
|
||||
|
||||
// Create a hash over this name for table
|
||||
static int FsdNameHash( FsdFcbEntry *parent, wchar_t *name ) {
|
||||
int i;
|
||||
int hashval = 0;
|
||||
|
||||
for( i = 0; name[i]; i++ )
|
||||
hashval ^= name[i] << (i & 0xf);
|
||||
|
||||
hashval ^= (int)parent;
|
||||
|
||||
return hashval;
|
||||
}
|
||||
|
||||
// Init the fcb system
|
||||
fcb_system *FsdFcbInit() {
|
||||
fcb_system *fss = ExAllocatePool( NonPagedPool,
|
||||
sizeof( fcb_system ) );
|
||||
|
||||
if( !fss ) return NULL;
|
||||
|
||||
RtlZeroMemory( fss, sizeof( *fss ) );
|
||||
|
||||
fss->fcb_table_size = 128;
|
||||
fss->fcb_table_mask = fss->fcb_table_size - 1;
|
||||
fss->fcb_table = ExAllocatePool( NonPagedPool,
|
||||
sizeof( FsdFcbEntry ** ) *
|
||||
fss->fcb_table_size );
|
||||
|
||||
if( !fss->fcb_table ) {
|
||||
ExFreePool( fss );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RtlZeroMemory( fss->fcb_table, sizeof( FsdFcbEntry ** ) *
|
||||
fss->fcb_table_size );
|
||||
|
||||
return fss;
|
||||
}
|
||||
|
||||
// Delete the fcb system
|
||||
void FsdFcbDeinit( fcb_system *fss ) {
|
||||
if( fss->fcb_table ) ExFreePool( fss->fcb_table );
|
||||
}
|
||||
|
||||
// Get one entry from the FCB system by name...
|
||||
FsdFcbEntry *FsdGetFcbEntry( fcb_system *fss, FsdFcbEntry *parent,
|
||||
wchar_t *name ) {
|
||||
int hashval;
|
||||
FsdFcbEntry *table_ent = NULL;
|
||||
|
||||
hashval = FsdNameHash( parent, name ) & fss->fcb_table_mask;
|
||||
table_ent = fss->fcb_table[hashval];
|
||||
|
||||
while( table_ent && _wcsicmp( table_ent->name, name ) &&
|
||||
table_ent->parent != parent )
|
||||
table_ent = table_ent->next;
|
||||
|
||||
return table_ent;
|
||||
}
|
||||
|
||||
// Create an fcb with the given name...
|
||||
FsdFcbEntry *FsdCreateFcb( fcb_system *fss, FsdFcbEntry *parent,
|
||||
wchar_t *filename ) {
|
||||
int hashval;
|
||||
int tableval;
|
||||
FsdFcbEntry *table_ent = FsdGetFcbEntry( fss, parent, filename );
|
||||
|
||||
if( table_ent ) return table_ent;
|
||||
|
||||
hashval = FsdNameHash( parent, filename );
|
||||
tableval = hashval & fss->fcb_table_mask;
|
||||
|
||||
table_ent = ExAllocatePool( NonPagedPool, sizeof( FsdFcbEntry ) );
|
||||
|
||||
if( table_ent ) {
|
||||
table_ent->next = fss->fcb_table[tableval];
|
||||
table_ent->hashval = hashval;
|
||||
table_ent->parent = parent;
|
||||
wcscpy( table_ent->name, filename );
|
||||
fss->fcb_table[tableval] = table_ent;
|
||||
}
|
||||
|
||||
return table_ent;
|
||||
}
|
||||
|
||||
// Delete this fcb...
|
||||
void FsdDelete( fcb_system *fss, FsdFcbEntry *which ) {
|
||||
int tableval = which->hashval & fss->fcb_table_mask;
|
||||
FsdFcbEntry *table_ent = fss->fcb_table[tableval];
|
||||
|
||||
if( table_ent == which ) {
|
||||
fss->fcb_table[tableval] = fss->fcb_table[tableval]->next;
|
||||
ExFreePool( which );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !table_ent ) return;
|
||||
|
||||
while( table_ent->next ) {
|
||||
if( table_ent->next == which ) {
|
||||
table_ent->next = table_ent->next->next;
|
||||
ExFreePool( which );
|
||||
return;
|
||||
}
|
||||
table_ent = table_ent->next;
|
||||
}
|
||||
}
|
15
reactos/drivers/fs/cdfs/makefile
Normal file
15
reactos/drivers/fs/cdfs/makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $Id: makefile,v 1.1 2002/04/12 15:41:39 ekohl Exp $
|
||||
|
||||
PATH_TO_TOP = ../../..
|
||||
|
||||
TARGET_TYPE = driver
|
||||
|
||||
TARGET_NAME = cdfs
|
||||
|
||||
TARGET_OBJECTS = $(TARGET_NAME).o common.o fcb.o
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
include $(TOOLS_PATH)/helper.mk
|
||||
|
||||
# EOF
|
|
@ -26,6 +26,7 @@ copy ntoskrnl\ntoskrnl.exe %ROS_INSTALL%\system32
|
|||
copy ntoskrnl\ntoskrnl.sym %ROS_INSTALL%\symbols
|
||||
copy hal\halx86\hal.dll %ROS_INSTALL%\system32
|
||||
copy services\fs\vfat\vfatfs.sys %ROS_INSTALL%\system32\drivers
|
||||
copy services\fs\cdfs\cdfs.sys %ROS_INSTALL%\system32\drivers
|
||||
copy services\fs\ms\msfs.sys %ROS_INSTALL%\system32\drivers
|
||||
copy services\fs\np\npfs.sys %ROS_INSTALL%\system32\drivers
|
||||
copy services\bus\acpi\acpi.sys %ROS_INSTALL%\system32\drivers
|
||||
|
|
Loading…
Reference in a new issue