4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/iface.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
11 24-10-1998 Fixed bugs in long filename support
12 Fixed a bug that prevented unsuccessful file open requests being reported
13 Now works with long filenames that span over a sector boundary
14 28-10-1998 Reads entire FAT into memory
15 VFatReadSector modified to read in more than one sector at a time
16 7-11-1998 Fixed bug that assumed that directory data could be fragmented
17 8-12-1998 Added FAT32 support
18 Added initial writability functions
19 WARNING: DO NOT ATTEMPT TO TEST WRITABILITY FUNCTIONS!!!
20 12-12-1998 Added basic support for FILE_STANDARD_INFORMATION request
24 /* INCLUDES *****************************************************************/
26 #include <ddk/ntddk.h>
27 #include <internal/string.h>
29 #include <ddk/cctypes.h>
32 #include <internal/debug.h>
36 //#include "dbgpool.c"
38 /* GLOBALS *****************************************************************/
40 static PDRIVER_OBJECT VFATDriverObject
;
43 /* FUNCTIONS ****************************************************************/
45 ULONG
Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
47 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
54 Block
= ExAllocatePool(NonPagedPool
,1024);
55 FATsector
=CurrentCluster
/(512/sizeof(ULONG
));
56 FATeis
=CurrentCluster
-(FATsector
*(512/sizeof(ULONG
)));
57 VFATReadSectors(DeviceExt
->StorageDevice
58 ,(ULONG
)(DeviceExt
->FATStart
+FATsector
), 1,(UCHAR
*) Block
);
59 CurrentCluster
= Block
[FATeis
];
60 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
61 CurrentCluster
= 0xffffffff;
63 return(CurrentCluster
);
66 ULONG
Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
68 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
73 Block
=(PUSHORT
)DeviceExt
->FAT
;
74 CurrentCluster
= Block
[CurrentCluster
];
75 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
76 CurrentCluster
= 0xffffffff;
77 DPRINT("Returning %x\n",CurrentCluster
);
78 return(CurrentCluster
);
81 ULONG
Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
83 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
87 unsigned char* CBlock
;
90 CBlock
= DeviceExt
->FAT
;
91 FATOffset
= (CurrentCluster
* 12)/ 8;//first byte containing value
92 if ((CurrentCluster
% 2) == 0)
94 Entry
= CBlock
[FATOffset
];
95 Entry
|= ((CBlock
[FATOffset
+1] & 0xf)<<8);
99 Entry
= (CBlock
[FATOffset
] >> 4);
100 Entry
|= (CBlock
[FATOffset
+1] << 4);
102 DPRINT("Entry %x\n",Entry
);
103 if (Entry
>= 0xff8 && Entry
<= 0xfff)
105 DPRINT("Returning %x\n",Entry
);
109 ULONG
GetNextCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
111 * FUNCTION: Retrieve the next cluster depending on the FAT type
115 DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
116 DeviceExt
,CurrentCluster
);
117 if (DeviceExt
->FatType
== FAT16
)
118 return(Fat16GetNextCluster(DeviceExt
, CurrentCluster
));
119 else if (DeviceExt
->FatType
== FAT32
)
120 return(Fat32GetNextCluster(DeviceExt
, CurrentCluster
));
122 return(Fat12GetNextCluster(DeviceExt
, CurrentCluster
));
125 ULONG
FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
127 * FUNCTION: Finds the first available cluster in a FAT16 table
132 Block
=(PUSHORT
)DeviceExt
->FAT
;
133 for(i
=2;i
<(DeviceExt
->Boot
->FATSectors
*256) ;i
++)
136 /* Give an error message (out of disk space) if we reach here) */
140 ULONG
FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
142 * FUNCTION: Finds the first available cluster in a FAT12 table
147 PUCHAR CBlock
=DeviceExt
->FAT
;
149 for(i
=2;i
<((DeviceExt
->Boot
->FATSectors
*512*8)/12) ;i
++)
151 FATOffset
= (i
* 12)/8;
154 Entry
= CBlock
[FATOffset
];
155 Entry
|= ((CBlock
[FATOffset
+ 1] & 0xf)<<8);
159 Entry
= (CBlock
[FATOffset
] >> 4);
160 Entry
|= (CBlock
[FATOffset
+ 1] << 4);
165 /* Give an error message (out of disk space) if we reach here) */
166 DbgPrint("Disk full, %d clusters used\n",i
);
170 ULONG
FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt
)
172 * FUNCTION: Finds the first available cluster in a FAT32 table
178 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
180 ;sector
< ((struct _BootSector32
*)(DeviceExt
->Boot
))->FATSectors32
183 VFATReadSectors(DeviceExt
->StorageDevice
184 ,(ULONG
)(DeviceExt
->FATStart
+sector
), 1,(UCHAR
*) Block
);
191 return (i
+sector
*128);
195 /* Give an error message (out of disk space) if we reach here) */
200 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
203 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
208 PUCHAR CBlock
=DeviceExt
->FAT
;
210 FATOffset
= (ClusterToWrite
* 12)/8;
211 if ((ClusterToWrite
% 2) == 0)
213 CBlock
[FATOffset
]=NewValue
;
214 CBlock
[FATOffset
+ 1] &=0xf0;
215 CBlock
[FATOffset
+ 1]
216 |= (NewValue
&0xf00)>>8;
220 CBlock
[FATOffset
] &=0x0f;
222 |= (NewValue
&0xf)<<4;
223 CBlock
[FATOffset
+1]=NewValue
>>4;
225 /* Write the changed FAT sector(s) to disk */
226 FATsector
=FATOffset
/BLOCKSIZE
;
227 for(i
=0;i
<DeviceExt
->Boot
->FATCount
;i
++)
229 if( (FATOffset
%BLOCKSIZE
)==(BLOCKSIZE
-1))//entry is on 2 sectors
231 VFATWriteSectors(DeviceExt
->StorageDevice
,
232 DeviceExt
->FATStart
+FATsector
233 +i
*DeviceExt
->Boot
->FATSectors
,
235 CBlock
+FATsector
*512);
239 VFATWriteSectors(DeviceExt
->StorageDevice
,
240 DeviceExt
->FATStart
+FATsector
241 +i
*DeviceExt
->Boot
->FATSectors
,
243 CBlock
+FATsector
*512);
248 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
251 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
256 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
257 Block
=(PUSHORT
)DeviceExt
->FAT
;
258 FATsector
=ClusterToWrite
/(512/sizeof(USHORT
));
260 /* Update the in-memory FAT */
261 Block
[ClusterToWrite
] = NewValue
;
262 /* Write the changed FAT sector to disk */
263 VFATWriteSectors(DeviceExt
->StorageDevice
,
264 DeviceExt
->FATStart
+FATsector
,
269 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
272 * FUNCTION: Writes a cluster to the FAT32 physical tables
278 DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite
,NewValue
);
279 Block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
280 FATsector
=ClusterToWrite
/128;
281 FATeis
=ClusterToWrite
-(FATsector
*128);
282 /* load sector, change value, then rewrite sector */
283 VFATReadSectors(DeviceExt
->StorageDevice
,
284 DeviceExt
->FATStart
+FATsector
,
287 Block
[FATeis
] = NewValue
;
288 VFATWriteSectors(DeviceExt
->StorageDevice
,
289 DeviceExt
->FATStart
+FATsector
,
295 void WriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG ClusterToWrite
,
298 * FUNCTION: Write a changed FAT entry
301 if(DeviceExt
->FatType
==FAT16
)
302 FAT16WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
303 else if(DeviceExt
->FatType
==FAT32
)
304 FAT32WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
306 FAT12WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
);
309 ULONG
GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt
, ULONG CurrentCluster
)
311 * FUNCTION: Determines the next cluster to be written
314 ULONG LastCluster
, NewCluster
;
315 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
316 DeviceExt
,CurrentCluster
);
318 /* Find out what was happening in the last cluster's AU */
319 LastCluster
=GetNextCluster(DeviceExt
,CurrentCluster
);
320 /* Check to see if we must append or overwrite */
321 if (LastCluster
==0xffffffff)
322 {//we are after last existing cluster : we must add one to file
324 /* Firstly, find the next available open allocation unit */
325 if(DeviceExt
->FatType
== FAT16
)
326 NewCluster
= FAT16FindAvailableCluster(DeviceExt
);
327 else if(DeviceExt
->FatType
== FAT32
)
328 NewCluster
= FAT32FindAvailableCluster(DeviceExt
);
330 NewCluster
= FAT12FindAvailableCluster(DeviceExt
);
331 /* Mark the new AU as the EOF */
332 WriteCluster(DeviceExt
, NewCluster
, 0xFFFFFFFF);
333 /* Now, write the AU of the LastCluster with the value of the newly
336 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
337 /* Return NewCluster as CurrentCluster */
342 /* Overwrite: Return LastCluster as CurrentCluster */
347 ULONG
ClusterToSector(PDEVICE_EXTENSION DeviceExt
,
348 unsigned long Cluster
)
350 * FUNCTION: Converts the cluster number to a sector number for this physical
354 return DeviceExt
->dataStart
+((Cluster
-2)*DeviceExt
->Boot
->SectorsPerCluster
);
357 void RtlAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
359 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
364 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
371 void RtlCatAnsiToUnicode(PWSTR Dest
, PCH Source
, ULONG Length
)
373 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
374 * existing Unicode string
383 for (i
=0; (i
<Length
&& Source
[i
] != ' '); i
++)
390 void vfat_initstr(wchar_t *wstr
, ULONG wsize
)
392 * FUNCTION: Initialize a string for use with a long file name
397 for(i
=0; i
<wsize
; i
++)
405 wchar_t * vfat_wcsncat(wchar_t * dest
, const wchar_t * src
,size_t wstart
, size_t wcount
)
407 * FUNCTION: Append a string for use with a long file name
413 for(i
=0; i
<wcount
; i
++)
418 dest
=dest
-(wcount
+wstart
);
423 wchar_t * vfat_wcsncpy(wchar_t * dest
, const wchar_t *src
,size_t wcount
)
425 * FUNCTION: Copy a string for use with long file names
430 for (i
=0;i
<wcount
;i
++)
438 wchar_t * vfat_movstr(const wchar_t *src
, ULONG dpos
,
439 ULONG spos
, ULONG len
)
441 * FUNCTION: Move the characters in a string to a new position in the same
451 src
[dpos
++]=src
[spos
++];
460 src
[dpos
--]=src
[spos
--];
467 BOOLEAN
IsLastEntry(PVOID Block
, ULONG Offset
)
469 * FUNCTION: Determine if the given directory entry is the last
472 return(((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0);
475 BOOLEAN
IsVolEntry(PVOID Block
, ULONG Offset
)
477 * FUNCTION: Determine if the given directory entry is a vol entry
480 if( (((FATDirEntry
*)Block
)[Offset
].Attrib
)==0x28 ) return TRUE
;
484 BOOLEAN
IsDeletedEntry(PVOID Block
, ULONG Offset
)
486 * FUNCTION: Determines if the given entry is a deleted one
489 /* Checks special character */
491 return ((((FATDirEntry
*)Block
)[Offset
].Filename
[0] == 0xe5));
494 BOOLEAN
GetEntryName(PVOID Block
, PULONG _Offset
, PWSTR Name
, PULONG _jloop
,
495 PDEVICE_EXTENSION DeviceExt
, ULONG
* _StartingSector
)
497 * FUNCTION: Retrieves the file name, be it in short or long file name format
502 ULONG Offset
= *_Offset
;
503 ULONG StartingSector
= *_StartingSector
;
504 ULONG jloop
= *_jloop
;
508 test
= (FATDirEntry
*)Block
;
509 test2
= (slot
*)Block
;
513 if (IsDeletedEntry(Block
,Offset
))
518 if(test2
[Offset
].attr
== 0x0f)
520 vfat_initstr(Name
, 256);
521 vfat_wcsncpy(Name
,test2
[Offset
].name0_4
,5);
522 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
523 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
526 while((test2
[Offset
].id
!=0x41) && (test2
[Offset
].id
!=0x01) &&
527 (test2
[Offset
].attr
>0))
530 if(Offset
==ENTRIES_PER_SECTOR
) {
532 StartingSector
++;//FIXME : nor always the next sector
534 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,Block
);
535 test2
= (slot
*)Block
;
538 vfat_movstr(Name
, 13, 0, cpos
*13);
539 vfat_wcsncpy(Name
, test2
[Offset
].name0_4
, 5);
540 vfat_wcsncat(Name
,test2
[Offset
].name5_10
,5,6);
541 vfat_wcsncat(Name
,test2
[Offset
].name11_12
,11,2);
545 if (IsDeletedEntry(Block
,Offset
+1))
550 *_StartingSector
= StartingSector
;
556 *_StartingSector
= StartingSector
;
561 RtlAnsiToUnicode(Name
,test
[Offset
].Filename
,8);
562 if (test
[Offset
].Ext
[0]!=' ')
564 RtlCatAnsiToUnicode(Name
,".",1);
566 RtlCatAnsiToUnicode(Name
,test
[Offset
].Ext
,3);
573 BOOLEAN
wstrcmpi(PWSTR s1
, PWSTR s2
)
575 * FUNCTION: Compare to wide character strings
576 * return TRUE if s1==s2
579 while (wtolower(*s1
)==wtolower(*s2
))
581 if ((*s1
)==0 && (*s2
)==0)
591 BOOLEAN
wstrcmpjoki(PWSTR s1
, PWSTR s2
)
593 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
594 * return TRUE if s1 like s2
597 while ((*s2
=='?')||(wtolower(*s1
)==wtolower(*s2
)))
599 if ((*s1
)==0 && (*s2
)==0)
608 if (wstrcmpjoki(s1
,s2
)) return TRUE
;
611 if ((*s1
)==0 && (*s2
)==0)
616 NTSTATUS
FindFile(PDEVICE_EXTENSION DeviceExt
, PVfatFCB Fcb
,
617 PVfatFCB Parent
, PWSTR FileToFind
,ULONG
*StartSector
,ULONG
*Entry
)
619 * FUNCTION: Find a file
626 ULONG StartingSector
;
628 DPRINT("FindFile(Parent %x, FileToFind %w)\n",Parent
,FileToFind
);
630 if (Parent
== NULL
||Parent
->entry
.FirstCluster
==1)
632 Size
= DeviceExt
->rootDirectorySectors
;//FIXME : in fat32, no limit
633 StartingSector
= DeviceExt
->rootStart
;
635 if(FileToFind
[0]==0 ||(FileToFind
[0]=='\\' && FileToFind
[1]==0))
636 {// it's root : complete essentials fields then return ok
637 memset(Fcb
,0,sizeof(VfatFCB
));
638 memset(Fcb
->entry
.Filename
,' ',11);
639 Fcb
->entry
.FileSize
=DeviceExt
->rootDirectorySectors
*BLOCKSIZE
;
640 Fcb
->entry
.Attrib
=FILE_ATTRIBUTE_DIRECTORY
;
641 if (DeviceExt
->FatType
== FAT32
)
642 Fcb
->entry
.FirstCluster
=2;
643 else Fcb
->entry
.FirstCluster
=1;//FIXME : is 1 the good value for mark root?
644 if(StartSector
) *StartSector
=StartingSector
;
646 return(STATUS_SUCCESS
);
651 DPRINT("Parent->entry.FileSize %x\n",Parent
->entry
.FileSize
);
654 if (DeviceExt
->FatType
== FAT32
)
655 NextCluster
= Parent
->entry
.FirstCluster
656 +Parent
->entry
.FirstClusterHigh
*65536;
658 NextCluster
= Parent
->entry
.FirstCluster
;
659 StartingSector
= ClusterToSector(DeviceExt
, NextCluster
);
660 if(Parent
->entry
.FirstCluster
==1 && DeviceExt
->FatType
!=FAT32
)
661 {// read of root directory in FAT16 or FAT12
662 StartingSector
=DeviceExt
->rootStart
;
665 block
= ExAllocatePool(NonPagedPool
,BLOCKSIZE
);
666 if (StartSector
&& (*StartSector
)) StartingSector
=*StartSector
;
667 i
=(Entry
)?(*Entry
):0;
668 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector
,i
);
669 for (j
=0; j
<Size
; j
++)
671 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
673 for (i
=(Entry
)?(*Entry
):0; i
<ENTRIES_PER_SECTOR
; i
++)
675 if (IsVolEntry((PVOID
)block
,i
))
677 if (IsLastEntry((PVOID
)block
,i
))
680 if(StartSector
) *StartSector
=StartingSector
;
682 return(STATUS_UNSUCCESSFUL
);
684 if (GetEntryName((PVOID
)block
,&i
,name
,&j
,DeviceExt
,&StartingSector
))
686 // DPRINT("Comparing %w %w\n",name,FileToFind);
687 if (wstrcmpjoki(name
,FileToFind
))
689 /* In the case of a long filename, the firstcluster is stored in
690 the next record -- where it's short name is */
691 if(((FATDirEntry
*)block
)[i
].Attrib
==0x0f) i
++;
692 if( i
==(ENTRIES_PER_SECTOR
))
693 {// entry is in next sector
695 //FIXME : treat case of next sector fragmented
696 VFATReadSectors(DeviceExt
->StorageDevice
,StartingSector
,1,block
);
699 memcpy(&Fcb
->entry
,&((FATDirEntry
*)block
)[i
],
700 sizeof(FATDirEntry
));
701 vfat_wcsncpy(Fcb
->ObjectName
,name
,MAX_PATH
);
703 if(StartSector
) *StartSector
=StartingSector
;
705 return(STATUS_SUCCESS
);
709 // not found in this sector, try next :
711 /* directory can be fragmented although it is best to keep them
715 if ((Parent
!= NULL
&& Parent
->entry
.FirstCluster
!=1)
716 || DeviceExt
->FatType
==FAT32
)
718 if(StartingSector
==ClusterToSector(DeviceExt
,NextCluster
+1))
720 NextCluster
= GetNextCluster(DeviceExt
,NextCluster
);
721 if (NextCluster
== 0||NextCluster
==0xffffffff)
723 if(StartSector
) *StartSector
=StartingSector
;
726 return(STATUS_UNSUCCESSFUL
);
728 StartingSector
= ClusterToSector(DeviceExt
,NextCluster
);
733 if(StartSector
) *StartSector
=StartingSector
;
735 return(STATUS_UNSUCCESSFUL
);
739 NTSTATUS
FsdCloseFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
)
741 * FUNCTION: Closes a file
746 //FIXME : update entry in directory ?
747 pCcb
= (PVfatCCB
)(FileObject
->FsContext2
);
750 if(pFcb
->RefCount
<=0)
753 pFcb
->prevFcb
->nextFcb
=pFcb
->nextFcb
;
755 pFirstFcb
=pFcb
->nextFcb
;
757 pFcb
->nextFcb
->prevFcb
=pFcb
->prevFcb
;
761 return STATUS_SUCCESS
;
764 NTSTATUS
FsdOpenFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
767 * FUNCTION: Opens a file
774 PVfatFCB Fcb
,pRelFcb
;
776 PVfatCCB newCCB
,pRelCcb
;
778 PFILE_OBJECT pRelFileObject
;
779 PWSTR AbsFileName
=NULL
;
782 DPRINT("FsdOpenFile(%08lx, %08lx, %08lx)\n",
786 //FIXME : treat relative name
787 if(FileObject
->RelatedFileObject
)
789 DbgPrint("try related for %w\n",FileName
);
790 pRelFileObject
=FileObject
->RelatedFileObject
;
791 pRelCcb
=pRelFileObject
->FsContext2
;
793 pRelFcb
=pRelCcb
->pFcb
;
795 // verify related object is a directory and target name don't start with \.
796 if( !(pRelFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
797 || (FileName
[0]!= '\\') )
799 Status
=STATUS_INVALID_PARAMETER
;
802 // construct absolute path name
803 AbsFileName
=ExAllocatePool(NonPagedPool
,MAX_PATH
);
804 for (i
=0;pRelFcb
->PathName
[i
];i
++)
805 AbsFileName
[i
]=pRelFcb
->PathName
[i
];
806 AbsFileName
[i
++]='\\';
807 for (j
=0;FileName
[j
]&&i
<MAX_PATH
;j
++)
808 AbsFileName
[i
++]=FileName
[j
];
811 FileName
=AbsFileName
;
813 // try first to find an existing FCB in memory
814 for (Fcb
=pFirstFcb
;Fcb
; Fcb
=Fcb
->nextFcb
)
816 if (DeviceExt
==Fcb
->pDevExt
817 && wstrcmpi(FileName
,Fcb
->PathName
))
820 FileObject
->FsContext
=(PVOID
) &Fcb
->NTRequiredFCB
;
821 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
822 memset(newCCB
,0,sizeof(VfatCCB
));
823 FileObject
->FsContext2
= newCCB
;
825 newCCB
->PtrFileObject
=FileObject
;
826 if(AbsFileName
)ExFreePool(AbsFileName
);
827 return(STATUS_SUCCESS
);
832 Fcb
= ExAllocatePool(NonPagedPool
, sizeof(VfatFCB
));
833 memset(Fcb
,0,sizeof(VfatFCB
));
834 Fcb
->ObjectName
=Fcb
->PathName
;
840 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,next
,NULL
,NULL
);
849 next
= wcschr(next
+1,'\\');
852 Status
= FindFile(DeviceExt
,Fcb
,ParentFcb
,current
,NULL
,NULL
);
853 if (Status
!= STATUS_SUCCESS
)
857 if (ParentFcb
!= NULL
)
858 ExFreePool(ParentFcb
);
859 if(AbsFileName
)ExFreePool(AbsFileName
);
863 if (ParentFcb
== NULL
)
865 Fcb
= ExAllocatePool(NonPagedPool
,sizeof(VfatFCB
));
866 memset(Fcb
,0,sizeof(VfatFCB
));
867 Fcb
->ObjectName
=Fcb
->PathName
;
869 else Fcb
= ParentFcb
;
872 FileObject
->FsContext
=(PVOID
) &ParentFcb
->NTRequiredFCB
;
873 newCCB
= ExAllocatePool(NonPagedPool
,sizeof(VfatCCB
));
874 memset(newCCB
,0,sizeof(VfatCCB
));
875 FileObject
->FsContext2
= newCCB
;
876 newCCB
->pFcb
=ParentFcb
;
877 newCCB
->PtrFileObject
=FileObject
;
878 ParentFcb
->RefCount
++;
879 //FIXME : initialize all fields in FCB and CCB
880 ParentFcb
->nextFcb
=pFirstFcb
;
882 vfat_wcsncpy(ParentFcb
->PathName
,FileName
,MAX_PATH
);
883 ParentFcb
->ObjectName
=ParentFcb
->PathName
+(current
-FileName
);
884 ParentFcb
->pDevExt
=DeviceExt
;
885 DPRINT("file open, fcb=%x\n",ParentFcb
);
886 DPRINT("FileSize %d\n",ParentFcb
->entry
.FileSize
);
887 if(Fcb
) ExFreePool(Fcb
);
888 if(AbsFileName
)ExFreePool(AbsFileName
);
889 return(STATUS_SUCCESS
);
892 BOOLEAN
FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
894 * FUNCTION: Tests if the device contains a filesystem that can be mounted
900 Boot
= ExAllocatePool(NonPagedPool
,512);
902 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)Boot
);
904 if (strncmp(Boot
->SysType
,"FAT12",5)==0 ||
905 strncmp(Boot
->SysType
,"FAT16",5)==0 ||
906 strncmp(((struct _BootSector32
*)(Boot
))->SysType
,"FAT32",5)==0)
915 NTSTATUS
FsdMountDevice(PDEVICE_EXTENSION DeviceExt
,
916 PDEVICE_OBJECT DeviceToMount
)
918 * FUNCTION: Mounts the device
921 DPRINT("Mounting VFAT device...");
922 DPRINT("DeviceExt %x\n",DeviceExt
);
924 DeviceExt
->Boot
= ExAllocatePool(NonPagedPool
,512);
925 VFATReadSectors(DeviceToMount
, 0, 1, (UCHAR
*)DeviceExt
->Boot
);
927 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
928 DeviceExt
->Boot
->BytesPerSector
);
930 DeviceExt
->FATStart
=DeviceExt
->Boot
->ReservedSectors
;
931 DeviceExt
->rootDirectorySectors
=
932 (DeviceExt
->Boot
->RootEntries
*32)/DeviceExt
->Boot
->BytesPerSector
;
933 DeviceExt
->rootStart
=
934 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
*DeviceExt
->Boot
->FATSectors
;
935 DeviceExt
->dataStart
=DeviceExt
->rootStart
+DeviceExt
->rootDirectorySectors
;
936 DeviceExt
->FATEntriesPerSector
=DeviceExt
->Boot
->BytesPerSector
/32;
937 DeviceExt
->BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
*
938 DeviceExt
->Boot
->BytesPerSector
;
940 if (strncmp(DeviceExt
->Boot
->SysType
,"FAT12",5)==0)
942 DeviceExt
->FatType
= FAT12
;
944 else if (strncmp(((struct _BootSector32
*)(DeviceExt
->Boot
))->SysType
,"FAT32",5)==0)
946 DeviceExt
->FatType
= FAT32
;
947 DeviceExt
->rootDirectorySectors
=DeviceExt
->Boot
->SectorsPerCluster
;
948 DeviceExt
->rootStart
=
949 DeviceExt
->FATStart
+DeviceExt
->Boot
->FATCount
950 * ((struct _BootSector32
*)( DeviceExt
->Boot
))->FATSectors32
;
951 DeviceExt
->dataStart
=DeviceExt
->rootStart
;
955 DeviceExt
->FatType
= FAT16
;
958 // with FAT32 it's not a good idea to load always fat in memory
959 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
960 if(DeviceExt
->FatType
!=FAT32
)
962 DeviceExt
->FAT
= ExAllocatePool(NonPagedPool
, BLOCKSIZE
*DeviceExt
->Boot
->FATSectors
);
963 VFATReadSectors(DeviceToMount
, DeviceExt
->FATStart
, DeviceExt
->Boot
->FATSectors
, (UCHAR
*)DeviceExt
->FAT
);
965 return STATUS_SUCCESS
;
968 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
970 * FUNCTION: Load a cluster from the physical device
975 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
976 DeviceExt
,Buffer
,Cluster
);
978 Sector
= ClusterToSector(DeviceExt
, Cluster
);
980 VFATReadSectors(DeviceExt
->StorageDevice
,
982 DeviceExt
->Boot
->SectorsPerCluster
,
986 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt
, PVOID Buffer
, ULONG Cluster
)
988 * FUNCTION: Write a cluster to the physical device
992 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
993 DeviceExt
,Buffer
,Cluster
);
995 Sector
= ClusterToSector(DeviceExt
, Cluster
);
997 VFATWriteSectors(DeviceExt
->StorageDevice
,
999 DeviceExt
->Boot
->SectorsPerCluster
,
1003 NTSTATUS
FsdReadFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1004 PVOID Buffer
, ULONG Length
, ULONG ReadOffset
,
1007 * FUNCTION: Reads data from a file
1010 ULONG CurrentCluster
;
1018 assert(DeviceExt
!= NULL
);
1019 assert(DeviceExt
->BytesPerCluster
!= 0);
1020 assert(FileObject
!= NULL
);
1021 assert(FileObject
->FsContext
!= NULL
);
1023 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1024 "Length %d, ReadOffset %d)\n",DeviceExt
,FileObject
,Buffer
,
1027 Fcb
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1028 if (DeviceExt
->FatType
== FAT32
)
1029 CurrentCluster
= Fcb
->entry
.FirstCluster
1030 +Fcb
->entry
.FirstClusterHigh
*65536;
1032 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1033 FirstCluster
=CurrentCluster
;
1034 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt
->BytesPerCluster
);
1036 if (ReadOffset
>= Fcb
->entry
.FileSize
1037 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1039 return(STATUS_END_OF_FILE
);
1041 if ((ReadOffset
+ Length
) > Fcb
->entry
.FileSize
1042 && !(Fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1044 Length
= Fcb
->entry
.FileSize
- ReadOffset
;
1047 /* FIXME: optimize by remembering the last cluster read and using if possible */
1048 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1049 if(!Temp
) return STATUS_UNSUCCESSFUL
;
1050 if (FirstCluster
==1)
1051 { //root of FAT16 or FAT12
1052 CurrentCluster
=DeviceExt
->rootStart
+ReadOffset
1053 /(DeviceExt
->BytesPerCluster
)*DeviceExt
->Boot
->SectorsPerCluster
;
1056 for (FileOffset
=0; FileOffset
< ReadOffset
/ DeviceExt
->BytesPerCluster
1059 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1062 if ((ReadOffset
% DeviceExt
->BytesPerCluster
)!=0)
1064 if (FirstCluster
==1)
1066 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1067 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1068 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1072 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1073 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1075 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1076 (ReadOffset
% DeviceExt
->BytesPerCluster
));
1078 memcpy(Buffer
, Temp
+ ReadOffset
% DeviceExt
->BytesPerCluster
,
1081 (*LengthRead
) = (*LengthRead
) + TempLength
;
1082 Length
= Length
- TempLength
;
1083 Buffer
= Buffer
+ TempLength
;
1086 while (Length
>= DeviceExt
->BytesPerCluster
)
1088 if (FirstCluster
==1)
1090 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1091 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1092 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1096 VFATLoadCluster(DeviceExt
,Buffer
,CurrentCluster
);
1097 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1099 if (CurrentCluster
== 0xffffffff)
1102 return(STATUS_SUCCESS
);
1105 (*LengthRead
) = (*LengthRead
) + DeviceExt
->BytesPerCluster
;
1106 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1107 Length
= Length
- DeviceExt
->BytesPerCluster
;
1112 (*LengthRead
) = (*LengthRead
) + Length
;
1113 if (FirstCluster
==1)
1115 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1116 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1117 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1121 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1122 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1124 memcpy(Buffer
, Temp
, Length
);
1127 return(STATUS_SUCCESS
);
1130 NTSTATUS
FsdWriteFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
1131 PVOID Buffer
, ULONG Length
, ULONG WriteOffset
)
1133 * FUNCTION: Writes data to file
1136 ULONG CurrentCluster
;
1142 ULONG TempLength
,Length2
=Length
;
1144 /* Locate the first cluster of the file */
1146 pCcb
=(PVfatCCB
)(FileObject
->FsContext2
);
1150 if (DeviceExt
->FatType
== FAT32
)
1151 CurrentCluster
= Fcb
->entry
.FirstCluster
+Fcb
->entry
.FirstClusterHigh
*65536;
1153 CurrentCluster
= Fcb
->entry
.FirstCluster
;
1154 FirstCluster
=CurrentCluster
;
1155 /* Allocate a buffer to hold 1 cluster of data */
1157 Temp
= ExAllocatePool(NonPagedPool
,DeviceExt
->BytesPerCluster
);
1160 /* Find the cluster according to the offset in the file */
1162 if (CurrentCluster
==1)
1163 { //root of FAT16 or FAT12
1164 CurrentCluster
=DeviceExt
->rootStart
+WriteOffset
1165 /DeviceExt
->BytesPerCluster
*DeviceExt
->Boot
->SectorsPerCluster
;
1168 if (CurrentCluster
==0)
1169 {// file of size 0 : allocate first cluster
1170 CurrentCluster
=GetNextWriteCluster(DeviceExt
,0);
1171 if (DeviceExt
->FatType
== FAT32
)
1173 Fcb
->entry
.FirstClusterHigh
=CurrentCluster
>>16;
1174 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1177 Fcb
->entry
.FirstCluster
=CurrentCluster
;
1180 for (FileOffset
=0; FileOffset
< WriteOffset
/ DeviceExt
->BytesPerCluster
; FileOffset
++)
1182 CurrentCluster
= GetNextCluster(DeviceExt
,CurrentCluster
);
1187 If the offset in the cluster doesn't fall on the cluster boundary then
1188 we have to write only from the specified offset
1191 if ((WriteOffset
% DeviceExt
->BytesPerCluster
)!=0)
1194 TempLength
= min(Length
,DeviceExt
->BytesPerCluster
-
1195 (WriteOffset
% DeviceExt
->BytesPerCluster
));
1196 /* Read in the existing cluster data */
1197 if (FirstCluster
==1)
1198 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1199 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1201 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1203 /* Overwrite the last parts of the data as necessary */
1204 memcpy(Temp
+ (WriteOffset
% DeviceExt
->BytesPerCluster
), Buffer
,
1207 /* Write the cluster back */
1208 if (FirstCluster
==1)
1210 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1211 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1212 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1216 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1217 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1219 Length2
-= TempLength
;
1220 Buffer
= Buffer
+ TempLength
;
1224 /* Write the buffer in chunks of 1 cluster */
1226 while (Length2
>= DeviceExt
->BytesPerCluster
)
1229 if (CurrentCluster
== 0)
1232 return(STATUS_UNSUCCESSFUL
);
1234 if (FirstCluster
==1)
1236 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1237 ,DeviceExt
->Boot
->SectorsPerCluster
,Buffer
);
1238 CurrentCluster
+= DeviceExt
->Boot
->SectorsPerCluster
;
1242 VFATWriteCluster(DeviceExt
,Buffer
,CurrentCluster
);
1243 CurrentCluster
= GetNextCluster(DeviceExt
, CurrentCluster
);
1245 Buffer
= Buffer
+ DeviceExt
->BytesPerCluster
;
1246 Length2
-= DeviceExt
->BytesPerCluster
;
1250 /* Write the remainder */
1255 if (CurrentCluster
== 0)
1258 return(STATUS_UNSUCCESSFUL
);
1261 /* Read in the existing cluster data */
1262 if (FirstCluster
==1)
1263 VFATReadSectors(DeviceExt
->StorageDevice
,CurrentCluster
1264 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1266 VFATLoadCluster(DeviceExt
,Temp
,CurrentCluster
);
1268 memcpy(Temp
, Buffer
, Length2
);
1270 if (FirstCluster
==1)
1272 VFATWriteSectors(DeviceExt
->StorageDevice
,CurrentCluster
1273 ,DeviceExt
->Boot
->SectorsPerCluster
,Temp
);
1276 VFATWriteCluster(DeviceExt
,Temp
,CurrentCluster
);
1279 //FIXME : set last write time and date
1280 if(Fcb
->entry
.FileSize
<WriteOffset
+Length
1281 && !(Fcb
->entry
.Attrib
&FILE_ATTRIBUTE_DIRECTORY
))
1283 Fcb
->entry
.FileSize
=WriteOffset
+Length
;
1284 // update entry in directory
1285 updEntry(DeviceExt
,FileObject
);
1288 return(STATUS_SUCCESS
);
1291 NTSTATUS
FsdClose(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1293 * FUNCTION: Close a file
1296 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1297 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1298 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
1301 Status
= FsdCloseFile(DeviceExtension
,FileObject
);
1303 Irp
->IoStatus
.Status
= Status
;
1304 Irp
->IoStatus
.Information
= 0;
1306 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1310 NTSTATUS
FsdCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1312 * FUNCTION: Create or open a file
1315 PIO_STACK_LOCATION Stack
;
1316 PFILE_OBJECT FileObject
;
1317 NTSTATUS Status
=STATUS_SUCCESS
;
1318 PDEVICE_EXTENSION DeviceExt
;
1319 ULONG RequestedDisposition
,RequestedOptions
;
1323 assert(DeviceObject
);
1325 if(DeviceObject
->Size
==sizeof(DEVICE_OBJECT
))
1326 {// DevieObject represent FileSystem instead of logical volume
1327 DbgPrint("FsdCreate called with file system\n");
1328 Irp
->IoStatus
.Status
=Status
;
1329 Irp
->IoStatus
.Information
=FILE_OPENED
;
1330 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1333 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1335 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>>24)&0xff);
1336 RequestedOptions
=Stack
->Parameters
.Create
.Options
&FILE_VALID_OPTION_FLAGS
;
1337 FileObject
= Stack
->FileObject
;
1338 DeviceExt
= DeviceObject
->DeviceExtension
;
1340 ExAcquireResourceExclusiveLite(&(DeviceExt
->Resource
),TRUE
);
1341 Status
= FsdOpenFile(DeviceExt
,FileObject
,FileObject
->FileName
.Buffer
);
1342 Irp
->IoStatus
.Information
= 0;
1343 if(!NT_SUCCESS(Status
))
1345 if(RequestedDisposition
==FILE_CREATE
1346 ||RequestedDisposition
==FILE_OPEN_IF
1347 ||RequestedDisposition
==FILE_OVERWRITE_IF
)
1349 Status
=addEntry(DeviceExt
,FileObject
,RequestedOptions
1350 ,(Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
1351 if(NT_SUCCESS(Status
))
1352 Irp
->IoStatus
.Information
= FILE_CREATED
;
1353 // FIXME set size if AllocationSize requested
1354 // FIXME set extended attributes ?
1355 // FIXME set share access
1356 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1357 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1362 if(RequestedDisposition
==FILE_CREATE
)
1364 Irp
->IoStatus
.Information
= FILE_EXISTS
;
1365 Status
=STATUS_OBJECT_NAME_COLLISION
;
1367 pCcb
=FileObject
->FsContext2
;
1369 if( (RequestedOptions
&FILE_NON_DIRECTORY_FILE
)
1370 && (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1372 Status
=STATUS_FILE_IS_A_DIRECTORY
;
1374 if( (RequestedOptions
&FILE_DIRECTORY_FILE
)
1375 && !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
1377 Status
=STATUS_NOT_A_DIRECTORY
;
1379 // FIXME : test share access
1380 // FIXME : test write access if requested
1381 if(!NT_SUCCESS(Status
))
1382 FsdCloseFile(DeviceExt
,FileObject
);
1383 else Irp
->IoStatus
.Information
= FILE_OPENED
;
1384 // FIXME : make supersed or overwrite if requested
1387 Irp
->IoStatus
.Status
= Status
;
1389 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1390 ExReleaseResourceForThreadLite(&(DeviceExt
->Resource
),ExGetCurrentResourceThread());
1395 NTSTATUS
FsdWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1397 * FUNCTION: Write to a file
1403 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1404 PFILE_OBJECT FileObject
= Stack
->FileObject
;
1405 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
1408 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject
,Irp
);
1410 Length
= Stack
->Parameters
.Write
.Length
;
1411 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1412 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Write
.ByteOffset
);
1414 Status
= FsdWriteFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
);
1416 Irp
->IoStatus
.Status
= Status
;
1417 Irp
->IoStatus
.Information
= Length
;
1418 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1423 NTSTATUS
FsdRead(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1425 * FUNCTION: Read from a file
1431 PIO_STACK_LOCATION Stack
;
1432 PFILE_OBJECT FileObject
;
1433 PDEVICE_EXTENSION DeviceExt
;
1437 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject
,Irp
);
1439 /* Precondition / Initialization */
1440 assert(Irp
!= NULL
);
1441 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1442 assert(Stack
!= NULL
);
1443 FileObject
= Stack
->FileObject
;
1444 assert(FileObject
!= NULL
);
1445 DeviceExt
= DeviceObject
->DeviceExtension
;
1446 assert(DeviceExt
!= NULL
);
1448 Length
= Stack
->Parameters
.Read
.Length
;
1449 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1450 Offset
= GET_LARGE_INTEGER_LOW_PART(Stack
->Parameters
.Read
.ByteOffset
);
1452 Status
= FsdReadFile(DeviceExt
,FileObject
,Buffer
,Length
,Offset
,
1455 Irp
->IoStatus
.Status
= Status
;
1456 Irp
->IoStatus
.Information
= LengthRead
;
1457 IoCompleteRequest(Irp
,IO_NO_INCREMENT
);
1463 NTSTATUS
FsdMount(PDEVICE_OBJECT DeviceToMount
)
1465 * FUNCTION: Mount the filesystem
1468 PDEVICE_OBJECT DeviceObject
;
1469 PDEVICE_EXTENSION DeviceExt
;
1471 IoCreateDevice(VFATDriverObject
,
1472 sizeof(DEVICE_EXTENSION
),
1474 FILE_DEVICE_FILE_SYSTEM
,
1478 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_DIRECT_IO
;
1479 DeviceExt
= (PVOID
)DeviceObject
->DeviceExtension
;
1480 // use same vpb as device disk
1481 DeviceObject
->Vpb
=DeviceToMount
->Vpb
;
1482 FsdMountDevice(DeviceExt
,DeviceToMount
);
1483 DeviceObject
->Vpb
->Flags
|= VPB_MOUNTED
;
1484 DeviceExt
->StorageDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1486 return(STATUS_SUCCESS
);
1489 NTSTATUS
FsdFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1491 * FUNCTION: File system control
1494 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1495 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1496 PDEVICE_OBJECT DeviceToMount
= Stack
->Parameters
.Mount
.DeviceObject
;
1499 DPRINT("VFAT FSC\n");
1501 /* FIXME: should make sure that this is actually a mount request! */
1503 if (FsdHasFileSystem(DeviceToMount
))
1505 Status
= FsdMount(DeviceToMount
);
1509 DPRINT("VFAT: Unrecognized Volume\n");
1510 Status
= STATUS_UNRECOGNIZED_VOLUME
;
1512 DPRINT("VFAT File system successfully mounted\n");
1514 Irp
->IoStatus
.Status
= Status
;
1515 Irp
->IoStatus
.Information
= 0;
1517 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1521 NTSTATUS
FsdGetStandardInformation(PVfatFCB FCB
, PDEVICE_OBJECT DeviceObject
,
1522 PFILE_STANDARD_INFORMATION StandardInfo
)
1524 * FUNCTION: Retrieve the standard file information
1527 PDEVICE_EXTENSION DeviceExtension
;
1528 unsigned long AllocSize
;
1530 DeviceExtension
= DeviceObject
->DeviceExtension
;
1532 assert(DeviceExtension
!= NULL
);
1533 assert(DeviceExtension
->BytesPerCluster
!= 0);
1534 assert(StandardInfo
!= NULL
);
1535 assert(FCB
!= NULL
);
1537 RtlZeroMemory(StandardInfo
, sizeof(FILE_STANDARD_INFORMATION
));
1539 /* Make allocsize a rounded up multiple of BytesPerCluster */
1540 AllocSize
= ((FCB
->entry
.FileSize
+ DeviceExtension
->BytesPerCluster
- 1) /
1541 DeviceExtension
->BytesPerCluster
) *
1542 DeviceExtension
->BytesPerCluster
;
1544 StandardInfo
->AllocationSize
= RtlConvertUlongToLargeInteger(AllocSize
);
1545 StandardInfo
->EndOfFile
= RtlConvertUlongToLargeInteger(FCB
->entry
.FileSize
);
1546 StandardInfo
->NumberOfLinks
= 0;
1547 StandardInfo
->DeletePending
= FALSE
;
1548 if((FCB
->entry
.Attrib
& 0x10)>0) {
1549 StandardInfo
->Directory
= TRUE
;
1551 StandardInfo
->Directory
= FALSE
;
1554 return STATUS_SUCCESS
;
1557 NTSTATUS
FsdQueryInformation(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
1559 * FUNCTION: Retrieve the specified file information
1562 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
1563 FILE_INFORMATION_CLASS FileInformationClass
=
1564 Stack
->Parameters
.QueryFile
.FileInformationClass
;
1565 PFILE_OBJECT FileObject
= NULL
;
1566 PVfatFCB FCB
= NULL
;
1567 // PVfatCCB CCB = NULL;
1569 NTSTATUS RC
= STATUS_SUCCESS
;
1573 assert(DeviceObject
!= NULL
);
1574 assert(Irp
!= NULL
);
1576 /* INITIALIZATION */
1577 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1578 FileInformationClass
= Stack
->Parameters
.QueryFile
.FileInformationClass
;
1579 FileObject
= Stack
->FileObject
;
1580 // CCB = (PVfatCCB)(FileObject->FsContext2);
1581 // FCB = CCB->Buffer; // Should be CCB->FCB???
1582 FCB
= ((PVfatCCB
)(FileObject
->FsContext2
))->pFcb
;
1584 // FIXME : determine Buffer for result :
1585 if (Irp
->MdlAddress
)
1586 SystemBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
1588 SystemBuffer
= Irp
->UserBuffer
;
1589 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1591 switch(FileInformationClass
) {
1592 case FileStandardInformation
:
1593 RC
= FsdGetStandardInformation(FCB
, DeviceObject
, SystemBuffer
);
1596 RC
=STATUS_NOT_IMPLEMENTED
;
1602 NTSTATUS
DriverEntry(PDRIVER_OBJECT _DriverObject
,
1603 PUNICODE_STRING RegistryPath
)
1605 * FUNCTION: Called by the system to initalize the driver
1607 * DriverObject = object describing this driver
1608 * RegistryPath = path to our configuration entries
1609 * RETURNS: Success or failure
1612 PDEVICE_OBJECT DeviceObject
;
1614 UNICODE_STRING ustr
;
1617 DbgPrint("VFAT 0.0.6\n");
1619 VFATDriverObject
= _DriverObject
;
1621 RtlInitAnsiString(&astr
,"\\Device\\VFAT");
1622 RtlAnsiStringToUnicodeString(&ustr
,&astr
,TRUE
);
1623 ret
= IoCreateDevice(VFATDriverObject
,0,&ustr
,
1624 FILE_DEVICE_FILE_SYSTEM
,0,FALSE
,&DeviceObject
);
1625 if (ret
!=STATUS_SUCCESS
)
1630 DeviceObject
->Flags
= DO_DIRECT_IO
;
1631 VFATDriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = FsdClose
;
1632 VFATDriverObject
->MajorFunction
[IRP_MJ_CREATE
] = FsdCreate
;
1633 VFATDriverObject
->MajorFunction
[IRP_MJ_READ
] = FsdRead
;
1634 VFATDriverObject
->MajorFunction
[IRP_MJ_WRITE
] = FsdWrite
;
1635 VFATDriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] =
1636 FsdFileSystemControl
;
1637 VFATDriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] =
1638 FsdQueryInformation
;
1639 VFATDriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] =
1640 FsdDirectoryControl
;
1642 VFATDriverObject
->DriverUnload
= NULL
;
1644 IoRegisterFileSystem(DeviceObject
);
1646 return(STATUS_SUCCESS
);