1998-10-05 04:00:59 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: services/fs/vfat/iface.c
|
|
|
|
* PURPOSE: VFAT Filesystem
|
|
|
|
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
1998-10-31 15:54:07 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
?? Created
|
|
|
|
24-10-1998 Fixed bugs in long filename support
|
|
|
|
Fixed a bug that prevented unsuccessful file open requests being reported
|
|
|
|
Now works with long filenames that span over a sector boundary
|
|
|
|
28-10-1998 Reads entire FAT into memory
|
|
|
|
VFatReadSector modified to read in more than one sector at a time
|
1998-11-07 20:30:33 +00:00
|
|
|
7-11-1998 Fixed bug that assumed that directory data could be fragmented
|
1998-12-20 19:41:39 +00:00
|
|
|
8-12-1998 Added FAT32 support
|
|
|
|
Added initial writability functions
|
|
|
|
WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
|
|
|
|
12-12-1998 Added basic support for FILE_STANDARD_INFORMATION request
|
1998-10-31 15:54:07 +00:00
|
|
|
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
#include <wchar.h>
|
1998-10-05 04:00:59 +00:00
|
|
|
#include <internal/string.h>
|
1999-03-19 05:55:55 +00:00
|
|
|
#include <ddk/ntddk.h>
|
1998-12-20 19:41:39 +00:00
|
|
|
#include <ddk/cctypes.h>
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-01-01 22:33:38 +00:00
|
|
|
#define NDEBUG
|
1998-10-05 04:00:59 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
#include "vfat.h"
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
//#include "dbgpool.c"
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
static PDRIVER_OBJECT VFATDriverObject;
|
|
|
|
PVfatFCB pFirstFcb;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
|
|
|
|
* disk read
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-20 19:02:05 +00:00
|
|
|
ULONG FATsector;
|
|
|
|
ULONG FATeis;
|
|
|
|
PULONG Block;
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
Block = ExAllocatePool(NonPagedPool,1024);
|
|
|
|
FATsector=CurrentCluster/(512/sizeof(ULONG));
|
|
|
|
FATeis=CurrentCluster-(FATsector*(512/sizeof(ULONG)));
|
1998-12-30 18:43:27 +00:00
|
|
|
VFATReadSectors(DeviceExt->StorageDevice
|
|
|
|
,(ULONG)(DeviceExt->FATStart+FATsector), 1,(UCHAR*) Block);
|
1998-12-20 19:41:39 +00:00
|
|
|
CurrentCluster = Block[FATeis];
|
|
|
|
if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
|
1999-01-04 12:08:54 +00:00
|
|
|
CurrentCluster = 0xffffffff;
|
1998-12-20 19:41:39 +00:00
|
|
|
ExFreePool(Block);
|
|
|
|
return(CurrentCluster);
|
|
|
|
}
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
|
|
|
|
* in-memory FAT
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-01-20 19:02:05 +00:00
|
|
|
PUSHORT Block;
|
1999-01-04 12:08:54 +00:00
|
|
|
Block=(PUSHORT)DeviceExt->FAT;
|
|
|
|
CurrentCluster = Block[CurrentCluster];
|
1998-11-07 20:30:33 +00:00
|
|
|
if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
|
1999-01-20 19:02:05 +00:00
|
|
|
CurrentCluster = 0xffffffff;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("Returning %x\n",CurrentCluster);
|
1998-10-05 04:00:59 +00:00
|
|
|
return(CurrentCluster);
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
|
|
|
|
* in-memory FAT
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
unsigned char* CBlock;
|
|
|
|
ULONG FATOffset;
|
|
|
|
ULONG Entry;
|
|
|
|
CBlock = DeviceExt->FAT;
|
|
|
|
FATOffset = (CurrentCluster * 12)/ 8;//first byte containing value
|
1998-10-05 04:00:59 +00:00
|
|
|
if ((CurrentCluster % 2) == 0)
|
1999-01-04 12:08:54 +00:00
|
|
|
{
|
|
|
|
Entry = CBlock[FATOffset];
|
|
|
|
Entry |= ((CBlock[FATOffset+1] & 0xf)<<8);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
else
|
1999-01-04 12:08:54 +00:00
|
|
|
{
|
|
|
|
Entry = (CBlock[FATOffset] >> 4);
|
|
|
|
Entry |= (CBlock[FATOffset+1] << 4);
|
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("Entry %x\n",Entry);
|
1998-10-05 04:00:59 +00:00
|
|
|
if (Entry >= 0xff8 && Entry <= 0xfff)
|
1999-01-04 12:08:54 +00:00
|
|
|
Entry = 0xffffffff;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("Returning %x\n",Entry);
|
1999-01-04 12:08:54 +00:00
|
|
|
return(Entry);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the next cluster depending on the FAT type
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
|
|
|
|
DeviceExt,CurrentCluster);
|
1998-10-05 04:00:59 +00:00
|
|
|
if (DeviceExt->FatType == FAT16)
|
|
|
|
return(Fat16GetNextCluster(DeviceExt, CurrentCluster));
|
1998-12-20 19:41:39 +00:00
|
|
|
else if (DeviceExt->FatType == FAT32)
|
|
|
|
return(Fat32GetNextCluster(DeviceExt, CurrentCluster));
|
1998-10-05 04:00:59 +00:00
|
|
|
else
|
|
|
|
return(Fat12GetNextCluster(DeviceExt, CurrentCluster));
|
|
|
|
}
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Finds the first available cluster in a FAT16 table
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
PUSHORT Block;
|
|
|
|
int i;
|
|
|
|
Block=(PUSHORT)DeviceExt->FAT;
|
|
|
|
for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
|
|
|
|
if(Block[i]==0)
|
|
|
|
return (i);
|
|
|
|
/* Give an error message (out of disk space) if we reach here) */
|
|
|
|
return 0;
|
|
|
|
}
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
ULONG FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Finds the first available cluster in a FAT12 table
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG FATOffset;
|
|
|
|
ULONG Entry;
|
|
|
|
PUCHAR CBlock=DeviceExt->FAT;
|
|
|
|
ULONG i;
|
|
|
|
for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
|
|
|
|
{
|
|
|
|
FATOffset = (i * 12)/8;
|
|
|
|
if ((i % 2) == 0)
|
|
|
|
{
|
|
|
|
Entry = CBlock[FATOffset];
|
|
|
|
Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Entry = (CBlock[FATOffset] >> 4);
|
|
|
|
Entry |= (CBlock[FATOffset + 1] << 4);
|
|
|
|
}
|
|
|
|
if(Entry==0)
|
|
|
|
return (i);
|
|
|
|
}
|
|
|
|
/* Give an error message (out of disk space) if we reach here) */
|
|
|
|
DbgPrint("Disk full, %d clusters used\n",i);
|
|
|
|
return 0;
|
|
|
|
}
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
ULONG FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Finds the first available cluster in a FAT32 table
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG sector;
|
|
|
|
PULONG Block;
|
|
|
|
int i;
|
|
|
|
Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
|
|
|
|
for(sector=0
|
|
|
|
;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
|
|
|
|
;sector++)
|
|
|
|
{
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice
|
|
|
|
,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
for(i=0; i<512; i++)
|
|
|
|
{
|
|
|
|
if(Block[i]==0)
|
|
|
|
{
|
1998-12-20 19:41:39 +00:00
|
|
|
ExFreePool(Block);
|
1999-01-04 12:08:54 +00:00
|
|
|
return (i+sector*128);
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Give an error message (out of disk space) if we reach here) */
|
|
|
|
ExFreePool(Block);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-05-06 17:59:55 +00:00
|
|
|
ULONG FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Counts free cluster in a FAT12 table
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG FATOffset;
|
|
|
|
ULONG Entry;
|
|
|
|
PUCHAR CBlock=DeviceExt->FAT;
|
|
|
|
ULONG ulCount = 0;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
|
|
|
|
{
|
|
|
|
FATOffset = (i * 12)/8;
|
|
|
|
if ((i % 2) == 0)
|
|
|
|
{
|
|
|
|
Entry = CBlock[FATOffset];
|
|
|
|
Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Entry = (CBlock[FATOffset] >> 4);
|
|
|
|
Entry |= (CBlock[FATOffset + 1] << 4);
|
|
|
|
}
|
|
|
|
if(Entry==0)
|
|
|
|
ulCount++;
|
|
|
|
}
|
|
|
|
return ulCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Counts free clusters in a FAT16 table
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PUSHORT Block;
|
|
|
|
ULONG ulCount = 0;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
Block=(PUSHORT)DeviceExt->FAT;
|
|
|
|
for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
|
|
|
|
if(Block[i]==0)
|
|
|
|
ulCount++;
|
|
|
|
return ulCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Counts free clusters in a FAT32 table
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG sector;
|
|
|
|
PULONG Block;
|
|
|
|
ULONG ulCount = 0;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
|
|
|
|
for(sector=0
|
|
|
|
;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
|
|
|
|
;sector++)
|
|
|
|
{
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice
|
|
|
|
,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
|
|
|
|
|
|
|
|
for(i=0; i<512; i++)
|
|
|
|
{
|
|
|
|
if(Block[i]==0)
|
|
|
|
ulCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Give an error message (out of disk space) if we reach here) */
|
|
|
|
ExFreePool(Block);
|
|
|
|
return ulCount;
|
|
|
|
}
|
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
|
|
|
|
ULONG NewValue)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG FATsector;
|
|
|
|
ULONG FATOffset;
|
|
|
|
PUCHAR CBlock=DeviceExt->FAT;
|
|
|
|
int i;
|
|
|
|
FATOffset = (ClusterToWrite * 12)/8;
|
|
|
|
if ((ClusterToWrite % 2) == 0)
|
|
|
|
{
|
|
|
|
CBlock[FATOffset]=NewValue;
|
|
|
|
CBlock[FATOffset + 1] &=0xf0;
|
|
|
|
CBlock[FATOffset + 1]
|
|
|
|
|= (NewValue&0xf00)>>8;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CBlock[FATOffset] &=0x0f;
|
|
|
|
CBlock[FATOffset]
|
|
|
|
|= (NewValue&0xf)<<4;
|
|
|
|
CBlock[FATOffset+1]=NewValue>>4;
|
|
|
|
}
|
|
|
|
/* Write the changed FAT sector(s) to disk */
|
|
|
|
FATsector=FATOffset/BLOCKSIZE;
|
|
|
|
for(i=0;i<DeviceExt->Boot->FATCount;i++)
|
|
|
|
{
|
|
|
|
if( (FATOffset%BLOCKSIZE)==(BLOCKSIZE-1))//entry is on 2 sectors
|
|
|
|
{
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,
|
|
|
|
DeviceExt->FATStart+FATsector
|
|
|
|
+i*DeviceExt->Boot->FATSectors,
|
|
|
|
2,
|
|
|
|
CBlock+FATsector*512);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,
|
|
|
|
DeviceExt->FATStart+FATsector
|
|
|
|
+i*DeviceExt->Boot->FATSectors,
|
|
|
|
1,
|
|
|
|
CBlock+FATsector*512);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
|
|
|
|
ULONG NewValue)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
ULONG FATsector;
|
|
|
|
PUSHORT Block;
|
|
|
|
DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite,NewValue);
|
|
|
|
Block=(PUSHORT)DeviceExt->FAT;
|
1998-12-20 19:41:39 +00:00
|
|
|
FATsector=ClusterToWrite/(512/sizeof(USHORT));
|
|
|
|
|
|
|
|
/* Update the in-memory FAT */
|
1999-01-04 12:08:54 +00:00
|
|
|
Block[ClusterToWrite] = NewValue;
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Write the changed FAT sector to disk */
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,
|
|
|
|
DeviceExt->FATStart+FATsector,
|
1999-01-04 12:08:54 +00:00
|
|
|
1,
|
|
|
|
(UCHAR *)Block);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
|
|
|
|
ULONG NewValue)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Writes a cluster to the FAT32 physical tables
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG FATsector;
|
|
|
|
ULONG FATeis;
|
|
|
|
PUSHORT Block;
|
|
|
|
DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite,NewValue);
|
|
|
|
Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
|
|
|
|
FATsector=ClusterToWrite/128;
|
|
|
|
FATeis=ClusterToWrite-(FATsector*128);
|
|
|
|
/* load sector, change value, then rewrite sector */
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,
|
|
|
|
DeviceExt->FATStart+FATsector,
|
|
|
|
1,
|
|
|
|
(UCHAR *)Block);
|
|
|
|
Block[FATeis] = NewValue;
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,
|
|
|
|
DeviceExt->FATStart+FATsector,
|
|
|
|
1,
|
1998-12-20 19:41:39 +00:00
|
|
|
(UCHAR *)Block);
|
|
|
|
ExFreePool(Block);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
|
|
|
|
ULONG NewValue)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Write a changed FAT entry
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
if(DeviceExt->FatType==FAT16)
|
1998-12-20 19:41:39 +00:00
|
|
|
FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
|
1999-01-04 12:08:54 +00:00
|
|
|
else if(DeviceExt->FatType==FAT32)
|
|
|
|
FAT32WriteCluster(DeviceExt, ClusterToWrite, NewValue);
|
|
|
|
else
|
|
|
|
FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue);
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Determines the next cluster to be written
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
ULONG LastCluster, NewCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
|
|
|
|
DeviceExt,CurrentCluster);
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Find out what was happening in the last cluster's AU */
|
1999-01-04 12:08:54 +00:00
|
|
|
LastCluster=GetNextCluster(DeviceExt,CurrentCluster);
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Check to see if we must append or overwrite */
|
1999-01-04 12:08:54 +00:00
|
|
|
if (LastCluster==0xffffffff)
|
|
|
|
{//we are after last existing cluster : we must add one to file
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Append */
|
|
|
|
/* Firstly, find the next available open allocation unit */
|
1999-01-04 12:08:54 +00:00
|
|
|
if(DeviceExt->FatType == FAT16)
|
|
|
|
NewCluster = FAT16FindAvailableCluster(DeviceExt);
|
|
|
|
else if(DeviceExt->FatType == FAT32)
|
|
|
|
NewCluster = FAT32FindAvailableCluster(DeviceExt);
|
|
|
|
else
|
|
|
|
NewCluster = FAT12FindAvailableCluster(DeviceExt);
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Mark the new AU as the EOF */
|
1999-01-04 12:08:54 +00:00
|
|
|
WriteCluster(DeviceExt, NewCluster, 0xFFFFFFFF);
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Now, write the AU of the LastCluster with the value of the newly
|
|
|
|
found AU */
|
1999-01-13 15:21:34 +00:00
|
|
|
if(CurrentCluster)
|
|
|
|
WriteCluster(DeviceExt, CurrentCluster, NewCluster);
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Return NewCluster as CurrentCluster */
|
|
|
|
return NewCluster;
|
1999-01-04 12:08:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-12-20 19:41:39 +00:00
|
|
|
/* Overwrite: Return LastCluster as CurrentCluster */
|
|
|
|
return LastCluster;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-30 18:43:27 +00:00
|
|
|
ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt,
|
1998-10-05 04:00:59 +00:00
|
|
|
unsigned long Cluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Converts the cluster number to a sector number for this physical
|
|
|
|
* device
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Convert an ANSI string to it's Unicode equivalent
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; (i<Length && Source[i] != ' '); i++)
|
|
|
|
{
|
|
|
|
Dest[i] = Source[i];
|
|
|
|
}
|
|
|
|
Dest[i]=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RtlCatAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Appends a converted ANSI to Unicode string to the end of an
|
|
|
|
* existing Unicode string
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
while((*Dest)!=0)
|
|
|
|
{
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
for (i=0; (i<Length && Source[i] != ' '); i++)
|
|
|
|
{
|
|
|
|
Dest[i] = Source[i];
|
|
|
|
}
|
|
|
|
Dest[i]=0;
|
|
|
|
}
|
|
|
|
|
1998-10-31 15:54:07 +00:00
|
|
|
void vfat_initstr(wchar_t *wstr, ULONG wsize)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Initialize a string for use with a long file name
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1998-10-31 15:54:07 +00:00
|
|
|
int i;
|
|
|
|
wchar_t nc=0;
|
|
|
|
for(i=0; i<wsize; i++)
|
|
|
|
{
|
|
|
|
*wstr=nc;
|
|
|
|
wstr++;
|
|
|
|
}
|
|
|
|
wstr=wstr-wsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
wchar_t * vfat_wcsncat(wchar_t * dest, const wchar_t * src,size_t wstart, size_t wcount)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Append a string for use with a long file name
|
|
|
|
*/
|
1998-10-31 15:54:07 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dest+=wstart;
|
|
|
|
for(i=0; i<wcount; i++)
|
|
|
|
{
|
|
|
|
*dest=src[i];
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
dest=dest-(wcount+wstart);
|
|
|
|
|
|
|
|
return dest;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1998-10-31 15:54:07 +00:00
|
|
|
wchar_t * vfat_wcsncpy(wchar_t * dest, const wchar_t *src,size_t wcount)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Copy a string for use with long file names
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-01-13 15:21:34 +00:00
|
|
|
int i;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1998-10-31 15:54:07 +00:00
|
|
|
for (i=0;i<wcount;i++)
|
1999-01-13 15:21:34 +00:00
|
|
|
{
|
|
|
|
dest[i]=src[i];
|
|
|
|
if(!dest[i]) break;
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
return(dest);
|
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
wchar_t * vfat_movstr(const wchar_t *src, ULONG dpos,
|
1998-10-31 15:54:07 +00:00
|
|
|
ULONG spos, ULONG len)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Move the characters in a string to a new position in the same
|
|
|
|
* string
|
|
|
|
*/
|
1998-10-31 15:54:07 +00:00
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
int i;
|
1998-10-31 15:54:07 +00:00
|
|
|
|
1999-01-20 13:05:53 +00:00
|
|
|
if(dpos<=spos)
|
|
|
|
{
|
|
|
|
for(i=0; i<len; i++)
|
|
|
|
{
|
|
|
|
src[dpos++]=src[spos++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1998-10-31 15:54:07 +00:00
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
dpos+=len-1;
|
|
|
|
spos+=len-1;
|
|
|
|
for(i=0; i<len; i++)
|
|
|
|
{
|
|
|
|
src[dpos--]=src[spos--];
|
|
|
|
}
|
1998-10-31 15:54:07 +00:00
|
|
|
}
|
|
|
|
|
1999-01-20 13:05:53 +00:00
|
|
|
return(src);
|
1998-10-31 15:54:07 +00:00
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Determine if the given directory entry is the last
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
BOOLEAN IsVolEntry(PVOID Block, ULONG Offset)
|
1999-01-04 12:08:54 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Determine if the given directory entry is a vol entry
|
|
|
|
*/
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
if( (((FATDirEntry *)Block)[Offset].Attrib)==0x28 ) return TRUE;
|
1999-01-04 12:08:54 +00:00
|
|
|
else return FALSE;
|
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Determines if the given entry is a deleted one
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-01-13 15:21:34 +00:00
|
|
|
/* Checks special character */
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5));
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
|
|
|
|
PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieves the file name, be it in short or long file name format
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
FATDirEntry* test;
|
|
|
|
slot* test2;
|
|
|
|
ULONG Offset = *_Offset;
|
|
|
|
ULONG StartingSector = *_StartingSector;
|
|
|
|
ULONG jloop = *_jloop;
|
|
|
|
ULONG cpos;
|
|
|
|
WCHAR tmp[256];
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
test = (FATDirEntry *)Block;
|
|
|
|
test2 = (slot *)Block;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
*Name = 0;
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
if (IsDeletedEntry(Block,Offset))
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
return(FALSE);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
if(test2[Offset].attr == 0x0f)
|
|
|
|
{
|
|
|
|
vfat_initstr(Name, 256);
|
|
|
|
vfat_wcsncpy(Name,test2[Offset].name0_4,5);
|
|
|
|
vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
|
|
|
|
vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
|
|
|
|
|
|
|
|
cpos=0;
|
|
|
|
while((test2[Offset].id!=0x41) && (test2[Offset].id!=0x01) &&
|
|
|
|
(test2[Offset].attr>0))
|
|
|
|
{
|
|
|
|
Offset++;
|
|
|
|
if(Offset==ENTRIES_PER_SECTOR) {
|
|
|
|
Offset=0;
|
|
|
|
StartingSector++;//FIXME : nor always the next sector
|
|
|
|
jloop++;
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
|
|
|
|
test2 = (slot *)Block;
|
|
|
|
}
|
|
|
|
cpos++;
|
|
|
|
vfat_movstr(Name, 13, 0, cpos*13);
|
|
|
|
vfat_wcsncpy(Name, test2[Offset].name0_4, 5);
|
|
|
|
vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
|
|
|
|
vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsDeletedEntry(Block,Offset+1))
|
|
|
|
{
|
|
|
|
Offset++;
|
|
|
|
*_Offset = Offset;
|
|
|
|
*_jloop = jloop;
|
|
|
|
*_StartingSector = StartingSector;
|
1999-02-10 12:52:48 +00:00
|
|
|
return(FALSE);
|
1999-03-19 05:55:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*_Offset = Offset;
|
|
|
|
*_jloop = jloop;
|
|
|
|
*_StartingSector = StartingSector;
|
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
RtlAnsiToUnicode(Name,test[Offset].Filename,8);
|
|
|
|
if (test[Offset].Ext[0]!=' ')
|
|
|
|
{
|
|
|
|
RtlCatAnsiToUnicode(Name,".",1);
|
|
|
|
}
|
|
|
|
RtlCatAnsiToUnicode(Name,test[Offset].Ext,3);
|
|
|
|
|
|
|
|
*_Offset = Offset;
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN wstrcmpi(PWSTR s1, PWSTR s2)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Compare to wide character strings
|
|
|
|
* return TRUE if s1==s2
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-05-05 11:23:46 +00:00
|
|
|
while (towlower(*s1)==towlower(*s2))
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
if ((*s1)==0 && (*s2)==0)
|
|
|
|
{
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
|
|
|
|
* return TRUE if s1 like s2
|
|
|
|
*/
|
|
|
|
{
|
1999-05-05 11:23:46 +00:00
|
|
|
while ((*s2=='?')||(towlower(*s1)==towlower(*s2)))
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
|
|
|
if ((*s1)==0 && (*s2)==0)
|
|
|
|
return(TRUE);
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
if(*s2=='*')
|
|
|
|
{
|
|
|
|
s2++;
|
|
|
|
while (*s1)
|
|
|
|
if (wstrcmpjoki(s1,s2)) return TRUE;
|
|
|
|
else s1++;
|
|
|
|
}
|
|
|
|
if ((*s1)==0 && (*s2)==0)
|
|
|
|
return(TRUE);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-05-13 18:02:24 +00:00
|
|
|
|
|
|
|
NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Read the volume label
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG i, j;
|
|
|
|
ULONG Size;
|
|
|
|
char* block;
|
|
|
|
ULONG StartingSector;
|
|
|
|
ULONG NextCluster;
|
|
|
|
|
|
|
|
Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
|
|
|
|
StartingSector = DeviceExt->rootStart;
|
|
|
|
NextCluster=0;
|
|
|
|
|
|
|
|
block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
|
|
|
|
DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
|
|
|
|
for (j=0; j<Size; j++)
|
|
|
|
{
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
|
|
|
|
|
|
|
|
for (i=0; i<ENTRIES_PER_SECTOR; i++)
|
|
|
|
{
|
|
|
|
if (IsVolEntry((PVOID)block,i))
|
|
|
|
{
|
|
|
|
FATDirEntry *test = (FATDirEntry *)block;
|
|
|
|
|
|
|
|
/* copy volume label */
|
|
|
|
RtlAnsiToUnicode(Vpb->VolumeLabel,test[i].Filename,8);
|
|
|
|
RtlCatAnsiToUnicode(Vpb->VolumeLabel,test[i].Ext,3);
|
|
|
|
Vpb->VolumeLabelLength = wcslen(Vpb->VolumeLabel);
|
|
|
|
|
|
|
|
ExFreePool(block);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
if (IsLastEntry((PVOID)block,i))
|
|
|
|
{
|
|
|
|
*(Vpb->VolumeLabel) = 0;
|
|
|
|
Vpb->VolumeLabelLength = 0;
|
|
|
|
ExFreePool(block);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// not found in this sector, try next :
|
|
|
|
|
|
|
|
/* directory can be fragmented although it is best to keep them
|
|
|
|
unfragmented */
|
|
|
|
StartingSector++;
|
|
|
|
if (DeviceExt->FatType ==FAT32)
|
|
|
|
{
|
|
|
|
if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
|
|
|
|
{
|
|
|
|
NextCluster = GetNextCluster(DeviceExt,NextCluster);
|
|
|
|
if (NextCluster == 0||NextCluster==0xffffffff)
|
|
|
|
{
|
|
|
|
*(Vpb->VolumeLabel) = 0;
|
|
|
|
Vpb->VolumeLabelLength = 0;
|
|
|
|
ExFreePool(block);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
StartingSector = ClusterToSector(DeviceExt,NextCluster);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*(Vpb->VolumeLabel) = 0;
|
|
|
|
Vpb->VolumeLabelLength = 0;
|
|
|
|
ExFreePool(block);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PVfatFCB Fcb,
|
1999-03-19 05:55:55 +00:00
|
|
|
PVfatFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Find a file
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
ULONG i, j;
|
1998-12-30 18:43:27 +00:00
|
|
|
ULONG Size;
|
1999-03-19 05:55:55 +00:00
|
|
|
char* block;
|
1998-12-30 18:43:27 +00:00
|
|
|
WCHAR name[256];
|
1999-03-19 05:55:55 +00:00
|
|
|
ULONG StartingSector;
|
|
|
|
ULONG NextCluster;
|
|
|
|
WCHAR TempStr[2];
|
|
|
|
|
|
|
|
DPRINT("FindFile(Parent %x, FileToFind '%w')\n",Parent,FileToFind);
|
|
|
|
|
|
|
|
if (wcslen(FileToFind)==0)
|
|
|
|
{
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
|
|
|
TempStr[0] = (WCHAR)'.';
|
1999-03-19 05:55:55 +00:00
|
|
|
TempStr[1] = 0;
|
|
|
|
FileToFind=&TempStr;
|
|
|
|
}
|
|
|
|
if (Parent != NULL)
|
|
|
|
{
|
|
|
|
DPRINT("Parent->entry.FirstCluster %d\n",Parent->entry.FirstCluster);
|
|
|
|
}
|
1999-06-27 23:06:50 +00:00
|
|
|
|
|
|
|
DPRINT("FindFile '%w'\n", FileToFind);
|
1999-01-05 12:04:08 +00:00
|
|
|
if (Parent == NULL||Parent->entry.FirstCluster==1)
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1998-12-30 18:43:27 +00:00
|
|
|
Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
|
1999-03-19 05:55:55 +00:00
|
|
|
StartingSector = DeviceExt->rootStart;
|
|
|
|
NextCluster=0;
|
|
|
|
if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0) ||
|
|
|
|
(FileToFind[0]=='.' && FileToFind[1]==0))
|
1999-01-04 12:08:54 +00:00
|
|
|
{// it's root : complete essentials fields then return ok
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-01-04 12:08:54 +00:00
|
|
|
memset(Fcb,0,sizeof(VfatFCB));
|
1998-12-30 18:43:27 +00:00
|
|
|
memset(Fcb->entry.Filename,' ',11);
|
1999-01-05 12:04:08 +00:00
|
|
|
Fcb->entry.FileSize=DeviceExt->rootDirectorySectors*BLOCKSIZE;
|
1999-01-13 15:21:34 +00:00
|
|
|
Fcb->entry.Attrib=FILE_ATTRIBUTE_DIRECTORY;
|
1998-12-30 18:43:27 +00:00
|
|
|
if (DeviceExt->FatType == FAT32)
|
|
|
|
Fcb->entry.FirstCluster=2;
|
1999-06-27 23:06:50 +00:00
|
|
|
else
|
|
|
|
Fcb->entry.FirstCluster=1;//FIXME : is 1 the good value for mark root?
|
|
|
|
if(StartSector)
|
|
|
|
*StartSector=StartingSector;
|
|
|
|
if(Entry)
|
|
|
|
*Entry=0;
|
1998-12-30 18:43:27 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
else
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
|
|
|
|
|
|
|
|
Size = ULONG_MAX;
|
|
|
|
if (DeviceExt->FatType == FAT32)
|
|
|
|
NextCluster = Parent->entry.FirstCluster
|
|
|
|
+Parent->entry.FirstClusterHigh*65536;
|
|
|
|
else
|
|
|
|
NextCluster = Parent->entry.FirstCluster;
|
|
|
|
StartingSector = ClusterToSector(DeviceExt, NextCluster);
|
|
|
|
if(Parent->entry.FirstCluster==1 && DeviceExt->FatType!=FAT32)
|
|
|
|
{// read of root directory in FAT16 or FAT12
|
|
|
|
StartingSector=DeviceExt->rootStart;
|
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
}
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-03-19 05:55:55 +00:00
|
|
|
block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-03-19 05:55:55 +00:00
|
|
|
if (StartSector && (*StartSector)) StartingSector=*StartSector;
|
1998-12-30 18:43:27 +00:00
|
|
|
i=(Entry)?(*Entry):0;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
|
|
|
|
for (j=0; j<Size; j++)
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
|
|
|
|
|
|
|
|
for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
if (IsVolEntry((PVOID)block,i))
|
|
|
|
continue;
|
|
|
|
if (IsLastEntry((PVOID)block,i))
|
|
|
|
{
|
|
|
|
ExFreePool(block);
|
|
|
|
if(StartSector) *StartSector=StartingSector;
|
|
|
|
if(Entry) *Entry=i;
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
|
|
|
|
{
|
|
|
|
DPRINT("Comparing '%w' '%w'\n",name,FileToFind);
|
|
|
|
if (wstrcmpjoki(name,FileToFind))
|
|
|
|
{
|
|
|
|
/* In the case of a long filename, the firstcluster is stored in
|
|
|
|
the next record -- where it's short name is */
|
|
|
|
if(((FATDirEntry *)block)[i].Attrib==0x0f) i++;
|
|
|
|
if( i==(ENTRIES_PER_SECTOR))
|
|
|
|
{// entry is in next sector
|
|
|
|
StartingSector++;
|
|
|
|
//FIXME : treat case of next sector fragmented
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
|
|
|
|
i=0;
|
|
|
|
}
|
|
|
|
memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
|
|
|
|
sizeof(FATDirEntry));
|
|
|
|
vfat_wcsncpy(Fcb->ObjectName,name,MAX_PATH);
|
|
|
|
ExFreePool(block);
|
|
|
|
if(StartSector) *StartSector=StartingSector;
|
|
|
|
if(Entry) *Entry=i;
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
// not found in this sector, try next :
|
|
|
|
|
|
|
|
/* directory can be fragmented although it is best to keep them
|
|
|
|
unfragmented */
|
|
|
|
if(Entry) *Entry=0;
|
|
|
|
StartingSector++;
|
|
|
|
if ((Parent != NULL && Parent->entry.FirstCluster!=1)
|
|
|
|
|| DeviceExt->FatType ==FAT32)
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
|
1998-12-30 18:43:27 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
NextCluster = GetNextCluster(DeviceExt,NextCluster);
|
|
|
|
if (NextCluster == 0||NextCluster==0xffffffff)
|
|
|
|
{
|
|
|
|
if(StartSector) *StartSector=StartingSector;
|
|
|
|
if(Entry) *Entry=i;
|
|
|
|
ExFreePool(block);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
StartingSector = ClusterToSector(DeviceExt,NextCluster);
|
1998-12-30 18:43:27 +00:00
|
|
|
}
|
1999-01-05 12:04:08 +00:00
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(block);
|
|
|
|
if(StartSector) *StartSector=StartingSector;
|
1999-01-04 12:08:54 +00:00
|
|
|
if(Entry) *Entry=i;
|
1998-10-05 04:00:59 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Closes a file
|
|
|
|
*/
|
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
PVfatFCB pFcb;
|
|
|
|
PVfatCCB pCcb;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
|
|
|
|
DeviceExt,FileObject);
|
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
//FIXME : update entry in directory ?
|
|
|
|
pCcb = (PVfatCCB)(FileObject->FsContext2);
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
DPRINT("pCcb %x\n",pCcb);
|
|
|
|
if (pCcb == NULL)
|
|
|
|
{
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
pFcb = pCcb->pFcb;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
pFcb->RefCount--;
|
|
|
|
if(pFcb->RefCount<=0)
|
|
|
|
{
|
|
|
|
if(pFcb->prevFcb)
|
|
|
|
pFcb->prevFcb->nextFcb=pFcb->nextFcb;
|
|
|
|
else
|
|
|
|
pFirstFcb=pFcb->nextFcb;
|
|
|
|
if(pFcb->nextFcb)
|
|
|
|
pFcb->nextFcb->prevFcb=pFcb->prevFcb;
|
|
|
|
ExFreePool(pFcb);
|
|
|
|
}
|
|
|
|
ExFreePool(pCcb);
|
1998-12-30 18:43:27 +00:00
|
|
|
return STATUS_SUCCESS;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
|
|
|
|
PWSTR FileName)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Opens a file
|
|
|
|
*/
|
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
PWSTR current;
|
|
|
|
PWSTR next;
|
|
|
|
PWSTR string;
|
|
|
|
PVfatFCB ParentFcb;
|
|
|
|
PVfatFCB Fcb,pRelFcb;
|
|
|
|
PVfatFCB Temp;
|
|
|
|
PVfatCCB newCCB,pRelCcb;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PFILE_OBJECT pRelFileObject;
|
|
|
|
PWSTR AbsFileName=NULL;
|
|
|
|
short i,j;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
|
|
|
|
DeviceExt,
|
|
|
|
FileObject,
|
|
|
|
FileName);
|
|
|
|
|
|
|
|
//FIXME : treat relative name
|
1999-01-20 13:05:53 +00:00
|
|
|
if(FileObject->RelatedFileObject)
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
DbgPrint("try related for %w\n",FileName);
|
1999-01-20 13:05:53 +00:00
|
|
|
pRelFileObject=FileObject->RelatedFileObject;
|
|
|
|
pRelCcb=pRelFileObject->FsContext2;
|
|
|
|
assert(pRelCcb);
|
|
|
|
pRelFcb=pRelCcb->pFcb;
|
|
|
|
assert(pRelFcb);
|
|
|
|
// verify related object is a directory and target name don't start with \.
|
|
|
|
if( !(pRelFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
|| (FileName[0]!= '\\') )
|
|
|
|
{
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
// construct absolute path name
|
1999-03-19 05:55:55 +00:00
|
|
|
AbsFileName=ExAllocatePool(NonPagedPool,MAX_PATH);
|
1999-01-20 13:05:53 +00:00
|
|
|
for (i=0;pRelFcb->PathName[i];i++)
|
|
|
|
AbsFileName[i]=pRelFcb->PathName[i];
|
|
|
|
AbsFileName[i++]='\\';
|
|
|
|
for (j=0;FileName[j]&&i<MAX_PATH;j++)
|
|
|
|
AbsFileName[i++]=FileName[j];
|
|
|
|
assert(i<MAX_PATH);
|
|
|
|
AbsFileName[i]=0;
|
|
|
|
FileName=AbsFileName;
|
|
|
|
}
|
1999-01-04 12:08:54 +00:00
|
|
|
// try first to find an existing FCB in memory
|
|
|
|
for (Fcb=pFirstFcb;Fcb; Fcb=Fcb->nextFcb)
|
|
|
|
{
|
|
|
|
if (DeviceExt==Fcb->pDevExt
|
|
|
|
&& wstrcmpi(FileName,Fcb->PathName))
|
|
|
|
{
|
|
|
|
Fcb->RefCount++;
|
|
|
|
FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
|
|
|
|
newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
|
|
|
|
memset(newCCB,0,sizeof(VfatCCB));
|
|
|
|
FileObject->FsContext2 = newCCB;
|
|
|
|
newCCB->pFcb=Fcb;
|
|
|
|
newCCB->PtrFileObject=FileObject;
|
1999-01-20 13:05:53 +00:00
|
|
|
if(AbsFileName)ExFreePool(AbsFileName);
|
1999-01-04 12:08:54 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
1998-12-30 22:48:14 +00:00
|
|
|
string = FileName;
|
|
|
|
ParentFcb = NULL;
|
1999-01-04 12:08:54 +00:00
|
|
|
Fcb = ExAllocatePool(NonPagedPool, sizeof(VfatFCB));
|
|
|
|
memset(Fcb,0,sizeof(VfatFCB));
|
|
|
|
Fcb->ObjectName=Fcb->PathName;
|
1999-03-19 05:55:55 +00:00
|
|
|
next = &string[0];
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
while (next!=NULL)
|
1999-01-13 15:21:34 +00:00
|
|
|
{
|
|
|
|
*next = '\\';
|
|
|
|
current = next+1;
|
|
|
|
next = wcschr(next+1,'\\');
|
|
|
|
if (next!=NULL)
|
1999-03-19 05:55:55 +00:00
|
|
|
{
|
|
|
|
*next=0;
|
|
|
|
}
|
|
|
|
DPRINT("current '%w'\n",current);
|
|
|
|
Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
if (Fcb != NULL)
|
|
|
|
ExFreePool(Fcb);
|
|
|
|
if (ParentFcb != NULL)
|
|
|
|
ExFreePool(ParentFcb);
|
1999-06-27 23:06:50 +00:00
|
|
|
if(AbsFileName)
|
|
|
|
ExFreePool(AbsFileName);
|
|
|
|
return(Status);
|
1999-03-19 05:55:55 +00:00
|
|
|
}
|
|
|
|
Temp = Fcb;
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-03-19 05:55:55 +00:00
|
|
|
if (ParentFcb == NULL)
|
|
|
|
{
|
|
|
|
Fcb = ExAllocatePool(NonPagedPool,sizeof(VfatFCB));
|
|
|
|
memset(Fcb,0,sizeof(VfatFCB));
|
|
|
|
Fcb->ObjectName=Fcb->PathName;
|
|
|
|
}
|
1999-06-27 23:06:50 +00:00
|
|
|
else
|
|
|
|
Fcb = ParentFcb;
|
|
|
|
CHECKPOINT;
|
1999-03-19 05:55:55 +00:00
|
|
|
ParentFcb = Temp;
|
1999-01-13 15:21:34 +00:00
|
|
|
}
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-03-19 05:55:55 +00:00
|
|
|
FileObject->FsContext =(PVOID) &ParentFcb->NTRequiredFCB;
|
|
|
|
newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
|
|
|
|
memset(newCCB,0,sizeof(VfatCCB));
|
|
|
|
FileObject->FsContext2 = newCCB;
|
|
|
|
newCCB->pFcb=ParentFcb;
|
|
|
|
newCCB->PtrFileObject=FileObject;
|
|
|
|
ParentFcb->RefCount++;
|
|
|
|
//FIXME : initialize all fields in FCB and CCB
|
|
|
|
ParentFcb->nextFcb=pFirstFcb;
|
|
|
|
pFirstFcb=ParentFcb;
|
1999-01-13 15:21:34 +00:00
|
|
|
vfat_wcsncpy(ParentFcb->PathName,FileName,MAX_PATH);
|
1999-03-19 05:55:55 +00:00
|
|
|
ParentFcb->ObjectName=ParentFcb->PathName+(current-FileName);
|
|
|
|
ParentFcb->pDevExt=DeviceExt;
|
|
|
|
DPRINT("file open, fcb=%x\n",ParentFcb);
|
|
|
|
DPRINT("FileSize %d\n",ParentFcb->entry.FileSize);
|
|
|
|
if(Fcb) ExFreePool(Fcb);
|
|
|
|
if(AbsFileName)ExFreePool(AbsFileName);
|
1998-10-05 04:00:59 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-03-19 05:55:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
|
1998-10-05 04:00:59 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Tests if the device contains a filesystem that can be mounted
|
1998-12-30 18:43:27 +00:00
|
|
|
* by this fsd
|
1998-10-05 04:00:59 +00:00
|
|
|
*/
|
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
BootSector* Boot;
|
1999-01-05 12:04:08 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
Boot = ExAllocatePool(NonPagedPool,512);
|
1998-10-31 15:54:07 +00:00
|
|
|
|
|
|
|
VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
if (strncmp(Boot->SysType,"FAT12",5)==0 ||
|
1998-12-20 19:41:39 +00:00
|
|
|
strncmp(Boot->SysType,"FAT16",5)==0 ||
|
|
|
|
strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
ExFreePool(Boot);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
ExFreePool(Boot);
|
1999-01-04 12:08:54 +00:00
|
|
|
return(FALSE);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
|
1998-10-05 04:00:59 +00:00
|
|
|
PDEVICE_OBJECT DeviceToMount)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Mounts the device
|
|
|
|
*/
|
|
|
|
{
|
1998-10-31 15:54:07 +00:00
|
|
|
DPRINT("Mounting VFAT device...");
|
1998-10-05 04:00:59 +00:00
|
|
|
DPRINT("DeviceExt %x\n",DeviceExt);
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
DeviceExt->Boot = ExAllocatePool(NonPagedPool,512);
|
1998-10-31 15:54:07 +00:00
|
|
|
VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)DeviceExt->Boot);
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
|
|
|
|
DeviceExt->Boot->BytesPerSector);
|
|
|
|
|
|
|
|
DeviceExt->FATStart=DeviceExt->Boot->ReservedSectors;
|
|
|
|
DeviceExt->rootDirectorySectors=
|
|
|
|
(DeviceExt->Boot->RootEntries*32)/DeviceExt->Boot->BytesPerSector;
|
|
|
|
DeviceExt->rootStart=
|
|
|
|
DeviceExt->FATStart+DeviceExt->Boot->FATCount*DeviceExt->Boot->FATSectors;
|
|
|
|
DeviceExt->dataStart=DeviceExt->rootStart+DeviceExt->rootDirectorySectors;
|
|
|
|
DeviceExt->FATEntriesPerSector=DeviceExt->Boot->BytesPerSector/32;
|
|
|
|
DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
|
|
|
|
DeviceExt->Boot->BytesPerSector;
|
|
|
|
|
|
|
|
if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
|
|
|
|
{
|
|
|
|
DeviceExt->FatType = FAT12;
|
|
|
|
}
|
1998-12-20 19:41:39 +00:00
|
|
|
else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
|
|
|
|
{
|
|
|
|
DeviceExt->FatType = FAT32;
|
|
|
|
DeviceExt->rootDirectorySectors=DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
DeviceExt->rootStart=
|
|
|
|
DeviceExt->FATStart+DeviceExt->Boot->FATCount
|
|
|
|
* ((struct _BootSector32 *)( DeviceExt->Boot))->FATSectors32;
|
|
|
|
DeviceExt->dataStart=DeviceExt->rootStart;
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DeviceExt->FatType = FAT16;
|
|
|
|
}
|
1998-10-31 15:54:07 +00:00
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
// with FAT32 it's not a good idea to load always fat in memory
|
|
|
|
// because on a 8GB partition with 2 KO clusters, the fat = 8 MO
|
|
|
|
if(DeviceExt->FatType!=FAT32)
|
|
|
|
{
|
|
|
|
DeviceExt->FAT = ExAllocatePool(NonPagedPool, BLOCKSIZE*DeviceExt->Boot->FATSectors);
|
|
|
|
VFATReadSectors(DeviceToMount, DeviceExt->FATStart, DeviceExt->Boot->FATSectors, (UCHAR *)DeviceExt->FAT);
|
|
|
|
}
|
1998-12-30 18:43:27 +00:00
|
|
|
return STATUS_SUCCESS;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Load a cluster from the physical device
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
ULONG Sector;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
|
|
|
|
DeviceExt,Buffer,Cluster);
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
Sector = ClusterToSector(DeviceExt, Cluster);
|
|
|
|
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,
|
|
|
|
Sector,
|
|
|
|
DeviceExt->Boot->SectorsPerCluster,
|
|
|
|
Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Write a cluster to the physical device
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
|
|
|
ULONG Sector;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
|
|
|
|
DeviceExt,Buffer,Cluster);
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
Sector = ClusterToSector(DeviceExt, Cluster);
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,
|
|
|
|
Sector,
|
|
|
|
DeviceExt->Boot->SectorsPerCluster,
|
|
|
|
Buffer);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
|
1998-12-19 19:26:02 +00:00
|
|
|
PVOID Buffer, ULONG Length, ULONG ReadOffset,
|
|
|
|
PULONG LengthRead)
|
1998-10-05 04:00:59 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Reads data from a file
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG CurrentCluster;
|
|
|
|
ULONG FileOffset;
|
|
|
|
ULONG FirstCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
PVfatFCB Fcb;
|
|
|
|
PVOID Temp;
|
1998-10-05 04:00:59 +00:00
|
|
|
ULONG TempLength;
|
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
/* PRECONDITION */
|
|
|
|
assert(DeviceExt != NULL);
|
|
|
|
assert(DeviceExt->BytesPerCluster != 0);
|
1999-03-19 05:55:55 +00:00
|
|
|
assert(FileObject != NULL);
|
|
|
|
assert(FileObject->FsContext != NULL);
|
1999-01-05 12:04:08 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
|
|
|
|
"Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
|
|
|
|
Length,ReadOffset);
|
|
|
|
|
|
|
|
Fcb = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
|
1998-12-20 19:41:39 +00:00
|
|
|
if (DeviceExt->FatType == FAT32)
|
1999-01-05 12:04:08 +00:00
|
|
|
CurrentCluster = Fcb->entry.FirstCluster
|
|
|
|
+Fcb->entry.FirstClusterHigh*65536;
|
1998-12-20 19:41:39 +00:00
|
|
|
else
|
1999-01-04 12:08:54 +00:00
|
|
|
CurrentCluster = Fcb->entry.FirstCluster;
|
1999-01-13 15:21:34 +00:00
|
|
|
FirstCluster=CurrentCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
if (ReadOffset >= Fcb->entry.FileSize
|
|
|
|
&& !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
|
1998-12-19 19:26:02 +00:00
|
|
|
{
|
|
|
|
return(STATUS_END_OF_FILE);
|
|
|
|
}
|
1999-01-13 15:21:34 +00:00
|
|
|
if ((ReadOffset + Length) > Fcb->entry.FileSize
|
|
|
|
&& !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
|
1998-12-19 19:26:02 +00:00
|
|
|
{
|
|
|
|
Length = Fcb->entry.FileSize - ReadOffset;
|
|
|
|
}
|
|
|
|
*LengthRead = 0;
|
1999-03-19 05:55:55 +00:00
|
|
|
/* FIXME: optimize by remembering the last cluster read and using if possible */
|
|
|
|
Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
|
|
|
|
if(!Temp) return STATUS_UNSUCCESSFUL;
|
1999-01-13 15:21:34 +00:00
|
|
|
if (FirstCluster==1)
|
|
|
|
{ //root of FAT16 or FAT12
|
|
|
|
CurrentCluster=DeviceExt->rootStart+ReadOffset
|
|
|
|
/(DeviceExt->BytesPerCluster)*DeviceExt->Boot->SectorsPerCluster;
|
1999-01-04 12:08:54 +00:00
|
|
|
}
|
1999-01-13 15:21:34 +00:00
|
|
|
else
|
|
|
|
for (FileOffset=0; FileOffset < ReadOffset / DeviceExt->BytesPerCluster
|
|
|
|
; FileOffset++)
|
|
|
|
{
|
|
|
|
CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
|
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
CHECKPOINT;
|
1998-10-05 04:00:59 +00:00
|
|
|
if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
|
1999-01-13 15:21:34 +00:00
|
|
|
{
|
|
|
|
if (FirstCluster==1)
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
|
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
TempLength = min(Length,DeviceExt->BytesPerCluster -
|
|
|
|
(ReadOffset % DeviceExt->BytesPerCluster));
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
|
1998-10-05 04:00:59 +00:00
|
|
|
TempLength);
|
|
|
|
|
1998-12-19 19:26:02 +00:00
|
|
|
(*LengthRead) = (*LengthRead) + TempLength;
|
1998-10-05 04:00:59 +00:00
|
|
|
Length = Length - TempLength;
|
|
|
|
Buffer = Buffer + TempLength;
|
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
CHECKPOINT;
|
1999-01-13 15:21:34 +00:00
|
|
|
while (Length >= DeviceExt->BytesPerCluster)
|
|
|
|
{
|
|
|
|
if (FirstCluster==1)
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
|
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Buffer);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATLoadCluster(DeviceExt,Buffer,CurrentCluster);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
|
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
if (CurrentCluster == 0xffffffff)
|
1999-01-20 19:02:05 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(Temp);
|
1999-01-20 19:02:05 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1998-12-19 19:26:02 +00:00
|
|
|
(*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
|
1998-10-05 04:00:59 +00:00
|
|
|
Buffer = Buffer + DeviceExt->BytesPerCluster;
|
|
|
|
Length = Length - DeviceExt->BytesPerCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
}
|
|
|
|
CHECKPOINT;
|
1998-10-05 04:00:59 +00:00
|
|
|
if (Length > 0)
|
1999-03-19 05:55:55 +00:00
|
|
|
{
|
1998-12-19 19:26:02 +00:00
|
|
|
(*LengthRead) = (*LengthRead) + Length;
|
1999-01-20 19:02:05 +00:00
|
|
|
if (FirstCluster==1)
|
1999-03-19 05:55:55 +00:00
|
|
|
{
|
1999-01-20 19:02:05 +00:00
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
|
1999-03-19 05:55:55 +00:00
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
|
|
|
CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
}
|
1999-01-20 19:02:05 +00:00
|
|
|
else
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
|
1999-01-20 19:02:05 +00:00
|
|
|
CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
|
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
memcpy(Buffer, Temp, Length);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(Temp);
|
1998-10-05 04:00:59 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
|
1998-12-20 19:41:39 +00:00
|
|
|
PVOID Buffer, ULONG Length, ULONG WriteOffset)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Writes data to file
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG CurrentCluster;
|
|
|
|
ULONG FileOffset;
|
|
|
|
ULONG FirstCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
PVfatFCB Fcb;
|
|
|
|
PVfatCCB pCcb;
|
|
|
|
PVOID Temp;
|
1999-01-13 15:21:34 +00:00
|
|
|
ULONG TempLength,Length2=Length;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
|
|
|
/* Locate the first cluster of the file */
|
1999-03-19 05:55:55 +00:00
|
|
|
assert(FileObject);
|
|
|
|
pCcb=(PVfatCCB)(FileObject->FsContext2);
|
|
|
|
assert(pCcb);
|
|
|
|
Fcb = pCcb->pFcb;
|
1999-01-20 13:05:53 +00:00
|
|
|
assert(Fcb);
|
1998-12-20 19:41:39 +00:00
|
|
|
if (DeviceExt->FatType == FAT32)
|
|
|
|
CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
|
|
|
|
else
|
|
|
|
CurrentCluster = Fcb->entry.FirstCluster;
|
1999-01-13 15:21:34 +00:00
|
|
|
FirstCluster=CurrentCluster;
|
1999-03-19 05:55:55 +00:00
|
|
|
/* Allocate a buffer to hold 1 cluster of data */
|
|
|
|
|
|
|
|
Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
|
|
|
|
assert(Temp);
|
1998-12-20 19:41:39 +00:00
|
|
|
|
|
|
|
/* Find the cluster according to the offset in the file */
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
if (CurrentCluster==1)
|
|
|
|
{ //root of FAT16 or FAT12
|
|
|
|
CurrentCluster=DeviceExt->rootStart+WriteOffset
|
|
|
|
/DeviceExt->BytesPerCluster*DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (CurrentCluster==0)
|
1999-01-20 13:05:53 +00:00
|
|
|
{// file of size 0 : allocate first cluster
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster=GetNextWriteCluster(DeviceExt,0);
|
|
|
|
if (DeviceExt->FatType == FAT32)
|
|
|
|
{
|
|
|
|
Fcb->entry.FirstClusterHigh=CurrentCluster>>16;
|
|
|
|
Fcb->entry.FirstCluster=CurrentCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Fcb->entry.FirstCluster=CurrentCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for (FileOffset=0; FileOffset < WriteOffset / DeviceExt->BytesPerCluster; FileOffset++)
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
If the offset in the cluster doesn't fall on the cluster boundary then
|
|
|
|
we have to write only from the specified offset
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
|
1999-01-13 15:21:34 +00:00
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
CHECKPOINT;
|
1999-01-13 15:21:34 +00:00
|
|
|
TempLength = min(Length,DeviceExt->BytesPerCluster -
|
1998-12-20 19:41:39 +00:00
|
|
|
(WriteOffset % DeviceExt->BytesPerCluster));
|
1999-01-13 15:21:34 +00:00
|
|
|
/* Read in the existing cluster data */
|
1999-03-19 05:55:55 +00:00
|
|
|
if (FirstCluster==1)
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
|
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
|
|
|
else
|
|
|
|
VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
/* Overwrite the last parts of the data as necessary */
|
1999-03-19 05:55:55 +00:00
|
|
|
memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster), Buffer,
|
1998-12-20 19:41:39 +00:00
|
|
|
TempLength);
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
/* Write the cluster back */
|
|
|
|
if (FirstCluster==1)
|
|
|
|
{
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
|
1999-03-19 05:55:55 +00:00
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
1999-01-13 15:21:34 +00:00
|
|
|
else
|
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
|
1999-01-13 15:21:34 +00:00
|
|
|
CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
|
|
|
|
}
|
|
|
|
Length2 -= TempLength;
|
|
|
|
Buffer = Buffer + TempLength;
|
|
|
|
}
|
1998-12-20 19:41:39 +00:00
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
/* Write the buffer in chunks of 1 cluster */
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
while (Length2 >= DeviceExt->BytesPerCluster)
|
1999-01-04 12:08:54 +00:00
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
CHECKPOINT;
|
1999-01-04 12:08:54 +00:00
|
|
|
if (CurrentCluster == 0)
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(Temp);
|
1999-01-04 12:08:54 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
1999-01-13 15:21:34 +00:00
|
|
|
if (FirstCluster==1)
|
|
|
|
{
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
|
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Buffer);
|
|
|
|
CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VFATWriteCluster(DeviceExt,Buffer,CurrentCluster);
|
|
|
|
CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
1999-01-13 15:21:34 +00:00
|
|
|
Buffer = Buffer + DeviceExt->BytesPerCluster;
|
|
|
|
Length2 -= DeviceExt->BytesPerCluster;
|
|
|
|
}
|
1998-12-20 19:41:39 +00:00
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
/* Write the remainder */
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
if (Length2 > 0)
|
1999-01-04 12:08:54 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
CHECKPOINT;
|
1999-01-04 12:08:54 +00:00
|
|
|
if (CurrentCluster == 0)
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(Temp);
|
1999-01-04 12:08:54 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
CHECKPOINT;
|
1999-01-13 15:21:34 +00:00
|
|
|
/* Read in the existing cluster data */
|
1999-03-19 05:55:55 +00:00
|
|
|
if (FirstCluster==1)
|
|
|
|
VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
|
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
|
|
|
else
|
|
|
|
VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
|
|
|
|
CHECKPOINT;
|
|
|
|
memcpy(Temp, Buffer, Length2);
|
|
|
|
CHECKPOINT;
|
1999-01-13 15:21:34 +00:00
|
|
|
if (FirstCluster==1)
|
|
|
|
{
|
|
|
|
VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
|
1999-03-19 05:55:55 +00:00
|
|
|
,DeviceExt->Boot->SectorsPerCluster,Temp);
|
1999-01-13 15:21:34 +00:00
|
|
|
}
|
|
|
|
else
|
1999-03-19 05:55:55 +00:00
|
|
|
VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
|
1999-01-04 12:08:54 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
CHECKPOINT;
|
1999-01-04 12:08:54 +00:00
|
|
|
//FIXME : set last write time and date
|
1999-01-13 15:21:34 +00:00
|
|
|
if(Fcb->entry.FileSize<WriteOffset+Length
|
|
|
|
&& !(Fcb->entry.Attrib &FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
Fcb->entry.FileSize=WriteOffset+Length;
|
1999-01-13 15:21:34 +00:00
|
|
|
// update entry in directory
|
1999-03-19 05:55:55 +00:00
|
|
|
updEntry(DeviceExt,FileObject);
|
1999-01-13 15:21:34 +00:00
|
|
|
}
|
1999-03-19 05:55:55 +00:00
|
|
|
ExFreePool(Temp);
|
1998-12-20 19:41:39 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Close a file
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
PFILE_OBJECT FileObject = Stack->FileObject;
|
|
|
|
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
NTSTATUS Status;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject, Irp);
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
Status = FsdCloseFile(DeviceExtension,FileObject);
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
1999-06-27 23:06:50 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Create or open a file
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1999-01-20 13:05:53 +00:00
|
|
|
PIO_STACK_LOCATION Stack;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
NTSTATUS Status=STATUS_SUCCESS;
|
|
|
|
PDEVICE_EXTENSION DeviceExt;
|
|
|
|
ULONG RequestedDisposition,RequestedOptions;
|
|
|
|
PVfatCCB pCcb;
|
|
|
|
PVfatFCB pFcb;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
1999-01-20 13:05:53 +00:00
|
|
|
assert(DeviceObject);
|
|
|
|
assert(Irp);
|
|
|
|
if(DeviceObject->Size==sizeof(DEVICE_OBJECT))
|
|
|
|
{// DevieObject represent FileSystem instead of logical volume
|
|
|
|
DbgPrint("FsdCreate called with file system\n");
|
|
|
|
Irp->IoStatus.Status=Status;
|
|
|
|
Irp->IoStatus.Information=FILE_OPENED;
|
|
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
return(Status);
|
|
|
|
}
|
1998-12-30 22:48:14 +00:00
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
1999-01-20 13:05:53 +00:00
|
|
|
assert(Stack);
|
1999-01-13 15:21:34 +00:00
|
|
|
RequestedDisposition = ((Stack->Parameters.Create.Options>>24)&0xff);
|
|
|
|
RequestedOptions=Stack->Parameters.Create.Options&FILE_VALID_OPTION_FLAGS;
|
1998-12-30 22:48:14 +00:00
|
|
|
FileObject = Stack->FileObject;
|
1998-10-05 04:00:59 +00:00
|
|
|
DeviceExt = DeviceObject->DeviceExtension;
|
1999-01-20 13:05:53 +00:00
|
|
|
assert(DeviceExt);
|
|
|
|
ExAcquireResourceExclusiveLite(&(DeviceExt->Resource),TRUE);
|
1998-10-05 04:00:59 +00:00
|
|
|
Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-01-20 13:05:53 +00:00
|
|
|
Irp->IoStatus.Information = 0;
|
1999-01-13 15:21:34 +00:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if(RequestedDisposition==FILE_CREATE
|
|
|
|
||RequestedDisposition==FILE_OPEN_IF
|
|
|
|
||RequestedDisposition==FILE_OVERWRITE_IF)
|
|
|
|
{
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1999-01-20 13:05:53 +00:00
|
|
|
Status=addEntry(DeviceExt,FileObject,RequestedOptions
|
|
|
|
,(Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
|
|
|
|
if(NT_SUCCESS(Status))
|
|
|
|
Irp->IoStatus.Information = FILE_CREATED;
|
|
|
|
// FIXME set size if AllocationSize requested
|
|
|
|
// FIXME set extended attributes ?
|
|
|
|
// FIXME set share access
|
|
|
|
// IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
|
|
|
|
// ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
|
1999-01-13 15:21:34 +00:00
|
|
|
}
|
|
|
|
}
|
1999-01-20 13:05:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if(RequestedDisposition==FILE_CREATE)
|
|
|
|
{
|
|
|
|
Irp->IoStatus.Information = FILE_EXISTS;
|
|
|
|
Status=STATUS_OBJECT_NAME_COLLISION;
|
|
|
|
}
|
|
|
|
pCcb=FileObject->FsContext2;
|
|
|
|
pFcb=pCcb->pFcb;
|
|
|
|
if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
|
|
|
|
&& (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
{
|
|
|
|
Status=STATUS_FILE_IS_A_DIRECTORY;
|
|
|
|
}
|
|
|
|
if( (RequestedOptions&FILE_DIRECTORY_FILE)
|
|
|
|
&& !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
{
|
|
|
|
Status=STATUS_NOT_A_DIRECTORY;
|
|
|
|
}
|
|
|
|
// FIXME : test share access
|
|
|
|
// FIXME : test write access if requested
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
FsdCloseFile(DeviceExt,FileObject);
|
|
|
|
else Irp->IoStatus.Information = FILE_OPENED;
|
|
|
|
// FIXME : make supersed or overwrite if requested
|
|
|
|
}
|
1999-06-27 23:06:50 +00:00
|
|
|
CHECKPOINT;
|
1998-10-05 04:00:59 +00:00
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
1999-01-20 13:05:53 +00:00
|
|
|
ExReleaseResourceForThreadLite(&(DeviceExt->Resource),ExGetCurrentResourceThread());
|
1998-12-30 22:48:14 +00:00
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Write to a file
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
1998-12-20 19:41:39 +00:00
|
|
|
ULONG Length;
|
|
|
|
PVOID Buffer;
|
|
|
|
ULONG Offset;
|
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
PFILE_OBJECT FileObject = Stack->FileObject;
|
|
|
|
PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
|
|
|
|
NTSTATUS Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
|
|
|
|
|
|
|
|
Length = Stack->Parameters.Write.Length;
|
|
|
|
Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
1999-05-11 19:32:15 +00:00
|
|
|
Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
|
1998-12-20 19:41:39 +00:00
|
|
|
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
Irp->IoStatus.Information = Length;
|
|
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return(Status);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Read from a file
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
ULONG Length;
|
|
|
|
PVOID Buffer;
|
|
|
|
ULONG Offset;
|
1999-01-05 12:04:08 +00:00
|
|
|
PIO_STACK_LOCATION Stack;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
PDEVICE_EXTENSION DeviceExt;
|
1998-10-05 04:00:59 +00:00
|
|
|
NTSTATUS Status;
|
1998-12-19 19:26:02 +00:00
|
|
|
ULONG LengthRead;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
|
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
/* Precondition / Initialization */
|
|
|
|
assert(Irp != NULL);
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
assert(Stack != NULL);
|
|
|
|
FileObject = Stack->FileObject;
|
|
|
|
assert(FileObject != NULL);
|
|
|
|
DeviceExt = DeviceObject->DeviceExtension;
|
|
|
|
assert(DeviceExt != NULL);
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
Length = Stack->Parameters.Read.Length;
|
|
|
|
Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
1999-05-11 19:32:15 +00:00
|
|
|
Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
|
|
|
Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
|
1998-12-19 19:26:02 +00:00
|
|
|
&LengthRead);
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
Irp->IoStatus.Status = Status;
|
1998-12-19 19:26:02 +00:00
|
|
|
Irp->IoStatus.Information = LengthRead;
|
1998-10-05 04:00:59 +00:00
|
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
1998-10-31 15:54:07 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Mount the filesystem
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PDEVICE_EXTENSION DeviceExt;
|
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
IoCreateDevice(VFATDriverObject,
|
1998-10-05 04:00:59 +00:00
|
|
|
sizeof(DEVICE_EXTENSION),
|
|
|
|
NULL,
|
|
|
|
FILE_DEVICE_FILE_SYSTEM,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
&DeviceObject);
|
|
|
|
DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
|
|
|
|
DeviceExt = (PVOID)DeviceObject->DeviceExtension;
|
1998-12-30 18:43:27 +00:00
|
|
|
// use same vpb as device disk
|
|
|
|
DeviceObject->Vpb=DeviceToMount->Vpb;
|
1998-10-05 04:00:59 +00:00
|
|
|
FsdMountDevice(DeviceExt,DeviceToMount);
|
1998-12-30 18:43:27 +00:00
|
|
|
DeviceObject->Vpb->Flags |= VPB_MOUNTED;
|
1998-10-05 04:00:59 +00:00
|
|
|
DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
|
|
|
|
DeviceToMount);
|
1999-05-05 11:23:46 +00:00
|
|
|
|
1999-05-13 18:02:24 +00:00
|
|
|
/* read serial number */
|
1999-05-05 11:23:46 +00:00
|
|
|
if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
|
1999-05-13 18:02:24 +00:00
|
|
|
DeviceObject->Vpb->SerialNumber =
|
|
|
|
((struct _BootSector *)(DeviceExt->Boot))->VolumeID;
|
1999-05-05 11:23:46 +00:00
|
|
|
else if (DeviceExt->FatType == FAT32)
|
1999-05-13 18:02:24 +00:00
|
|
|
DeviceObject->Vpb->SerialNumber =
|
|
|
|
((struct _BootSector32 *)(DeviceExt->Boot))->VolumeID;
|
|
|
|
|
|
|
|
/* read volume label */
|
|
|
|
ReadVolumeLabel (DeviceExt, DeviceObject->Vpb);
|
1999-05-05 11:23:46 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: File system control
|
|
|
|
*/
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
1998-12-20 19:41:39 +00:00
|
|
|
// PVPB vpb = Stack->Parameters.Mount.Vpb;
|
1998-10-05 04:00:59 +00:00
|
|
|
PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
|
|
|
|
NTSTATUS Status;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
// DPRINT("VFAT FSC\n");
|
|
|
|
DbgPrint("VFAT FSC\n");
|
1998-10-05 04:00:59 +00:00
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
/* FIXME: should make sure that this is actually a mount request! */
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
if (FsdHasFileSystem(DeviceToMount))
|
|
|
|
{
|
|
|
|
Status = FsdMount(DeviceToMount);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-10-31 15:54:07 +00:00
|
|
|
DPRINT("VFAT: Unrecognized Volume\n");
|
1998-10-05 04:00:59 +00:00
|
|
|
Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
|
|
}
|
1998-10-31 15:54:07 +00:00
|
|
|
DPRINT("VFAT File system successfully mounted\n");
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
Irp->IoStatus.Information = 0;
|
1999-03-19 05:55:55 +00:00
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
NTSTATUS FsdGetStandardInformation(PVfatFCB FCB, PDEVICE_OBJECT DeviceObject,
|
1998-12-30 18:43:27 +00:00
|
|
|
PFILE_STANDARD_INFORMATION StandardInfo)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the standard file information
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-05 12:04:08 +00:00
|
|
|
PDEVICE_EXTENSION DeviceExtension;
|
1998-12-20 19:41:39 +00:00
|
|
|
unsigned long AllocSize;
|
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
/* PRECONDITION */
|
|
|
|
assert(DeviceExtension != NULL);
|
|
|
|
assert(DeviceExtension->BytesPerCluster != 0);
|
|
|
|
assert(StandardInfo != NULL);
|
|
|
|
assert(FCB != NULL);
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
|
|
|
|
|
|
|
|
/* Make allocsize a rounded up multiple of BytesPerCluster */
|
1998-12-30 18:43:27 +00:00
|
|
|
AllocSize = ((FCB->entry.FileSize + DeviceExtension->BytesPerCluster - 1) /
|
|
|
|
DeviceExtension->BytesPerCluster) *
|
|
|
|
DeviceExtension->BytesPerCluster;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
|
|
|
StandardInfo->AllocationSize = RtlConvertUlongToLargeInteger(AllocSize);
|
|
|
|
StandardInfo->EndOfFile = RtlConvertUlongToLargeInteger(FCB->entry.FileSize);
|
|
|
|
StandardInfo->NumberOfLinks = 0;
|
|
|
|
StandardInfo->DeletePending = FALSE;
|
|
|
|
if((FCB->entry.Attrib & 0x10)>0) {
|
|
|
|
StandardInfo->Directory = TRUE;
|
|
|
|
} else {
|
|
|
|
StandardInfo->Directory = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1999-04-14 00:52:19 +00:00
|
|
|
NTSTATUS FsdSetPositionInformation(PFILE_OBJECT FileObject,
|
|
|
|
PVfatFCB FCB,
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_POSITION_INFORMATION PositionInfo)
|
|
|
|
{
|
1999-04-18 08:56:23 +00:00
|
|
|
DPRINT("FsdSetPositionInformation()\n");
|
1999-04-14 00:52:19 +00:00
|
|
|
|
1999-04-18 08:56:23 +00:00
|
|
|
DPRINT("PositionInfo %x\n", PositionInfo);
|
1999-06-27 23:06:50 +00:00
|
|
|
DPRINT("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
|
1999-04-14 00:52:19 +00:00
|
|
|
memcpy(&FileObject->CurrentByteOffset,&PositionInfo->CurrentByteOffset,
|
|
|
|
sizeof(LARGE_INTEGER));
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS FsdGetPositionInformation(PFILE_OBJECT FileObject,
|
|
|
|
PVfatFCB FCB,
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_POSITION_INFORMATION PositionInfo)
|
|
|
|
{
|
1999-04-18 08:56:23 +00:00
|
|
|
DPRINT("FsdGetPositionInformation()\n");
|
1999-04-14 00:52:19 +00:00
|
|
|
|
|
|
|
memcpy(&PositionInfo->CurrentByteOffset, &FileObject->CurrentByteOffset,
|
|
|
|
sizeof(LARGE_INTEGER));
|
1999-06-27 23:06:50 +00:00
|
|
|
DPRINT("Getting position %x\n", PositionInfo->CurrentByteOffset.u.LowPart);
|
1999-04-14 00:52:19 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-04-21 19:16:31 +00:00
|
|
|
|
|
|
|
NTSTATUS FsdGetBasicInformation(PFILE_OBJECT FileObject,
|
|
|
|
PVfatFCB FCB,
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_BASIC_INFORMATION BasicInfo)
|
|
|
|
{
|
|
|
|
DPRINT("FsdGetBasicInformation()\n");
|
1999-05-15 17:25:02 +00:00
|
|
|
|
|
|
|
FsdDosDateTimeToFileTime(FCB->entry.CreationDate,FCB->entry.CreationTime,
|
|
|
|
&BasicInfo->CreationTime);
|
|
|
|
FsdDosDateTimeToFileTime(FCB->entry.AccessDate,0,
|
|
|
|
&BasicInfo->LastAccessTime);
|
|
|
|
FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
|
|
|
|
&BasicInfo->LastWriteTime);
|
|
|
|
FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
|
|
|
|
&BasicInfo->ChangeTime);
|
1999-04-21 19:16:31 +00:00
|
|
|
|
|
|
|
BasicInfo->FileAttributes = FCB->entry.Attrib;
|
|
|
|
|
|
|
|
DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-04-14 00:52:19 +00:00
|
|
|
|
1999-06-27 23:06:50 +00:00
|
|
|
NTSTATUS FsdSetDispositionInformation(PFILE_OBJECT FileObject,
|
|
|
|
PVfatFCB FCB,
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_DISPOSITION_INFORMATION DispositionInfo)
|
|
|
|
{
|
|
|
|
DPRINT("FsdSetDispositionInformation()\n");
|
|
|
|
|
|
|
|
FileObject->DeletePending = DispositionInfo->DeleteFile;
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
1998-12-30 18:43:27 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the specified file information
|
|
|
|
*/
|
1998-12-20 19:41:39 +00:00
|
|
|
{
|
1999-01-04 12:08:54 +00:00
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FILE_INFORMATION_CLASS FileInformationClass =
|
|
|
|
Stack->Parameters.QueryFile.FileInformationClass;
|
|
|
|
PFILE_OBJECT FileObject = NULL;
|
|
|
|
PVfatFCB FCB = NULL;
|
|
|
|
// PVfatCCB CCB = NULL;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-01-04 12:08:54 +00:00
|
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
|
|
void *SystemBuffer;
|
1999-01-01 22:33:38 +00:00
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
/* PRECONDITION */
|
|
|
|
assert(DeviceObject != NULL);
|
|
|
|
assert(Irp != NULL);
|
|
|
|
|
|
|
|
/* INITIALIZATION */
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
|
1998-12-20 19:41:39 +00:00
|
|
|
FileObject = Stack->FileObject;
|
1999-01-04 12:08:54 +00:00
|
|
|
// CCB = (PVfatCCB)(FileObject->FsContext2);
|
1998-12-30 18:43:27 +00:00
|
|
|
// FCB = CCB->Buffer; // Should be CCB->FCB???
|
1999-01-04 12:08:54 +00:00
|
|
|
FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
// FIXME : determine Buffer for result :
|
|
|
|
if (Irp->MdlAddress)
|
|
|
|
SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
|
|
else
|
|
|
|
SystemBuffer = Irp->UserBuffer;
|
|
|
|
// SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
1998-12-20 19:41:39 +00:00
|
|
|
|
|
|
|
switch(FileInformationClass) {
|
|
|
|
case FileStandardInformation:
|
|
|
|
RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
|
1999-01-04 12:08:54 +00:00
|
|
|
break;
|
1999-04-14 00:52:19 +00:00
|
|
|
case FilePositionInformation:
|
|
|
|
RC = FsdGetPositionInformation(FileObject,
|
|
|
|
FCB,
|
|
|
|
DeviceObject,
|
|
|
|
SystemBuffer);
|
|
|
|
break;
|
1999-04-21 19:16:31 +00:00
|
|
|
case FileBasicInformation:
|
|
|
|
RC = FsdGetBasicInformation(FileObject,
|
|
|
|
FCB,
|
|
|
|
DeviceObject,
|
|
|
|
SystemBuffer);
|
|
|
|
break;
|
1999-01-01 22:33:38 +00:00
|
|
|
default:
|
1999-01-04 12:08:54 +00:00
|
|
|
RC=STATUS_NOT_IMPLEMENTED;
|
1998-12-20 19:41:39 +00:00
|
|
|
}
|
|
|
|
|
1999-04-21 19:16:31 +00:00
|
|
|
Irp->IoStatus.Status = RC;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
1998-12-20 19:41:39 +00:00
|
|
|
return RC;
|
|
|
|
}
|
|
|
|
|
1999-04-14 00:52:19 +00:00
|
|
|
NTSTATUS FsdSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the specified file information
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FILE_INFORMATION_CLASS FileInformationClass;
|
|
|
|
PFILE_OBJECT FileObject = NULL;
|
|
|
|
PVfatFCB FCB = NULL;
|
|
|
|
// PVfatCCB CCB = NULL;
|
|
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
|
|
PVOID SystemBuffer;
|
|
|
|
|
|
|
|
/* PRECONDITION */
|
|
|
|
assert(DeviceObject != NULL);
|
|
|
|
assert(Irp != NULL);
|
|
|
|
|
1999-04-18 08:56:23 +00:00
|
|
|
DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
|
1999-04-14 00:52:19 +00:00
|
|
|
DeviceObject,Irp);
|
|
|
|
|
|
|
|
/* INITIALIZATION */
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
|
|
|
|
FileObject = Stack->FileObject;
|
|
|
|
FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
|
|
|
|
|
|
|
|
// FIXME : determine Buffer for result :
|
|
|
|
if (Irp->MdlAddress)
|
|
|
|
SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
|
|
else
|
|
|
|
SystemBuffer = Irp->UserBuffer;
|
|
|
|
// SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
1999-04-18 08:56:23 +00:00
|
|
|
DPRINT("FileInformationClass %d\n",FileInformationClass);
|
|
|
|
DPRINT("SystemBuffer %x\n",SystemBuffer);
|
1999-04-14 00:52:19 +00:00
|
|
|
|
|
|
|
switch(FileInformationClass)
|
|
|
|
{
|
|
|
|
case FilePositionInformation:
|
|
|
|
RC = FsdSetPositionInformation(FileObject,
|
|
|
|
FCB,
|
|
|
|
DeviceObject,
|
|
|
|
SystemBuffer);
|
|
|
|
break;
|
1999-06-27 23:06:50 +00:00
|
|
|
case FileDispositionInformation:
|
|
|
|
RC = FsdSetDispositionInformation(FileObject,
|
|
|
|
FCB,
|
|
|
|
DeviceObject,
|
|
|
|
SystemBuffer);
|
|
|
|
break;
|
1999-04-14 00:52:19 +00:00
|
|
|
default:
|
|
|
|
RC = STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
1999-04-21 19:16:31 +00:00
|
|
|
Irp->IoStatus.Status = RC;
|
|
|
|
Irp->IoStatus.Information = 0;
|
1999-04-14 00:52:19 +00:00
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return RC;
|
|
|
|
}
|
1999-04-21 19:16:31 +00:00
|
|
|
|
1999-04-23 11:54:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS FsdGetFsVolumeInformation(PFILE_OBJECT FileObject,
|
|
|
|
PVfatFCB FCB,
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_FS_VOLUME_INFORMATION FsVolumeInfo)
|
|
|
|
{
|
|
|
|
DPRINT("FsdGetFsVolumeInformation()\n");
|
|
|
|
DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
|
|
|
|
|
|
|
|
if (!FsVolumeInfo)
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
1999-05-05 11:23:46 +00:00
|
|
|
|
|
|
|
/* valid entries */
|
|
|
|
FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
|
|
|
|
FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
|
|
|
|
wcscpy (FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel);
|
|
|
|
|
1999-04-23 11:54:47 +00:00
|
|
|
/* dummy entries */
|
1999-04-27 14:15:56 +00:00
|
|
|
FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
|
1999-04-23 11:54:47 +00:00
|
|
|
FsVolumeInfo->SupportsObjects = FALSE;
|
|
|
|
|
|
|
|
DPRINT("Finished FsdGetFsVolumeInformation()\n");
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-06 17:59:55 +00:00
|
|
|
NTSTATUS FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo)
|
1999-04-23 11:54:47 +00:00
|
|
|
{
|
|
|
|
DPRINT("FsdGetFsAttributeInformation()\n");
|
|
|
|
DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
|
|
|
|
|
|
|
|
if (!FsAttributeInfo)
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
1999-05-05 11:23:46 +00:00
|
|
|
FsAttributeInfo->FileSystemAttributes = FS_CASE_IS_PRESERVED;
|
|
|
|
FsAttributeInfo->MaximumComponentNameLength = 255;
|
1999-04-23 11:54:47 +00:00
|
|
|
FsAttributeInfo->FileSystemNameLength = 3;
|
|
|
|
wcscpy (FsAttributeInfo->FileSystemName, L"FAT");
|
|
|
|
|
|
|
|
DPRINT("Finished FsdGetFsAttributeInformation()\n");
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-05-06 17:59:55 +00:00
|
|
|
NTSTATUS FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
|
|
|
|
PFILE_FS_SIZE_INFORMATION FsSizeInfo)
|
|
|
|
{
|
|
|
|
PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
DPRINT("FsdGetFsSizeInformation()\n");
|
|
|
|
DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
|
|
|
|
|
|
|
|
if (!FsSizeInfo)
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
|
|
|
|
if (DeviceExt->FatType == FAT32)
|
|
|
|
{
|
|
|
|
struct _BootSector32 *BootSect = (struct _BootSector32 *)DeviceExt->Boot;
|
|
|
|
|
|
|
|
if (BootSect->Sectors)
|
|
|
|
FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
|
|
|
|
else
|
|
|
|
FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
|
|
|
|
|
|
|
|
FsSizeInfo->AvailableAllocationUnits.QuadPart =
|
|
|
|
FAT32CountAvailableClusters(DeviceExt);
|
|
|
|
|
|
|
|
FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
|
|
|
|
FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct _BootSector *BootSect = (struct _BootSector *)DeviceExt->Boot;
|
|
|
|
|
|
|
|
if (BootSect->Sectors)
|
|
|
|
FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
|
|
|
|
else
|
|
|
|
FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
|
|
|
|
|
|
|
|
if (DeviceExt->FatType == FAT16)
|
|
|
|
FsSizeInfo->AvailableAllocationUnits.QuadPart =
|
|
|
|
FAT16CountAvailableClusters(DeviceExt);
|
|
|
|
else
|
|
|
|
FsSizeInfo->AvailableAllocationUnits.QuadPart =
|
|
|
|
FAT12CountAvailableClusters(DeviceExt);
|
|
|
|
|
|
|
|
FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
|
|
|
|
FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINT("Finished FsdGetFsSizeInformation()\n");
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-04-23 11:54:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Retrieve the specified file information
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FILE_INFORMATION_CLASS FileInformationClass =
|
|
|
|
Stack->Parameters.QueryVolume.FileInformationClass;
|
|
|
|
PFILE_OBJECT FileObject = NULL;
|
|
|
|
PVfatFCB FCB = NULL;
|
|
|
|
// PVfatCCB CCB = NULL;
|
|
|
|
|
|
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
|
|
void *SystemBuffer;
|
|
|
|
|
|
|
|
/* PRECONDITION */
|
|
|
|
assert(DeviceObject != NULL);
|
|
|
|
assert(Irp != NULL);
|
|
|
|
|
|
|
|
DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
|
|
|
|
DeviceObject,Irp);
|
|
|
|
|
|
|
|
/* INITIALIZATION */
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FileInformationClass = Stack->Parameters.QueryVolume.FileInformationClass;
|
|
|
|
FileObject = Stack->FileObject;
|
|
|
|
// CCB = (PVfatCCB)(FileObject->FsContext2);
|
|
|
|
// FCB = CCB->Buffer; // Should be CCB->FCB???
|
|
|
|
FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
|
|
|
|
|
|
|
|
// FIXME : determine Buffer for result :
|
|
|
|
if (Irp->MdlAddress)
|
|
|
|
SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
|
|
else
|
|
|
|
SystemBuffer = Irp->UserBuffer;
|
|
|
|
// SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
|
|
|
|
DPRINT("FileInformationClass %d\n",FileInformationClass);
|
|
|
|
DPRINT("SystemBuffer %x\n",SystemBuffer);
|
|
|
|
|
1999-05-06 17:59:55 +00:00
|
|
|
switch (FileInformationClass)
|
|
|
|
{
|
1999-04-23 11:54:47 +00:00
|
|
|
case FileFsVolumeInformation:
|
|
|
|
RC = FsdGetFsVolumeInformation(FileObject,
|
|
|
|
FCB,
|
|
|
|
DeviceObject,
|
|
|
|
SystemBuffer);
|
1999-05-06 17:59:55 +00:00
|
|
|
break;
|
|
|
|
|
1999-04-23 11:54:47 +00:00
|
|
|
case FileFsAttributeInformation:
|
1999-05-06 17:59:55 +00:00
|
|
|
RC = FsdGetFsAttributeInformation(SystemBuffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FileFsSizeInformation:
|
|
|
|
RC = FsdGetFsSizeInformation(DeviceObject, SystemBuffer);
|
|
|
|
break;
|
|
|
|
|
1999-04-23 11:54:47 +00:00
|
|
|
default:
|
1999-05-06 17:59:55 +00:00
|
|
|
RC=STATUS_NOT_IMPLEMENTED;
|
1999-04-23 11:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = RC;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return RC;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-15 00:36:59 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
DriverEntry(PDRIVER_OBJECT _DriverObject, PUNICODE_STRING RegistryPath)
|
1998-10-05 04:00:59 +00:00
|
|
|
/*
|
|
|
|
* 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 ret;
|
|
|
|
UNICODE_STRING ustr;
|
|
|
|
ANSI_STRING astr;
|
|
|
|
|
1999-03-19 05:55:55 +00:00
|
|
|
DbgPrint("VFAT 0.0.6\n");
|
1999-01-04 12:08:54 +00:00
|
|
|
pFirstFcb=NULL;
|
1999-01-13 15:21:34 +00:00
|
|
|
VFATDriverObject = _DriverObject;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
RtlInitAnsiString(&astr,"\\Device\\VFAT");
|
|
|
|
RtlAnsiStringToUnicodeString(&ustr,&astr,TRUE);
|
1999-01-13 15:21:34 +00:00
|
|
|
ret = IoCreateDevice(VFATDriverObject,0,&ustr,
|
1998-10-05 04:00:59 +00:00
|
|
|
FILE_DEVICE_FILE_SYSTEM,0,FALSE,&DeviceObject);
|
|
|
|
if (ret!=STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
1999-01-05 12:04:08 +00:00
|
|
|
DeviceObject->Flags = DO_DIRECT_IO;
|
1999-01-13 15:21:34 +00:00
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
|
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
|
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
|
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
|
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
|
1998-10-05 04:00:59 +00:00
|
|
|
FsdFileSystemControl;
|
1999-01-13 15:21:34 +00:00
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
1998-12-20 19:41:39 +00:00
|
|
|
FsdQueryInformation;
|
1999-04-14 00:52:19 +00:00
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
|
|
|
FsdSetInformation;
|
1999-01-13 15:21:34 +00:00
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
|
1998-12-30 18:43:27 +00:00
|
|
|
FsdDirectoryControl;
|
1999-04-23 11:54:47 +00:00
|
|
|
VFATDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
|
|
|
|
FsdQueryVolumeInformation;
|
1998-12-30 18:43:27 +00:00
|
|
|
|
1999-01-13 15:21:34 +00:00
|
|
|
VFATDriverObject->DriverUnload = NULL;
|
1998-10-05 04:00:59 +00:00
|
|
|
|
|
|
|
IoRegisterFileSystem(DeviceObject);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|