4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/iface.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
11 24-10-1998 Fixed bugs in long filename support
12 Fixed a bug that prevented unsuccessful file open requests being reported
13 Now works with long filenames that span over a sector boundary
14 28-10-1998 Reads entire FAT into memory
15 VFatReadSector modified to read in more than one sector at a time
16 7-11-1998 Fixed bug that assumed that directory data could be fragmented
17 8-12-1998 Added FAT32 support
18 Added initial writability functions
19 WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
20 12-12-1998 Added basic support for FILE_STANDARD_INFORMATION request
24 /* INCLUDES *****************************************************************/
26 #include <ddk/ntddk.h>
27 #include <internal/string.h>
29 #include <ddk/cctypes.h>
32 #include <internal/debug.h>
36 //#include "dbgpool.c"
38 /* GLOBALS *****************************************************************/
40 static PDRIVER_OBJECT VFATDriverObject
;
43 /* FUNCTIONS ****************************************************************/
45 ULONG
Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
47 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
55 Block
= ExAllocatePool(NonPagedPool
,1024);
56 FATsector
=CurrentCluster
/(512/sizeof(ULONG
));
57 FATeis
=CurrentCluster
-(FATsector
*(512/sizeof(ULONG
)));
58 VFATReadSectors(DeviceExt
->StorageDevice
59 ,(ULONG
)(DeviceExt
->FATStart
+FATsector
), 1,(UCHAR
*) Block
);
60 CurrentCluster
= Block
[FATeis
];
61 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
62 CurrentCluster
= 0xffffffff;
64 return(CurrentCluster
);
67 ULONG
Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
69 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
74 Block
=(PUSHORT
)DeviceExt
->FAT
;
75 CurrentCluster
= Block
[CurrentCluster
];
76 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
77 CurrentCluster
= 0xffffffff;
78 DPRINT("Returning %x\n",CurrentCluster
);
79 return(CurrentCluster
);
82 ULONG
Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
84 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
88 unsigned char* CBlock
;
91 CBlock
= DeviceExt
->FAT
;
92 FATOffset
= (CurrentCluster
* 12)/ 8;//first byte containing value
93 if ((CurrentCluster
% 2) == 0)
95 Entry
= CBlock
[FATOffset
];
96 Entry
|= ((CBlock
[FATOffset
+1] & 0xf)<<8);
100 Entry
= (CBlock
[FATOffset
] >> 4);
101 Entry
|= (CBlock
[FATOffset
+1] << 4);
103 DPRINT("Entry %x\n",Entry
);
104 if (Entry
>= 0xff8 && Entry
<= 0xfff)
106 DPRINT("Returning %x\n",Entry
);
110 ULONG
GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
112 * FUNCTION: Retrieve the next cluster depending on the FAT type
116 DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
117 DeviceExt
,CurrentCluster
);
118 if (DeviceExt
->FatType
== FAT16
)
119 return(Fat16GetNextCluster(DeviceExt
, CurrentCluster
));
120 else if (DeviceExt
->FatType
== FAT32
)
121 return(Fat32GetNextCluster(DeviceExt
, CurrentCluster
));
123 return(Fat12GetNextCluster(DeviceExt
, CurrentCluster
));
126 ULONG
FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
128 * FUNCTION: Finds the first available cluster in a FAT16 table
133 Block
=(PUSHORT
)DeviceExt
->FAT
;
134 for(i
=2;i
<(DeviceExt
->Boot
->FATSectors
*256) ;i
++)
137 /* Give an error message (out of disk space) if we reach here) */
141 ULONG
FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
143 * FUNCTION: Finds the first available cluster in a FAT12 table
148 PUCHAR CBlock
=DeviceExt
->FAT
;
150 for(i
=2;i
<((DeviceExt
->Boot
->FATSectors
*512*8)/12) ;i
++)
152 FATOffset
= (i
* 12)/8;
155 Entry
= CBlock
[FATOffset
];
156 Entry
|= ((CBlock
[FATOffset
+ 1] & 0xf)<<8);
160 Entry
= (CBlock
[FATOffset
] >> 4);
161 Entry
|= (CBlock
[FATOffset
+ 1] << 4);
166 /* Give an error message (out of disk space) if we reach here) */
167 DbgPrint("Disk full, %d clusters used\n",i
);
171 ULONG
FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
173 * FUNCTION: Finds the first available cluster in a FAT32 table
179 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
181 ;sector
< ((struct _BootSector32
*)(DeviceExt
->Boot
))->FATSectors32
184 VFATReadSectors(DeviceExt
->StorageDevice
185 ,(ULONG
)(DeviceExt
->FATStart
+sector
), 1,(UCHAR
*) Block
);
192 return (i
+sector
*128);
196 /* Give an error message (out of disk space) if we reach here) */
201 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
204 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
209 PUCHAR CBlock
=DeviceExt
->FAT
;
211 FATOffset
= (ClusterToWrite
* 12)/8;
212 if ((ClusterToWrite
% 2) == 0)
214 CBlock
[FATOffset
]=NewValue
;
215 CBlock
[FATOffset
+ 1] &=0xf0;
216 CBlock
[FATOffset
+ 1]
217 |= (NewValue
&0xf00)>>8;
221 CBlock
[FATOffset
] &=0x0f;
223 |= (NewValue
&0xf)<<4;
224 CBlock
[FATOffset
+1]=NewValue
>>4;
226 /* Write the changed FAT sector(s) to disk */
227 FATsector
=FATOffset
/BLOCKSIZE
;
228 for(i
=0;i
<DeviceExt
->Boot
->FATCount
;i
++)
230 if( (FATOffset
%BLOCKSIZE
)==(BLOCKSIZE
-1))//entry is on 2 sectors
232 VFATWriteSectors(DeviceExt
->StorageDevice
,
233 DeviceExt
->FATStart
+FATsector
234 +i
*DeviceExt
->Boot
->FATSectors
,
236 CBlock
+FATsector
*512);
240 VFATWriteSectors(DeviceExt
->StorageDevice
,
241 DeviceExt
->FATStart
+FATsector
242 +i
*DeviceExt
->Boot
->FATSectors
,
244 CBlock
+FATsector
*512);
249 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
252 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
257 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
258 Block
=(PUSHORT
)DeviceExt
->FAT
;
259 FATsector
=ClusterToWrite
/(512/sizeof(USHORT
));
261 /* Update the in-memory FAT */
262 Block
[ClusterToWrite
] = NewValue
;
263 /* Write the changed FAT sector to disk */
264 VFATWriteSectors(DeviceExt
->StorageDevice
,
265 DeviceExt
->FATStart
+FATsector
,
270 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
273 * FUNCTION: Writes a cluster to the FAT32 physical tables
279 DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
280 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
281 FATsector
=ClusterToWrite
/128;
282 FATeis
=ClusterToWrite
-(FATsector
*128);
283 /* load sector, change value, then rewrite sector */
284 VFATReadSectors(DeviceExt
->StorageDevice
,
285 DeviceExt
->FATStart
+FATsector
,
288 Block
[FATeis
] = NewValue
;
289 VFATWriteSectors(DeviceExt
->StorageDevice
,
290 DeviceExt
->FATStart
+FATsector
,
296 void WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
299 * FUNCTION: Write a changed FAT entry
302 if(DeviceExt
->FatType
==FAT16
)
303 FAT16WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
304 else if(DeviceExt
->FatType
==FAT32
)
305 FAT32WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
307 FAT12WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
310 ULONG
GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
312 * FUNCTION: Determines the next cluster to be written
315 ULONG LastCluster
, NewCluster
;
316 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
317 DeviceExt
,CurrentCluster
);
319 /* Find out what was happening in the last cluster's AU */
320 LastCluster
=GetNextCluster(DeviceExt
,CurrentCluster
);
321 /* Check to see if we must append or overwrite */
322 if (LastCluster
==0xffffffff)
323 {//we are after last existing cluster : we must add one to file
325 /* Firstly, find the next available open allocation unit */
326 if(DeviceExt
->FatType
== FAT16
)
327 NewCluster
= FAT16FindAvailableCluster(DeviceExt
);
328 else if(DeviceExt
->FatType
== FAT32
)
329 NewCluster
= FAT32FindAvailableCluster(DeviceExt
);
331 NewCluster
= FAT12FindAvailableCluster(DeviceExt
);
332 /* Mark the new AU as the EOF */
333 WriteCluster(DeviceExt
, NewCluster
, 0xFFFFFFFF);
334 /* Now, write the AU of the LastCluster with the value of the newly
337 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
338 /* Return NewCluster as CurrentCluster */
343 /* Overwrite: Return LastCluster as CurrentCluster */
348 ULONG
ClusterToSector(PDEVICE_EXTENSION DeviceExt
,
349 unsigned long Cluster
)
351 * FUNCTION: Converts the cluster number to a sector number for this physical
355 return DeviceExt
->dataStart
+((Cluster
-2)*DeviceExt
->Boot
->SectorsPerCluster
);
358 void RtlAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
360 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
365 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
372 void RtlCatAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
374 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
375 * existing Unicode string
384 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
391 void vfat_initstr(wchar_t *wstr
, ULONG wsize
)
393 * FUNCTION: Initialize a string for use with a long file name
398 for(i
=0; i
<wsize
; i
++)
406 wchar_t * vfat_wcsncat(wchar_t * dest
, const wchar_t * src
,size_t wstart
, size_t wcount
)
408 * FUNCTION: Append a string for use with a long file name
414 for(i
=0; i
<wcount
; i
++)
419 dest
=dest
-(wcount
+wstart
);
424 wchar_t * vfat_wcsncpy(wchar_t * dest
, const wchar_t *src
,size_t wcount
)
426 * FUNCTION: Copy a string for use with long file names
431 for (i
=0;i
<wcount
;i
++)
439 wchar_t * vfat_movstr(const wchar_t *src
, ULONG dpos
,
440 ULONG spos
, ULONG len
)
442 * FUNCTION: Move the characters in a string to a new position in the same
452 src
[dpos
++]=src
[spos
++];
461 src
[dpos
--]=src
[spos
--];
468 BOOLEAN
IsLastEntry(PVOID Block
, ULONG Offset
)
470 * FUNCTION: Determine if the given directory entry is the last
473 return(((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0);
476 BOOLEAN
IsVolEntry(PVOID Block
, ULONG Offset
)
478 * FUNCTION: Determine if the given directory entry is a vol entry
481 if( (((FATDirEntry
*)Block
)[Offset
].Attrib
)==0x28 ) return TRUE
;
485 BOOLEAN
IsDeletedEntry(PVOID Block
, ULONG Offset
)
487 * FUNCTION: Determines if the given entry is a deleted one
490 /* Checks special character */
492 return ((((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0xe5));
495 BOOLEAN
GetEntryName(PVOID Block
, PULONG _Offset
, PWSTR Name
, PULONG _jloop
,
496 PDEVICE_EXTENSION DeviceExt
, ULONG
* _StartingSector
)
498 * FUNCTION: Retrieves the file name, be it in short or long file name format
503 ULONG Offset
= *_Offset
;
504 ULONG StartingSector
= *_StartingSector
;
505 ULONG jloop
= *_jloop
;
509 test
= (FATDirEntry
*)Block
;
510 test2
= (slot
*)Block
;
514 if (IsDeletedEntry(Block
,Offset
))
519 if(test2
[Offset
].attr
== 0x0f)
521 vfat_initstr(Name
, 256);
522 vfat_wcsncpy(Name
,test2
[Offset
].name0_4
,5);
523 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
524 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
527 while((test2
[Offset
].id
!=0x41) && (test2
[Offset
].id
!=0x01) &&
528 (test2
[Offset
].attr
>0))
531 if(Offset
==ENTRIES_PER_SECTOR
) {
533 StartingSector
++;//FIXME : nor always the next sector
535 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,Block
);
536 test2
= (slot
*)Block
;
539 vfat_movstr(Name
, 13, 0, cpos
*13);
540 vfat_wcsncpy(Name
, test2
[Offset
].name0_4
, 5);
541 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
542 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
546 if (IsDeletedEntry(Block
,Offset
+1))
551 *_StartingSector
= StartingSector
;
557 *_StartingSector
= StartingSector
;
562 RtlAnsiToUnicode(Name
,test
[Offset
].Filename
,8);
563 if (test
[Offset
].Ext
[0]!=' ')
565 RtlCatAnsiToUnicode(Name
,".",1);
567 RtlCatAnsiToUnicode(Name
,test
[Offset
].Ext
,3);
574 BOOLEAN
wstrcmpi(PWSTR s1
, PWSTR s2
)
576 * FUNCTION: Compare to wide character strings
577 * return TRUE if s1==s2
580 while (wtolower(*s1
)==wtolower(*s2
))
582 if ((*s1
)==0 && (*s2
)==0)
592 BOOLEAN
wstrcmpjoki(PWSTR s1
, PWSTR s2
)
594 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
595 * return TRUE if s1 like s2
598 while ((*s2
=='?')||(wtolower(*s1
)==wtolower(*s2
)))
600 if ((*s1
)==0 && (*s2
)==0)
609 if (wstrcmpjoki(s1
,s2
)) return TRUE
;
612 if ((*s1
)==0 && (*s2
)==0)
617 NTSTATUS
FindFile(PDEVICE_EXTENSION DeviceExt
, PVfatFCB Fcb
,
618 PVfatFCB Parent
, PWSTR FileToFind
,ULONG
*StartSector
,ULONG
*Entry
)
620 * FUNCTION: Find a file
627 ULONG StartingSector
;
631 DPRINT("FindFile(Parent %x, FileToFind '%w')\n",Parent
,FileToFind
);
633 if (wcslen(FileToFind
)==0)
635 TempStr
[0] = (WCHAR
)'.';
641 DPRINT("Parent->entry.FirstCluster %d\n",Parent
->entry
.FirstCluster
);
644 if (Parent
== NULL
||Parent
->entry
.FirstCluster
==1)
646 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
647 StartingSector
= DeviceExt
->rootStart
;
649 if(FileToFind
[0]==0 ||(FileToFind
[0]=='\\' && FileToFind
[1]==0) ||
650 (FileToFind
[0]=='.' && FileToFind
[1]==0))
651 {// it's root : complete essentials fields then return ok
652 memset(Fcb
,0,sizeof(VfatFCB
));
653 memset(Fcb
->entry
.Filename
,' ',11);
654 Fcb
->entry
.FileSize
=DeviceExt
->rootDirectorySectors
*BLOCKSIZE
;
655 Fcb
->entry
.Attrib
=FILE_ATTRIBUTE_DIRECTORY
;
656 if (DeviceExt
->FatType
== FAT32
)
657 Fcb
->entry
.FirstCluster
=2;
658 else Fcb
->entry
.FirstCluster
=1;//FIXME : is 1 the good value for mark root?
659 if(StartSector
) *StartSector
=StartingSector
;
661 return(STATUS_SUCCESS
);
666 DPRINT("Parent->entry.FileSize %x\n",Parent
->entry
.FileSize
);
669 if (DeviceExt
->FatType
== FAT32
)
670 NextCluster
= Parent
->entry
.FirstCluster
671 +Parent
->entry
.FirstClusterHigh
*65536;
673 NextCluster
= Parent
->entry
.FirstCluster
;
674 StartingSector
= ClusterToSector(DeviceExt
, NextCluster
);
675 if(Parent
->entry
.FirstCluster
==1 && DeviceExt
->FatType
!=FAT32
)
676 {// read of root directory in FAT16 or FAT12
677 StartingSector
=DeviceExt
->rootStart
;
680 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
681 if (StartSector
&& (*StartSector
)) StartingSector
=*StartSector
;
682 i
=(Entry
)?(*Entry
):0;
683 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
684 for (j
=0; j
<Size
; j
++)
686 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
688 for (i
=(Entry
)?(*Entry
):0; i
<ENTRIES_PER_SECTOR
; i
++)
690 if (IsVolEntry((PVOID
)block
,i
))
692 if (IsLastEntry((PVOID
)block
,i
))
695 if(StartSector
) *StartSector
=StartingSector
;
697 return(STATUS_UNSUCCESSFUL
);
699 if (GetEntryName((PVOID
)block
,&i
,name
,&j
,DeviceExt
,&StartingSector
))
701 DPRINT("Comparing '%w' '%w'\n",name
,FileToFind
);
702 if (wstrcmpjoki(name
,FileToFind
))
704 /* In the case of a long filename, the firstcluster is stored in
705 the next record -- where it's short name is */
706 if(((FATDirEntry
*)block
)[i
].Attrib
==0x0f) i
++;
707 if( i
==(ENTRIES_PER_SECTOR
))
708 {// entry is in next sector
710 //FIXME : treat case of next sector fragmented
711 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
714 memcpy(&Fcb
->entry
,&((FATDirEntry
*)block
)[i
],
715 sizeof(FATDirEntry
));
716 vfat_wcsncpy(Fcb
->ObjectName
,name
,MAX_PATH
);
718 if(StartSector
) *StartSector
=StartingSector
;
720 return(STATUS_SUCCESS
);
724 // not found in this sector, try next :
726 /* directory can be fragmented although it is best to keep them
730 if ((Parent
!= NULL
&& Parent
->entry
.FirstCluster
!=1)
731 || DeviceExt
->FatType
==FAT32
)
733 if(StartingSector
==ClusterToSector(DeviceExt
,NextCluster
+1))
735 NextCluster
= GetNextCluster(DeviceExt
,NextCluster
);
736 if (NextCluster
== 0||NextCluster
==0xffffffff)
738 if(StartSector
) *StartSector
=StartingSector
;
741 return(STATUS_UNSUCCESSFUL
);
743 StartingSector
= ClusterToSector(DeviceExt
,NextCluster
);
748 if(StartSector
) *StartSector
=StartingSector
;
750 return(STATUS_UNSUCCESSFUL
);
754 NTSTATUS
FsdCloseFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
)
756 * FUNCTION: Closes a file
762 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
763 DeviceExt
,FileObject
);
765 //FIXME : update entry in directory ?
766 pCcb
= (PVfatCCB
)(FileObject
->FsContext2
);
768 DPRINT("pCcb %x\n",pCcb
);
771 return(STATUS_SUCCESS
);
777 if(pFcb
->RefCount
<=0)
780 pFcb
->prevFcb
->nextFcb
=pFcb
->nextFcb
;
782 pFirstFcb
=pFcb
->nextFcb
;
784 pFcb
->nextFcb
->prevFcb
=pFcb
->prevFcb
;
788 return STATUS_SUCCESS
;
791 NTSTATUS
FsdOpenFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
794 * FUNCTION: Opens a file
801 PVfatFCB Fcb
,pRelFcb
;
803 PVfatCCB newCCB
,pRelCcb
;
805 PFILE_OBJECT pRelFileObject
;
806 PWSTR AbsFileName
=NULL
;
809 DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
814 //FIXME : treat relative name
815 if(FileObject
->RelatedFileObject
)
817 DbgPrint("try related for %w\n",FileName
);
818 pRelFileObject
=FileObject
->RelatedFileObject
;
819 pRelCcb
=pRelFileObject
->FsContext2
;
821 pRelFcb
=pRelCcb
->pFcb
;
823 // verify related object is a directory and target name don't start with \.
824 if( !(pRelFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
825 || (FileName
[0]!= '\\') )
827 Status
=STATUS_INVALID_PARAMETER
;
830 // construct absolute path name
831 AbsFileName
=ExAllocatePool(NonPagedPool
,MAX_PATH
);
832 for (i
=0;pRelFcb
->PathName
[i
];i
++)
833 AbsFileName
[i
]=pRelFcb
->PathName
[i
];
834 AbsFileName
[i
++]='\\';
835 for (j
=0;FileName
[j
]&&i
<MAX_PATH
;j
++)
836 AbsFileName
[i
++]=FileName
[j
];
839 FileName
=AbsFileName
;
841 // try first to find an existing FCB in memory
842 for (Fcb
=pFirstFcb
;Fcb
; Fcb
=Fcb
->nextFcb
)
844 if (DeviceExt
==Fcb
->pDevExt
845 && wstrcmpi(FileName
,Fcb
->PathName
))
848 FileObject
->FsContext
=(PVOID
) &Fcb
->NTRequiredFCB
;
849 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
850 memset(newCCB
,0,sizeof(VfatCCB
));
851 FileObject
->FsContext2
= newCCB
;
853 newCCB
->PtrFileObject
=FileObject
;
854 if(AbsFileName
)ExFreePool(AbsFileName
);
855 return(STATUS_SUCCESS
);
860 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(VfatFCB
));
861 memset(Fcb
,0,sizeof(VfatFCB
));
862 Fcb
->ObjectName
=Fcb
->PathName
;
869 next
= wcschr(next
+1,'\\');
874 DPRINT("current '%w'\n",current
);
875 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,current
,NULL
,NULL
);
876 if (Status
!= STATUS_SUCCESS
)
880 if (ParentFcb
!= NULL
)
881 ExFreePool(ParentFcb
);
882 if(AbsFileName
)ExFreePool(AbsFileName
);
886 if (ParentFcb
== NULL
)
888 Fcb
= ExAllocatePool(NonPagedPool
,sizeof(VfatFCB
));
889 memset(Fcb
,0,sizeof(VfatFCB
));
890 Fcb
->ObjectName
=Fcb
->PathName
;
892 else Fcb
= ParentFcb
;
895 FileObject
->FsContext
=(PVOID
) &ParentFcb
->NTRequiredFCB
;
896 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
897 memset(newCCB
,0,sizeof(VfatCCB
));
898 FileObject
->FsContext2
= newCCB
;
899 newCCB
->pFcb
=ParentFcb
;
900 newCCB
->PtrFileObject
=FileObject
;
901 ParentFcb
->RefCount
++;
902 //FIXME : initialize all fields in FCB and CCB
903 ParentFcb
->nextFcb
=pFirstFcb
;
905 vfat_wcsncpy(ParentFcb
->PathName
,FileName
,MAX_PATH
);
906 ParentFcb
->ObjectName
=ParentFcb
->PathName
+(current
-FileName
);
907 ParentFcb
->pDevExt
=DeviceExt
;
908 DPRINT("file open, fcb=%x\n",ParentFcb
);
909 DPRINT("FileSize %d\n",ParentFcb
->entry
.FileSize
);
910 if(Fcb
) ExFreePool(Fcb
);
911 if(AbsFileName
)ExFreePool(AbsFileName
);
912 return(STATUS_SUCCESS
);
916 BOOLEAN
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
918 * FUNCTION: Tests if the device contains a filesystem that can be mounted
924 Boot
= ExAllocatePool(NonPagedPool
,512);
926 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)Boot
);
928 if (strncmp(Boot
->SysType
,"FAT12",5)==0 ||
929 strncmp(Boot
->SysType
,"FAT16",5)==0 ||
930 strncmp(((struct _BootSector32
*)(Boot
))->SysType
,"FAT32",5)==0)
939 NTSTATUS
FsdMountDevice(PDEVICE_EXTENSION DeviceExt
,
940 PDEVICE_OBJECT DeviceToMount
)
942 * FUNCTION: Mounts the device
945 DPRINT("Mounting VFAT device...");
946 DPRINT("DeviceExt %x\n",DeviceExt
);
948 DeviceExt
->Boot
= ExAllocatePool(NonPagedPool
,512);
949 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)DeviceExt
->Boot
);
951 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
952 DeviceExt
->Boot
->BytesPerSector
);
954 DeviceExt
->FATStart
=DeviceExt
->Boot
->ReservedSectors
;
955 DeviceExt
->rootDirectorySectors
=
956 (DeviceExt
->Boot
->RootEntries
*32)/DeviceExt
->Boot
->BytesPerSector
;
957 DeviceExt
->rootStart
=
958 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
*DeviceExt
->Boot
->FATSectors
;
959 DeviceExt
->dataStart
=DeviceExt
->rootStart
+DeviceExt
->rootDirectorySectors
;
960 DeviceExt
->FATEntriesPerSector
=DeviceExt
->Boot
->BytesPerSector
/32;
961 DeviceExt
->BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
*
962 DeviceExt
->Boot
->BytesPerSector
;
964 if (strncmp(DeviceExt
->Boot
->SysType
,"FAT12",5)==0)
966 DeviceExt
->FatType
= FAT12
;
968 else if (strncmp(((struct _BootSector32
*)(DeviceExt
->Boot
))->SysType
,"FAT32",5)==0)
970 DeviceExt
->FatType
= FAT32
;
971 DeviceExt
->rootDirectorySectors
=DeviceExt
->Boot
->SectorsPerCluster
;
972 DeviceExt
->rootStart
=
973 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
974 * ((struct _BootSector32
*)( DeviceExt
->Boot
))->FATSectors32
;
975 DeviceExt
->dataStart
=DeviceExt
->rootStart
;
979 DeviceExt
->FatType
= FAT16
;
982 // with FAT32 it's not a good idea to load always fat in memory
983 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
984 if(DeviceExt
->FatType
!=FAT32
)
986 DeviceExt
->FAT
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
*DeviceExt
->Boot
->FATSectors
);
987 VFATReadSectors(DeviceToMount
, DeviceExt
->FATStart
, DeviceExt
->Boot
->FATSectors
, (UCHAR
*)DeviceExt
->FAT
);
989 return STATUS_SUCCESS
;
992 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
994 * FUNCTION: Load a cluster from the physical device
999 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1000 DeviceExt
,Buffer
,Cluster
);
1002 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1004 VFATReadSectors(DeviceExt
->StorageDevice
,
1006 DeviceExt
->Boot
->SectorsPerCluster
,
1010 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
1012 * FUNCTION: Write a cluster to the physical device
1016 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1017 DeviceExt
,Buffer
,Cluster
);
1019 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1021 VFATWriteSectors(DeviceExt
->StorageDevice
,
1023 DeviceExt
->Boot
->SectorsPerCluster
,
1027 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1028 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
1031 * FUNCTION: Reads data from a file
1034 ULONG CurrentCluster
;
1042 assert(DeviceExt
!= NULL
);
1043 assert(DeviceExt
->BytesPerCluster
!= 0);
1044 assert(FileObject
!= NULL
);
1045 assert(FileObject
->FsContext
!= NULL
);
1047 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1048 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
1051 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1052 if (DeviceExt
->FatType
== FAT32
)
1053 CurrentCluster
= Fcb
->entry
.FirstCluster
1054 +Fcb
->entry
.FirstClusterHigh
*65536;
1056 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1057 FirstCluster
=CurrentCluster
;
1058 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
1060 if (ReadOffset
>= Fcb
->entry
.FileSize
1061 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1063 return(STATUS_END_OF_FILE
);
1065 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
1066 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1068 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
1071 /* FIXME: optimize by remembering the last cluster read and using if possible */
1072 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1073 if(!Temp
) return STATUS_UNSUCCESSFUL
;
1074 if (FirstCluster
==1)
1075 { //root of FAT16 or FAT12
1076 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
1077 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
1080 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
1083 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1086 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
1088 if (FirstCluster
==1)
1090 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1091 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1092 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1096 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1097 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1099 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1100 (ReadOffset
% DeviceExt
->BytesPerCluster
));
1102 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
1105 (*LengthRead
) = (*LengthRead
) + TempLength
;
1106 Length
= Length
- TempLength
;
1107 Buffer
= Buffer
+ TempLength
;
1110 while (Length
>= DeviceExt
->BytesPerCluster
)
1112 if (FirstCluster
==1)
1114 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1115 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1116 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1120 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
1121 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1123 if (CurrentCluster
== 0xffffffff)
1126 return(STATUS_SUCCESS
);
1129 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
1130 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1131 Length
= Length
- DeviceExt
->BytesPerCluster
;
1136 (*LengthRead
) = (*LengthRead
) + Length
;
1137 if (FirstCluster
==1)
1139 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1140 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1141 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1145 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1146 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1148 memcpy(Buffer
, Temp
, Length
);
1151 return(STATUS_SUCCESS
);
1154 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1155 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
1157 * FUNCTION: Writes data to file
1160 ULONG CurrentCluster
;
1166 ULONG TempLength
,Length2
=Length
;
1168 /* Locate the first cluster of the file */
1170 pCcb
=(PVfatCCB
)(FileObject
->FsContext2
);
1174 if (DeviceExt
->FatType
== FAT32
)
1175 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
1177 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1178 FirstCluster
=CurrentCluster
;
1179 /* Allocate a buffer to hold 1 cluster of data */
1181 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1184 /* Find the cluster according to the offset in the file */
1186 if (CurrentCluster
==1)
1187 { //root of FAT16 or FAT12
1188 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
1189 /DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
1192 if (CurrentCluster
==0)
1193 {// file of size 0 : allocate first cluster
1194 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
1195 if (DeviceExt
->FatType
== FAT32
)
1197 Fcb
->entry
.FirstClusterHigh
=CurrentCluster
>>16;
1198 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1201 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1204 for (FileOffset
=0; FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
; FileOffset
++)
1206 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1211 If the offset in the cluster doesn't fall on the cluster boundary then
1212 we have to write only from the specified offset
1215 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
1218 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1219 (WriteOffset
% DeviceExt
->BytesPerCluster
));
1220 /* Read in the existing cluster data */
1221 if (FirstCluster
==1)
1222 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1223 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1225 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1227 /* Overwrite the last parts of the data as necessary */
1228 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
), Buffer
,
1231 /* Write the cluster back */
1232 if (FirstCluster
==1)
1234 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1235 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1236 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1240 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1241 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1243 Length2
-= TempLength
;
1244 Buffer
= Buffer
+ TempLength
;
1248 /* Write the buffer in chunks of 1 cluster */
1250 while (Length2
>= DeviceExt
->BytesPerCluster
)
1253 if (CurrentCluster
== 0)
1256 return(STATUS_UNSUCCESSFUL
);
1258 if (FirstCluster
==1)
1260 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1261 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1262 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1266 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
1267 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1269 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1270 Length2
-= DeviceExt
->BytesPerCluster
;
1274 /* Write the remainder */
1279 if (CurrentCluster
== 0)
1282 return(STATUS_UNSUCCESSFUL
);
1285 /* Read in the existing cluster data */
1286 if (FirstCluster
==1)
1287 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1288 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1290 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1292 memcpy(Temp
, Buffer
, Length2
);
1294 if (FirstCluster
==1)
1296 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1297 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1300 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1303 //FIXME : set last write time and date
1304 if(Fcb
->entry
.FileSize
<WriteOffset
+Length
1305 && !(Fcb
->entry
.Attrib
&FILE_ATTRIBUTE_DIRECTORY
))
1307 Fcb
->entry
.FileSize
=WriteOffset
+Length
;
1308 // update entry in directory
1309 updEntry(DeviceExt
,FileObject
);
1312 return(STATUS_SUCCESS
);
1315 NTSTATUS
FsdClose(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1317 * FUNCTION: Close a file
1320 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1321 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1322 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1325 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject
, Irp
);
1327 Status
= FsdCloseFile(DeviceExtension
,FileObject
);
1329 Irp
->IoStatus
.Status
= Status
;
1330 Irp
->IoStatus
.Information
= 0;
1332 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1336 NTSTATUS
FsdCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1338 * FUNCTION: Create or open a file
1341 PIO_STACK_LOCATION Stack
;
1342 PFILE_OBJECT FileObject
;
1343 NTSTATUS Status
=STATUS_SUCCESS
;
1344 PDEVICE_EXTENSION DeviceExt
;
1345 ULONG RequestedDisposition
,RequestedOptions
;
1349 assert(DeviceObject
);
1351 if(DeviceObject
->Size
==sizeof(DEVICE_OBJECT
))
1352 {// DevieObject represent FileSystem instead of logical volume
1353 DbgPrint("FsdCreate called with file system\n");
1354 Irp
->IoStatus
.Status
=Status
;
1355 Irp
->IoStatus
.Information
=FILE_OPENED
;
1356 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1359 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1361 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>>24)&0xff);
1362 RequestedOptions
=Stack
->Parameters
.Create
.Options
&FILE_VALID_OPTION_FLAGS
;
1363 FileObject
= Stack
->FileObject
;
1364 DeviceExt
= DeviceObject
->DeviceExtension
;
1366 ExAcquireResourceExclusiveLite(&(DeviceExt
->Resource
),TRUE
);
1367 Status
= FsdOpenFile(DeviceExt
,FileObject
,FileObject
->FileName
.Buffer
);
1368 Irp
->IoStatus
.Information
= 0;
1369 if(!NT_SUCCESS(Status
))
1371 if(RequestedDisposition
==FILE_CREATE
1372 ||RequestedDisposition
==FILE_OPEN_IF
1373 ||RequestedDisposition
==FILE_OVERWRITE_IF
)
1375 Status
=addEntry(DeviceExt
,FileObject
,RequestedOptions
1376 ,(Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
1377 if(NT_SUCCESS(Status
))
1378 Irp
->IoStatus
.Information
= FILE_CREATED
;
1379 // FIXME set size if AllocationSize requested
1380 // FIXME set extended attributes ?
1381 // FIXME set share access
1382 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1383 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1388 if(RequestedDisposition
==FILE_CREATE
)
1390 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1391 Status
=STATUS_OBJECT_NAME_COLLISION
;
1393 pCcb
=FileObject
->FsContext2
;
1395 if( (RequestedOptions
&FILE_NON_DIRECTORY_FILE
)
1396 && (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1398 Status
=STATUS_FILE_IS_A_DIRECTORY
;
1400 if( (RequestedOptions
&FILE_DIRECTORY_FILE
)
1401 && !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1403 Status
=STATUS_NOT_A_DIRECTORY
;
1405 // FIXME : test share access
1406 // FIXME : test write access if requested
1407 if(!NT_SUCCESS(Status
))
1408 FsdCloseFile(DeviceExt
,FileObject
);
1409 else Irp
->IoStatus
.Information
= FILE_OPENED
;
1410 // FIXME : make supersed or overwrite if requested
1413 Irp
->IoStatus
.Status
= Status
;
1415 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1416 ExReleaseResourceForThreadLite(&(DeviceExt
->Resource
),ExGetCurrentResourceThread());
1421 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1423 * FUNCTION: Write to a file
1429 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1430 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1431 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1434 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
1436 Length
= Stack
->Parameters
.Write
.Length
;
1437 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1438 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Write
.ByteOffset
);
1440 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
1442 Irp
->IoStatus
.Status
= Status
;
1443 Irp
->IoStatus
.Information
= Length
;
1444 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1449 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1451 * FUNCTION: Read from a file
1457 PIO_STACK_LOCATION Stack
;
1458 PFILE_OBJECT FileObject
;
1459 PDEVICE_EXTENSION DeviceExt
;
1463 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1465 /* Precondition / Initialization */
1466 assert(Irp
!= NULL
);
1467 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1468 assert(Stack
!= NULL
);
1469 FileObject
= Stack
->FileObject
;
1470 assert(FileObject
!= NULL
);
1471 DeviceExt
= DeviceObject
->DeviceExtension
;
1472 assert(DeviceExt
!= NULL
);
1474 Length
= Stack
->Parameters
.Read
.Length
;
1475 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1476 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Read
.ByteOffset
);
1478 Status
= FsdReadFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
,
1481 Irp
->IoStatus
.Status
= Status
;
1482 Irp
->IoStatus
.Information
= LengthRead
;
1483 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1489 NTSTATUS
FsdMount(PDEVICE_OBJECT DeviceToMount
)
1491 * FUNCTION: Mount the filesystem
1494 PDEVICE_OBJECT DeviceObject
;
1495 PDEVICE_EXTENSION DeviceExt
;
1497 IoCreateDevice(VFATDriverObject
,
1498 sizeof(DEVICE_EXTENSION
),
1500 FILE_DEVICE_FILE_SYSTEM
,
1504 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
1505 DeviceExt
= (PVOID
)DeviceObject
->DeviceExtension
;
1506 // use same vpb as device disk
1507 DeviceObject
->Vpb
=DeviceToMount
->Vpb
;
1508 FsdMountDevice(DeviceExt
,DeviceToMount
);
1509 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
1510 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1512 return(STATUS_SUCCESS
);
1515 NTSTATUS
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1517 * FUNCTION: File system control
1520 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1521 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1522 PDEVICE_OBJECT DeviceToMount
= Stack
->Parameters
.Mount
.DeviceObject
;
1525 DPRINT("VFAT FSC\n");
1527 /* FIXME: should make sure that this is actually a mount request! */
1529 if (FsdHasFileSystem(DeviceToMount
))
1531 Status
= FsdMount(DeviceToMount
);
1535 DPRINT("VFAT: Unrecognized Volume\n");
1536 Status
= STATUS_UNRECOGNIZED_VOLUME
;
1538 DPRINT("VFAT File system successfully mounted\n");
1540 Irp
->IoStatus
.Status
= Status
;
1541 Irp
->IoStatus
.Information
= 0;
1543 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1547 NTSTATUS
FsdGetStandardInformation(PVfatFCB FCB
, PDEVICE_OBJECT DeviceObject
,
1548 PFILE_STANDARD_INFORMATION StandardInfo
)
1550 * FUNCTION: Retrieve the standard file information
1553 PDEVICE_EXTENSION DeviceExtension
;
1554 unsigned long AllocSize
;
1556 DeviceExtension
= DeviceObject
->DeviceExtension
;
1558 assert(DeviceExtension
!= NULL
);
1559 assert(DeviceExtension
->BytesPerCluster
!= 0);
1560 assert(StandardInfo
!= NULL
);
1561 assert(FCB
!= NULL
);
1563 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
1565 /* Make allocsize a rounded up multiple of BytesPerCluster */
1566 AllocSize
= ((FCB
->entry
.FileSize
+ DeviceExtension
->BytesPerCluster
- 1) /
1567 DeviceExtension
->BytesPerCluster
) *
1568 DeviceExtension
->BytesPerCluster
;
1570 StandardInfo
->AllocationSize
= RtlConvertUlongToLargeInteger(AllocSize
);
1571 StandardInfo
->EndOfFile
= RtlConvertUlongToLargeInteger(FCB
->entry
.FileSize
);
1572 StandardInfo
->NumberOfLinks
= 0;
1573 StandardInfo
->DeletePending
= FALSE
;
1574 if((FCB
->entry
.Attrib
& 0x10)>0) {
1575 StandardInfo
->Directory
= TRUE
;
1577 StandardInfo
->Directory
= FALSE
;
1580 return STATUS_SUCCESS
;
1583 NTSTATUS
FsdQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1585 * FUNCTION: Retrieve the specified file information
1588 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1589 FILE_INFORMATION_CLASS FileInformationClass
=
1590 Stack
->Parameters
.QueryFile
.FileInformationClass
;
1591 PFILE_OBJECT FileObject
= NULL
;
1592 PVfatFCB FCB
= NULL
;
1593 // PVfatCCB CCB = NULL;
1595 NTSTATUS RC
= STATUS_SUCCESS
;
1599 assert(DeviceObject
!= NULL
);
1600 assert(Irp
!= NULL
);
1602 /* INITIALIZATION */
1603 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1604 FileInformationClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
1605 FileObject
= Stack
->FileObject
;
1606 // CCB = (PVfatCCB)(FileObject->FsContext2);
1607 // FCB = CCB->Buffer; // Should be CCB->FCB???
1608 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1610 // FIXME : determine Buffer for result :
1611 if (Irp
->MdlAddress
)
1612 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1614 SystemBuffer
= Irp
->UserBuffer
;
1615 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1617 switch(FileInformationClass
) {
1618 case FileStandardInformation
:
1619 RC
= FsdGetStandardInformation(FCB
, DeviceObject
, SystemBuffer
);
1622 RC
=STATUS_NOT_IMPLEMENTED
;
1628 NTSTATUS
DriverEntry(PDRIVER_OBJECT _DriverObject
,
1629 PUNICODE_STRING RegistryPath
)
1631 * FUNCTION: Called by the system to initalize the driver
1633 * DriverObject = object describing this driver
1634 * RegistryPath = path to our configuration entries
1635 * RETURNS: Success or failure
1638 PDEVICE_OBJECT DeviceObject
;
1640 UNICODE_STRING ustr
;
1643 DbgPrint("VFAT 0.0.6\n");
1645 VFATDriverObject
= _DriverObject
;
1647 RtlInitAnsiString(&astr
,"\\Device\\VFAT");
1648 RtlAnsiStringToUnicodeString(&ustr
,&astr
,TRUE
);
1649 ret
= IoCreateDevice(VFATDriverObject
,0,&ustr
,
1650 FILE_DEVICE_FILE_SYSTEM
,0,FALSE
,&DeviceObject
);
1651 if (ret
!=STATUS_SUCCESS
)
1656 DeviceObject
->Flags
= DO_DIRECT_IO
;
1657 VFATDriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FsdClose
;
1658 VFATDriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FsdCreate
;
1659 VFATDriverObject
->MajorFunction
[IRP_MJ_READ
] = FsdRead
;
1660 VFATDriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FsdWrite
;
1661 VFATDriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
1662 FsdFileSystemControl
;
1663 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
1664 FsdQueryInformation
;
1665 VFATDriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] =
1666 FsdDirectoryControl
;
1668 VFATDriverObject
->DriverUnload
= NULL
;
1670 IoRegisterFileSystem(DeviceObject
);
1672 return(STATUS_SUCCESS
);