many changes to :
[reactos.git] / reactos / drivers / fs / vfat / iface.c
1
2
3 /*
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)
9 * UPDATE HISTORY:
10 ?? Created
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
21
22 */
23
24 /* INCLUDES *****************************************************************/
25
26 #include <ddk/ntddk.h>
27 #include <internal/string.h>
28 #include <wstring.h>
29 #include <ddk/cctypes.h>
30
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 #include "vfat.h"
35
36 //#include "dbgpool.c"
37
38 /* GLOBALS *****************************************************************/
39
40 static PDRIVER_OBJECT DriverObject;
41 static PVfatFCB pFirstFcb;
42
43 /* FUNCTIONS ****************************************************************/
44
45 ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
46 /*
47 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
48 * disk read
49 */
50 {
51 ULONG FATsector;
52 ULONG FATeis;
53 PULONG Block;
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;
62 ExFreePool(Block);
63 return(CurrentCluster);
64 }
65
66 ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
67 /*
68 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
69 * in-memory FAT
70 */
71 {
72 PUSHORT Block;
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);
79 }
80
81 ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
82 /*
83 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
84 * in-memory FAT
85 */
86 {
87 unsigned char* CBlock;
88 ULONG FATOffset;
89 ULONG Entry;
90 CBlock = DeviceExt->FAT;
91 FATOffset = (CurrentCluster * 12)/ 8;//first byte containing value
92 if ((CurrentCluster % 2) == 0)
93 {
94 Entry = CBlock[FATOffset];
95 Entry |= ((CBlock[FATOffset+1] & 0xf)<<8);
96 }
97 else
98 {
99 Entry = (CBlock[FATOffset] >> 4);
100 Entry |= (CBlock[FATOffset+1] << 4);
101 }
102 DPRINT("Entry %x\n",Entry);
103 if (Entry >= 0xff8 && Entry <= 0xfff)
104 Entry = 0xffffffff;
105 DPRINT("Returning %x\n",Entry);
106 return(Entry);
107 }
108
109 ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
110 /*
111 * FUNCTION: Retrieve the next cluster depending on the FAT type
112 */
113 {
114
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));
121 else
122 return(Fat12GetNextCluster(DeviceExt, CurrentCluster));
123 }
124
125 ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
126 /*
127 * FUNCTION: Finds the first available cluster in a FAT16 table
128 */
129 {
130 PUSHORT Block;
131 int i;
132 Block=(PUSHORT)DeviceExt->FAT;
133 for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
134 if(Block[i]==0)
135 return (i);
136 /* Give an error message (out of disk space) if we reach here) */
137 return 0;
138 }
139
140 ULONG FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
141 /*
142 * FUNCTION: Finds the first available cluster in a FAT12 table
143 */
144 {
145 ULONG FATOffset;
146 ULONG Entry;
147 PUCHAR CBlock=DeviceExt->FAT;
148 ULONG i;
149 for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
150 {
151 FATOffset = (i * 12)/8;
152 if ((i % 2) == 0)
153 {
154 Entry = CBlock[FATOffset];
155 Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
156 }
157 else
158 {
159 Entry = (CBlock[FATOffset] >> 4);
160 Entry |= (CBlock[FATOffset + 1] << 4);
161 }
162 if(Entry==0)
163 return (i);
164 }
165 /* Give an error message (out of disk space) if we reach here) */
166 DbgPrint("Disk full, %d clusters used\n",i);
167 return 0;
168 }
169
170 ULONG FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
171 /*
172 * FUNCTION: Finds the first available cluster in a FAT32 table
173 */
174 {
175 ULONG sector;
176 PULONG Block;
177 int i;
178 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
179 for(sector=0
180 ;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
181 ;sector++)
182 {
183 VFATReadSectors(DeviceExt->StorageDevice
184 ,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
185
186 for(i=0; i<512; i++)
187 {
188 if(Block[i]==0)
189 {
190 ExFreePool(Block);
191 return (i+sector*128);
192 }
193 }
194 }
195 /* Give an error message (out of disk space) if we reach here) */
196 ExFreePool(Block);
197 return 0;
198 }
199
200 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
201 ULONG NewValue)
202 /*
203 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
204 */
205 {
206 ULONG FATsector;
207 ULONG FATOffset;
208 PUCHAR CBlock=DeviceExt->FAT;
209 int i;
210 FATOffset = (ClusterToWrite * 12)/8;
211 if ((ClusterToWrite % 2) == 0)
212 {
213 CBlock[FATOffset]=NewValue;
214 CBlock[FATOffset + 1] &=0xf0;
215 CBlock[FATOffset + 1]
216 |= (NewValue&0xf00)>>8;
217 }
218 else
219 {
220 CBlock[FATOffset] &=0x0f;
221 CBlock[FATOffset]
222 |= (NewValue&0xf)<<4;
223 CBlock[FATOffset+1]=NewValue>>4;
224 }
225 /* Write the changed FAT sector(s) to disk */
226 FATsector=FATOffset/BLOCKSIZE;
227 for(i=0;i<DeviceExt->Boot->FATCount;i++)
228 {
229 if( (FATOffset%BLOCKSIZE)==(BLOCKSIZE-1))//entry is on 2 sectors
230 {
231 VFATWriteSectors(DeviceExt->StorageDevice,
232 DeviceExt->FATStart+FATsector
233 +i*DeviceExt->Boot->FATSectors,
234 2,
235 CBlock+FATsector*512);
236 }
237 else
238 {
239 VFATWriteSectors(DeviceExt->StorageDevice,
240 DeviceExt->FATStart+FATsector
241 +i*DeviceExt->Boot->FATSectors,
242 1,
243 CBlock+FATsector*512);
244 }
245 }
246 }
247
248 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
249 ULONG NewValue)
250 /*
251 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
252 */
253 {
254 ULONG FATsector;
255 PUSHORT Block;
256 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite,NewValue);
257 Block=(PUSHORT)DeviceExt->FAT;
258 FATsector=ClusterToWrite/(512/sizeof(USHORT));
259
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,
265 1,
266 (UCHAR *)Block);
267 }
268
269 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
270 ULONG NewValue)
271 /*
272 * FUNCTION: Writes a cluster to the FAT32 physical tables
273 */
274 {
275 ULONG FATsector;
276 ULONG FATeis;
277 PUSHORT Block;
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,
285 1,
286 (UCHAR *)Block);
287 Block[FATeis] = NewValue;
288 VFATWriteSectors(DeviceExt->StorageDevice,
289 DeviceExt->FATStart+FATsector,
290 1,
291 (UCHAR *)Block);
292 ExFreePool(Block);
293 }
294
295 void WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
296 ULONG NewValue)
297 /*
298 * FUNCTION: Write a changed FAT entry
299 */
300 {
301 if(DeviceExt->FatType==FAT16)
302 FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
303 else if(DeviceExt->FatType==FAT32)
304 FAT32WriteCluster(DeviceExt, ClusterToWrite, NewValue);
305 else
306 FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue);
307 }
308
309 ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
310 /*
311 * FUNCTION: Determines the next cluster to be written
312 */
313 {
314 ULONG LastCluster, NewCluster;
315 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
316 DeviceExt,CurrentCluster);
317
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
323 /* Append */
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);
329 else
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
334 found AU */
335 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
336 /* Return NewCluster as CurrentCluster */
337 return NewCluster;
338 }
339 else
340 {
341 /* Overwrite: Return LastCluster as CurrentCluster */
342 return LastCluster;
343 }
344 }
345
346 ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt,
347 unsigned long Cluster)
348 /*
349 * FUNCTION: Converts the cluster number to a sector number for this physical
350 * device
351 */
352 {
353 return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
354 }
355
356 void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
357 /*
358 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
359 */
360 {
361 int i;
362
363 for (i=0; (i<Length && Source[i] != ' '); i++)
364 {
365 Dest[i] = Source[i];
366 }
367 Dest[i]=0;
368 }
369
370 void RtlCatAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
371 /*
372 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
373 * existing Unicode string
374 */
375 {
376 ULONG i;
377
378 while((*Dest)!=0)
379 {
380 Dest++;
381 }
382 for (i=0; (i<Length && Source[i] != ' '); i++)
383 {
384 Dest[i] = Source[i];
385 }
386 Dest[i]=0;
387 }
388
389 void vfat_initstr(wchar_t *wstr, ULONG wsize)
390 /*
391 * FUNCTION: Initialize a string for use with a long file name
392 */
393 {
394 int i;
395 wchar_t nc=0;
396 for(i=0; i<wsize; i++)
397 {
398 *wstr=nc;
399 wstr++;
400 }
401 wstr=wstr-wsize;
402 }
403
404 wchar_t * vfat_wcsncat(wchar_t * dest, const wchar_t * src,size_t wstart, size_t wcount)
405 /*
406 * FUNCTION: Append a string for use with a long file name
407 */
408 {
409 int i;
410
411 dest+=wstart;
412 for(i=0; i<wcount; i++)
413 {
414 *dest=src[i];
415 dest++;
416 }
417 dest=dest-(wcount+wstart);
418
419 return dest;
420 }
421
422 wchar_t * vfat_wcsncpy(wchar_t * dest, const wchar_t *src,size_t wcount)
423 /*
424 * FUNCTION: Copy a string for use with long file names
425 */
426 {
427 int i;
428
429 for (i=0;i<wcount;i++)
430 {
431 *dest=src[i];
432 dest++;
433 }
434 dest=dest-wcount;
435
436 return(dest);
437 }
438
439 wchar_t * vfat_movstr(wchar_t * dest, const wchar_t *src, ULONG dpos,
440 ULONG spos, ULONG len)
441 /*
442 * FUNCTION: Move the characters in a string to a new position in the same
443 * string
444 */
445 {
446 int i;
447
448 dest+=dpos;
449 for(i=spos; i<spos+len; i++)
450 {
451 *dest=src[i];
452 dest++;
453 }
454 dest-=(dpos+len);
455
456 return(dest);
457 }
458
459 BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
460 /*
461 * FUNCTION: Determine if the given directory entry is the last
462 */
463 {
464 return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
465 }
466
467 BOOLEAN IsVolEntry(PVOID Block, ULONG Offset)
468 /*
469 * FUNCTION: Determine if the given directory entry is a vol entry
470 */
471 {
472 if( (((FATDirEntry *)Block)[Offset].Attrib)==0x28 ) return TRUE;
473 else return FALSE;
474 }
475
476 BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
477 /*
478 * FUNCTION: Determines if the given entry is a deleted one
479 */
480 {
481 /* Checks special character (short names) or attrib=0 (long names) */
482
483 return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5) ||
484 (((FATDirEntry *)Block)[Offset].Attrib == 0x00));
485 }
486
487 BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
488 PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
489 /*
490 * FUNCTION: Retrieves the file name, be it in short or long file name format
491 */
492 {
493 FATDirEntry* test;
494 slot* test2;
495 ULONG Offset = *_Offset;
496 ULONG StartingSector = *_StartingSector;
497 ULONG jloop = *_jloop;
498 ULONG cpos;
499 WCHAR tmp[256];
500
501 test = (FATDirEntry *)Block;
502 test2 = (slot *)Block;
503
504 *Name = 0;
505
506 if (IsDeletedEntry(Block,Offset))
507 {
508 return(FALSE);
509 }
510
511 if(test2[Offset].attr == 0x0f)
512 {
513 vfat_initstr(Name, 256);
514 vfat_wcsncpy(Name,test2[Offset].name0_4,5);
515 vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
516 vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
517
518 cpos=0;
519 while((test2[Offset].id!=0x41) && (test2[Offset].id!=0x01) &&
520 (test2[Offset].attr>0))
521 {
522 Offset++;
523 if(Offset==ENTRIES_PER_SECTOR) {
524 Offset=0;
525 StartingSector++;
526 jloop++;
527 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
528 test2 = (slot *)Block;
529 }
530 cpos++;
531
532 vfat_initstr(tmp, 256);
533 vfat_movstr(tmp, Name, 13, 0, cpos*13);
534 vfat_wcsncpy(Name, tmp, 256);
535 vfat_wcsncpy(Name, test2[Offset].name0_4, 5);
536 vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
537 vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
538
539 }
540
541 if (IsDeletedEntry(Block,Offset+1))
542 {
543 Offset++;
544 *_Offset = Offset;
545 *_jloop = jloop;
546 *_StartingSector = StartingSector;
547 return(FALSE);
548 }
549
550 *_Offset = Offset;
551 *_jloop = jloop;
552 *_StartingSector = StartingSector;
553
554 return(TRUE);
555 }
556
557 RtlAnsiToUnicode(Name,test[Offset].Filename,8);
558 if (test[Offset].Ext[0]!=' ')
559 {
560 RtlCatAnsiToUnicode(Name,".",1);
561 }
562 RtlCatAnsiToUnicode(Name,test[Offset].Ext,3);
563
564 *_Offset = Offset;
565
566 return(TRUE);
567 }
568
569 BOOLEAN wstrcmpi(PWSTR s1, PWSTR s2)
570 /*
571 * FUNCTION: Compare to wide character strings
572 * return TRUE if s1==s2
573 */
574 {
575 while (wtolower(*s1)==wtolower(*s2))
576 {
577 if ((*s1)==0 && (*s2)==0)
578 {
579 return(TRUE);
580 }
581
582 s1++;
583 s2++;
584 }
585 return(FALSE);
586 }
587 BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2)
588 /*
589 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
590 * return TRUE if s1 like s2
591 */
592 {
593 while ((*s2=='?')||(wtolower(*s1)==wtolower(*s2)))
594 {
595 if ((*s1)==0 && (*s2)==0)
596 return(TRUE);
597 s1++;
598 s2++;
599 }
600 if(*s2=='*')
601 {
602 s2++;
603 while (*s1)
604 if (wstrcmpjoki(s1,s2)) return TRUE;
605 else s1++;
606 }
607 if ((*s1)==0 && (*s2)==0)
608 return(TRUE);
609 return(FALSE);
610 }
611
612 NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PVfatFCB Fcb,
613 PVfatFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
614 /*
615 * FUNCTION: Find a file
616 */
617 {
618 ULONG i, j;
619 ULONG Size;
620 char* block;
621 WCHAR name[256];
622 ULONG StartingSector;
623 ULONG NextCluster;
624 DPRINT("FindFile(Parent %x, FileToFind %w)\n",Parent,FileToFind);
625
626 if (Parent == NULL)
627 {
628 Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
629 StartingSector = DeviceExt->rootStart;
630 if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0))
631 {// it's root : complete essentials fields then return ok
632 memset(Fcb,0,sizeof(VfatFCB));
633 memset(Fcb->entry.Filename,' ',11);
634 if (DeviceExt->FatType == FAT32)
635 Fcb->entry.FirstCluster=2;
636 else Fcb->entry.FirstCluster=1;//FIXME : is 1 the good value ?
637 if(StartSector) *StartSector=StartingSector;
638 if(Entry) *Entry=0;
639 return(STATUS_SUCCESS);
640 }
641 }
642 else
643 {
644 DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
645
646 Size = ULONG_MAX;
647 if (DeviceExt->FatType == FAT32)
648 NextCluster = Parent->entry.FirstCluster+Parent->entry.FirstClusterHigh*65536;
649 else
650 NextCluster = Parent->entry.FirstCluster;
651 StartingSector = ClusterToSector(DeviceExt, NextCluster);
652 if(Parent->entry.FirstCluster==1 && DeviceExt->FatType!=FAT32)
653 {// read of root directory in FAT16 or FAT12
654 StartingSector=DeviceExt->rootStart;
655 }
656 }
657 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
658 if (StartSector && (*StartSector)) StartingSector=*StartSector;
659 i=(Entry)?(*Entry):0;
660 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
661 for (j=0; j<Size; j++)
662 {
663 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
664
665 for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
666 {
667 if (IsVolEntry((PVOID)block,i))
668 continue;
669 if (IsLastEntry((PVOID)block,i))
670 {
671 ExFreePool(block);
672 if(StartSector) *StartSector=StartingSector;
673 if(Entry) *Entry=i;
674 return(STATUS_UNSUCCESSFUL);
675 }
676 if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
677 {
678 // DPRINT("Comparing %w %w\n",name,FileToFind);
679 if (wstrcmpjoki(name,FileToFind))
680 {
681 /* In the case of a long filename, the firstcluster is stored in
682 the next record -- where it's short name is */
683 if(((FATDirEntry *)block)[i].Attrib==0x0f) i++;
684 // if(DeviceExt->FatType==FAT32)
685 // {
686 // if(((FATDirEntry *)block)[i].FirstCluster==0
687 // &&((FATDirEntry *)block)[i].FirstClusterHigh==0
688 // ) i++;
689 // }
690 // else
691 // if(((FATDirEntry *)block)[i].FirstCluster==0) i++;
692 if( i==(ENTRIES_PER_SECTOR))
693 {// entry is in next sector
694 StartingSector++;
695 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
696 i=0;
697 }
698 memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
699 sizeof(FATDirEntry));
700 vfat_wcsncpy(Fcb->ObjectName,name,261);
701 ExFreePool(block);
702 if(StartSector) *StartSector=StartingSector;
703 if(Entry) *Entry=i;
704 return(STATUS_SUCCESS);
705 }
706 }
707 }
708 // not found in this sector, try next :
709
710 /* It seems that directory sectors cannot be fragmented and therefore,
711 they only have a first cluster, but the one's after it are marked
712 with 0xffff. This theory is still not 100% certain, so the following
713 lines are commented and not removed */
714
715 StartingSector++;
716 if(Entry) *Entry=0;
717 /* if (Parent == NULL)
718 {
719 StartingSector++;
720 }
721 else
722 {
723 NextCluster = GetNextCluster(DeviceExt,NextCluster);
724 if (NextCluster == 0||NextCluster==0xffffffff)
725 {
726 if(StartSector) *StartSector=StartingSector;
727 if(Entry) *Entry=i;
728 ExFreePool(block);
729 return(STATUS_UNSUCCESSFUL);
730 }
731 StartingSector = ClusterToSector(DeviceExt,NextCluster);
732 } */
733 }
734 ExFreePool(block);
735 if(StartSector) *StartSector=StartingSector;
736 if(Entry) *Entry=i;
737 return(STATUS_UNSUCCESSFUL);
738 }
739
740
741 NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
742 /*
743 * FUNCTION: Closes a file
744 */
745 {
746 PVfatFCB pFcb;
747 PVfatCCB pCcb;
748 //FIXME : update entry in directory ?
749 pCcb = (PVfatCCB)(FileObject->FsContext2);
750 pFcb = pCcb->pFcb;
751 pFcb->RefCount--;
752 if(pFcb->RefCount<=0)
753 {
754 if(pFcb->prevFcb)
755 pFcb->prevFcb->nextFcb=pFcb->nextFcb;
756 else
757 pFirstFcb=pFcb->nextFcb;
758 if(pFcb->nextFcb)
759 pFcb->nextFcb->prevFcb=pFcb->prevFcb;
760 ExFreePool(pFcb);
761 }
762 ExFreePool(pCcb);
763 return STATUS_SUCCESS;
764 }
765
766 NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
767 PWSTR FileName)
768 /*
769 * FUNCTION: Opens a file
770 */
771 {
772 PWSTR current;
773 PWSTR next;
774 PWSTR string;
775 PVfatFCB ParentFcb;
776 PVfatFCB Fcb;
777 PVfatFCB Temp;
778 PVfatCCB newCCB;
779 NTSTATUS Status;
780
781 DPRINT("FsdOpenFile(%08lx, %08lx, %08lx)\n",
782 DeviceExt,
783 FileObject,
784 FileName);
785 // try first to find an existing FCB in memory
786 for (Fcb=pFirstFcb;Fcb; Fcb=Fcb->nextFcb)
787 {
788 if (DeviceExt==Fcb->pDevExt
789 && wstrcmpi(FileName,Fcb->PathName))
790 {
791 Fcb->RefCount++;
792 FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
793 newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
794 memset(newCCB,0,sizeof(VfatCCB));
795 FileObject->FsContext2 = newCCB;
796 newCCB->pFcb=Fcb;
797 newCCB->PtrFileObject=FileObject;
798 return(STATUS_SUCCESS);
799 }
800 }
801 string = FileName;
802 ParentFcb = NULL;
803 Fcb = ExAllocatePool(NonPagedPool, sizeof(VfatFCB));
804 memset(Fcb,0,sizeof(VfatFCB));
805 Fcb->ObjectName=Fcb->PathName;
806 next = &string[0];
807 current = next+1;
808
809 while (next!=NULL)
810 {
811 DPRINT("current %w next %x\n",current,next);
812
813 *next = '\\';
814 current = next+1;
815 next = wcschr(next+1,'\\');
816 if (next!=NULL)
817 {
818 *next=0;
819 }
820
821 Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
822 if (Status != STATUS_SUCCESS)
823 {
824 /* FIXME: should the VfatFCB be freed here? */
825 return(Status);
826 }
827 Temp = Fcb;
828 if (ParentFcb == NULL)
829 {
830 Fcb = ExAllocatePool(NonPagedPool,sizeof(VfatFCB));
831 memset(Fcb,0,sizeof(VfatFCB));
832 Fcb->ObjectName=Fcb->PathName;
833 }
834 else
835 {
836 Fcb = ParentFcb;
837 }
838 ParentFcb = Temp;
839 }
840 FileObject->FsContext =(PVOID) &ParentFcb->NTRequiredFCB;
841 newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
842 memset(newCCB,0,sizeof(VfatCCB));
843 FileObject->FsContext2 = newCCB;
844 newCCB->pFcb=ParentFcb;
845 newCCB->PtrFileObject=FileObject;
846 ParentFcb->RefCount++;
847 //FIXME : initialize all fields in FCB and CCB
848 ParentFcb->nextFcb=pFirstFcb;
849 pFirstFcb=ParentFcb;
850 vfat_wcsncpy(ParentFcb->PathName,FileName,261);
851 ParentFcb->ObjectName=Fcb->PathName+(current-string);
852 ParentFcb->pDevExt=DeviceExt;
853 DPRINT("file open, fcb=%x\n",ParentFcb);
854 DPRINT("FileSize %d\n",ParentFcb->entry.FileSize);
855 ExFreePool(Fcb);
856 return(STATUS_SUCCESS);
857 }
858
859 BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
860 /*
861 * FUNCTION: Tests if the device contains a filesystem that can be mounted
862 * by this fsd
863 */
864 {
865 BootSector* Boot;
866
867 Boot = ExAllocatePool(NonPagedPool,512);
868
869 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
870
871 if (strncmp(Boot->SysType,"FAT12",5)==0 ||
872 strncmp(Boot->SysType,"FAT16",5)==0 ||
873 strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
874 {
875 ExFreePool(Boot);
876 return(TRUE);
877 }
878 ExFreePool(Boot);
879 return(FALSE);
880 }
881
882 NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
883 PDEVICE_OBJECT DeviceToMount)
884 /*
885 * FUNCTION: Mounts the device
886 */
887 {
888 DPRINT("Mounting VFAT device...");
889 DPRINT("DeviceExt %x\n",DeviceExt);
890
891 DeviceExt->Boot = ExAllocatePool(NonPagedPool,512);
892 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)DeviceExt->Boot);
893
894 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
895 DeviceExt->Boot->BytesPerSector);
896
897 DeviceExt->FATStart=DeviceExt->Boot->ReservedSectors;
898 DeviceExt->rootDirectorySectors=
899 (DeviceExt->Boot->RootEntries*32)/DeviceExt->Boot->BytesPerSector;
900 DeviceExt->rootStart=
901 DeviceExt->FATStart+DeviceExt->Boot->FATCount*DeviceExt->Boot->FATSectors;
902 DeviceExt->dataStart=DeviceExt->rootStart+DeviceExt->rootDirectorySectors;
903 DeviceExt->FATEntriesPerSector=DeviceExt->Boot->BytesPerSector/32;
904 DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
905 DeviceExt->Boot->BytesPerSector;
906
907 if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
908 {
909 DeviceExt->FatType = FAT12;
910 }
911 else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
912 {
913 DeviceExt->FatType = FAT32;
914 DeviceExt->rootDirectorySectors=DeviceExt->Boot->SectorsPerCluster;
915 DeviceExt->rootStart=
916 DeviceExt->FATStart+DeviceExt->Boot->FATCount
917 * ((struct _BootSector32 *)( DeviceExt->Boot))->FATSectors32;
918 DeviceExt->dataStart=DeviceExt->rootStart;
919 }
920 else
921 {
922 DeviceExt->FatType = FAT16;
923 }
924
925 // with FAT32 it's not a good idea to load always fat in memory
926 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
927 if(DeviceExt->FatType!=FAT32)
928 {
929 DeviceExt->FAT = ExAllocatePool(NonPagedPool, BLOCKSIZE*DeviceExt->Boot->FATSectors);
930 VFATReadSectors(DeviceToMount, DeviceExt->FATStart, DeviceExt->Boot->FATSectors, (UCHAR *)DeviceExt->FAT);
931 }
932 return STATUS_SUCCESS;
933 }
934
935 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
936 /*
937 * FUNCTION: Load a cluster from the physical device
938 */
939 {
940 ULONG Sector;
941
942 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
943 DeviceExt,Buffer,Cluster);
944
945 Sector = ClusterToSector(DeviceExt, Cluster);
946
947 VFATReadSectors(DeviceExt->StorageDevice,
948 Sector,
949 DeviceExt->Boot->SectorsPerCluster,
950 Buffer);
951 }
952
953 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
954 /*
955 * FUNCTION: Write a cluster to the physical device
956 */
957 {
958 ULONG Sector;
959 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
960 DeviceExt,Buffer,Cluster);
961
962 Sector = ClusterToSector(DeviceExt, Cluster);
963
964 VFATWriteSectors(DeviceExt->StorageDevice,
965 Sector,
966 DeviceExt->Boot->SectorsPerCluster,
967 Buffer);
968 }
969
970 NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
971 PVOID Buffer, ULONG Length, ULONG ReadOffset,
972 PULONG LengthRead)
973 /*
974 * FUNCTION: Reads data from a file
975 */
976 {
977 ULONG CurrentCluster;
978 ULONG FileOffset;
979 ULONG FirstCluster;
980 PVfatFCB Fcb;
981 PVOID Temp;
982 ULONG TempLength;
983
984 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
985 "Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
986 Length,ReadOffset);
987
988 FirstCluster = ReadOffset / DeviceExt->BytesPerCluster;
989 Fcb = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
990 if (DeviceExt->FatType == FAT32)
991 CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
992 else
993 CurrentCluster = Fcb->entry.FirstCluster;
994 if (CurrentCluster<2)
995 return STATUS_UNSUCCESSFUL;// FIXME : root of FAT16 or FAT12
996 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
997
998 if (ReadOffset >= Fcb->entry.FileSize)
999 {
1000 return(STATUS_END_OF_FILE);
1001 }
1002 if ((ReadOffset + Length) > Fcb->entry.FileSize)
1003 {
1004 Length = Fcb->entry.FileSize - ReadOffset;
1005 }
1006 *LengthRead = 0;
1007 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1008 if(!Temp) return STATUS_UNSUCCESSFUL;
1009 for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
1010 {
1011 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1012 }
1013 CHECKPOINT;
1014 if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
1015 {
1016 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1017 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1018
1019 TempLength = min(Length,DeviceExt->BytesPerCluster -
1020 (ReadOffset % DeviceExt->BytesPerCluster));
1021
1022 memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
1023 TempLength);
1024
1025 (*LengthRead) = (*LengthRead) + TempLength;
1026 Length = Length - TempLength;
1027 Buffer = Buffer + TempLength;
1028 }
1029 CHECKPOINT;
1030 while (Length > DeviceExt->BytesPerCluster)
1031 {
1032 VFATLoadCluster(DeviceExt, Buffer, CurrentCluster);
1033 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1034
1035 if (CurrentCluster == 0xffffffff)
1036 {
1037 ExFreePool(Temp);
1038 return(STATUS_SUCCESS);
1039 }
1040
1041 (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
1042 Buffer = Buffer + DeviceExt->BytesPerCluster;
1043 Length = Length - DeviceExt->BytesPerCluster;
1044 }
1045 CHECKPOINT;
1046 if (Length > 0)
1047 {
1048 (*LengthRead) = (*LengthRead) + Length;
1049 VFATLoadCluster(DeviceExt, Temp, CurrentCluster);
1050 memcpy(Buffer, Temp, Length);
1051 }
1052 ExFreePool(Temp);
1053 return(STATUS_SUCCESS);
1054 }
1055
1056 NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1057 PVOID Buffer, ULONG Length, ULONG WriteOffset)
1058 /*
1059 * FUNCTION: Writes data to file
1060 */
1061 {
1062 ULONG CurrentCluster;
1063 ULONG FileOffset;
1064 ULONG FirstCluster;
1065 PVfatFCB Fcb;
1066 PVOID Temp;
1067 ULONG TempLength;
1068
1069 /* Locate the first cluster of the file */
1070 FirstCluster = WriteOffset / DeviceExt->BytesPerCluster;
1071 Fcb = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1072 if (DeviceExt->FatType == FAT32)
1073 CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
1074 else
1075 CurrentCluster = Fcb->entry.FirstCluster;
1076
1077 /* Allocate a buffer to hold 1 cluster of data */
1078
1079 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1080
1081 /* Find the cluster according to the offset in the file */
1082
1083 for (FileOffset=0; FileOffset < FirstCluster; FileOffset++)
1084 {
1085 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1086 }
1087 CHECKPOINT;
1088
1089 /*
1090 If the offset in the cluster doesn't fall on the cluster boundary then
1091 we have to write only from the specified offset
1092 */
1093
1094 if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
1095 {
1096 TempLength = min(Length,DeviceExt->BytesPerCluster -
1097 (WriteOffset % DeviceExt->BytesPerCluster));
1098 /* Read in the existing cluster data */
1099 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1100
1101 /* Overwrite the last parts of the data as necessary */
1102 memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster), Buffer,
1103 TempLength);
1104
1105 /* Write the cluster back */
1106 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1107 Length = Length - TempLength;
1108 Buffer = Buffer + TempLength;
1109 }
1110 CHECKPOINT;
1111
1112 /* Write the buffer in chunks of 1 cluster */
1113
1114 while (Length > DeviceExt->BytesPerCluster)
1115 {
1116 /* Next write cluster */
1117 CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
1118 if (CurrentCluster == 0)
1119 {
1120 ExFreePool(Temp);
1121 return(STATUS_UNSUCCESSFUL);
1122 }
1123 VFATWriteCluster(DeviceExt, Buffer, CurrentCluster);
1124 CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
1125
1126
1127 Buffer = Buffer + DeviceExt->BytesPerCluster;
1128 Length = Length - DeviceExt->BytesPerCluster;
1129 }
1130 CHECKPOINT;
1131
1132 /* Write the remainder */
1133
1134 if (Length > 0)
1135 {
1136 CurrentCluster = GetNextWriteCluster(DeviceExt, CurrentCluster);
1137 if (CurrentCluster == 0)
1138 {
1139 ExFreePool(Temp);
1140 return(STATUS_UNSUCCESSFUL);
1141 }
1142 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1143 memcpy(Temp, Buffer, Length);
1144 VFATWriteCluster(DeviceExt, Temp, CurrentCluster);
1145 }
1146 //FIXME : set last write time and date
1147 if(Fcb->entry.FileSize<WriteOffset+Length)
1148 Fcb->entry.FileSize=WriteOffset+Length;
1149 //FIXME : update entry in directory
1150 ExFreePool(Temp);
1151 return(STATUS_SUCCESS);
1152 }
1153
1154 NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1155 /*
1156 * FUNCTION: Close a file
1157 */
1158 {
1159 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1160 PFILE_OBJECT FileObject = Stack->FileObject;
1161 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1162 NTSTATUS Status;
1163
1164 Status = FsdCloseFile(DeviceExtension,FileObject);
1165
1166 Irp->IoStatus.Status = Status;
1167 Irp->IoStatus.Information = 0;
1168
1169 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1170 return(Status);
1171 }
1172
1173 NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1174 /*
1175 * FUNCTION: Create or open a file
1176 */
1177 {
1178 PIO_STACK_LOCATION Stack;
1179 PFILE_OBJECT FileObject;
1180 NTSTATUS Status;
1181 PDEVICE_EXTENSION DeviceExt;
1182
1183 DPRINT("FsdCreate(DeviceObject %08lx, Irp %08lx)\n",
1184 DeviceObject,
1185 Irp);
1186
1187 Stack = IoGetCurrentIrpStackLocation(Irp);
1188 CHECKPOINT;
1189 FileObject = Stack->FileObject;
1190 CHECKPOINT;
1191 DeviceExt = DeviceObject->DeviceExtension;
1192 CHECKPOINT;
1193 Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
1194 CHECKPOINT;
1195
1196 Irp->IoStatus.Status = Status;
1197 CHECKPOINT;
1198 Irp->IoStatus.Information = 0;
1199 CHECKPOINT;
1200
1201 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1202 CHECKPOINT;
1203
1204 return Status;
1205 }
1206
1207
1208 NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1209 /*
1210 * FUNCTION: Write to a file
1211 */
1212 {
1213 ULONG Length;
1214 PVOID Buffer;
1215 ULONG Offset;
1216 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1217 PFILE_OBJECT FileObject = Stack->FileObject;
1218 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1219 NTSTATUS Status;
1220
1221 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
1222
1223 Length = Stack->Parameters.Write.Length;
1224 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1225 Offset = GET_LARGE_INTEGER_LOW_PART(Stack->Parameters.Write.ByteOffset);
1226
1227 Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
1228
1229 Irp->IoStatus.Status = Status;
1230 Irp->IoStatus.Information = Length;
1231 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1232
1233 return(Status);
1234 }
1235
1236 NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1237 /*
1238 * FUNCTION: Read from a file
1239 */
1240 {
1241 ULONG Length;
1242 PVOID Buffer;
1243 ULONG Offset;
1244 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1245 PFILE_OBJECT FileObject = Stack->FileObject;
1246 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1247 NTSTATUS Status;
1248 ULONG LengthRead;
1249
1250 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
1251
1252 Length = Stack->Parameters.Read.Length;
1253 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1254 Offset = GET_LARGE_INTEGER_LOW_PART(Stack->Parameters.Read.ByteOffset);
1255
1256 Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
1257 &LengthRead);
1258
1259 Irp->IoStatus.Status = Status;
1260 Irp->IoStatus.Information = LengthRead;
1261 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1262
1263 return(Status);
1264 }
1265
1266
1267 NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
1268 /*
1269 * FUNCTION: Mount the filesystem
1270 */
1271 {
1272 PDEVICE_OBJECT DeviceObject;
1273 PDEVICE_EXTENSION DeviceExt;
1274
1275 IoCreateDevice(DriverObject,
1276 sizeof(DEVICE_EXTENSION),
1277 NULL,
1278 FILE_DEVICE_FILE_SYSTEM,
1279 0,
1280 FALSE,
1281 &DeviceObject);
1282 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
1283 DeviceExt = (PVOID)DeviceObject->DeviceExtension;
1284 // use same vpb as device disk
1285 DeviceObject->Vpb=DeviceToMount->Vpb;
1286 FsdMountDevice(DeviceExt,DeviceToMount);
1287 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
1288 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
1289 DeviceToMount);
1290 return(STATUS_SUCCESS);
1291 }
1292
1293 NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1294 /*
1295 * FUNCTION: File system control
1296 */
1297 {
1298 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1299 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1300 PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
1301 NTSTATUS Status;
1302
1303 DPRINT("VFAT FSC\n");
1304
1305 if (FsdHasFileSystem(DeviceToMount))
1306 {
1307 Status = FsdMount(DeviceToMount);
1308 }
1309 else
1310 {
1311 DPRINT("VFAT: Unrecognized Volume\n");
1312 Status = STATUS_UNRECOGNIZED_VOLUME;
1313 }
1314 DPRINT("VFAT File system successfully mounted\n");
1315
1316 Irp->IoStatus.Status = Status;
1317 Irp->IoStatus.Information = 0;
1318
1319 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1320 return(Status);
1321 }
1322
1323 NTSTATUS FsdGetStandardInformation(PVfatFCB FCB, PDEVICE_OBJECT DeviceObject,
1324 PFILE_STANDARD_INFORMATION StandardInfo)
1325 /*
1326 * FUNCTION: Retrieve the standard file information
1327 */
1328 {
1329 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1330 unsigned long AllocSize;
1331
1332 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
1333
1334 /* Make allocsize a rounded up multiple of BytesPerCluster */
1335 AllocSize = ((FCB->entry.FileSize + DeviceExtension->BytesPerCluster - 1) /
1336 DeviceExtension->BytesPerCluster) *
1337 DeviceExtension->BytesPerCluster;
1338
1339 StandardInfo->AllocationSize = RtlConvertUlongToLargeInteger(AllocSize);
1340 StandardInfo->EndOfFile = RtlConvertUlongToLargeInteger(FCB->entry.FileSize);
1341 StandardInfo->NumberOfLinks = 0;
1342 StandardInfo->DeletePending = FALSE;
1343 if((FCB->entry.Attrib & 0x10)>0) {
1344 StandardInfo->Directory = TRUE;
1345 } else {
1346 StandardInfo->Directory = FALSE;
1347 }
1348
1349 return STATUS_SUCCESS;
1350 }
1351
1352 NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1353 /*
1354 * FUNCTION: Retrieve the specified file information
1355 */
1356 {
1357 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1358 FILE_INFORMATION_CLASS FileInformationClass =
1359 Stack->Parameters.QueryFile.FileInformationClass;
1360 PFILE_OBJECT FileObject = NULL;
1361 PVfatFCB FCB = NULL;
1362 // PVfatCCB CCB = NULL;
1363
1364 NTSTATUS RC = STATUS_SUCCESS;
1365 void *SystemBuffer;
1366
1367 FileObject = Stack->FileObject;
1368 // CCB = (PVfatCCB)(FileObject->FsContext2);
1369 // FCB = CCB->Buffer; // Should be CCB->FCB???
1370 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1371
1372 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1373
1374 switch(FileInformationClass) {
1375 case FileStandardInformation:
1376 RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
1377 break;
1378 default:
1379 RC=STATUS_NOT_IMPLEMENTED;
1380 }
1381
1382 return RC;
1383 }
1384
1385 NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
1386 PUNICODE_STRING RegistryPath)
1387 /*
1388 * FUNCTION: Called by the system to initalize the driver
1389 * ARGUMENTS:
1390 * DriverObject = object describing this driver
1391 * RegistryPath = path to our configuration entries
1392 * RETURNS: Success or failure
1393 */
1394 {
1395 PDEVICE_OBJECT DeviceObject;
1396 NTSTATUS ret;
1397 UNICODE_STRING ustr;
1398 ANSI_STRING astr;
1399
1400 DbgPrint("VFAT 0.0.6\n");
1401 pFirstFcb=NULL;
1402 DriverObject = _DriverObject;
1403
1404 RtlInitAnsiString(&astr,"\\Device\\VFAT");
1405 RtlAnsiStringToUnicodeString(&ustr,&astr,TRUE);
1406 ret = IoCreateDevice(DriverObject,0,&ustr,
1407 FILE_DEVICE_FILE_SYSTEM,0,FALSE,&DeviceObject);
1408 if (ret!=STATUS_SUCCESS)
1409 {
1410 return(ret);
1411 }
1412
1413 DeviceObject->Flags=0;
1414 DriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
1415 DriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
1416 DriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
1417 DriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
1418 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
1419 FsdFileSystemControl;
1420 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
1421 FsdQueryInformation;
1422 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
1423 FsdDirectoryControl;
1424
1425 DriverObject->DriverUnload = NULL;
1426
1427 IoRegisterFileSystem(DeviceObject);
1428
1429 return(STATUS_SUCCESS);
1430 }
1431