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)
691 NTSTATUS
ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt
, PVPB Vpb
)
693 * FUNCTION: Read the volume label
699 ULONG StartingSector
;
702 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
703 StartingSector
= DeviceExt
->rootStart
;
706 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
707 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
708 for (j
=0; j
<Size
; j
++)
710 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
712 for (i
=0; i
<ENTRIES_PER_SECTOR
; i
++)
714 if (IsVolEntry((PVOID
)block
,i
))
716 FATDirEntry
*test
= (FATDirEntry
*)block
;
718 /* copy volume label */
719 RtlAnsiToUnicode(Vpb
->VolumeLabel
,test
[i
].Filename
,8);
720 RtlCatAnsiToUnicode(Vpb
->VolumeLabel
,test
[i
].Ext
,3);
721 Vpb
->VolumeLabelLength
= wcslen(Vpb
->VolumeLabel
);
724 return(STATUS_SUCCESS
);
726 if (IsLastEntry((PVOID
)block
,i
))
728 *(Vpb
->VolumeLabel
) = 0;
729 Vpb
->VolumeLabelLength
= 0;
731 return(STATUS_UNSUCCESSFUL
);
734 // not found in this sector, try next :
736 /* directory can be fragmented although it is best to keep them
739 if (DeviceExt
->FatType
==FAT32
)
741 if(StartingSector
==ClusterToSector(DeviceExt
,NextCluster
+1))
743 NextCluster
= GetNextCluster(DeviceExt
,NextCluster
);
744 if (NextCluster
== 0||NextCluster
==0xffffffff)
746 *(Vpb
->VolumeLabel
) = 0;
747 Vpb
->VolumeLabelLength
= 0;
749 return(STATUS_UNSUCCESSFUL
);
751 StartingSector
= ClusterToSector(DeviceExt
,NextCluster
);
755 *(Vpb
->VolumeLabel
) = 0;
756 Vpb
->VolumeLabelLength
= 0;
758 return(STATUS_UNSUCCESSFUL
);
762 NTSTATUS
FindFile(PDEVICE_EXTENSION DeviceExt
, PVfatFCB Fcb
,
763 PVfatFCB Parent
, PWSTR FileToFind
,ULONG
*StartSector
,ULONG
*Entry
)
765 * FUNCTION: Find a file
772 ULONG StartingSector
;
776 DPRINT("FindFile(Parent %x, FileToFind '%w')\n",Parent
,FileToFind
);
778 if (wcslen(FileToFind
)==0)
781 TempStr
[0] = (WCHAR
)'.';
787 DPRINT("Parent->entry.FirstCluster %d\n",Parent
->entry
.FirstCluster
);
790 DPRINT("FindFile '%w'\n", FileToFind
);
791 if (Parent
== NULL
||Parent
->entry
.FirstCluster
==1)
794 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
795 StartingSector
= DeviceExt
->rootStart
;
797 if(FileToFind
[0]==0 ||(FileToFind
[0]=='\\' && FileToFind
[1]==0) ||
798 (FileToFind
[0]=='.' && FileToFind
[1]==0))
799 {// it's root : complete essentials fields then return ok
801 memset(Fcb
,0,sizeof(VfatFCB
));
802 memset(Fcb
->entry
.Filename
,' ',11);
803 Fcb
->entry
.FileSize
=DeviceExt
->rootDirectorySectors
*BLOCKSIZE
;
804 Fcb
->entry
.Attrib
=FILE_ATTRIBUTE_DIRECTORY
;
805 if (DeviceExt
->FatType
== FAT32
)
806 Fcb
->entry
.FirstCluster
=2;
808 Fcb
->entry
.FirstCluster
=1;//FIXME : is 1 the good value for mark root?
810 *StartSector
=StartingSector
;
813 return(STATUS_SUCCESS
);
818 DPRINT("Parent->entry.FileSize %x\n",Parent
->entry
.FileSize
);
821 if (DeviceExt
->FatType
== FAT32
)
822 NextCluster
= Parent
->entry
.FirstCluster
823 +Parent
->entry
.FirstClusterHigh
*65536;
825 NextCluster
= Parent
->entry
.FirstCluster
;
826 StartingSector
= ClusterToSector(DeviceExt
, NextCluster
);
827 if(Parent
->entry
.FirstCluster
==1 && DeviceExt
->FatType
!=FAT32
)
828 {// read of root directory in FAT16 or FAT12
829 StartingSector
=DeviceExt
->rootStart
;
833 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
835 if (StartSector
&& (*StartSector
)) StartingSector
=*StartSector
;
836 i
=(Entry
)?(*Entry
):0;
837 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
838 for (j
=0; j
<Size
; j
++)
840 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
842 for (i
=(Entry
)?(*Entry
):0; i
<ENTRIES_PER_SECTOR
; i
++)
844 if (IsVolEntry((PVOID
)block
,i
))
846 if (IsLastEntry((PVOID
)block
,i
))
849 if(StartSector
) *StartSector
=StartingSector
;
851 return(STATUS_UNSUCCESSFUL
);
853 if (GetEntryName((PVOID
)block
,&i
,name
,&j
,DeviceExt
,&StartingSector
))
855 DPRINT("Comparing '%w' '%w'\n",name
,FileToFind
);
856 if (wstrcmpjoki(name
,FileToFind
))
858 /* In the case of a long filename, the firstcluster is stored in
859 the next record -- where it's short name is */
860 if(((FATDirEntry
*)block
)[i
].Attrib
==0x0f) i
++;
861 if( i
==(ENTRIES_PER_SECTOR
))
862 {// entry is in next sector
864 //FIXME : treat case of next sector fragmented
865 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
868 memcpy(&Fcb
->entry
,&((FATDirEntry
*)block
)[i
],
869 sizeof(FATDirEntry
));
870 vfat_wcsncpy(Fcb
->ObjectName
,name
,MAX_PATH
);
872 if(StartSector
) *StartSector
=StartingSector
;
874 return(STATUS_SUCCESS
);
878 // not found in this sector, try next :
880 /* directory can be fragmented although it is best to keep them
884 if ((Parent
!= NULL
&& Parent
->entry
.FirstCluster
!=1)
885 || DeviceExt
->FatType
==FAT32
)
887 if(StartingSector
==ClusterToSector(DeviceExt
,NextCluster
+1))
889 NextCluster
= GetNextCluster(DeviceExt
,NextCluster
);
890 if (NextCluster
== 0||NextCluster
==0xffffffff)
892 if(StartSector
) *StartSector
=StartingSector
;
895 return(STATUS_UNSUCCESSFUL
);
897 StartingSector
= ClusterToSector(DeviceExt
,NextCluster
);
902 if(StartSector
) *StartSector
=StartingSector
;
904 return(STATUS_UNSUCCESSFUL
);
908 NTSTATUS
FsdCloseFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
)
910 * FUNCTION: Closes a file
916 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
917 DeviceExt
,FileObject
);
919 //FIXME : update entry in directory ?
920 pCcb
= (PVfatCCB
)(FileObject
->FsContext2
);
922 DPRINT("pCcb %x\n",pCcb
);
925 return(STATUS_SUCCESS
);
931 if(pFcb
->RefCount
<=0)
934 pFcb
->prevFcb
->nextFcb
=pFcb
->nextFcb
;
936 pFirstFcb
=pFcb
->nextFcb
;
938 pFcb
->nextFcb
->prevFcb
=pFcb
->prevFcb
;
942 return STATUS_SUCCESS
;
945 NTSTATUS
FsdOpenFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
948 * FUNCTION: Opens a file
955 PVfatFCB Fcb
,pRelFcb
;
957 PVfatCCB newCCB
,pRelCcb
;
959 PFILE_OBJECT pRelFileObject
;
960 PWSTR AbsFileName
=NULL
;
963 DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
968 //FIXME : treat relative name
969 if(FileObject
->RelatedFileObject
)
971 DbgPrint("try related for %w\n",FileName
);
972 pRelFileObject
=FileObject
->RelatedFileObject
;
973 pRelCcb
=pRelFileObject
->FsContext2
;
975 pRelFcb
=pRelCcb
->pFcb
;
977 // verify related object is a directory and target name don't start with \.
978 if( !(pRelFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
979 || (FileName
[0]!= '\\') )
981 Status
=STATUS_INVALID_PARAMETER
;
984 // construct absolute path name
985 AbsFileName
=ExAllocatePool(NonPagedPool
,MAX_PATH
);
986 for (i
=0;pRelFcb
->PathName
[i
];i
++)
987 AbsFileName
[i
]=pRelFcb
->PathName
[i
];
988 AbsFileName
[i
++]='\\';
989 for (j
=0;FileName
[j
]&&i
<MAX_PATH
;j
++)
990 AbsFileName
[i
++]=FileName
[j
];
993 FileName
=AbsFileName
;
995 // try first to find an existing FCB in memory
996 for (Fcb
=pFirstFcb
;Fcb
; Fcb
=Fcb
->nextFcb
)
998 if (DeviceExt
==Fcb
->pDevExt
999 && wstrcmpi(FileName
,Fcb
->PathName
))
1002 FileObject
->FsContext
=(PVOID
) &Fcb
->NTRequiredFCB
;
1003 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
1004 memset(newCCB
,0,sizeof(VfatCCB
));
1005 FileObject
->FsContext2
= newCCB
;
1007 newCCB
->PtrFileObject
=FileObject
;
1008 if(AbsFileName
)ExFreePool(AbsFileName
);
1009 return(STATUS_SUCCESS
);
1014 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(VfatFCB
));
1015 memset(Fcb
,0,sizeof(VfatFCB
));
1016 Fcb
->ObjectName
=Fcb
->PathName
;
1023 next
= wcschr(next
+1,'\\');
1028 DPRINT("current '%w'\n",current
);
1029 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,current
,NULL
,NULL
);
1030 if (Status
!= STATUS_SUCCESS
)
1034 if (ParentFcb
!= NULL
)
1035 ExFreePool(ParentFcb
);
1037 ExFreePool(AbsFileName
);
1042 if (ParentFcb
== NULL
)
1044 Fcb
= ExAllocatePool(NonPagedPool
,sizeof(VfatFCB
));
1045 memset(Fcb
,0,sizeof(VfatFCB
));
1046 Fcb
->ObjectName
=Fcb
->PathName
;
1054 FileObject
->FsContext
=(PVOID
) &ParentFcb
->NTRequiredFCB
;
1055 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
1056 memset(newCCB
,0,sizeof(VfatCCB
));
1057 FileObject
->FsContext2
= newCCB
;
1058 newCCB
->pFcb
=ParentFcb
;
1059 newCCB
->PtrFileObject
=FileObject
;
1060 ParentFcb
->RefCount
++;
1061 //FIXME : initialize all fields in FCB and CCB
1062 ParentFcb
->nextFcb
=pFirstFcb
;
1063 pFirstFcb
=ParentFcb
;
1064 vfat_wcsncpy(ParentFcb
->PathName
,FileName
,MAX_PATH
);
1065 ParentFcb
->ObjectName
=ParentFcb
->PathName
+(current
-FileName
);
1066 ParentFcb
->pDevExt
=DeviceExt
;
1067 DPRINT("file open, fcb=%x\n",ParentFcb
);
1068 DPRINT("FileSize %d\n",ParentFcb
->entry
.FileSize
);
1069 if(Fcb
) ExFreePool(Fcb
);
1070 if(AbsFileName
)ExFreePool(AbsFileName
);
1071 return(STATUS_SUCCESS
);
1075 BOOLEAN
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
1077 * FUNCTION: Tests if the device contains a filesystem that can be mounted
1083 Boot
= ExAllocatePool(NonPagedPool
,512);
1085 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)Boot
);
1087 if (strncmp(Boot
->SysType
,"FAT12",5)==0 ||
1088 strncmp(Boot
->SysType
,"FAT16",5)==0 ||
1089 strncmp(((struct _BootSector32
*)(Boot
))->SysType
,"FAT32",5)==0)
1098 NTSTATUS
FsdMountDevice(PDEVICE_EXTENSION DeviceExt
,
1099 PDEVICE_OBJECT DeviceToMount
)
1101 * FUNCTION: Mounts the device
1104 DPRINT("Mounting VFAT device...");
1105 DPRINT("DeviceExt %x\n",DeviceExt
);
1107 DeviceExt
->Boot
= ExAllocatePool(NonPagedPool
,512);
1108 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)DeviceExt
->Boot
);
1110 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
1111 DeviceExt
->Boot
->BytesPerSector
);
1113 DeviceExt
->FATStart
=DeviceExt
->Boot
->ReservedSectors
;
1114 DeviceExt
->rootDirectorySectors
=
1115 (DeviceExt
->Boot
->RootEntries
*32)/DeviceExt
->Boot
->BytesPerSector
;
1116 DeviceExt
->rootStart
=
1117 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
*DeviceExt
->Boot
->FATSectors
;
1118 DeviceExt
->dataStart
=DeviceExt
->rootStart
+DeviceExt
->rootDirectorySectors
;
1119 DeviceExt
->FATEntriesPerSector
=DeviceExt
->Boot
->BytesPerSector
/32;
1120 DeviceExt
->BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
*
1121 DeviceExt
->Boot
->BytesPerSector
;
1123 if (strncmp(DeviceExt
->Boot
->SysType
,"FAT12",5)==0)
1125 DeviceExt
->FatType
= FAT12
;
1127 else if (strncmp(((struct _BootSector32
*)(DeviceExt
->Boot
))->SysType
,"FAT32",5)==0)
1129 DeviceExt
->FatType
= FAT32
;
1130 DeviceExt
->rootDirectorySectors
=DeviceExt
->Boot
->SectorsPerCluster
;
1131 DeviceExt
->rootStart
=
1132 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
1133 * ((struct _BootSector32
*)( DeviceExt
->Boot
))->FATSectors32
;
1134 DeviceExt
->dataStart
=DeviceExt
->rootStart
;
1138 DeviceExt
->FatType
= FAT16
;
1141 // with FAT32 it's not a good idea to load always fat in memory
1142 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
1143 if(DeviceExt
->FatType
!=FAT32
)
1145 DeviceExt
->FAT
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
*DeviceExt
->Boot
->FATSectors
);
1146 VFATReadSectors(DeviceToMount
, DeviceExt
->FATStart
, DeviceExt
->Boot
->FATSectors
, (UCHAR
*)DeviceExt
->FAT
);
1148 return STATUS_SUCCESS
;
1151 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
1153 * FUNCTION: Load a cluster from the physical device
1158 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1159 DeviceExt
,Buffer
,Cluster
);
1161 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1163 VFATReadSectors(DeviceExt
->StorageDevice
,
1165 DeviceExt
->Boot
->SectorsPerCluster
,
1167 DPRINT("Finished VFATReadSectors\n");
1170 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
1172 * FUNCTION: Write a cluster to the physical device
1176 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1177 DeviceExt
,Buffer
,Cluster
);
1179 Sector
= ClusterToSector(DeviceExt
, Cluster
);
1181 VFATWriteSectors(DeviceExt
->StorageDevice
,
1183 DeviceExt
->Boot
->SectorsPerCluster
,
1187 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1188 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
1191 * FUNCTION: Reads data from a file
1194 ULONG CurrentCluster
;
1202 assert(DeviceExt
!= NULL
);
1203 assert(DeviceExt
->BytesPerCluster
!= 0);
1204 assert(FileObject
!= NULL
);
1205 assert(FileObject
->FsContext
!= NULL
);
1207 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1208 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
1211 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1212 if (DeviceExt
->FatType
== FAT32
)
1213 CurrentCluster
= Fcb
->entry
.FirstCluster
1214 +Fcb
->entry
.FirstClusterHigh
*65536;
1216 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1217 FirstCluster
=CurrentCluster
;
1218 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
1220 if (ReadOffset
>= Fcb
->entry
.FileSize
1221 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1223 return(STATUS_END_OF_FILE
);
1225 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
1226 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1228 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
1231 /* FIXME: optimize by remembering the last cluster read and using if possible */
1232 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1233 if(!Temp
) return STATUS_UNSUCCESSFUL
;
1234 if (FirstCluster
==1)
1235 { //root of FAT16 or FAT12
1236 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
1237 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
1240 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
1243 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1246 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
1248 if (FirstCluster
==1)
1250 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1251 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1252 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1256 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1257 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1259 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1260 (ReadOffset
% DeviceExt
->BytesPerCluster
));
1262 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
1265 (*LengthRead
) = (*LengthRead
) + TempLength
;
1266 Length
= Length
- TempLength
;
1267 Buffer
= Buffer
+ TempLength
;
1270 while (Length
>= DeviceExt
->BytesPerCluster
)
1272 if (FirstCluster
==1)
1274 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1275 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1276 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1280 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
1281 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1283 if (CurrentCluster
== 0xffffffff)
1286 return(STATUS_SUCCESS
);
1289 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
1290 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1291 Length
= Length
- DeviceExt
->BytesPerCluster
;
1296 (*LengthRead
) = (*LengthRead
) + Length
;
1297 if (FirstCluster
==1)
1299 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1300 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1301 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1305 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1306 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1308 memcpy(Buffer
, Temp
, Length
);
1311 return(STATUS_SUCCESS
);
1314 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1315 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
1317 * FUNCTION: Writes data to file
1320 ULONG CurrentCluster
;
1326 ULONG TempLength
,Length2
=Length
;
1328 /* Locate the first cluster of the file */
1330 pCcb
=(PVfatCCB
)(FileObject
->FsContext2
);
1334 if (DeviceExt
->FatType
== FAT32
)
1335 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
1337 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1338 FirstCluster
=CurrentCluster
;
1339 /* Allocate a buffer to hold 1 cluster of data */
1341 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1344 /* Find the cluster according to the offset in the file */
1346 if (CurrentCluster
==1)
1347 { //root of FAT16 or FAT12
1348 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
1349 /DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
1352 if (CurrentCluster
==0)
1353 {// file of size 0 : allocate first cluster
1354 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
1355 if (DeviceExt
->FatType
== FAT32
)
1357 Fcb
->entry
.FirstClusterHigh
=CurrentCluster
>>16;
1358 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1361 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1364 for (FileOffset
=0; FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
; FileOffset
++)
1366 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1371 If the offset in the cluster doesn't fall on the cluster boundary then
1372 we have to write only from the specified offset
1375 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
1378 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1379 (WriteOffset
% DeviceExt
->BytesPerCluster
));
1380 /* Read in the existing cluster data */
1381 if (FirstCluster
==1)
1382 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1383 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1385 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1387 /* Overwrite the last parts of the data as necessary */
1388 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
), Buffer
,
1391 /* Write the cluster back */
1392 if (FirstCluster
==1)
1394 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1395 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1396 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1400 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1401 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1403 Length2
-= TempLength
;
1404 Buffer
= Buffer
+ TempLength
;
1408 /* Write the buffer in chunks of 1 cluster */
1410 while (Length2
>= DeviceExt
->BytesPerCluster
)
1413 if (CurrentCluster
== 0)
1416 return(STATUS_UNSUCCESSFUL
);
1418 if (FirstCluster
==1)
1420 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1421 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1422 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1426 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
1427 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1429 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1430 Length2
-= DeviceExt
->BytesPerCluster
;
1434 /* Write the remainder */
1439 if (CurrentCluster
== 0)
1442 return(STATUS_UNSUCCESSFUL
);
1445 /* Read in the existing cluster data */
1446 if (FirstCluster
==1)
1447 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1448 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1450 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1452 memcpy(Temp
, Buffer
, Length2
);
1454 if (FirstCluster
==1)
1456 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1457 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1460 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1463 //FIXME : set last write time and date
1464 if(Fcb
->entry
.FileSize
<WriteOffset
+Length
1465 && !(Fcb
->entry
.Attrib
&FILE_ATTRIBUTE_DIRECTORY
))
1467 Fcb
->entry
.FileSize
=WriteOffset
+Length
;
1468 // update entry in directory
1469 updEntry(DeviceExt
,FileObject
);
1472 return(STATUS_SUCCESS
);
1475 NTSTATUS
FsdClose(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1477 * FUNCTION: Close a file
1480 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1481 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1482 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1485 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject
, Irp
);
1487 Status
= FsdCloseFile(DeviceExtension
,FileObject
);
1489 Irp
->IoStatus
.Status
= Status
;
1490 Irp
->IoStatus
.Information
= 0;
1492 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1497 NTSTATUS
FsdCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1499 * FUNCTION: Create or open a file
1502 PIO_STACK_LOCATION Stack
;
1503 PFILE_OBJECT FileObject
;
1504 NTSTATUS Status
=STATUS_SUCCESS
;
1505 PDEVICE_EXTENSION DeviceExt
;
1506 ULONG RequestedDisposition
,RequestedOptions
;
1510 assert(DeviceObject
);
1512 if(DeviceObject
->Size
==sizeof(DEVICE_OBJECT
))
1513 {// DevieObject represent FileSystem instead of logical volume
1514 DbgPrint("FsdCreate called with file system\n");
1515 Irp
->IoStatus
.Status
=Status
;
1516 Irp
->IoStatus
.Information
=FILE_OPENED
;
1517 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1520 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1522 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>>24)&0xff);
1523 RequestedOptions
=Stack
->Parameters
.Create
.Options
&FILE_VALID_OPTION_FLAGS
;
1524 FileObject
= Stack
->FileObject
;
1525 DeviceExt
= DeviceObject
->DeviceExtension
;
1527 ExAcquireResourceExclusiveLite(&(DeviceExt
->Resource
),TRUE
);
1528 Status
= FsdOpenFile(DeviceExt
,FileObject
,FileObject
->FileName
.Buffer
);
1530 Irp
->IoStatus
.Information
= 0;
1531 if(!NT_SUCCESS(Status
))
1533 if(RequestedDisposition
==FILE_CREATE
1534 ||RequestedDisposition
==FILE_OPEN_IF
1535 ||RequestedDisposition
==FILE_OVERWRITE_IF
)
1538 Status
=addEntry(DeviceExt
,FileObject
,RequestedOptions
1539 ,(Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
1540 if(NT_SUCCESS(Status
))
1541 Irp
->IoStatus
.Information
= FILE_CREATED
;
1542 // FIXME set size if AllocationSize requested
1543 // FIXME set extended attributes ?
1544 // FIXME set share access
1545 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1546 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1551 if(RequestedDisposition
==FILE_CREATE
)
1553 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1554 Status
=STATUS_OBJECT_NAME_COLLISION
;
1556 pCcb
=FileObject
->FsContext2
;
1558 if( (RequestedOptions
&FILE_NON_DIRECTORY_FILE
)
1559 && (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1561 Status
=STATUS_FILE_IS_A_DIRECTORY
;
1563 if( (RequestedOptions
&FILE_DIRECTORY_FILE
)
1564 && !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1566 Status
=STATUS_NOT_A_DIRECTORY
;
1568 // FIXME : test share access
1569 // FIXME : test write access if requested
1570 if(!NT_SUCCESS(Status
))
1571 FsdCloseFile(DeviceExt
,FileObject
);
1572 else Irp
->IoStatus
.Information
= FILE_OPENED
;
1573 // FIXME : make supersed or overwrite if requested
1576 Irp
->IoStatus
.Status
= Status
;
1578 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1579 ExReleaseResourceForThreadLite(&(DeviceExt
->Resource
),ExGetCurrentResourceThread());
1584 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1586 * FUNCTION: Write to a file
1592 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1593 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1594 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1597 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
1599 Length
= Stack
->Parameters
.Write
.Length
;
1600 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1601 Offset
= Stack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
1603 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
1605 Irp
->IoStatus
.Status
= Status
;
1606 Irp
->IoStatus
.Information
= Length
;
1607 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1612 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1614 * FUNCTION: Read from a file
1620 PIO_STACK_LOCATION Stack
;
1621 PFILE_OBJECT FileObject
;
1622 PDEVICE_EXTENSION DeviceExt
;
1626 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1628 /* Precondition / Initialization */
1629 assert(Irp
!= NULL
);
1630 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1631 assert(Stack
!= NULL
);
1632 FileObject
= Stack
->FileObject
;
1633 assert(FileObject
!= NULL
);
1634 DeviceExt
= DeviceObject
->DeviceExtension
;
1635 assert(DeviceExt
!= NULL
);
1637 Length
= Stack
->Parameters
.Read
.Length
;
1638 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1639 Offset
= Stack
->Parameters
.Read
.ByteOffset
.u
.LowPart
;
1641 Status
= FsdReadFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
,
1644 Irp
->IoStatus
.Status
= Status
;
1645 Irp
->IoStatus
.Information
= LengthRead
;
1646 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1652 NTSTATUS
FsdMount(PDEVICE_OBJECT DeviceToMount
)
1654 * FUNCTION: Mount the filesystem
1657 PDEVICE_OBJECT DeviceObject
;
1658 PDEVICE_EXTENSION DeviceExt
;
1660 IoCreateDevice(VFATDriverObject
,
1661 sizeof(DEVICE_EXTENSION
),
1663 FILE_DEVICE_FILE_SYSTEM
,
1667 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
1668 DeviceExt
= (PVOID
)DeviceObject
->DeviceExtension
;
1669 // use same vpb as device disk
1670 DeviceObject
->Vpb
=DeviceToMount
->Vpb
;
1671 FsdMountDevice(DeviceExt
,DeviceToMount
);
1672 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
1673 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1676 /* read serial number */
1677 if (DeviceExt
->FatType
== FAT12
|| DeviceExt
->FatType
== FAT16
)
1678 DeviceObject
->Vpb
->SerialNumber
=
1679 ((struct _BootSector
*)(DeviceExt
->Boot
))->VolumeID
;
1680 else if (DeviceExt
->FatType
== FAT32
)
1681 DeviceObject
->Vpb
->SerialNumber
=
1682 ((struct _BootSector32
*)(DeviceExt
->Boot
))->VolumeID
;
1684 /* read volume label */
1685 ReadVolumeLabel (DeviceExt
, DeviceObject
->Vpb
);
1687 return(STATUS_SUCCESS
);
1690 NTSTATUS
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1692 * FUNCTION: File system control
1695 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1696 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1697 PDEVICE_OBJECT DeviceToMount
= Stack
->Parameters
.Mount
.DeviceObject
;
1700 // DPRINT("VFAT FSC\n");
1701 DbgPrint("VFAT FSC\n");
1703 /* FIXME: should make sure that this is actually a mount request! */
1705 if (FsdHasFileSystem(DeviceToMount
))
1707 Status
= FsdMount(DeviceToMount
);
1711 DPRINT("VFAT: Unrecognized Volume\n");
1712 Status
= STATUS_UNRECOGNIZED_VOLUME
;
1714 DPRINT("VFAT File system successfully mounted\n");
1716 Irp
->IoStatus
.Status
= Status
;
1717 Irp
->IoStatus
.Information
= 0;
1719 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1723 NTSTATUS
FsdGetStandardInformation(PVfatFCB FCB
, PDEVICE_OBJECT DeviceObject
,
1724 PFILE_STANDARD_INFORMATION StandardInfo
)
1726 * FUNCTION: Retrieve the standard file information
1729 PDEVICE_EXTENSION DeviceExtension
;
1730 unsigned long AllocSize
;
1732 DeviceExtension
= DeviceObject
->DeviceExtension
;
1734 assert(DeviceExtension
!= NULL
);
1735 assert(DeviceExtension
->BytesPerCluster
!= 0);
1736 assert(StandardInfo
!= NULL
);
1737 assert(FCB
!= NULL
);
1739 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
1741 /* Make allocsize a rounded up multiple of BytesPerCluster */
1742 AllocSize
= ((FCB
->entry
.FileSize
+ DeviceExtension
->BytesPerCluster
- 1) /
1743 DeviceExtension
->BytesPerCluster
) *
1744 DeviceExtension
->BytesPerCluster
;
1746 StandardInfo
->AllocationSize
= RtlConvertUlongToLargeInteger(AllocSize
);
1747 StandardInfo
->EndOfFile
= RtlConvertUlongToLargeInteger(FCB
->entry
.FileSize
);
1748 StandardInfo
->NumberOfLinks
= 0;
1749 StandardInfo
->DeletePending
= FALSE
;
1750 if((FCB
->entry
.Attrib
& 0x10)>0) {
1751 StandardInfo
->Directory
= TRUE
;
1753 StandardInfo
->Directory
= FALSE
;
1756 return STATUS_SUCCESS
;
1759 NTSTATUS
FsdSetPositionInformation(PFILE_OBJECT FileObject
,
1761 PDEVICE_OBJECT DeviceObject
,
1762 PFILE_POSITION_INFORMATION PositionInfo
)
1764 DPRINT("FsdSetPositionInformation()\n");
1766 DPRINT("PositionInfo %x\n", PositionInfo
);
1767 DPRINT("Setting position %d\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
1768 memcpy(&FileObject
->CurrentByteOffset
,&PositionInfo
->CurrentByteOffset
,
1769 sizeof(LARGE_INTEGER
));
1771 return(STATUS_SUCCESS
);
1774 NTSTATUS
FsdGetPositionInformation(PFILE_OBJECT FileObject
,
1776 PDEVICE_OBJECT DeviceObject
,
1777 PFILE_POSITION_INFORMATION PositionInfo
)
1779 DPRINT("FsdGetPositionInformation()\n");
1781 memcpy(&PositionInfo
->CurrentByteOffset
, &FileObject
->CurrentByteOffset
,
1782 sizeof(LARGE_INTEGER
));
1783 DPRINT("Getting position %x\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
1784 return(STATUS_SUCCESS
);
1787 NTSTATUS
FsdGetBasicInformation(PFILE_OBJECT FileObject
,
1789 PDEVICE_OBJECT DeviceObject
,
1790 PFILE_BASIC_INFORMATION BasicInfo
)
1792 DPRINT("FsdGetBasicInformation()\n");
1794 FsdDosDateTimeToFileTime(FCB
->entry
.CreationDate
,FCB
->entry
.CreationTime
,
1795 &BasicInfo
->CreationTime
);
1796 FsdDosDateTimeToFileTime(FCB
->entry
.AccessDate
,0,
1797 &BasicInfo
->LastAccessTime
);
1798 FsdDosDateTimeToFileTime(FCB
->entry
.UpdateDate
,FCB
->entry
.UpdateTime
,
1799 &BasicInfo
->LastWriteTime
);
1800 FsdDosDateTimeToFileTime(FCB
->entry
.UpdateDate
,FCB
->entry
.UpdateTime
,
1801 &BasicInfo
->ChangeTime
);
1803 BasicInfo
->FileAttributes
= FCB
->entry
.Attrib
;
1805 DPRINT("Getting attributes %x\n", BasicInfo
->FileAttributes
);
1807 return(STATUS_SUCCESS
);
1811 NTSTATUS
FsdSetDispositionInformation(PFILE_OBJECT FileObject
,
1813 PDEVICE_OBJECT DeviceObject
,
1814 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
1816 DPRINT("FsdSetDispositionInformation()\n");
1818 FileObject
->DeletePending
= DispositionInfo
->DeleteFile
;
1820 return(STATUS_SUCCESS
);
1824 NTSTATUS
FsdQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1826 * FUNCTION: Retrieve the specified file information
1829 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1830 FILE_INFORMATION_CLASS FileInformationClass
=
1831 Stack
->Parameters
.QueryFile
.FileInformationClass
;
1832 PFILE_OBJECT FileObject
= NULL
;
1833 PVfatFCB FCB
= NULL
;
1834 // PVfatCCB CCB = NULL;
1836 NTSTATUS RC
= STATUS_SUCCESS
;
1840 assert(DeviceObject
!= NULL
);
1841 assert(Irp
!= NULL
);
1843 /* INITIALIZATION */
1844 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1845 FileInformationClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
1846 FileObject
= Stack
->FileObject
;
1847 // CCB = (PVfatCCB)(FileObject->FsContext2);
1848 // FCB = CCB->Buffer; // Should be CCB->FCB???
1849 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1851 // FIXME : determine Buffer for result :
1852 if (Irp
->MdlAddress
)
1853 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1855 SystemBuffer
= Irp
->UserBuffer
;
1856 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1858 switch(FileInformationClass
) {
1859 case FileStandardInformation
:
1860 RC
= FsdGetStandardInformation(FCB
, DeviceObject
, SystemBuffer
);
1862 case FilePositionInformation
:
1863 RC
= FsdGetPositionInformation(FileObject
,
1868 case FileBasicInformation
:
1869 RC
= FsdGetBasicInformation(FileObject
,
1875 RC
=STATUS_NOT_IMPLEMENTED
;
1878 Irp
->IoStatus
.Status
= RC
;
1879 Irp
->IoStatus
.Information
= 0;
1880 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1885 NTSTATUS
FsdSetInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1887 * FUNCTION: Retrieve the specified file information
1890 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1891 FILE_INFORMATION_CLASS FileInformationClass
;
1892 PFILE_OBJECT FileObject
= NULL
;
1893 PVfatFCB FCB
= NULL
;
1894 // PVfatCCB CCB = NULL;
1895 NTSTATUS RC
= STATUS_SUCCESS
;
1899 assert(DeviceObject
!= NULL
);
1900 assert(Irp
!= NULL
);
1902 DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
1905 /* INITIALIZATION */
1906 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1907 FileInformationClass
= Stack
->Parameters
.SetFile
.FileInformationClass
;
1908 FileObject
= Stack
->FileObject
;
1909 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1911 // FIXME : determine Buffer for result :
1912 if (Irp
->MdlAddress
)
1913 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1915 SystemBuffer
= Irp
->UserBuffer
;
1916 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1918 DPRINT("FileInformationClass %d\n",FileInformationClass
);
1919 DPRINT("SystemBuffer %x\n",SystemBuffer
);
1921 switch(FileInformationClass
)
1923 case FilePositionInformation
:
1924 RC
= FsdSetPositionInformation(FileObject
,
1929 case FileDispositionInformation
:
1930 RC
= FsdSetDispositionInformation(FileObject
,
1936 RC
= STATUS_NOT_IMPLEMENTED
;
1939 Irp
->IoStatus
.Status
= RC
;
1940 Irp
->IoStatus
.Information
= 0;
1941 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1948 NTSTATUS
FsdGetFsVolumeInformation(PFILE_OBJECT FileObject
,
1950 PDEVICE_OBJECT DeviceObject
,
1951 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
)
1953 DPRINT("FsdGetFsVolumeInformation()\n");
1954 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
1957 return(STATUS_SUCCESS
);
1961 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
1962 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
1963 wcscpy (FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
);
1966 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
1967 FsVolumeInfo
->SupportsObjects
= FALSE
;
1969 DPRINT("Finished FsdGetFsVolumeInformation()\n");
1971 return(STATUS_SUCCESS
);
1975 NTSTATUS
FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
)
1977 DPRINT("FsdGetFsAttributeInformation()\n");
1978 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
1980 if (!FsAttributeInfo
)
1981 return(STATUS_SUCCESS
);
1983 FsAttributeInfo
->FileSystemAttributes
= FS_CASE_IS_PRESERVED
;
1984 FsAttributeInfo
->MaximumComponentNameLength
= 255;
1985 FsAttributeInfo
->FileSystemNameLength
= 3;
1986 wcscpy (FsAttributeInfo
->FileSystemName
, L
"FAT");
1988 DPRINT("Finished FsdGetFsAttributeInformation()\n");
1990 return(STATUS_SUCCESS
);
1993 NTSTATUS
FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject
,
1994 PFILE_FS_SIZE_INFORMATION FsSizeInfo
)
1996 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1998 DPRINT("FsdGetFsSizeInformation()\n");
1999 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
2002 return(STATUS_SUCCESS
);
2004 if (DeviceExt
->FatType
== FAT32
)
2006 struct _BootSector32
*BootSect
= (struct _BootSector32
*)DeviceExt
->Boot
;
2008 if (BootSect
->Sectors
)
2009 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->Sectors
;
2011 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->SectorsHuge
;
2013 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
2014 FAT32CountAvailableClusters(DeviceExt
);
2016 FsSizeInfo
->SectorsPerAllocationUnit
= BootSect
->SectorsPerCluster
;
2017 FsSizeInfo
->BytesPerSector
= BootSect
->BytesPerSector
;
2021 struct _BootSector
*BootSect
= (struct _BootSector
*)DeviceExt
->Boot
;
2023 if (BootSect
->Sectors
)
2024 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->Sectors
;
2026 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= BootSect
->SectorsHuge
;
2028 if (DeviceExt
->FatType
== FAT16
)
2029 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
2030 FAT16CountAvailableClusters(DeviceExt
);
2032 FsSizeInfo
->AvailableAllocationUnits
.QuadPart
=
2033 FAT12CountAvailableClusters(DeviceExt
);
2035 FsSizeInfo
->SectorsPerAllocationUnit
= BootSect
->SectorsPerCluster
;
2036 FsSizeInfo
->BytesPerSector
= BootSect
->BytesPerSector
;
2039 DPRINT("Finished FsdGetFsSizeInformation()\n");
2041 return(STATUS_SUCCESS
);
2045 NTSTATUS
FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
2047 * FUNCTION: Retrieve the specified file information
2050 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
2051 FILE_INFORMATION_CLASS FileInformationClass
=
2052 Stack
->Parameters
.QueryVolume
.FileInformationClass
;
2053 PFILE_OBJECT FileObject
= NULL
;
2054 PVfatFCB FCB
= NULL
;
2055 // PVfatCCB CCB = NULL;
2057 NTSTATUS RC
= STATUS_SUCCESS
;
2061 assert(DeviceObject
!= NULL
);
2062 assert(Irp
!= NULL
);
2064 DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
2067 /* INITIALIZATION */
2068 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2069 FileInformationClass
= Stack
->Parameters
.QueryVolume
.FileInformationClass
;
2070 FileObject
= Stack
->FileObject
;
2071 // CCB = (PVfatCCB)(FileObject->FsContext2);
2072 // FCB = CCB->Buffer; // Should be CCB->FCB???
2073 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
2075 // FIXME : determine Buffer for result :
2076 if (Irp
->MdlAddress
)
2077 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
2079 SystemBuffer
= Irp
->UserBuffer
;
2080 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
2082 DPRINT("FileInformationClass %d\n",FileInformationClass
);
2083 DPRINT("SystemBuffer %x\n",SystemBuffer
);
2085 switch (FileInformationClass
)
2087 case FileFsVolumeInformation
:
2088 RC
= FsdGetFsVolumeInformation(FileObject
,
2094 case FileFsAttributeInformation
:
2095 RC
= FsdGetFsAttributeInformation(SystemBuffer
);
2098 case FileFsSizeInformation
:
2099 RC
= FsdGetFsSizeInformation(DeviceObject
, SystemBuffer
);
2103 RC
=STATUS_NOT_IMPLEMENTED
;
2106 Irp
->IoStatus
.Status
= RC
;
2107 Irp
->IoStatus
.Information
= 0;
2108 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2115 DriverEntry(PDRIVER_OBJECT _DriverObject
, PUNICODE_STRING RegistryPath
)
2117 * FUNCTION: Called by the system to initalize the driver
2119 * DriverObject = object describing this driver
2120 * RegistryPath = path to our configuration entries
2121 * RETURNS: Success or failure
2124 PDEVICE_OBJECT DeviceObject
;
2126 UNICODE_STRING ustr
;
2129 DbgPrint("VFAT 0.0.6\n");
2131 VFATDriverObject
= _DriverObject
;
2133 RtlInitAnsiString(&astr
,"\\Device\\VFAT");
2134 RtlAnsiStringToUnicodeString(&ustr
,&astr
,TRUE
);
2135 ret
= IoCreateDevice(VFATDriverObject
,0,&ustr
,
2136 FILE_DEVICE_FILE_SYSTEM
,0,FALSE
,&DeviceObject
);
2137 if (ret
!=STATUS_SUCCESS
)
2142 DeviceObject
->Flags
= DO_DIRECT_IO
;
2143 VFATDriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FsdClose
;
2144 VFATDriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FsdCreate
;
2145 VFATDriverObject
->MajorFunction
[IRP_MJ_READ
] = FsdRead
;
2146 VFATDriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FsdWrite
;
2147 VFATDriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
2148 FsdFileSystemControl
;
2149 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
2150 FsdQueryInformation
;
2151 VFATDriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] =
2153 VFATDriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] =
2154 FsdDirectoryControl
;
2155 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] =
2156 FsdQueryVolumeInformation
;
2158 VFATDriverObject
->DriverUnload
= NULL
;
2160 IoRegisterFileSystem(DeviceObject
);
2162 return(STATUS_SUCCESS
);