2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: services/fs/vfat/iface.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 24-10-1998 Fixed bugs in long filename support
10 Fixed a bug that prevented unsuccessful file open requests being reported
11 Now works with long filenames that span over a sector boundary
12 28-10-1998 Reads entire FAT into memory
13 VFatReadSector modified to read in more than one sector at a time
14 7-11-1998 Fixed bug that assumed that directory data could be fragmented
15 8-12-1998 Added FAT32 support
16 Added initial writability functions
17 WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
18 12-12-1998 Added basic support for FILE_STANDARD_INFORMATION request
22 /* INCLUDES *****************************************************************/
25 #include <internal/string.h>
26 #include <ddk/ntddk.h>
27 #include <ddk/cctypes.h>
30 #include <internal/debug.h>
34 //#include "dbgpool.c"
36 /* GLOBALS *****************************************************************/
38 static PDRIVER_OBJECT VFATDriverObject
;
41 /* FUNCTIONS ****************************************************************/
43 ULONG
Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
45 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
53 Block
= ExAllocatePool(NonPagedPool
,1024);
54 FATsector
=CurrentCluster
/(512/sizeof(ULONG
));
55 FATeis
=CurrentCluster
-(FATsector
*(512/sizeof(ULONG
)));
56 VFATReadSectors(DeviceExt
->StorageDevice
57 ,(ULONG
)(DeviceExt
->FATStart
+FATsector
), 1,(UCHAR
*) Block
);
58 CurrentCluster
= Block
[FATeis
];
59 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
60 CurrentCluster
= 0xffffffff;
62 return(CurrentCluster
);
65 ULONG
Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
67 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
72 Block
=(PUSHORT
)DeviceExt
->FAT
;
73 CurrentCluster
= Block
[CurrentCluster
];
74 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
75 CurrentCluster
= 0xffffffff;
76 DPRINT("Returning %x\n",CurrentCluster
);
77 return(CurrentCluster
);
80 ULONG
Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
82 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
86 unsigned char* CBlock
;
89 CBlock
= DeviceExt
->FAT
;
90 FATOffset
= (CurrentCluster
* 12)/ 8;//first byte containing value
91 if ((CurrentCluster
% 2) == 0)
93 Entry
= CBlock
[FATOffset
];
94 Entry
|= ((CBlock
[FATOffset
+1] & 0xf)<<8);
98 Entry
= (CBlock
[FATOffset
] >> 4);
99 Entry
|= (CBlock
[FATOffset
+1] << 4);
101 DPRINT("Entry %x\n",Entry
);
102 if (Entry
>= 0xff8 && Entry
<= 0xfff)
104 DPRINT("Returning %x\n",Entry
);
108 ULONG
GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
110 * FUNCTION: Retrieve the next cluster depending on the FAT type
114 DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
115 DeviceExt
,CurrentCluster
);
116 if (DeviceExt
->FatType
== FAT16
)
117 return(Fat16GetNextCluster(DeviceExt
, CurrentCluster
));
118 else if (DeviceExt
->FatType
== FAT32
)
119 return(Fat32GetNextCluster(DeviceExt
, CurrentCluster
));
121 return(Fat12GetNextCluster(DeviceExt
, CurrentCluster
));
124 ULONG
FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
126 * FUNCTION: Finds the first available cluster in a FAT16 table
131 Block
=(PUSHORT
)DeviceExt
->FAT
;
132 for(i
=2;i
<(DeviceExt
->Boot
->FATSectors
*256) ;i
++)
135 /* Give an error message (out of disk space) if we reach here) */
139 ULONG
FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
141 * FUNCTION: Finds the first available cluster in a FAT12 table
146 PUCHAR CBlock
=DeviceExt
->FAT
;
148 for(i
=2;i
<((DeviceExt
->Boot
->FATSectors
*512*8)/12) ;i
++)
150 FATOffset
= (i
* 12)/8;
153 Entry
= CBlock
[FATOffset
];
154 Entry
|= ((CBlock
[FATOffset
+ 1] & 0xf)<<8);
158 Entry
= (CBlock
[FATOffset
] >> 4);
159 Entry
|= (CBlock
[FATOffset
+ 1] << 4);
164 /* Give an error message (out of disk space) if we reach here) */
165 DbgPrint("Disk full, %d clusters used\n",i
);
169 ULONG
FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
171 * FUNCTION: Finds the first available cluster in a FAT32 table
177 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
179 ;sector
< ((struct _BootSector32
*)(DeviceExt
->Boot
))->FATSectors32
182 VFATReadSectors(DeviceExt
->StorageDevice
183 ,(ULONG
)(DeviceExt
->FATStart
+sector
), 1,(UCHAR
*) Block
);
190 return (i
+sector
*128);
194 /* Give an error message (out of disk space) if we reach here) */
199 ULONG
FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt
)
201 * FUNCTION: Counts free cluster in a FAT12 table
206 PUCHAR CBlock
=DeviceExt
->FAT
;
210 for(i
=2;i
<((DeviceExt
->Boot
->FATSectors
*512*8)/12) ;i
++)
212 FATOffset
= (i
* 12)/8;
215 Entry
= CBlock
[FATOffset
];
216 Entry
|= ((CBlock
[FATOffset
+ 1] & 0xf)<<8);
220 Entry
= (CBlock
[FATOffset
] >> 4);
221 Entry
|= (CBlock
[FATOffset
+ 1] << 4);
229 ULONG
FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt
)
231 * FUNCTION: Counts free clusters in a FAT16 table
238 Block
=(PUSHORT
)DeviceExt
->FAT
;
239 for(i
=2;i
<(DeviceExt
->Boot
->FATSectors
*256) ;i
++)
245 ULONG
FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt
)
247 * FUNCTION: Counts free clusters in a FAT32 table
255 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
257 ;sector
< ((struct _BootSector32
*)(DeviceExt
->Boot
))->FATSectors32
260 VFATReadSectors(DeviceExt
->StorageDevice
261 ,(ULONG
)(DeviceExt
->FATStart
+sector
), 1,(UCHAR
*) Block
);
269 /* Give an error message (out of disk space) if we reach here) */
274 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
277 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
282 PUCHAR CBlock
=DeviceExt
->FAT
;
284 FATOffset
= (ClusterToWrite
* 12)/8;
285 if ((ClusterToWrite
% 2) == 0)
287 CBlock
[FATOffset
]=NewValue
;
288 CBlock
[FATOffset
+ 1] &=0xf0;
289 CBlock
[FATOffset
+ 1]
290 |= (NewValue
&0xf00)>>8;
294 CBlock
[FATOffset
] &=0x0f;
296 |= (NewValue
&0xf)<<4;
297 CBlock
[FATOffset
+1]=NewValue
>>4;
299 /* Write the changed FAT sector(s) to disk */
300 FATsector
=FATOffset
/BLOCKSIZE
;
301 for(i
=0;i
<DeviceExt
->Boot
->FATCount
;i
++)
303 if( (FATOffset
%BLOCKSIZE
)==(BLOCKSIZE
-1))//entry is on 2 sectors
305 VFATWriteSectors(DeviceExt
->StorageDevice
,
306 DeviceExt
->FATStart
+FATsector
307 +i
*DeviceExt
->Boot
->FATSectors
,
309 CBlock
+FATsector
*512);
313 VFATWriteSectors(DeviceExt
->StorageDevice
,
314 DeviceExt
->FATStart
+FATsector
315 +i
*DeviceExt
->Boot
->FATSectors
,
317 CBlock
+FATsector
*512);
322 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
325 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
330 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
331 Block
=(PUSHORT
)DeviceExt
->FAT
;
332 FATsector
=ClusterToWrite
/(512/sizeof(USHORT
));
334 /* Update the in-memory FAT */
335 Block
[ClusterToWrite
] = NewValue
;
336 /* Write the changed FAT sector to disk */
337 VFATWriteSectors(DeviceExt
->StorageDevice
,
338 DeviceExt
->FATStart
+FATsector
,
343 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
346 * FUNCTION: Writes a cluster to the FAT32 physical tables
352 DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
353 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
354 FATsector
=ClusterToWrite
/128;
355 FATeis
=ClusterToWrite
-(FATsector
*128);
356 /* load sector, change value, then rewrite sector */
357 VFATReadSectors(DeviceExt
->StorageDevice
,
358 DeviceExt
->FATStart
+FATsector
,
361 Block
[FATeis
] = NewValue
;
362 VFATWriteSectors(DeviceExt
->StorageDevice
,
363 DeviceExt
->FATStart
+FATsector
,
369 void WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
372 * FUNCTION: Write a changed FAT entry
375 if(DeviceExt
->FatType
==FAT16
)
376 FAT16WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
377 else if(DeviceExt
->FatType
==FAT32
)
378 FAT32WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
380 FAT12WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
383 ULONG
GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
385 * FUNCTION: Determines the next cluster to be written
388 ULONG LastCluster
, NewCluster
;
389 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
390 DeviceExt
,CurrentCluster
);
392 /* Find out what was happening in the last cluster's AU */
393 LastCluster
=GetNextCluster(DeviceExt
,CurrentCluster
);
394 /* Check to see if we must append or overwrite */
395 if (LastCluster
==0xffffffff)
396 {//we are after last existing cluster : we must add one to file
398 /* Firstly, find the next available open allocation unit */
399 if(DeviceExt
->FatType
== FAT16
)
400 NewCluster
= FAT16FindAvailableCluster(DeviceExt
);
401 else if(DeviceExt
->FatType
== FAT32
)
402 NewCluster
= FAT32FindAvailableCluster(DeviceExt
);
404 NewCluster
= FAT12FindAvailableCluster(DeviceExt
);
405 /* Mark the new AU as the EOF */
406 WriteCluster(DeviceExt
, NewCluster
, 0xFFFFFFFF);
407 /* Now, write the AU of the LastCluster with the value of the newly
410 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
411 /* Return NewCluster as CurrentCluster */
416 /* Overwrite: Return LastCluster as CurrentCluster */
421 ULONG
ClusterToSector(PDEVICE_EXTENSION DeviceExt
,
422 unsigned long Cluster
)
424 * FUNCTION: Converts the cluster number to a sector number for this physical
428 return DeviceExt
->dataStart
+((Cluster
-2)*DeviceExt
->Boot
->SectorsPerCluster
);
431 void RtlAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
433 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
438 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
445 void RtlCatAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
447 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
448 * existing Unicode string
457 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
464 void vfat_initstr(wchar_t *wstr
, ULONG wsize
)
466 * FUNCTION: Initialize a string for use with a long file name
471 for(i
=0; i
<wsize
; i
++)
479 wchar_t * vfat_wcsncat(wchar_t * dest
, const wchar_t * src
,size_t wstart
, size_t wcount
)
481 * FUNCTION: Append a string for use with a long file name
487 for(i
=0; i
<wcount
; i
++)
492 dest
=dest
-(wcount
+wstart
);
497 wchar_t * vfat_wcsncpy(wchar_t * dest
, const wchar_t *src
,size_t wcount
)
499 * FUNCTION: Copy a string for use with long file names
504 for (i
=0;i
<wcount
;i
++)
512 wchar_t * vfat_movstr(const wchar_t *src
, ULONG dpos
,
513 ULONG spos
, ULONG len
)
515 * FUNCTION: Move the characters in a string to a new position in the same
525 src
[dpos
++]=src
[spos
++];
534 src
[dpos
--]=src
[spos
--];
541 BOOLEAN
IsLastEntry(PVOID Block
, ULONG Offset
)
543 * FUNCTION: Determine if the given directory entry is the last
546 return(((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0);
549 BOOLEAN
IsVolEntry(PVOID Block
, ULONG Offset
)
551 * FUNCTION: Determine if the given directory entry is a vol entry
554 if( (((FATDirEntry
*)Block
)[Offset
].Attrib
)==0x28 ) return TRUE
;
558 BOOLEAN
IsDeletedEntry(PVOID Block
, ULONG Offset
)
560 * FUNCTION: Determines if the given entry is a deleted one
563 /* Checks special character */
565 return ((((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0xe5));
568 BOOLEAN
GetEntryName(PVOID Block
, PULONG _Offset
, PWSTR Name
, PULONG _jloop
,
569 PDEVICE_EXTENSION DeviceExt
, ULONG
* _StartingSector
)
571 * FUNCTION: Retrieves the file name, be it in short or long file name format
576 ULONG Offset
= *_Offset
;
577 ULONG StartingSector
= *_StartingSector
;
578 ULONG jloop
= *_jloop
;
582 test
= (FATDirEntry
*)Block
;
583 test2
= (slot
*)Block
;
587 if (IsDeletedEntry(Block
,Offset
))
592 if(test2
[Offset
].attr
== 0x0f)
594 vfat_initstr(Name
, 256);
595 vfat_wcsncpy(Name
,test2
[Offset
].name0_4
,5);
596 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
597 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
600 while((test2
[Offset
].id
!=0x41) && (test2
[Offset
].id
!=0x01) &&
601 (test2
[Offset
].attr
>0))
604 if(Offset
==ENTRIES_PER_SECTOR
) {
606 StartingSector
++;//FIXME : nor always the next sector
608 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,Block
);
609 test2
= (slot
*)Block
;
612 vfat_movstr(Name
, 13, 0, cpos
*13);
613 vfat_wcsncpy(Name
, test2
[Offset
].name0_4
, 5);
614 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
615 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
619 if (IsDeletedEntry(Block
,Offset
+1))
624 *_StartingSector
= StartingSector
;
630 *_StartingSector
= StartingSector
;
635 RtlAnsiToUnicode(Name
,test
[Offset
].Filename
,8);
636 if (test
[Offset
].Ext
[0]!=' ')
638 RtlCatAnsiToUnicode(Name
,".",1);
640 RtlCatAnsiToUnicode(Name
,test
[Offset
].Ext
,3);
647 BOOLEAN
wstrcmpi(PWSTR s1
, PWSTR s2
)
649 * FUNCTION: Compare to wide character strings
650 * return TRUE if s1==s2
653 while (towlower(*s1
)==towlower(*s2
))
655 if ((*s1
)==0 && (*s2
)==0)
665 BOOLEAN
wstrcmpjoki(PWSTR s1
, PWSTR s2
)
667 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
668 * return TRUE if s1 like s2
671 while ((*s2
=='?')||(towlower(*s1
)==towlower(*s2
)))
673 if ((*s1
)==0 && (*s2
)==0)
682 if (wstrcmpjoki(s1
,s2
)) return TRUE
;
685 if ((*s1
)==0 && (*s2
)==0)
690 NTSTATUS
FindFile(PDEVICE_EXTENSION DeviceExt
, PVfatFCB Fcb
,
691 PVfatFCB Parent
, PWSTR FileToFind
,ULONG
*StartSector
,ULONG
*Entry
)
693 * FUNCTION: Find a file
700 ULONG StartingSector
;
704 DPRINT("FindFile(Parent %x, FileToFind '%w')\n",Parent
,FileToFind
);
706 if (wcslen(FileToFind
)==0)
708 TempStr
[0] = (WCHAR
)'.';
714 DPRINT("Parent->entry.FirstCluster %d\n",Parent
->entry
.FirstCluster
);
717 if (Parent
== NULL
||Parent
->entry
.FirstCluster
==1)
719 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
720 StartingSector
= DeviceExt
->rootStart
;
722 if(FileToFind
[0]==0 ||(FileToFind
[0]=='\\' && FileToFind
[1]==0) ||
723 (FileToFind
[0]=='.' && FileToFind
[1]==0))
724 {// it's root : complete essentials fields then return ok
725 memset(Fcb
,0,sizeof(VfatFCB
));
726 memset(Fcb
->entry
.Filename
,' ',11);
727 Fcb
->entry
.FileSize
=DeviceExt
->rootDirectorySectors
*BLOCKSIZE
;
728 Fcb
->entry
.Attrib
=FILE_ATTRIBUTE_DIRECTORY
;
729 if (DeviceExt
->FatType
== FAT32
)
730 Fcb
->entry
.FirstCluster
=2;
731 else Fcb
->entry
.FirstCluster
=1;//FIXME : is 1 the good value for mark root?
732 if(StartSector
) *StartSector
=StartingSector
;
734 return(STATUS_SUCCESS
);
739 DPRINT("Parent->entry.FileSize %x\n",Parent
->entry
.FileSize
);
742 if (DeviceExt
->FatType
== FAT32
)
743 NextCluster
= Parent
->entry
.FirstCluster
744 +Parent
->entry
.FirstClusterHigh
*65536;
746 NextCluster
= Parent
->entry
.FirstCluster
;
747 StartingSector
= ClusterToSector(DeviceExt
, NextCluster
);
748 if(Parent
->entry
.FirstCluster
==1 && DeviceExt
->FatType
!=FAT32
)
749 {// read of root directory in FAT16 or FAT12
750 StartingSector
=DeviceExt
->rootStart
;
753 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
754 if (StartSector
&& (*StartSector
)) StartingSector
=*StartSector
;
755 i
=(Entry
)?(*Entry
):0;
756 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
757 for (j
=0; j
<Size
; j
++)
759 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
761 for (i
=(Entry
)?(*Entry
):0; i
<ENTRIES_PER_SECTOR
; i
++)
763 if (IsVolEntry((PVOID
)block
,i
))
765 if (IsLastEntry((PVOID
)block
,i
))
768 if(StartSector
) *StartSector
=StartingSector
;
770 return(STATUS_UNSUCCESSFUL
);
772 if (GetEntryName((PVOID
)block
,&i
,name
,&j
,DeviceExt
,&StartingSector
))
774 DPRINT("Comparing '%w' '%w'\n",name
,FileToFind
);
775 if (wstrcmpjoki(name
,FileToFind
))
777 /* In the case of a long filename, the firstcluster is stored in
778 the next record -- where it's short name is */
779 if(((FATDirEntry
*)block
)[i
].Attrib
==0x0f) i
++;
780 if( i
==(ENTRIES_PER_SECTOR
))
781 {// entry is in next sector
783 //FIXME : treat case of next sector fragmented
784 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
787 memcpy(&Fcb
->entry
,&((FATDirEntry
*)block
)[i
],
788 sizeof(FATDirEntry
));
789 vfat_wcsncpy(Fcb
->ObjectName
,name
,MAX_PATH
);
791 if(StartSector
) *StartSector
=StartingSector
;
793 return(STATUS_SUCCESS
);
797 // not found in this sector, try next :
799 /* directory can be fragmented although it is best to keep them
803 if ((Parent
!= NULL
&& Parent
->entry
.FirstCluster
!=1)
804 || DeviceExt
->FatType
==FAT32
)
806 if(StartingSector
==ClusterToSector(DeviceExt
,NextCluster
+1))
808 NextCluster
= GetNextCluster(DeviceExt
,NextCluster
);
809 if (NextCluster
== 0||NextCluster
==0xffffffff)
811 if(StartSector
) *StartSector
=StartingSector
;
814 return(STATUS_UNSUCCESSFUL
);
816 StartingSector
= ClusterToSector(DeviceExt
,NextCluster
);
821 if(StartSector
) *StartSector
=StartingSector
;
823 return(STATUS_UNSUCCESSFUL
);
827 NTSTATUS
FsdCloseFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
)
829 * FUNCTION: Closes a file
835 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
836 DeviceExt
,FileObject
);
838 //FIXME : update entry in directory ?
839 pCcb
= (PVfatCCB
)(FileObject
->FsContext2
);
841 DPRINT("pCcb %x\n",pCcb
);
844 return(STATUS_SUCCESS
);
850 if(pFcb
->RefCount
<=0)
853 pFcb
->prevFcb
->nextFcb
=pFcb
->nextFcb
;
855 pFirstFcb
=pFcb
->nextFcb
;
857 pFcb
->nextFcb
->prevFcb
=pFcb
->prevFcb
;
861 return STATUS_SUCCESS
;
864 NTSTATUS
FsdOpenFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
867 * FUNCTION: Opens a file
874 PVfatFCB Fcb
,pRelFcb
;
876 PVfatCCB newCCB
,pRelCcb
;
878 PFILE_OBJECT pRelFileObject
;
879 PWSTR AbsFileName
=NULL
;
882 DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
887 //FIXME : treat relative name
888 if(FileObject
->RelatedFileObject
)
890 DbgPrint("try related for %w\n",FileName
);
891 pRelFileObject
=FileObject
->RelatedFileObject
;
892 pRelCcb
=pRelFileObject
->FsContext2
;
894 pRelFcb
=pRelCcb
->pFcb
;
896 // verify related object is a directory and target name don't start with \.
897 if( !(pRelFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
898 || (FileName
[0]!= '\\') )
900 Status
=STATUS_INVALID_PARAMETER
;
903 // construct absolute path name
904 AbsFileName
=ExAllocatePool(NonPagedPool
,MAX_PATH
);
905 for (i
=0;pRelFcb
->PathName
[i
];i
++)
906 AbsFileName
[i
]=pRelFcb
->PathName
[i
];
907 AbsFileName
[i
++]='\\';
908 for (j
=0;FileName
[j
]&&i
<MAX_PATH
;j
++)
909 AbsFileName
[i
++]=FileName
[j
];
912 FileName
=AbsFileName
;
914 // try first to find an existing FCB in memory
915 for (Fcb
=pFirstFcb
;Fcb
; Fcb
=Fcb
->nextFcb
)
917 if (DeviceExt
==Fcb
->pDevExt
918 && wstrcmpi(FileName
,Fcb
->PathName
))
921 FileObject
->FsContext
=(PVOID
) &Fcb
->NTRequiredFCB
;
922 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
923 memset(newCCB
,0,sizeof(VfatCCB
));
924 FileObject
->FsContext2
= newCCB
;
926 newCCB
->PtrFileObject
=FileObject
;
927 if(AbsFileName
)ExFreePool(AbsFileName
);
928 return(STATUS_SUCCESS
);
933 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(VfatFCB
));
934 memset(Fcb
,0,sizeof(VfatFCB
));
935 Fcb
->ObjectName
=Fcb
->PathName
;
942 next
= wcschr(next
+1,'\\');
947 DPRINT("current '%w'\n",current
);
948 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,current
,NULL
,NULL
);
949 if (Status
!= STATUS_SUCCESS
)
953 if (ParentFcb
!= NULL
)
954 ExFreePool(ParentFcb
);
955 if(AbsFileName
)ExFreePool(AbsFileName
);
959 if (ParentFcb
== NULL
)
961 Fcb
= ExAllocatePool(NonPagedPool
,sizeof(VfatFCB
));
962 memset(Fcb
,0,sizeof(VfatFCB
));
963 Fcb
->ObjectName
=Fcb
->PathName
;
965 else Fcb
= ParentFcb
;
968 FileObject
->FsContext
=(PVOID
) &ParentFcb
->NTRequiredFCB
;
969 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
970 memset(newCCB
,0,sizeof(VfatCCB
));
971 FileObject
->FsContext2
= newCCB
;
972 newCCB
->pFcb
=ParentFcb
;
973 newCCB
->PtrFileObject
=FileObject
;
974 ParentFcb
->RefCount
++;
975 //FIXME : initialize all fields in FCB and CCB
976 ParentFcb
->nextFcb
=pFirstFcb
;
978 vfat_wcsncpy(ParentFcb
->PathName
,FileName
,MAX_PATH
);
979 ParentFcb
->ObjectName
=ParentFcb
->PathName
+(current
-FileName
);
980 ParentFcb
->pDevExt
=DeviceExt
;
981 DPRINT("file open, fcb=%x\n",ParentFcb
);
982 DPRINT("FileSize %d\n",ParentFcb
->entry
.FileSize
);
983 if(Fcb
) ExFreePool(Fcb
);
984 if(AbsFileName
)ExFreePool(AbsFileName
);
985 return(STATUS_SUCCESS
);
989 BOOLEAN
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
991 * FUNCTION: Tests if the device contains a filesystem that can be mounted
997 Boot
= ExAllocatePool(NonPagedPool
,512);
999 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)Boot
);
1001 if (strncmp(Boot
->SysType
,"FAT12",5)==0 ||
1002 strncmp(Boot
->SysType
,"FAT16",5)==0 ||
1003 strncmp(((struct _BootSector32
*)(Boot
))->SysType
,"FAT32",5)==0)
1012 NTSTATUS
FsdMountDevice(PDEVICE_EXTENSION DeviceExt
,
1013 PDEVICE_OBJECT DeviceToMount
)
1015 * FUNCTION: Mounts the device
1018 DPRINT("Mounting VFAT device...");
1019 DPRINT("DeviceExt %x\n",DeviceExt
);
1021 DeviceExt
->Boot
= ExAllocatePool(NonPagedPool
,512);
1022 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)DeviceExt
->Boot
);
1024 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
1025 DeviceExt
->Boot
->BytesPerSector
);
1027 DeviceExt
->FATStart
=DeviceExt
->Boot
->ReservedSectors
;
1028 DeviceExt
->rootDirectorySectors
=
1029 (DeviceExt
->Boot
->RootEntries
*32)/DeviceExt
->Boot
->BytesPerSector
;
1030 DeviceExt
->rootStart
=
1031 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
*DeviceExt
->Boot
->FATSectors
;
1032 DeviceExt
->dataStart
=DeviceExt
->rootStart
+DeviceExt
->rootDirectorySectors
;
1033 DeviceExt
->FATEntriesPerSector
=DeviceExt
->Boot
->BytesPerSector
/32;
1034 DeviceExt
->BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
*
1035 DeviceExt
->Boot
->BytesPerSector
;
1037 if (strncmp(DeviceExt
->Boot
->SysType
,"FAT12",5)==0)
1039 DeviceExt
->FatType
= FAT12
;
1041 else if (strncmp(((struct _BootSector32
*)(DeviceExt
->Boot
))->SysType
,"FAT32",5)==0)
1043 DeviceExt
->FatType
= FAT32
;
1044 DeviceExt
->rootDirectorySectors
=DeviceExt
->Boot
->SectorsPerCluster
;
1045 DeviceExt
->rootStart
=
1046 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
1047 * ((struct _BootSector32
*)( DeviceExt
->Boot
))->FATSectors32
;
1048 DeviceExt
->dataStart
=DeviceExt
->rootStart
;
1052 DeviceExt
->FatType
= FAT16
;
1055 // with FAT32 it's not a good idea to load always fat in memory
1056 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
1057 if(DeviceExt
->FatType
!=FAT32
)
1059 DeviceExt
->FAT
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
*DeviceExt
->Boot
->FATSectors
);
1060 VFATReadSectors(DeviceToMount
, DeviceExt
->FATStart
, DeviceExt
->Boot
->FATSectors
, (UCHAR
*)DeviceExt
->FAT
);
1062 return STATUS_SUCCESS
;
1065 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
1067 * FUNCTION: Load a cluster from the physical device
1072 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1073 DeviceExt
,Buffer
,Cluster
);
1075 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1077 VFATReadSectors(DeviceExt
->StorageDevice
,
1079 DeviceExt
->Boot
->SectorsPerCluster
,
1083 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
1085 * FUNCTION: Write a cluster to the physical device
1089 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1090 DeviceExt
,Buffer
,Cluster
);
1092 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1094 VFATWriteSectors(DeviceExt
->StorageDevice
,
1096 DeviceExt
->Boot
->SectorsPerCluster
,
1100 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1101 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
1104 * FUNCTION: Reads data from a file
1107 ULONG CurrentCluster
;
1115 assert(DeviceExt
!= NULL
);
1116 assert(DeviceExt
->BytesPerCluster
!= 0);
1117 assert(FileObject
!= NULL
);
1118 assert(FileObject
->FsContext
!= NULL
);
1120 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1121 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
1124 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1125 if (DeviceExt
->FatType
== FAT32
)
1126 CurrentCluster
= Fcb
->entry
.FirstCluster
1127 +Fcb
->entry
.FirstClusterHigh
*65536;
1129 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1130 FirstCluster
=CurrentCluster
;
1131 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
1133 if (ReadOffset
>= Fcb
->entry
.FileSize
1134 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1136 return(STATUS_END_OF_FILE
);
1138 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
1139 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1141 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
1144 /* FIXME: optimize by remembering the last cluster read and using if possible */
1145 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1146 if(!Temp
) return STATUS_UNSUCCESSFUL
;
1147 if (FirstCluster
==1)
1148 { //root of FAT16 or FAT12
1149 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
1150 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
1153 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
1156 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1159 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
1161 if (FirstCluster
==1)
1163 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1164 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1165 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1169 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1170 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1172 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1173 (ReadOffset
% DeviceExt
->BytesPerCluster
));
1175 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
1178 (*LengthRead
) = (*LengthRead
) + TempLength
;
1179 Length
= Length
- TempLength
;
1180 Buffer
= Buffer
+ TempLength
;
1183 while (Length
>= DeviceExt
->BytesPerCluster
)
1185 if (FirstCluster
==1)
1187 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1188 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1189 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1193 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
1194 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1196 if (CurrentCluster
== 0xffffffff)
1199 return(STATUS_SUCCESS
);
1202 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
1203 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1204 Length
= Length
- DeviceExt
->BytesPerCluster
;
1209 (*LengthRead
) = (*LengthRead
) + Length
;
1210 if (FirstCluster
==1)
1212 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1213 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1214 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1218 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1219 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1221 memcpy(Buffer
, Temp
, Length
);
1224 return(STATUS_SUCCESS
);
1227 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1228 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
1230 * FUNCTION: Writes data to file
1233 ULONG CurrentCluster
;
1239 ULONG TempLength
,Length2
=Length
;
1241 /* Locate the first cluster of the file */
1243 pCcb
=(PVfatCCB
)(FileObject
->FsContext2
);
1247 if (DeviceExt
->FatType
== FAT32
)
1248 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
1250 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1251 FirstCluster
=CurrentCluster
;
1252 /* Allocate a buffer to hold 1 cluster of data */
1254 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1257 /* Find the cluster according to the offset in the file */
1259 if (CurrentCluster
==1)
1260 { //root of FAT16 or FAT12
1261 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
1262 /DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
1265 if (CurrentCluster
==0)
1266 {// file of size 0 : allocate first cluster
1267 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
1268 if (DeviceExt
->FatType
== FAT32
)
1270 Fcb
->entry
.FirstClusterHigh
=CurrentCluster
>>16;
1271 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1274 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1277 for (FileOffset
=0; FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
; FileOffset
++)
1279 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1284 If the offset in the cluster doesn't fall on the cluster boundary then
1285 we have to write only from the specified offset
1288 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
1291 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1292 (WriteOffset
% DeviceExt
->BytesPerCluster
));
1293 /* Read in the existing cluster data */
1294 if (FirstCluster
==1)
1295 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1296 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1298 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1300 /* Overwrite the last parts of the data as necessary */
1301 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
), Buffer
,
1304 /* Write the cluster back */
1305 if (FirstCluster
==1)
1307 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1308 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1309 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1313 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1314 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1316 Length2
-= TempLength
;
1317 Buffer
= Buffer
+ TempLength
;
1321 /* Write the buffer in chunks of 1 cluster */
1323 while (Length2
>= DeviceExt
->BytesPerCluster
)
1326 if (CurrentCluster
== 0)
1329 return(STATUS_UNSUCCESSFUL
);
1331 if (FirstCluster
==1)
1333 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1334 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1335 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1339 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
1340 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1342 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1343 Length2
-= DeviceExt
->BytesPerCluster
;
1347 /* Write the remainder */
1352 if (CurrentCluster
== 0)
1355 return(STATUS_UNSUCCESSFUL
);
1358 /* Read in the existing cluster data */
1359 if (FirstCluster
==1)
1360 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1361 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1363 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1365 memcpy(Temp
, Buffer
, Length2
);
1367 if (FirstCluster
==1)
1369 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1370 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1373 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1376 //FIXME : set last write time and date
1377 if(Fcb
->entry
.FileSize
<WriteOffset
+Length
1378 && !(Fcb
->entry
.Attrib
&FILE_ATTRIBUTE_DIRECTORY
))
1380 Fcb
->entry
.FileSize
=WriteOffset
+Length
;
1381 // update entry in directory
1382 updEntry(DeviceExt
,FileObject
);
1385 return(STATUS_SUCCESS
);
1388 NTSTATUS
FsdClose(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1390 * FUNCTION: Close a file
1393 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1394 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1395 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1398 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject
, Irp
);
1400 Status
= FsdCloseFile(DeviceExtension
,FileObject
);
1402 Irp
->IoStatus
.Status
= Status
;
1403 Irp
->IoStatus
.Information
= 0;
1405 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1409 NTSTATUS
FsdCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1411 * FUNCTION: Create or open a file
1414 PIO_STACK_LOCATION Stack
;
1415 PFILE_OBJECT FileObject
;
1416 NTSTATUS Status
=STATUS_SUCCESS
;
1417 PDEVICE_EXTENSION DeviceExt
;
1418 ULONG RequestedDisposition
,RequestedOptions
;
1422 assert(DeviceObject
);
1424 if(DeviceObject
->Size
==sizeof(DEVICE_OBJECT
))
1425 {// DevieObject represent FileSystem instead of logical volume
1426 DbgPrint("FsdCreate called with file system\n");
1427 Irp
->IoStatus
.Status
=Status
;
1428 Irp
->IoStatus
.Information
=FILE_OPENED
;
1429 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1432 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1434 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>>24)&0xff);
1435 RequestedOptions
=Stack
->Parameters
.Create
.Options
&FILE_VALID_OPTION_FLAGS
;
1436 FileObject
= Stack
->FileObject
;
1437 DeviceExt
= DeviceObject
->DeviceExtension
;
1439 ExAcquireResourceExclusiveLite(&(DeviceExt
->Resource
),TRUE
);
1440 Status
= FsdOpenFile(DeviceExt
,FileObject
,FileObject
->FileName
.Buffer
);
1441 Irp
->IoStatus
.Information
= 0;
1442 if(!NT_SUCCESS(Status
))
1444 if(RequestedDisposition
==FILE_CREATE
1445 ||RequestedDisposition
==FILE_OPEN_IF
1446 ||RequestedDisposition
==FILE_OVERWRITE_IF
)
1448 Status
=addEntry(DeviceExt
,FileObject
,RequestedOptions
1449 ,(Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
1450 if(NT_SUCCESS(Status
))
1451 Irp
->IoStatus
.Information
= FILE_CREATED
;
1452 // FIXME set size if AllocationSize requested
1453 // FIXME set extended attributes ?
1454 // FIXME set share access
1455 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1456 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1461 if(RequestedDisposition
==FILE_CREATE
)
1463 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1464 Status
=STATUS_OBJECT_NAME_COLLISION
;
1466 pCcb
=FileObject
->FsContext2
;
1468 if( (RequestedOptions
&FILE_NON_DIRECTORY_FILE
)
1469 && (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1471 Status
=STATUS_FILE_IS_A_DIRECTORY
;
1473 if( (RequestedOptions
&FILE_DIRECTORY_FILE
)
1474 && !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1476 Status
=STATUS_NOT_A_DIRECTORY
;
1478 // FIXME : test share access
1479 // FIXME : test write access if requested
1480 if(!NT_SUCCESS(Status
))
1481 FsdCloseFile(DeviceExt
,FileObject
);
1482 else Irp
->IoStatus
.Information
= FILE_OPENED
;
1483 // FIXME : make supersed or overwrite if requested
1486 Irp
->IoStatus
.Status
= Status
;
1488 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1489 ExReleaseResourceForThreadLite(&(DeviceExt
->Resource
),ExGetCurrentResourceThread());
1494 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1496 * FUNCTION: Write to a file
1502 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1503 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1504 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1507 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
1509 Length
= Stack
->Parameters
.Write
.Length
;
1510 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1511 Offset
= Stack
->Parameters
.Write
.ByteOffset
.LowPart
;
1513 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
1515 Irp
->IoStatus
.Status
= Status
;
1516 Irp
->IoStatus
.Information
= Length
;
1517 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1522 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1524 * FUNCTION: Read from a file
1530 PIO_STACK_LOCATION Stack
;
1531 PFILE_OBJECT FileObject
;
1532 PDEVICE_EXTENSION DeviceExt
;
1536 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1538 /* Precondition / Initialization */
1539 assert(Irp
!= NULL
);
1540 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1541 assert(Stack
!= NULL
);
1542 FileObject
= Stack
->FileObject
;
1543 assert(FileObject
!= NULL
);
1544 DeviceExt
= DeviceObject
->DeviceExtension
;
1545 assert(DeviceExt
!= NULL
);
1547 Length
= Stack
->Parameters
.Read
.Length
;
1548 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1549 Offset
= Stack
->Parameters
.Read
.ByteOffset
.LowPart
;
1551 Status
= FsdReadFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
,
1554 Irp
->IoStatus
.Status
= Status
;
1555 Irp
->IoStatus
.Information
= LengthRead
;
1556 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1562 NTSTATUS
FsdMount(PDEVICE_OBJECT DeviceToMount
)
1564 * FUNCTION: Mount the filesystem
1567 PDEVICE_OBJECT DeviceObject
;
1568 PDEVICE_EXTENSION DeviceExt
;
1570 IoCreateDevice(VFATDriverObject
,
1571 sizeof(DEVICE_EXTENSION
),
1573 FILE_DEVICE_FILE_SYSTEM
,
1577 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
1578 DeviceExt
= (PVOID
)DeviceObject
->DeviceExtension
;
1579 // use same vpb as device disk
1580 DeviceObject
->Vpb
=DeviceToMount
->Vpb
;
1581 FsdMountDevice(DeviceExt
,DeviceToMount
);
1582 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
1583 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1586 // fill in missing information in vpb
1587 if (DeviceExt
->FatType
== FAT12
|| DeviceExt
->FatType
== FAT16
)
1589 struct _BootSector
*BootSect
= (PVOID
)DeviceExt
->Boot
;
1590 PSTR s
= BootSect
->VolumeLabel
;
1591 PWSTR w
= DeviceObject
->Vpb
->VolumeLabel
;
1594 // get serial number
1595 DeviceObject
->Vpb
->SerialNumber
= BootSect
->VolumeID
;
1598 while (*s
!= ' ' && n
< 11)
1604 DeviceObject
->Vpb
->VolumeLabelLength
= n
;
1606 else if (DeviceExt
->FatType
== FAT32
)
1608 struct _BootSector32
*BootSect
= (PVOID
)DeviceExt
->Boot
;
1609 PSTR s
= BootSect
->VolumeLabel
;
1610 PWSTR w
= DeviceObject
->Vpb
->VolumeLabel
;
1613 // get serial number
1614 DeviceObject
->Vpb
->SerialNumber
= BootSect
->VolumeID
;
1617 while (*s
!= ' ' && n
< 11)
1623 DeviceObject
->Vpb
->VolumeLabelLength
= n
;
1626 return(STATUS_SUCCESS
);
1629 NTSTATUS
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1631 * FUNCTION: File system control
1634 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1635 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1636 PDEVICE_OBJECT DeviceToMount
= Stack
->Parameters
.Mount
.DeviceObject
;
1639 DPRINT("VFAT FSC\n");
1641 /* FIXME: should make sure that this is actually a mount request! */
1643 if (FsdHasFileSystem(DeviceToMount
))
1645 Status
= FsdMount(DeviceToMount
);
1649 DPRINT("VFAT: Unrecognized Volume\n");
1650 Status
= STATUS_UNRECOGNIZED_VOLUME
;
1652 DPRINT("VFAT File system successfully mounted\n");
1654 Irp
->IoStatus
.Status
= Status
;
1655 Irp
->IoStatus
.Information
= 0;
1657 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1661 NTSTATUS
FsdGetStandardInformation(PVfatFCB FCB
, PDEVICE_OBJECT DeviceObject
,
1662 PFILE_STANDARD_INFORMATION StandardInfo
)
1664 * FUNCTION: Retrieve the standard file information
1667 PDEVICE_EXTENSION DeviceExtension
;
1668 unsigned long AllocSize
;
1670 DeviceExtension
= DeviceObject
->DeviceExtension
;
1672 assert(DeviceExtension
!= NULL
);
1673 assert(DeviceExtension
->BytesPerCluster
!= 0);
1674 assert(StandardInfo
!= NULL
);
1675 assert(FCB
!= NULL
);
1677 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
1679 /* Make allocsize a rounded up multiple of BytesPerCluster */
1680 AllocSize
= ((FCB
->entry
.FileSize
+ DeviceExtension
->BytesPerCluster
- 1) /
1681 DeviceExtension
->BytesPerCluster
) *
1682 DeviceExtension
->BytesPerCluster
;
1684 StandardInfo
->AllocationSize
= RtlConvertUlongToLargeInteger(AllocSize
);
1685 StandardInfo
->EndOfFile
= RtlConvertUlongToLargeInteger(FCB
->entry
.FileSize
);
1686 StandardInfo
->NumberOfLinks
= 0;
1687 StandardInfo
->DeletePending
= FALSE
;
1688 if((FCB
->entry
.Attrib
& 0x10)>0) {
1689 StandardInfo
->Directory
= TRUE
;
1691 StandardInfo
->Directory
= FALSE
;
1694 return STATUS_SUCCESS
;
1697 NTSTATUS
FsdSetPositionInformation(PFILE_OBJECT FileObject
,
1699 PDEVICE_OBJECT DeviceObject
,
1700 PFILE_POSITION_INFORMATION PositionInfo
)
1702 DPRINT("FsdSetPositionInformation()\n");
1704 DPRINT("PositionInfo %x\n", PositionInfo
);
1705 DPRINT("Setting position %d\n", PositionInfo
->CurrentByteOffset
.LowPart
);
1706 memcpy(&FileObject
->CurrentByteOffset
,&PositionInfo
->CurrentByteOffset
,
1707 sizeof(LARGE_INTEGER
));
1709 return(STATUS_SUCCESS
);
1712 NTSTATUS
FsdGetPositionInformation(PFILE_OBJECT FileObject
,
1714 PDEVICE_OBJECT DeviceObject
,
1715 PFILE_POSITION_INFORMATION PositionInfo
)
1717 DPRINT("FsdGetPositionInformation()\n");
1719 memcpy(&PositionInfo
->CurrentByteOffset
, &FileObject
->CurrentByteOffset
,
1720 sizeof(LARGE_INTEGER
));
1721 DPRINT("Getting position %x\n", PositionInfo
->CurrentByteOffset
.LowPart
);
1722 return(STATUS_SUCCESS
);
1725 NTSTATUS
FsdGetBasicInformation(PFILE_OBJECT FileObject
,
1727 PDEVICE_OBJECT DeviceObject
,
1728 PFILE_BASIC_INFORMATION BasicInfo
)
1730 DPRINT("FsdGetBasicInformation()\n");
1732 // BasicInfo->CreationTime =
1733 // BasicInfo->LastAccessTime =
1734 // BasicInfo->LastWriteTime =
1735 // BasicInfo->ChangeTime =
1737 BasicInfo
->FileAttributes
= FCB
->entry
.Attrib
;
1739 DPRINT("Getting attributes %x\n", BasicInfo
->FileAttributes
);
1741 return(STATUS_SUCCESS
);
1745 NTSTATUS
FsdQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1747 * FUNCTION: Retrieve the specified file information
1750 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1751 FILE_INFORMATION_CLASS FileInformationClass
=
1752 Stack
->Parameters
.QueryFile
.FileInformationClass
;
1753 PFILE_OBJECT FileObject
= NULL
;
1754 PVfatFCB FCB
= NULL
;
1755 // PVfatCCB CCB = NULL;
1757 NTSTATUS RC
= STATUS_SUCCESS
;
1761 assert(DeviceObject
!= NULL
);
1762 assert(Irp
!= NULL
);
1764 /* INITIALIZATION */
1765 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1766 FileInformationClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
1767 FileObject
= Stack
->FileObject
;
1768 // CCB = (PVfatCCB)(FileObject->FsContext2);
1769 // FCB = CCB->Buffer; // Should be CCB->FCB???
1770 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1772 // FIXME : determine Buffer for result :
1773 if (Irp
->MdlAddress
)
1774 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1776 SystemBuffer
= Irp
->UserBuffer
;
1777 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1779 switch(FileInformationClass
) {
1780 case FileStandardInformation
:
1781 RC
= FsdGetStandardInformation(FCB
, DeviceObject
, SystemBuffer
);
1783 case FilePositionInformation
:
1784 RC
= FsdGetPositionInformation(FileObject
,
1789 case FileBasicInformation
:
1790 RC
= FsdGetBasicInformation(FileObject
,
1796 RC
=STATUS_NOT_IMPLEMENTED
;
1799 Irp
->IoStatus
.Status
= RC
;
1800 Irp
->IoStatus
.Information
= 0;
1801 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1806 NTSTATUS
FsdSetInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1808 * FUNCTION: Retrieve the specified file information
1811 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1812 FILE_INFORMATION_CLASS FileInformationClass
;
1813 PFILE_OBJECT FileObject
= NULL
;
1814 PVfatFCB FCB
= NULL
;
1815 // PVfatCCB CCB = NULL;
1816 NTSTATUS RC
= STATUS_SUCCESS
;
1820 assert(DeviceObject
!= NULL
);
1821 assert(Irp
!= NULL
);
1823 DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
1826 /* INITIALIZATION */
1827 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1828 FileInformationClass
= Stack
->Parameters
.SetFile
.FileInformationClass
;
1829 FileObject
= Stack
->FileObject
;
1830 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1832 // FIXME : determine Buffer for result :
1833 if (Irp
->MdlAddress
)
1834 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1836 SystemBuffer
= Irp
->UserBuffer
;
1837 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1839 DPRINT("FileInformationClass %d\n",FileInformationClass
);
1840 DPRINT("SystemBuffer %x\n",SystemBuffer
);
1842 switch(FileInformationClass
)
1844 case FilePositionInformation
:
1845 RC
= FsdSetPositionInformation(FileObject
,
1851 RC
= STATUS_NOT_IMPLEMENTED
;
1854 Irp
->IoStatus
.Status
= RC
;
1855 Irp
->IoStatus
.Information
= 0;
1856 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1863 NTSTATUS
FsdGetFsVolumeInformation(PFILE_OBJECT FileObject
,
1865 PDEVICE_OBJECT DeviceObject
,
1866 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
)
1868 DPRINT("FsdGetFsVolumeInformation()\n");
1869 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
1872 return(STATUS_SUCCESS
);
1876 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
1877 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
1878 wcscpy (FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
);
1881 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
1882 FsVolumeInfo
->SupportsObjects
= FALSE
;
1884 DPRINT("Finished FsdGetFsVolumeInformation()\n");
1886 return(STATUS_SUCCESS
);
1890 NTSTATUS
FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
)
1892 DPRINT("FsdGetFsAttributeInformation()\n");
1893 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
1895 if (!FsAttributeInfo
)
1896 return(STATUS_SUCCESS
);
1898 FsAttributeInfo
->FileSystemAttributes
= FS_CASE_IS_PRESERVED
;
1899 FsAttributeInfo
->MaximumComponentNameLength
= 255;
1900 FsAttributeInfo
->FileSystemNameLength
= 3;
1901 wcscpy (FsAttributeInfo
->FileSystemName
, L
"FAT");
1903 DPRINT("Finished FsdGetFsAttributeInformation()\n");
1905 return(STATUS_SUCCESS
);
1908 NTSTATUS
FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject
,
1909 PFILE_FS_SIZE_INFORMATION FsSizeInfo
)
1911 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1913 DPRINT("FsdGetFsSizeInformation()\n");
1914 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
1917 return(STATUS_SUCCESS
);
1919 if (DeviceExt
->FatType
== FAT32
)
1921 struct _BootSector32
*BootSect
= (struct _BootSector32
*)DeviceExt
->Boot
;
1923 if (BootSect
->Sectors
)
1924 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->Sectors
;
1926 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->SectorsHuge
;
1928 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
1929 FAT32CountAvailableClusters(DeviceExt
);
1931 FsSizeInfo
->SectorsPerAllocationUnit
= BootSect
->SectorsPerCluster
;
1932 FsSizeInfo
->BytesPerSector
= BootSect
->BytesPerSector
;
1936 struct _BootSector
*BootSect
= (struct _BootSector
*)DeviceExt
->Boot
;
1938 if (BootSect
->Sectors
)
1939 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->Sectors
;
1941 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->SectorsHuge
;
1943 if (DeviceExt
->FatType
== FAT16
)
1944 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
1945 FAT16CountAvailableClusters(DeviceExt
);
1947 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
1948 FAT12CountAvailableClusters(DeviceExt
);
1950 FsSizeInfo
->SectorsPerAllocationUnit
= BootSect
->SectorsPerCluster
;
1951 FsSizeInfo
->BytesPerSector
= BootSect
->BytesPerSector
;
1954 DPRINT("Finished FsdGetFsSizeInformation()\n");
1956 return(STATUS_SUCCESS
);
1960 NTSTATUS
FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1962 * FUNCTION: Retrieve the specified file information
1965 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1966 FILE_INFORMATION_CLASS FileInformationClass
=
1967 Stack
->Parameters
.QueryVolume
.FileInformationClass
;
1968 PFILE_OBJECT FileObject
= NULL
;
1969 PVfatFCB FCB
= NULL
;
1970 // PVfatCCB CCB = NULL;
1972 NTSTATUS RC
= STATUS_SUCCESS
;
1976 assert(DeviceObject
!= NULL
);
1977 assert(Irp
!= NULL
);
1979 DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
1982 /* INITIALIZATION */
1983 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1984 FileInformationClass
= Stack
->Parameters
.QueryVolume
.FileInformationClass
;
1985 FileObject
= Stack
->FileObject
;
1986 // CCB = (PVfatCCB)(FileObject->FsContext2);
1987 // FCB = CCB->Buffer; // Should be CCB->FCB???
1988 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1990 // FIXME : determine Buffer for result :
1991 if (Irp
->MdlAddress
)
1992 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1994 SystemBuffer
= Irp
->UserBuffer
;
1995 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1997 DPRINT("FileInformationClass %d\n",FileInformationClass
);
1998 DPRINT("SystemBuffer %x\n",SystemBuffer
);
2000 switch (FileInformationClass
)
2002 case FileFsVolumeInformation
:
2003 RC
= FsdGetFsVolumeInformation(FileObject
,
2009 case FileFsAttributeInformation
:
2010 RC
= FsdGetFsAttributeInformation(SystemBuffer
);
2013 case FileFsSizeInformation
:
2014 RC
= FsdGetFsSizeInformation(DeviceObject
, SystemBuffer
);
2018 RC
=STATUS_NOT_IMPLEMENTED
;
2021 Irp
->IoStatus
.Status
= RC
;
2022 Irp
->IoStatus
.Information
= 0;
2023 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2029 STDCALL NTSTATUS
DriverEntry(PDRIVER_OBJECT _DriverObject
,
2030 PUNICODE_STRING RegistryPath
)
2032 * FUNCTION: Called by the system to initalize the driver
2034 * DriverObject = object describing this driver
2035 * RegistryPath = path to our configuration entries
2036 * RETURNS: Success or failure
2039 PDEVICE_OBJECT DeviceObject
;
2041 UNICODE_STRING ustr
;
2044 DbgPrint("VFAT 0.0.6\n");
2046 VFATDriverObject
= _DriverObject
;
2048 RtlInitAnsiString(&astr
,"\\Device\\VFAT");
2049 RtlAnsiStringToUnicodeString(&ustr
,&astr
,TRUE
);
2050 ret
= IoCreateDevice(VFATDriverObject
,0,&ustr
,
2051 FILE_DEVICE_FILE_SYSTEM
,0,FALSE
,&DeviceObject
);
2052 if (ret
!=STATUS_SUCCESS
)
2057 DeviceObject
->Flags
= DO_DIRECT_IO
;
2058 VFATDriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FsdClose
;
2059 VFATDriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FsdCreate
;
2060 VFATDriverObject
->MajorFunction
[IRP_MJ_READ
] = FsdRead
;
2061 VFATDriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FsdWrite
;
2062 VFATDriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
2063 FsdFileSystemControl
;
2064 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
2065 FsdQueryInformation
;
2066 VFATDriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] =
2068 VFATDriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] =
2069 FsdDirectoryControl
;
2070 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] =
2071 FsdQueryVolumeInformation
;
2073 VFATDriverObject
->DriverUnload
= NULL
;
2075 IoRegisterFileSystem(DeviceObject
);
2077 return(STATUS_SUCCESS
);