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 DriverObject
;
41 static PVfatFCB pFirstFcb
;
43 /* FUNCTIONS ****************************************************************/
45 ULONG
Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
47 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
54 Block
= ExAllocatePool(NonPagedPool
,1024);
55 FATsector
=CurrentCluster
/(512/sizeof(ULONG
));
56 FATeis
=CurrentCluster
-(FATsector
*(512/sizeof(ULONG
)));
57 VFATReadSectors(DeviceExt
->StorageDevice
58 ,(ULONG
)(DeviceExt
->FATStart
+FATsector
), 1,(UCHAR
*) Block
);
59 CurrentCluster
= Block
[FATeis
];
60 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
61 CurrentCluster
= 0xffffffff;
63 return(CurrentCluster
);
66 ULONG
Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
68 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
73 Block
=(PUSHORT
)DeviceExt
->FAT
;
74 CurrentCluster
= Block
[CurrentCluster
];
75 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
76 CurrentCluster
= 0xffffffff;
77 DPRINT("Returning %x\n",CurrentCluster
);
78 return(CurrentCluster
);
81 ULONG
Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
83 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
87 unsigned char* CBlock
;
90 CBlock
= DeviceExt
->FAT
;
91 FATOffset
= (CurrentCluster
* 12)/ 8;//first byte containing value
92 if ((CurrentCluster
% 2) == 0)
94 Entry
= CBlock
[FATOffset
];
95 Entry
|= ((CBlock
[FATOffset
+1] & 0xf)<<8);
99 Entry
= (CBlock
[FATOffset
] >> 4);
100 Entry
|= (CBlock
[FATOffset
+1] << 4);
102 DPRINT("Entry %x\n",Entry
);
103 if (Entry
>= 0xff8 && Entry
<= 0xfff)
105 DPRINT("Returning %x\n",Entry
);
109 ULONG
GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
111 * FUNCTION: Retrieve the next cluster depending on the FAT type
115 DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
116 DeviceExt
,CurrentCluster
);
117 if (DeviceExt
->FatType
== FAT16
)
118 return(Fat16GetNextCluster(DeviceExt
, CurrentCluster
));
119 else if (DeviceExt
->FatType
== FAT32
)
120 return(Fat32GetNextCluster(DeviceExt
, CurrentCluster
));
122 return(Fat12GetNextCluster(DeviceExt
, CurrentCluster
));
125 ULONG
FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
127 * FUNCTION: Finds the first available cluster in a FAT16 table
132 Block
=(PUSHORT
)DeviceExt
->FAT
;
133 for(i
=2;i
<(DeviceExt
->Boot
->FATSectors
*256) ;i
++)
136 /* Give an error message (out of disk space) if we reach here) */
140 ULONG
FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
142 * FUNCTION: Finds the first available cluster in a FAT12 table
147 PUCHAR CBlock
=DeviceExt
->FAT
;
149 for(i
=2;i
<((DeviceExt
->Boot
->FATSectors
*512*8)/12) ;i
++)
151 FATOffset
= (i
* 12)/8;
154 Entry
= CBlock
[FATOffset
];
155 Entry
|= ((CBlock
[FATOffset
+ 1] & 0xf)<<8);
159 Entry
= (CBlock
[FATOffset
] >> 4);
160 Entry
|= (CBlock
[FATOffset
+ 1] << 4);
165 /* Give an error message (out of disk space) if we reach here) */
166 DbgPrint("Disk full, %d clusters used\n",i
);
170 ULONG
FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
172 * FUNCTION: Finds the first available cluster in a FAT32 table
178 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
180 ;sector
< ((struct _BootSector32
*)(DeviceExt
->Boot
))->FATSectors32
183 VFATReadSectors(DeviceExt
->StorageDevice
184 ,(ULONG
)(DeviceExt
->FATStart
+sector
), 1,(UCHAR
*) Block
);
191 return (i
+sector
*128);
195 /* Give an error message (out of disk space) if we reach here) */
200 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
203 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
208 PUCHAR CBlock
=DeviceExt
->FAT
;
210 FATOffset
= (ClusterToWrite
* 12)/8;
211 if ((ClusterToWrite
% 2) == 0)
213 CBlock
[FATOffset
]=NewValue
;
214 CBlock
[FATOffset
+ 1] &=0xf0;
215 CBlock
[FATOffset
+ 1]
216 |= (NewValue
&0xf00)>>8;
220 CBlock
[FATOffset
] &=0x0f;
222 |= (NewValue
&0xf)<<4;
223 CBlock
[FATOffset
+1]=NewValue
>>4;
225 /* Write the changed FAT sector(s) to disk */
226 FATsector
=FATOffset
/BLOCKSIZE
;
227 for(i
=0;i
<DeviceExt
->Boot
->FATCount
;i
++)
229 if( (FATOffset
%BLOCKSIZE
)==(BLOCKSIZE
-1))//entry is on 2 sectors
231 VFATWriteSectors(DeviceExt
->StorageDevice
,
232 DeviceExt
->FATStart
+FATsector
233 +i
*DeviceExt
->Boot
->FATSectors
,
235 CBlock
+FATsector
*512);
239 VFATWriteSectors(DeviceExt
->StorageDevice
,
240 DeviceExt
->FATStart
+FATsector
241 +i
*DeviceExt
->Boot
->FATSectors
,
243 CBlock
+FATsector
*512);
248 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
251 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
256 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
257 Block
=(PUSHORT
)DeviceExt
->FAT
;
258 FATsector
=ClusterToWrite
/(512/sizeof(USHORT
));
260 /* Update the in-memory FAT */
261 Block
[ClusterToWrite
] = NewValue
;
262 /* Write the changed FAT sector to disk */
263 VFATWriteSectors(DeviceExt
->StorageDevice
,
264 DeviceExt
->FATStart
+FATsector
,
269 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
272 * FUNCTION: Writes a cluster to the FAT32 physical tables
278 DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
279 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
280 FATsector
=ClusterToWrite
/128;
281 FATeis
=ClusterToWrite
-(FATsector
*128);
282 /* load sector, change value, then rewrite sector */
283 VFATReadSectors(DeviceExt
->StorageDevice
,
284 DeviceExt
->FATStart
+FATsector
,
287 Block
[FATeis
] = NewValue
;
288 VFATWriteSectors(DeviceExt
->StorageDevice
,
289 DeviceExt
->FATStart
+FATsector
,
295 void WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
298 * FUNCTION: Write a changed FAT entry
301 if(DeviceExt
->FatType
==FAT16
)
302 FAT16WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
303 else if(DeviceExt
->FatType
==FAT32
)
304 FAT32WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
306 FAT12WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
309 ULONG
GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
311 * FUNCTION: Determines the next cluster to be written
314 ULONG LastCluster
, NewCluster
;
315 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
316 DeviceExt
,CurrentCluster
);
318 /* Find out what was happening in the last cluster's AU */
319 LastCluster
=GetNextCluster(DeviceExt
,CurrentCluster
);
320 /* Check to see if we must append or overwrite */
321 if (LastCluster
==0xffffffff)
322 {//we are after last existing cluster : we must add one to file
324 /* Firstly, find the next available open allocation unit */
325 if(DeviceExt
->FatType
== FAT16
)
326 NewCluster
= FAT16FindAvailableCluster(DeviceExt
);
327 else if(DeviceExt
->FatType
== FAT32
)
328 NewCluster
= FAT32FindAvailableCluster(DeviceExt
);
330 NewCluster
= FAT12FindAvailableCluster(DeviceExt
);
331 /* Mark the new AU as the EOF */
332 WriteCluster(DeviceExt
, NewCluster
, 0xFFFFFFFF);
333 /* Now, write the AU of the LastCluster with the value of the newly
335 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
336 /* Return NewCluster as CurrentCluster */
341 /* Overwrite: Return LastCluster as CurrentCluster */
346 ULONG
ClusterToSector(PDEVICE_EXTENSION DeviceExt
,
347 unsigned long Cluster
)
349 * FUNCTION: Converts the cluster number to a sector number for this physical
353 return DeviceExt
->dataStart
+((Cluster
-2)*DeviceExt
->Boot
->SectorsPerCluster
);
356 void RtlAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
358 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
363 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
370 void RtlCatAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
372 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
373 * existing Unicode string
382 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
389 void vfat_initstr(wchar_t *wstr
, ULONG wsize
)
391 * FUNCTION: Initialize a string for use with a long file name
396 for(i
=0; i
<wsize
; i
++)
404 wchar_t * vfat_wcsncat(wchar_t * dest
, const wchar_t * src
,size_t wstart
, size_t wcount
)
406 * FUNCTION: Append a string for use with a long file name
412 for(i
=0; i
<wcount
; i
++)
417 dest
=dest
-(wcount
+wstart
);
422 wchar_t * vfat_wcsncpy(wchar_t * dest
, const wchar_t *src
,size_t wcount
)
424 * FUNCTION: Copy a string for use with long file names
429 for (i
=0;i
<wcount
;i
++)
439 wchar_t * vfat_movstr(wchar_t * dest
, 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
449 for(i
=spos
; i
<spos
+len
; i
++)
459 BOOLEAN
IsLastEntry(PVOID Block
, ULONG Offset
)
461 * FUNCTION: Determine if the given directory entry is the last
464 return(((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0);
467 BOOLEAN
IsVolEntry(PVOID Block
, ULONG Offset
)
469 * FUNCTION: Determine if the given directory entry is a vol entry
472 if( (((FATDirEntry
*)Block
)[Offset
].Attrib
)==0x28 ) return TRUE
;
476 BOOLEAN
IsDeletedEntry(PVOID Block
, ULONG Offset
)
478 * FUNCTION: Determines if the given entry is a deleted one
481 /* Checks special character (short names) or attrib=0 (long names) */
483 return ((((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0xe5) ||
484 (((FATDirEntry
*)Block
)[Offset
].Attrib
== 0x00));
487 BOOLEAN
GetEntryName(PVOID Block
, PULONG _Offset
, PWSTR Name
, PULONG _jloop
,
488 PDEVICE_EXTENSION DeviceExt
, ULONG
* _StartingSector
)
490 * FUNCTION: Retrieves the file name, be it in short or long file name format
495 ULONG Offset
= *_Offset
;
496 ULONG StartingSector
= *_StartingSector
;
497 ULONG jloop
= *_jloop
;
501 test
= (FATDirEntry
*)Block
;
502 test2
= (slot
*)Block
;
506 if (IsDeletedEntry(Block
,Offset
))
511 if(test2
[Offset
].attr
== 0x0f)
513 vfat_initstr(Name
, 256);
514 vfat_wcsncpy(Name
,test2
[Offset
].name0_4
,5);
515 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
516 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
519 while((test2
[Offset
].id
!=0x41) && (test2
[Offset
].id
!=0x01) &&
520 (test2
[Offset
].attr
>0))
523 if(Offset
==ENTRIES_PER_SECTOR
) {
527 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,Block
);
528 test2
= (slot
*)Block
;
532 vfat_initstr(tmp
, 256);
533 vfat_movstr(tmp
, Name
, 13, 0, cpos
*13);
534 vfat_wcsncpy(Name
, tmp
, 256);
535 vfat_wcsncpy(Name
, test2
[Offset
].name0_4
, 5);
536 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
537 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
541 if (IsDeletedEntry(Block
,Offset
+1))
546 *_StartingSector
= StartingSector
;
552 *_StartingSector
= StartingSector
;
557 RtlAnsiToUnicode(Name
,test
[Offset
].Filename
,8);
558 if (test
[Offset
].Ext
[0]!=' ')
560 RtlCatAnsiToUnicode(Name
,".",1);
562 RtlCatAnsiToUnicode(Name
,test
[Offset
].Ext
,3);
569 BOOLEAN
wstrcmpi(PWSTR s1
, PWSTR s2
)
571 * FUNCTION: Compare to wide character strings
572 * return TRUE if s1==s2
575 while (wtolower(*s1
)==wtolower(*s2
))
577 if ((*s1
)==0 && (*s2
)==0)
587 BOOLEAN
wstrcmpjoki(PWSTR s1
, PWSTR s2
)
589 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
590 * return TRUE if s1 like s2
593 while ((*s2
=='?')||(wtolower(*s1
)==wtolower(*s2
)))
595 if ((*s1
)==0 && (*s2
)==0)
604 if (wstrcmpjoki(s1
,s2
)) return TRUE
;
607 if ((*s1
)==0 && (*s2
)==0)
612 NTSTATUS
FindFile(PDEVICE_EXTENSION DeviceExt
, PVfatFCB Fcb
,
613 PVfatFCB Parent
, PWSTR FileToFind
,ULONG
*StartSector
,ULONG
*Entry
)
615 * FUNCTION: Find a file
622 ULONG StartingSector
;
624 DPRINT("FindFile(Parent %x, FileToFind %w)\n",Parent
,FileToFind
);
628 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
629 StartingSector
= DeviceExt
->rootStart
;
630 if(FileToFind
[0]==0 ||(FileToFind
[0]=='\\' && FileToFind
[1]==0))
631 {// it's root : complete essentials fields then return ok
632 memset(Fcb
,0,sizeof(VfatFCB
));
633 memset(Fcb
->entry
.Filename
,' ',11);
634 if (DeviceExt
->FatType
== FAT32
)
635 Fcb
->entry
.FirstCluster
=2;
636 else Fcb
->entry
.FirstCluster
=1;//FIXME : is 1 the good value ?
637 if(StartSector
) *StartSector
=StartingSector
;
639 return(STATUS_SUCCESS
);
644 DPRINT("Parent->entry.FileSize %x\n",Parent
->entry
.FileSize
);
647 if (DeviceExt
->FatType
== FAT32
)
648 NextCluster
= Parent
->entry
.FirstCluster
+Parent
->entry
.FirstClusterHigh
*65536;
650 NextCluster
= Parent
->entry
.FirstCluster
;
651 StartingSector
= ClusterToSector(DeviceExt
, NextCluster
);
652 if(Parent
->entry
.FirstCluster
==1 && DeviceExt
->FatType
!=FAT32
)
653 {// read of root directory in FAT16 or FAT12
654 StartingSector
=DeviceExt
->rootStart
;
657 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
658 if (StartSector
&& (*StartSector
)) StartingSector
=*StartSector
;
659 i
=(Entry
)?(*Entry
):0;
660 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
661 for (j
=0; j
<Size
; j
++)
663 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
665 for (i
=(Entry
)?(*Entry
):0; i
<ENTRIES_PER_SECTOR
; i
++)
667 if (IsVolEntry((PVOID
)block
,i
))
669 if (IsLastEntry((PVOID
)block
,i
))
672 if(StartSector
) *StartSector
=StartingSector
;
674 return(STATUS_UNSUCCESSFUL
);
676 if (GetEntryName((PVOID
)block
,&i
,name
,&j
,DeviceExt
,&StartingSector
))
678 // DPRINT("Comparing %w %w\n",name,FileToFind);
679 if (wstrcmpjoki(name
,FileToFind
))
681 /* In the case of a long filename, the firstcluster is stored in
682 the next record -- where it's short name is */
683 if(((FATDirEntry
*)block
)[i
].Attrib
==0x0f) i
++;
684 // if(DeviceExt->FatType==FAT32)
686 // if(((FATDirEntry *)block)[i].FirstCluster==0
687 // &&((FATDirEntry *)block)[i].FirstClusterHigh==0
691 // if(((FATDirEntry *)block)[i].FirstCluster==0) i++;
692 if( i
==(ENTRIES_PER_SECTOR
))
693 {// entry is in next sector
695 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
698 memcpy(&Fcb
->entry
,&((FATDirEntry
*)block
)[i
],
699 sizeof(FATDirEntry
));
700 vfat_wcsncpy(Fcb
->ObjectName
,name
,261);
702 if(StartSector
) *StartSector
=StartingSector
;
704 return(STATUS_SUCCESS
);
708 // not found in this sector, try next :
710 /* It seems that directory sectors cannot be fragmented and therefore,
711 they only have a first cluster, but the one's after it are marked
712 with 0xffff. This theory is still not 100% certain, so the following
713 lines are commented and not removed */
717 /* if (Parent == NULL)
723 NextCluster = GetNextCluster(DeviceExt,NextCluster);
724 if (NextCluster == 0||NextCluster==0xffffffff)
726 if(StartSector) *StartSector=StartingSector;
729 return(STATUS_UNSUCCESSFUL);
731 StartingSector = ClusterToSector(DeviceExt,NextCluster);
735 if(StartSector
) *StartSector
=StartingSector
;
737 return(STATUS_UNSUCCESSFUL
);
741 NTSTATUS
FsdCloseFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
)
743 * FUNCTION: Closes a file
748 //FIXME : update entry in directory ?
749 pCcb
= (PVfatCCB
)(FileObject
->FsContext2
);
752 if(pFcb
->RefCount
<=0)
755 pFcb
->prevFcb
->nextFcb
=pFcb
->nextFcb
;
757 pFirstFcb
=pFcb
->nextFcb
;
759 pFcb
->nextFcb
->prevFcb
=pFcb
->prevFcb
;
763 return STATUS_SUCCESS
;
766 NTSTATUS
FsdOpenFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
769 * FUNCTION: Opens a file
781 DPRINT("FsdOpenFile(%08lx, %08lx, %08lx)\n",
785 // try first to find an existing FCB in memory
786 for (Fcb
=pFirstFcb
;Fcb
; Fcb
=Fcb
->nextFcb
)
788 if (DeviceExt
==Fcb
->pDevExt
789 && wstrcmpi(FileName
,Fcb
->PathName
))
792 FileObject
->FsContext
=(PVOID
) &Fcb
->NTRequiredFCB
;
793 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
794 memset(newCCB
,0,sizeof(VfatCCB
));
795 FileObject
->FsContext2
= newCCB
;
797 newCCB
->PtrFileObject
=FileObject
;
798 return(STATUS_SUCCESS
);
803 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(VfatFCB
));
804 memset(Fcb
,0,sizeof(VfatFCB
));
805 Fcb
->ObjectName
=Fcb
->PathName
;
811 DPRINT("current %w next %x\n",current
,next
);
815 next
= wcschr(next
+1,'\\');
821 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,current
,NULL
,NULL
);
822 if (Status
!= STATUS_SUCCESS
)
824 /* FIXME: should the VfatFCB be freed here? */
828 if (ParentFcb
== NULL
)
830 Fcb
= ExAllocatePool(NonPagedPool
,sizeof(VfatFCB
));
831 memset(Fcb
,0,sizeof(VfatFCB
));
832 Fcb
->ObjectName
=Fcb
->PathName
;
840 FileObject
->FsContext
=(PVOID
) &ParentFcb
->NTRequiredFCB
;
841 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
842 memset(newCCB
,0,sizeof(VfatCCB
));
843 FileObject
->FsContext2
= newCCB
;
844 newCCB
->pFcb
=ParentFcb
;
845 newCCB
->PtrFileObject
=FileObject
;
846 ParentFcb
->RefCount
++;
847 //FIXME : initialize all fields in FCB and CCB
848 ParentFcb
->nextFcb
=pFirstFcb
;
850 vfat_wcsncpy(ParentFcb
->PathName
,FileName
,261);
851 ParentFcb
->ObjectName
=Fcb
->PathName
+(current
-string
);
852 ParentFcb
->pDevExt
=DeviceExt
;
853 DPRINT("file open, fcb=%x\n",ParentFcb
);
854 DPRINT("FileSize %d\n",ParentFcb
->entry
.FileSize
);
856 return(STATUS_SUCCESS
);
859 BOOLEAN
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
861 * FUNCTION: Tests if the device contains a filesystem that can be mounted
867 Boot
= ExAllocatePool(NonPagedPool
,512);
869 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)Boot
);
871 if (strncmp(Boot
->SysType
,"FAT12",5)==0 ||
872 strncmp(Boot
->SysType
,"FAT16",5)==0 ||
873 strncmp(((struct _BootSector32
*)(Boot
))->SysType
,"FAT32",5)==0)
882 NTSTATUS
FsdMountDevice(PDEVICE_EXTENSION DeviceExt
,
883 PDEVICE_OBJECT DeviceToMount
)
885 * FUNCTION: Mounts the device
888 DPRINT("Mounting VFAT device...");
889 DPRINT("DeviceExt %x\n",DeviceExt
);
891 DeviceExt
->Boot
= ExAllocatePool(NonPagedPool
,512);
892 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)DeviceExt
->Boot
);
894 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
895 DeviceExt
->Boot
->BytesPerSector
);
897 DeviceExt
->FATStart
=DeviceExt
->Boot
->ReservedSectors
;
898 DeviceExt
->rootDirectorySectors
=
899 (DeviceExt
->Boot
->RootEntries
*32)/DeviceExt
->Boot
->BytesPerSector
;
900 DeviceExt
->rootStart
=
901 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
*DeviceExt
->Boot
->FATSectors
;
902 DeviceExt
->dataStart
=DeviceExt
->rootStart
+DeviceExt
->rootDirectorySectors
;
903 DeviceExt
->FATEntriesPerSector
=DeviceExt
->Boot
->BytesPerSector
/32;
904 DeviceExt
->BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
*
905 DeviceExt
->Boot
->BytesPerSector
;
907 if (strncmp(DeviceExt
->Boot
->SysType
,"FAT12",5)==0)
909 DeviceExt
->FatType
= FAT12
;
911 else if (strncmp(((struct _BootSector32
*)(DeviceExt
->Boot
))->SysType
,"FAT32",5)==0)
913 DeviceExt
->FatType
= FAT32
;
914 DeviceExt
->rootDirectorySectors
=DeviceExt
->Boot
->SectorsPerCluster
;
915 DeviceExt
->rootStart
=
916 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
917 * ((struct _BootSector32
*)( DeviceExt
->Boot
))->FATSectors32
;
918 DeviceExt
->dataStart
=DeviceExt
->rootStart
;
922 DeviceExt
->FatType
= FAT16
;
925 // with FAT32 it's not a good idea to load always fat in memory
926 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
927 if(DeviceExt
->FatType
!=FAT32
)
929 DeviceExt
->FAT
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
*DeviceExt
->Boot
->FATSectors
);
930 VFATReadSectors(DeviceToMount
, DeviceExt
->FATStart
, DeviceExt
->Boot
->FATSectors
, (UCHAR
*)DeviceExt
->FAT
);
932 return STATUS_SUCCESS
;
935 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
937 * FUNCTION: Load a cluster from the physical device
942 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
943 DeviceExt
,Buffer
,Cluster
);
945 Sector
= ClusterToSector(DeviceExt
, Cluster
);
947 VFATReadSectors(DeviceExt
->StorageDevice
,
949 DeviceExt
->Boot
->SectorsPerCluster
,
953 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
955 * FUNCTION: Write a cluster to the physical device
959 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
960 DeviceExt
,Buffer
,Cluster
);
962 Sector
= ClusterToSector(DeviceExt
, Cluster
);
964 VFATWriteSectors(DeviceExt
->StorageDevice
,
966 DeviceExt
->Boot
->SectorsPerCluster
,
970 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
971 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
974 * FUNCTION: Reads data from a file
977 ULONG CurrentCluster
;
984 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
985 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
988 FirstCluster
= ReadOffset
/ DeviceExt
->BytesPerCluster
;
989 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
990 if (DeviceExt
->FatType
== FAT32
)
991 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
993 CurrentCluster
= Fcb
->entry
.FirstCluster
;
994 if (CurrentCluster
<2)
995 return STATUS_UNSUCCESSFUL
;// FIXME : root of FAT16 or FAT12
996 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
998 if (ReadOffset
>= Fcb
->entry
.FileSize
)
1000 return(STATUS_END_OF_FILE
);
1002 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
)
1004 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
1007 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1008 if(!Temp
) return STATUS_UNSUCCESSFUL
;
1009 for (FileOffset
=0; FileOffset
< FirstCluster
; FileOffset
++)
1011 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1014 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
1016 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1017 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1019 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1020 (ReadOffset
% DeviceExt
->BytesPerCluster
));
1022 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
1025 (*LengthRead
) = (*LengthRead
) + TempLength
;
1026 Length
= Length
- TempLength
;
1027 Buffer
= Buffer
+ TempLength
;
1030 while (Length
> DeviceExt
->BytesPerCluster
)
1032 VFATLoadCluster(DeviceExt
, Buffer
, CurrentCluster
);
1033 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1035 if (CurrentCluster
== 0xffffffff)
1038 return(STATUS_SUCCESS
);
1041 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
1042 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1043 Length
= Length
- DeviceExt
->BytesPerCluster
;
1048 (*LengthRead
) = (*LengthRead
) + Length
;
1049 VFATLoadCluster(DeviceExt
, Temp
, CurrentCluster
);
1050 memcpy(Buffer
, Temp
, Length
);
1053 return(STATUS_SUCCESS
);
1056 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1057 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
1059 * FUNCTION: Writes data to file
1062 ULONG CurrentCluster
;
1069 /* Locate the first cluster of the file */
1070 FirstCluster
= WriteOffset
/ DeviceExt
->BytesPerCluster
;
1071 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1072 if (DeviceExt
->FatType
== FAT32
)
1073 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
1075 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1077 /* Allocate a buffer to hold 1 cluster of data */
1079 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1081 /* Find the cluster according to the offset in the file */
1083 for (FileOffset
=0; FileOffset
< FirstCluster
; FileOffset
++)
1085 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1090 If the offset in the cluster doesn't fall on the cluster boundary then
1091 we have to write only from the specified offset
1094 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
1096 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1097 (WriteOffset
% DeviceExt
->BytesPerCluster
));
1098 /* Read in the existing cluster data */
1099 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1101 /* Overwrite the last parts of the data as necessary */
1102 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
), Buffer
,
1105 /* Write the cluster back */
1106 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1107 Length
= Length
- TempLength
;
1108 Buffer
= Buffer
+ TempLength
;
1112 /* Write the buffer in chunks of 1 cluster */
1114 while (Length
> DeviceExt
->BytesPerCluster
)
1116 /* Next write cluster */
1117 CurrentCluster
= GetNextWriteCluster(DeviceExt
, CurrentCluster
);
1118 if (CurrentCluster
== 0)
1121 return(STATUS_UNSUCCESSFUL
);
1123 VFATWriteCluster(DeviceExt
, Buffer
, CurrentCluster
);
1124 CurrentCluster
= GetNextWriteCluster(DeviceExt
, CurrentCluster
);
1127 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1128 Length
= Length
- DeviceExt
->BytesPerCluster
;
1132 /* Write the remainder */
1136 CurrentCluster
= GetNextWriteCluster(DeviceExt
, CurrentCluster
);
1137 if (CurrentCluster
== 0)
1140 return(STATUS_UNSUCCESSFUL
);
1142 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1143 memcpy(Temp
, Buffer
, Length
);
1144 VFATWriteCluster(DeviceExt
, Temp
, CurrentCluster
);
1146 //FIXME : set last write time and date
1147 if(Fcb
->entry
.FileSize
<WriteOffset
+Length
)
1148 Fcb
->entry
.FileSize
=WriteOffset
+Length
;
1149 //FIXME : update entry in directory
1151 return(STATUS_SUCCESS
);
1154 NTSTATUS
FsdClose(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1156 * FUNCTION: Close a file
1159 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1160 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1161 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1164 Status
= FsdCloseFile(DeviceExtension
,FileObject
);
1166 Irp
->IoStatus
.Status
= Status
;
1167 Irp
->IoStatus
.Information
= 0;
1169 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1173 NTSTATUS
FsdCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1175 * FUNCTION: Create or open a file
1178 PIO_STACK_LOCATION Stack
;
1179 PFILE_OBJECT FileObject
;
1181 PDEVICE_EXTENSION DeviceExt
;
1183 DPRINT("FsdCreate(DeviceObject %08lx, Irp %08lx)\n",
1187 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1189 FileObject
= Stack
->FileObject
;
1191 DeviceExt
= DeviceObject
->DeviceExtension
;
1193 Status
= FsdOpenFile(DeviceExt
,FileObject
,FileObject
->FileName
.Buffer
);
1196 Irp
->IoStatus
.Status
= Status
;
1198 Irp
->IoStatus
.Information
= 0;
1201 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1208 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1210 * FUNCTION: Write to a file
1216 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1217 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1218 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1221 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
1223 Length
= Stack
->Parameters
.Write
.Length
;
1224 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1225 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Write
.ByteOffset
);
1227 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
1229 Irp
->IoStatus
.Status
= Status
;
1230 Irp
->IoStatus
.Information
= Length
;
1231 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1236 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1238 * FUNCTION: Read from a file
1244 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1245 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1246 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1250 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1252 Length
= Stack
->Parameters
.Read
.Length
;
1253 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1254 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Read
.ByteOffset
);
1256 Status
= FsdReadFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
,
1259 Irp
->IoStatus
.Status
= Status
;
1260 Irp
->IoStatus
.Information
= LengthRead
;
1261 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1267 NTSTATUS
FsdMount(PDEVICE_OBJECT DeviceToMount
)
1269 * FUNCTION: Mount the filesystem
1272 PDEVICE_OBJECT DeviceObject
;
1273 PDEVICE_EXTENSION DeviceExt
;
1275 IoCreateDevice(DriverObject
,
1276 sizeof(DEVICE_EXTENSION
),
1278 FILE_DEVICE_FILE_SYSTEM
,
1282 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
1283 DeviceExt
= (PVOID
)DeviceObject
->DeviceExtension
;
1284 // use same vpb as device disk
1285 DeviceObject
->Vpb
=DeviceToMount
->Vpb
;
1286 FsdMountDevice(DeviceExt
,DeviceToMount
);
1287 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
1288 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1290 return(STATUS_SUCCESS
);
1293 NTSTATUS
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1295 * FUNCTION: File system control
1298 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1299 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1300 PDEVICE_OBJECT DeviceToMount
= Stack
->Parameters
.Mount
.DeviceObject
;
1303 DPRINT("VFAT FSC\n");
1305 if (FsdHasFileSystem(DeviceToMount
))
1307 Status
= FsdMount(DeviceToMount
);
1311 DPRINT("VFAT: Unrecognized Volume\n");
1312 Status
= STATUS_UNRECOGNIZED_VOLUME
;
1314 DPRINT("VFAT File system successfully mounted\n");
1316 Irp
->IoStatus
.Status
= Status
;
1317 Irp
->IoStatus
.Information
= 0;
1319 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1323 NTSTATUS
FsdGetStandardInformation(PVfatFCB FCB
, PDEVICE_OBJECT DeviceObject
,
1324 PFILE_STANDARD_INFORMATION StandardInfo
)
1326 * FUNCTION: Retrieve the standard file information
1329 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1330 unsigned long AllocSize
;
1332 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
1334 /* Make allocsize a rounded up multiple of BytesPerCluster */
1335 AllocSize
= ((FCB
->entry
.FileSize
+ DeviceExtension
->BytesPerCluster
- 1) /
1336 DeviceExtension
->BytesPerCluster
) *
1337 DeviceExtension
->BytesPerCluster
;
1339 StandardInfo
->AllocationSize
= RtlConvertUlongToLargeInteger(AllocSize
);
1340 StandardInfo
->EndOfFile
= RtlConvertUlongToLargeInteger(FCB
->entry
.FileSize
);
1341 StandardInfo
->NumberOfLinks
= 0;
1342 StandardInfo
->DeletePending
= FALSE
;
1343 if((FCB
->entry
.Attrib
& 0x10)>0) {
1344 StandardInfo
->Directory
= TRUE
;
1346 StandardInfo
->Directory
= FALSE
;
1349 return STATUS_SUCCESS
;
1352 NTSTATUS
FsdQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1354 * FUNCTION: Retrieve the specified file information
1357 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1358 FILE_INFORMATION_CLASS FileInformationClass
=
1359 Stack
->Parameters
.QueryFile
.FileInformationClass
;
1360 PFILE_OBJECT FileObject
= NULL
;
1361 PVfatFCB FCB
= NULL
;
1362 // PVfatCCB CCB = NULL;
1364 NTSTATUS RC
= STATUS_SUCCESS
;
1367 FileObject
= Stack
->FileObject
;
1368 // CCB = (PVfatCCB)(FileObject->FsContext2);
1369 // FCB = CCB->Buffer; // Should be CCB->FCB???
1370 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1372 SystemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1374 switch(FileInformationClass
) {
1375 case FileStandardInformation
:
1376 RC
= FsdGetStandardInformation(FCB
, DeviceObject
, SystemBuffer
);
1379 RC
=STATUS_NOT_IMPLEMENTED
;
1385 NTSTATUS
DriverEntry(PDRIVER_OBJECT _DriverObject
,
1386 PUNICODE_STRING RegistryPath
)
1388 * FUNCTION: Called by the system to initalize the driver
1390 * DriverObject = object describing this driver
1391 * RegistryPath = path to our configuration entries
1392 * RETURNS: Success or failure
1395 PDEVICE_OBJECT DeviceObject
;
1397 UNICODE_STRING ustr
;
1400 DbgPrint("VFAT 0.0.6\n");
1402 DriverObject
= _DriverObject
;
1404 RtlInitAnsiString(&astr
,"\\Device\\VFAT");
1405 RtlAnsiStringToUnicodeString(&ustr
,&astr
,TRUE
);
1406 ret
= IoCreateDevice(DriverObject
,0,&ustr
,
1407 FILE_DEVICE_FILE_SYSTEM
,0,FALSE
,&DeviceObject
);
1408 if (ret
!=STATUS_SUCCESS
)
1413 DeviceObject
->Flags
=0;
1414 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FsdClose
;
1415 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FsdCreate
;
1416 DriverObject
->MajorFunction
[IRP_MJ_READ
] = FsdRead
;
1417 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FsdWrite
;
1418 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
1419 FsdFileSystemControl
;
1420 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
1421 FsdQueryInformation
;
1422 DriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] =
1423 FsdDirectoryControl
;
1425 DriverObject
->DriverUnload
= NULL
;
1427 IoRegisterFileSystem(DeviceObject
);
1429 return(STATUS_SUCCESS
);