Improved scheduling code
[reactos.git] / reactos / drivers / fs / vfat / iface.c
1 /*
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)
7 * UPDATE HISTORY:
8 ?? Created
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
19
20 */
21
22 /* INCLUDES *****************************************************************/
23
24 #include <wchar.h>
25 #include <internal/string.h>
26 #include <ddk/ntddk.h>
27 #include <ddk/cctypes.h>
28
29 #define NDEBUG
30 #include <internal/debug.h>
31
32 #include "vfat.h"
33
34 //#include "dbgpool.c"
35
36 /* GLOBALS *****************************************************************/
37
38 static PDRIVER_OBJECT VFATDriverObject;
39 PVfatFCB pFirstFcb;
40
41 /* FUNCTIONS ****************************************************************/
42
43 ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
44 /*
45 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
46 * disk read
47 */
48 {
49 ULONG FATsector;
50 ULONG FATeis;
51 PULONG Block;
52
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;
61 ExFreePool(Block);
62 return(CurrentCluster);
63 }
64
65 ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
66 /*
67 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
68 * in-memory FAT
69 */
70 {
71 PUSHORT Block;
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);
78 }
79
80 ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
81 /*
82 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
83 * in-memory FAT
84 */
85 {
86 unsigned char* CBlock;
87 ULONG FATOffset;
88 ULONG Entry;
89 CBlock = DeviceExt->FAT;
90 FATOffset = (CurrentCluster * 12)/ 8;//first byte containing value
91 if ((CurrentCluster % 2) == 0)
92 {
93 Entry = CBlock[FATOffset];
94 Entry |= ((CBlock[FATOffset+1] & 0xf)<<8);
95 }
96 else
97 {
98 Entry = (CBlock[FATOffset] >> 4);
99 Entry |= (CBlock[FATOffset+1] << 4);
100 }
101 DPRINT("Entry %x\n",Entry);
102 if (Entry >= 0xff8 && Entry <= 0xfff)
103 Entry = 0xffffffff;
104 DPRINT("Returning %x\n",Entry);
105 return(Entry);
106 }
107
108 ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
109 /*
110 * FUNCTION: Retrieve the next cluster depending on the FAT type
111 */
112 {
113
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));
120 else
121 return(Fat12GetNextCluster(DeviceExt, CurrentCluster));
122 }
123
124 ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
125 /*
126 * FUNCTION: Finds the first available cluster in a FAT16 table
127 */
128 {
129 PUSHORT Block;
130 int i;
131 Block=(PUSHORT)DeviceExt->FAT;
132 for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
133 if(Block[i]==0)
134 return (i);
135 /* Give an error message (out of disk space) if we reach here) */
136 return 0;
137 }
138
139 ULONG FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
140 /*
141 * FUNCTION: Finds the first available cluster in a FAT12 table
142 */
143 {
144 ULONG FATOffset;
145 ULONG Entry;
146 PUCHAR CBlock=DeviceExt->FAT;
147 ULONG i;
148 for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
149 {
150 FATOffset = (i * 12)/8;
151 if ((i % 2) == 0)
152 {
153 Entry = CBlock[FATOffset];
154 Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
155 }
156 else
157 {
158 Entry = (CBlock[FATOffset] >> 4);
159 Entry |= (CBlock[FATOffset + 1] << 4);
160 }
161 if(Entry==0)
162 return (i);
163 }
164 /* Give an error message (out of disk space) if we reach here) */
165 DbgPrint("Disk full, %d clusters used\n",i);
166 return 0;
167 }
168
169 ULONG FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
170 /*
171 * FUNCTION: Finds the first available cluster in a FAT32 table
172 */
173 {
174 ULONG sector;
175 PULONG Block;
176 int i;
177 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
178 for(sector=0
179 ;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
180 ;sector++)
181 {
182 VFATReadSectors(DeviceExt->StorageDevice
183 ,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
184
185 for(i=0; i<512; i++)
186 {
187 if(Block[i]==0)
188 {
189 ExFreePool(Block);
190 return (i+sector*128);
191 }
192 }
193 }
194 /* Give an error message (out of disk space) if we reach here) */
195 ExFreePool(Block);
196 return 0;
197 }
198
199 ULONG FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
200 /*
201 * FUNCTION: Counts free cluster in a FAT12 table
202 */
203 {
204 ULONG FATOffset;
205 ULONG Entry;
206 PUCHAR CBlock=DeviceExt->FAT;
207 ULONG ulCount = 0;
208 ULONG i;
209
210 for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
211 {
212 FATOffset = (i * 12)/8;
213 if ((i % 2) == 0)
214 {
215 Entry = CBlock[FATOffset];
216 Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
217 }
218 else
219 {
220 Entry = (CBlock[FATOffset] >> 4);
221 Entry |= (CBlock[FATOffset + 1] << 4);
222 }
223 if(Entry==0)
224 ulCount++;
225 }
226 return ulCount;
227 }
228
229 ULONG FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
230 /*
231 * FUNCTION: Counts free clusters in a FAT16 table
232 */
233 {
234 PUSHORT Block;
235 ULONG ulCount = 0;
236 ULONG i;
237
238 Block=(PUSHORT)DeviceExt->FAT;
239 for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
240 if(Block[i]==0)
241 ulCount++;
242 return ulCount;
243 }
244
245 ULONG FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
246 /*
247 * FUNCTION: Counts free clusters in a FAT32 table
248 */
249 {
250 ULONG sector;
251 PULONG Block;
252 ULONG ulCount = 0;
253 ULONG i;
254
255 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
256 for(sector=0
257 ;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
258 ;sector++)
259 {
260 VFATReadSectors(DeviceExt->StorageDevice
261 ,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
262
263 for(i=0; i<512; i++)
264 {
265 if(Block[i]==0)
266 ulCount++;
267 }
268 }
269 /* Give an error message (out of disk space) if we reach here) */
270 ExFreePool(Block);
271 return ulCount;
272 }
273
274 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
275 ULONG NewValue)
276 /*
277 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
278 */
279 {
280 ULONG FATsector;
281 ULONG FATOffset;
282 PUCHAR CBlock=DeviceExt->FAT;
283 int i;
284 FATOffset = (ClusterToWrite * 12)/8;
285 if ((ClusterToWrite % 2) == 0)
286 {
287 CBlock[FATOffset]=NewValue;
288 CBlock[FATOffset + 1] &=0xf0;
289 CBlock[FATOffset + 1]
290 |= (NewValue&0xf00)>>8;
291 }
292 else
293 {
294 CBlock[FATOffset] &=0x0f;
295 CBlock[FATOffset]
296 |= (NewValue&0xf)<<4;
297 CBlock[FATOffset+1]=NewValue>>4;
298 }
299 /* Write the changed FAT sector(s) to disk */
300 FATsector=FATOffset/BLOCKSIZE;
301 for(i=0;i<DeviceExt->Boot->FATCount;i++)
302 {
303 if( (FATOffset%BLOCKSIZE)==(BLOCKSIZE-1))//entry is on 2 sectors
304 {
305 VFATWriteSectors(DeviceExt->StorageDevice,
306 DeviceExt->FATStart+FATsector
307 +i*DeviceExt->Boot->FATSectors,
308 2,
309 CBlock+FATsector*512);
310 }
311 else
312 {
313 VFATWriteSectors(DeviceExt->StorageDevice,
314 DeviceExt->FATStart+FATsector
315 +i*DeviceExt->Boot->FATSectors,
316 1,
317 CBlock+FATsector*512);
318 }
319 }
320 }
321
322 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
323 ULONG NewValue)
324 /*
325 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
326 */
327 {
328 ULONG FATsector;
329 PUSHORT Block;
330 DbgPrint("FAT16WriteCluster %u : %u\n",ClusterToWrite,NewValue);
331 Block=(PUSHORT)DeviceExt->FAT;
332 FATsector=ClusterToWrite/(512/sizeof(USHORT));
333
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,
339 1,
340 (UCHAR *)Block);
341 }
342
343 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
344 ULONG NewValue)
345 /*
346 * FUNCTION: Writes a cluster to the FAT32 physical tables
347 */
348 {
349 ULONG FATsector;
350 ULONG FATeis;
351 PUSHORT Block;
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,
359 1,
360 (UCHAR *)Block);
361 Block[FATeis] = NewValue;
362 VFATWriteSectors(DeviceExt->StorageDevice,
363 DeviceExt->FATStart+FATsector,
364 1,
365 (UCHAR *)Block);
366 ExFreePool(Block);
367 }
368
369 void WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
370 ULONG NewValue)
371 /*
372 * FUNCTION: Write a changed FAT entry
373 */
374 {
375 if(DeviceExt->FatType==FAT16)
376 FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
377 else if(DeviceExt->FatType==FAT32)
378 FAT32WriteCluster(DeviceExt, ClusterToWrite, NewValue);
379 else
380 FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue);
381 }
382
383 ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
384 /*
385 * FUNCTION: Determines the next cluster to be written
386 */
387 {
388 ULONG LastCluster, NewCluster;
389 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
390 DeviceExt,CurrentCluster);
391
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
397 /* Append */
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);
403 else
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
408 found AU */
409 if(CurrentCluster)
410 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
411 /* Return NewCluster as CurrentCluster */
412 return NewCluster;
413 }
414 else
415 {
416 /* Overwrite: Return LastCluster as CurrentCluster */
417 return LastCluster;
418 }
419 }
420
421 ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt,
422 unsigned long Cluster)
423 /*
424 * FUNCTION: Converts the cluster number to a sector number for this physical
425 * device
426 */
427 {
428 return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
429 }
430
431 void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
432 /*
433 * FUNCTION: Convert an ANSI string to it's Unicode equivalent
434 */
435 {
436 int i;
437
438 for (i=0; (i<Length && Source[i] != ' '); i++)
439 {
440 Dest[i] = Source[i];
441 }
442 Dest[i]=0;
443 }
444
445 void RtlCatAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length)
446 /*
447 * FUNCTION: Appends a converted ANSI to Unicode string to the end of an
448 * existing Unicode string
449 */
450 {
451 ULONG i;
452
453 while((*Dest)!=0)
454 {
455 Dest++;
456 }
457 for (i=0; (i<Length && Source[i] != ' '); i++)
458 {
459 Dest[i] = Source[i];
460 }
461 Dest[i]=0;
462 }
463
464 void vfat_initstr(wchar_t *wstr, ULONG wsize)
465 /*
466 * FUNCTION: Initialize a string for use with a long file name
467 */
468 {
469 int i;
470 wchar_t nc=0;
471 for(i=0; i<wsize; i++)
472 {
473 *wstr=nc;
474 wstr++;
475 }
476 wstr=wstr-wsize;
477 }
478
479 wchar_t * vfat_wcsncat(wchar_t * dest, const wchar_t * src,size_t wstart, size_t wcount)
480 /*
481 * FUNCTION: Append a string for use with a long file name
482 */
483 {
484 int i;
485
486 dest+=wstart;
487 for(i=0; i<wcount; i++)
488 {
489 *dest=src[i];
490 dest++;
491 }
492 dest=dest-(wcount+wstart);
493
494 return dest;
495 }
496
497 wchar_t * vfat_wcsncpy(wchar_t * dest, const wchar_t *src,size_t wcount)
498 /*
499 * FUNCTION: Copy a string for use with long file names
500 */
501 {
502 int i;
503
504 for (i=0;i<wcount;i++)
505 {
506 dest[i]=src[i];
507 if(!dest[i]) break;
508 }
509 return(dest);
510 }
511
512 wchar_t * vfat_movstr(const wchar_t *src, ULONG dpos,
513 ULONG spos, ULONG len)
514 /*
515 * FUNCTION: Move the characters in a string to a new position in the same
516 * string
517 */
518 {
519 int i;
520
521 if(dpos<=spos)
522 {
523 for(i=0; i<len; i++)
524 {
525 src[dpos++]=src[spos++];
526 }
527 }
528 else
529 {
530 dpos+=len-1;
531 spos+=len-1;
532 for(i=0; i<len; i++)
533 {
534 src[dpos--]=src[spos--];
535 }
536 }
537
538 return(src);
539 }
540
541 BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
542 /*
543 * FUNCTION: Determine if the given directory entry is the last
544 */
545 {
546 return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
547 }
548
549 BOOLEAN IsVolEntry(PVOID Block, ULONG Offset)
550 /*
551 * FUNCTION: Determine if the given directory entry is a vol entry
552 */
553 {
554 if( (((FATDirEntry *)Block)[Offset].Attrib)==0x28 ) return TRUE;
555 else return FALSE;
556 }
557
558 BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
559 /*
560 * FUNCTION: Determines if the given entry is a deleted one
561 */
562 {
563 /* Checks special character */
564
565 return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5));
566 }
567
568 BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
569 PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
570 /*
571 * FUNCTION: Retrieves the file name, be it in short or long file name format
572 */
573 {
574 FATDirEntry* test;
575 slot* test2;
576 ULONG Offset = *_Offset;
577 ULONG StartingSector = *_StartingSector;
578 ULONG jloop = *_jloop;
579 ULONG cpos;
580 WCHAR tmp[256];
581
582 test = (FATDirEntry *)Block;
583 test2 = (slot *)Block;
584
585 *Name = 0;
586
587 if (IsDeletedEntry(Block,Offset))
588 {
589 return(FALSE);
590 }
591
592 if(test2[Offset].attr == 0x0f)
593 {
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);
598
599 cpos=0;
600 while((test2[Offset].id!=0x41) && (test2[Offset].id!=0x01) &&
601 (test2[Offset].attr>0))
602 {
603 Offset++;
604 if(Offset==ENTRIES_PER_SECTOR) {
605 Offset=0;
606 StartingSector++;//FIXME : nor always the next sector
607 jloop++;
608 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
609 test2 = (slot *)Block;
610 }
611 cpos++;
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);
616
617 }
618
619 if (IsDeletedEntry(Block,Offset+1))
620 {
621 Offset++;
622 *_Offset = Offset;
623 *_jloop = jloop;
624 *_StartingSector = StartingSector;
625 return(FALSE);
626 }
627
628 *_Offset = Offset;
629 *_jloop = jloop;
630 *_StartingSector = StartingSector;
631
632 return(TRUE);
633 }
634
635 RtlAnsiToUnicode(Name,test[Offset].Filename,8);
636 if (test[Offset].Ext[0]!=' ')
637 {
638 RtlCatAnsiToUnicode(Name,".",1);
639 }
640 RtlCatAnsiToUnicode(Name,test[Offset].Ext,3);
641
642 *_Offset = Offset;
643
644 return(TRUE);
645 }
646
647 BOOLEAN wstrcmpi(PWSTR s1, PWSTR s2)
648 /*
649 * FUNCTION: Compare to wide character strings
650 * return TRUE if s1==s2
651 */
652 {
653 while (towlower(*s1)==towlower(*s2))
654 {
655 if ((*s1)==0 && (*s2)==0)
656 {
657 return(TRUE);
658 }
659
660 s1++;
661 s2++;
662 }
663 return(FALSE);
664 }
665 BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2)
666 /*
667 * FUNCTION: Compare to wide character strings, s2 with jokers (* or ?)
668 * return TRUE if s1 like s2
669 */
670 {
671 while ((*s2=='?')||(towlower(*s1)==towlower(*s2)))
672 {
673 if ((*s1)==0 && (*s2)==0)
674 return(TRUE);
675 s1++;
676 s2++;
677 }
678 if(*s2=='*')
679 {
680 s2++;
681 while (*s1)
682 if (wstrcmpjoki(s1,s2)) return TRUE;
683 else s1++;
684 }
685 if ((*s1)==0 && (*s2)==0)
686 return(TRUE);
687 return(FALSE);
688 }
689
690
691 NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
692 /*
693 * FUNCTION: Read the volume label
694 */
695 {
696 ULONG i, j;
697 ULONG Size;
698 char* block;
699 ULONG StartingSector;
700 ULONG NextCluster;
701
702 Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
703 StartingSector = DeviceExt->rootStart;
704 NextCluster=0;
705
706 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
707 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
708 for (j=0; j<Size; j++)
709 {
710 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
711
712 for (i=0; i<ENTRIES_PER_SECTOR; i++)
713 {
714 if (IsVolEntry((PVOID)block,i))
715 {
716 FATDirEntry *test = (FATDirEntry *)block;
717
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);
722
723 ExFreePool(block);
724 return(STATUS_SUCCESS);
725 }
726 if (IsLastEntry((PVOID)block,i))
727 {
728 *(Vpb->VolumeLabel) = 0;
729 Vpb->VolumeLabelLength = 0;
730 ExFreePool(block);
731 return(STATUS_UNSUCCESSFUL);
732 }
733 }
734 // not found in this sector, try next :
735
736 /* directory can be fragmented although it is best to keep them
737 unfragmented */
738 StartingSector++;
739 if (DeviceExt->FatType ==FAT32)
740 {
741 if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
742 {
743 NextCluster = GetNextCluster(DeviceExt,NextCluster);
744 if (NextCluster == 0||NextCluster==0xffffffff)
745 {
746 *(Vpb->VolumeLabel) = 0;
747 Vpb->VolumeLabelLength = 0;
748 ExFreePool(block);
749 return(STATUS_UNSUCCESSFUL);
750 }
751 StartingSector = ClusterToSector(DeviceExt,NextCluster);
752 }
753 }
754 }
755 *(Vpb->VolumeLabel) = 0;
756 Vpb->VolumeLabelLength = 0;
757 ExFreePool(block);
758 return(STATUS_UNSUCCESSFUL);
759 }
760
761
762 NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PVfatFCB Fcb,
763 PVfatFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
764 /*
765 * FUNCTION: Find a file
766 */
767 {
768 ULONG i, j;
769 ULONG Size;
770 char* block;
771 WCHAR name[256];
772 ULONG StartingSector;
773 ULONG NextCluster;
774 WCHAR TempStr[2];
775
776 DPRINT("FindFile(Parent %x, FileToFind '%w')\n",Parent,FileToFind);
777
778 if (wcslen(FileToFind)==0)
779 {
780 CHECKPOINT;
781 TempStr[0] = (WCHAR)'.';
782 TempStr[1] = 0;
783 FileToFind=&TempStr;
784 }
785 if (Parent != NULL)
786 {
787 DPRINT("Parent->entry.FirstCluster %d\n",Parent->entry.FirstCluster);
788 }
789
790 DPRINT("FindFile '%w'\n", FileToFind);
791 if (Parent == NULL||Parent->entry.FirstCluster==1)
792 {
793 CHECKPOINT;
794 Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
795 StartingSector = DeviceExt->rootStart;
796 NextCluster=0;
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
800 CHECKPOINT;
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;
807 else
808 Fcb->entry.FirstCluster=1;//FIXME : is 1 the good value for mark root?
809 if(StartSector)
810 *StartSector=StartingSector;
811 if(Entry)
812 *Entry=0;
813 return(STATUS_SUCCESS);
814 }
815 }
816 else
817 {
818 DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
819
820 Size = ULONG_MAX;
821 if (DeviceExt->FatType == FAT32)
822 NextCluster = Parent->entry.FirstCluster
823 +Parent->entry.FirstClusterHigh*65536;
824 else
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;
830 }
831 }
832 CHECKPOINT;
833 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
834 CHECKPOINT;
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++)
839 {
840 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
841
842 for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
843 {
844 if (IsVolEntry((PVOID)block,i))
845 continue;
846 if (IsLastEntry((PVOID)block,i))
847 {
848 ExFreePool(block);
849 if(StartSector) *StartSector=StartingSector;
850 if(Entry) *Entry=i;
851 return(STATUS_UNSUCCESSFUL);
852 }
853 if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
854 {
855 DPRINT("Comparing '%w' '%w'\n",name,FileToFind);
856 if (wstrcmpjoki(name,FileToFind))
857 {
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
863 StartingSector++;
864 //FIXME : treat case of next sector fragmented
865 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
866 i=0;
867 }
868 memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
869 sizeof(FATDirEntry));
870 vfat_wcsncpy(Fcb->ObjectName,name,MAX_PATH);
871 ExFreePool(block);
872 if(StartSector) *StartSector=StartingSector;
873 if(Entry) *Entry=i;
874 return(STATUS_SUCCESS);
875 }
876 }
877 }
878 // not found in this sector, try next :
879
880 /* directory can be fragmented although it is best to keep them
881 unfragmented */
882 if(Entry) *Entry=0;
883 StartingSector++;
884 if ((Parent != NULL && Parent->entry.FirstCluster!=1)
885 || DeviceExt->FatType ==FAT32)
886 {
887 if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
888 {
889 NextCluster = GetNextCluster(DeviceExt,NextCluster);
890 if (NextCluster == 0||NextCluster==0xffffffff)
891 {
892 if(StartSector) *StartSector=StartingSector;
893 if(Entry) *Entry=i;
894 ExFreePool(block);
895 return(STATUS_UNSUCCESSFUL);
896 }
897 StartingSector = ClusterToSector(DeviceExt,NextCluster);
898 }
899 }
900 }
901 ExFreePool(block);
902 if(StartSector) *StartSector=StartingSector;
903 if(Entry) *Entry=i;
904 return(STATUS_UNSUCCESSFUL);
905 }
906
907
908 NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
909 /*
910 * FUNCTION: Closes a file
911 */
912 {
913 PVfatFCB pFcb;
914 PVfatCCB pCcb;
915
916 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
917 DeviceExt,FileObject);
918
919 //FIXME : update entry in directory ?
920 pCcb = (PVfatCCB)(FileObject->FsContext2);
921
922 DPRINT("pCcb %x\n",pCcb);
923 if (pCcb == NULL)
924 {
925 return(STATUS_SUCCESS);
926 }
927
928 pFcb = pCcb->pFcb;
929
930 pFcb->RefCount--;
931 if(pFcb->RefCount<=0)
932 {
933 if(pFcb->prevFcb)
934 pFcb->prevFcb->nextFcb=pFcb->nextFcb;
935 else
936 pFirstFcb=pFcb->nextFcb;
937 if(pFcb->nextFcb)
938 pFcb->nextFcb->prevFcb=pFcb->prevFcb;
939 ExFreePool(pFcb);
940 }
941 ExFreePool(pCcb);
942 return STATUS_SUCCESS;
943 }
944
945 NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
946 PWSTR FileName)
947 /*
948 * FUNCTION: Opens a file
949 */
950 {
951 PWSTR current;
952 PWSTR next;
953 PWSTR string;
954 PVfatFCB ParentFcb;
955 PVfatFCB Fcb,pRelFcb;
956 PVfatFCB Temp;
957 PVfatCCB newCCB,pRelCcb;
958 NTSTATUS Status;
959 PFILE_OBJECT pRelFileObject;
960 PWSTR AbsFileName=NULL;
961 short i,j;
962
963 DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
964 DeviceExt,
965 FileObject,
966 FileName);
967
968 //FIXME : treat relative name
969 if(FileObject->RelatedFileObject)
970 {
971 DbgPrint("try related for %w\n",FileName);
972 pRelFileObject=FileObject->RelatedFileObject;
973 pRelCcb=pRelFileObject->FsContext2;
974 assert(pRelCcb);
975 pRelFcb=pRelCcb->pFcb;
976 assert(pRelFcb);
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]!= '\\') )
980 {
981 Status=STATUS_INVALID_PARAMETER;
982 return Status;
983 }
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];
991 assert(i<MAX_PATH);
992 AbsFileName[i]=0;
993 FileName=AbsFileName;
994 }
995 // try first to find an existing FCB in memory
996 for (Fcb=pFirstFcb;Fcb; Fcb=Fcb->nextFcb)
997 {
998 if (DeviceExt==Fcb->pDevExt
999 && wstrcmpi(FileName,Fcb->PathName))
1000 {
1001 Fcb->RefCount++;
1002 FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
1003 newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
1004 memset(newCCB,0,sizeof(VfatCCB));
1005 FileObject->FsContext2 = newCCB;
1006 newCCB->pFcb=Fcb;
1007 newCCB->PtrFileObject=FileObject;
1008 if(AbsFileName)ExFreePool(AbsFileName);
1009 return(STATUS_SUCCESS);
1010 }
1011 }
1012 string = FileName;
1013 ParentFcb = NULL;
1014 Fcb = ExAllocatePool(NonPagedPool, sizeof(VfatFCB));
1015 memset(Fcb,0,sizeof(VfatFCB));
1016 Fcb->ObjectName=Fcb->PathName;
1017 next = &string[0];
1018
1019 while (next!=NULL)
1020 {
1021 *next = '\\';
1022 current = next+1;
1023 next = wcschr(next+1,'\\');
1024 if (next!=NULL)
1025 {
1026 *next=0;
1027 }
1028 DPRINT("current '%w'\n",current);
1029 Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
1030 if (Status != STATUS_SUCCESS)
1031 {
1032 if (Fcb != NULL)
1033 ExFreePool(Fcb);
1034 if (ParentFcb != NULL)
1035 ExFreePool(ParentFcb);
1036 if(AbsFileName)
1037 ExFreePool(AbsFileName);
1038 return(Status);
1039 }
1040 Temp = Fcb;
1041 CHECKPOINT;
1042 if (ParentFcb == NULL)
1043 {
1044 Fcb = ExAllocatePool(NonPagedPool,sizeof(VfatFCB));
1045 memset(Fcb,0,sizeof(VfatFCB));
1046 Fcb->ObjectName=Fcb->PathName;
1047 }
1048 else
1049 Fcb = ParentFcb;
1050 CHECKPOINT;
1051 ParentFcb = Temp;
1052 }
1053 CHECKPOINT;
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);
1072 }
1073
1074
1075 BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
1076 /*
1077 * FUNCTION: Tests if the device contains a filesystem that can be mounted
1078 * by this fsd
1079 */
1080 {
1081 BootSector* Boot;
1082
1083 Boot = ExAllocatePool(NonPagedPool,512);
1084
1085 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
1086
1087 if (strncmp(Boot->SysType,"FAT12",5)==0 ||
1088 strncmp(Boot->SysType,"FAT16",5)==0 ||
1089 strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
1090 {
1091 ExFreePool(Boot);
1092 return(TRUE);
1093 }
1094 ExFreePool(Boot);
1095 return(FALSE);
1096 }
1097
1098 NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
1099 PDEVICE_OBJECT DeviceToMount)
1100 /*
1101 * FUNCTION: Mounts the device
1102 */
1103 {
1104 DPRINT("Mounting VFAT device...");
1105 DPRINT("DeviceExt %x\n",DeviceExt);
1106
1107 DeviceExt->Boot = ExAllocatePool(NonPagedPool,512);
1108 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)DeviceExt->Boot);
1109
1110 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
1111 DeviceExt->Boot->BytesPerSector);
1112
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;
1122
1123 if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
1124 {
1125 DeviceExt->FatType = FAT12;
1126 }
1127 else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
1128 {
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;
1135 }
1136 else
1137 {
1138 DeviceExt->FatType = FAT16;
1139 }
1140
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)
1144 {
1145 DeviceExt->FAT = ExAllocatePool(NonPagedPool, BLOCKSIZE*DeviceExt->Boot->FATSectors);
1146 VFATReadSectors(DeviceToMount, DeviceExt->FATStart, DeviceExt->Boot->FATSectors, (UCHAR *)DeviceExt->FAT);
1147 }
1148 return STATUS_SUCCESS;
1149 }
1150
1151 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
1152 /*
1153 * FUNCTION: Load a cluster from the physical device
1154 */
1155 {
1156 ULONG Sector;
1157
1158 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1159 DeviceExt,Buffer,Cluster);
1160
1161 Sector = ClusterToSector(DeviceExt, Cluster);
1162
1163 VFATReadSectors(DeviceExt->StorageDevice,
1164 Sector,
1165 DeviceExt->Boot->SectorsPerCluster,
1166 Buffer);
1167 DPRINT("Finished VFATReadSectors\n");
1168 }
1169
1170 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
1171 /*
1172 * FUNCTION: Write a cluster to the physical device
1173 */
1174 {
1175 ULONG Sector;
1176 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1177 DeviceExt,Buffer,Cluster);
1178
1179 Sector = ClusterToSector(DeviceExt, Cluster);
1180
1181 VFATWriteSectors(DeviceExt->StorageDevice,
1182 Sector,
1183 DeviceExt->Boot->SectorsPerCluster,
1184 Buffer);
1185 }
1186
1187 NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1188 PVOID Buffer, ULONG Length, ULONG ReadOffset,
1189 PULONG LengthRead)
1190 /*
1191 * FUNCTION: Reads data from a file
1192 */
1193 {
1194 ULONG CurrentCluster;
1195 ULONG FileOffset;
1196 ULONG FirstCluster;
1197 PVfatFCB Fcb;
1198 PVOID Temp;
1199 ULONG TempLength;
1200
1201 /* PRECONDITION */
1202 assert(DeviceExt != NULL);
1203 assert(DeviceExt->BytesPerCluster != 0);
1204 assert(FileObject != NULL);
1205 assert(FileObject->FsContext != NULL);
1206
1207 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1208 "Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
1209 Length,ReadOffset);
1210
1211 Fcb = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1212 if (DeviceExt->FatType == FAT32)
1213 CurrentCluster = Fcb->entry.FirstCluster
1214 +Fcb->entry.FirstClusterHigh*65536;
1215 else
1216 CurrentCluster = Fcb->entry.FirstCluster;
1217 FirstCluster=CurrentCluster;
1218 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
1219
1220 if (ReadOffset >= Fcb->entry.FileSize
1221 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1222 {
1223 return(STATUS_END_OF_FILE);
1224 }
1225 if ((ReadOffset + Length) > Fcb->entry.FileSize
1226 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1227 {
1228 Length = Fcb->entry.FileSize - ReadOffset;
1229 }
1230 *LengthRead = 0;
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;
1238 }
1239 else
1240 for (FileOffset=0; FileOffset < ReadOffset / DeviceExt->BytesPerCluster
1241 ; FileOffset++)
1242 {
1243 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1244 }
1245 CHECKPOINT;
1246 if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
1247 {
1248 if (FirstCluster==1)
1249 {
1250 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1251 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1252 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1253 }
1254 else
1255 {
1256 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1257 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1258 }
1259 TempLength = min(Length,DeviceExt->BytesPerCluster -
1260 (ReadOffset % DeviceExt->BytesPerCluster));
1261
1262 memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
1263 TempLength);
1264
1265 (*LengthRead) = (*LengthRead) + TempLength;
1266 Length = Length - TempLength;
1267 Buffer = Buffer + TempLength;
1268 }
1269 CHECKPOINT;
1270 while (Length >= DeviceExt->BytesPerCluster)
1271 {
1272 if (FirstCluster==1)
1273 {
1274 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1275 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1276 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1277 }
1278 else
1279 {
1280 VFATLoadCluster(DeviceExt,Buffer,CurrentCluster);
1281 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1282 }
1283 if (CurrentCluster == 0xffffffff)
1284 {
1285 ExFreePool(Temp);
1286 return(STATUS_SUCCESS);
1287 }
1288
1289 (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
1290 Buffer = Buffer + DeviceExt->BytesPerCluster;
1291 Length = Length - DeviceExt->BytesPerCluster;
1292 }
1293 CHECKPOINT;
1294 if (Length > 0)
1295 {
1296 (*LengthRead) = (*LengthRead) + Length;
1297 if (FirstCluster==1)
1298 {
1299 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1300 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1301 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1302 }
1303 else
1304 {
1305 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1306 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1307 }
1308 memcpy(Buffer, Temp, Length);
1309 }
1310 ExFreePool(Temp);
1311 return(STATUS_SUCCESS);
1312 }
1313
1314 NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1315 PVOID Buffer, ULONG Length, ULONG WriteOffset)
1316 /*
1317 * FUNCTION: Writes data to file
1318 */
1319 {
1320 ULONG CurrentCluster;
1321 ULONG FileOffset;
1322 ULONG FirstCluster;
1323 PVfatFCB Fcb;
1324 PVfatCCB pCcb;
1325 PVOID Temp;
1326 ULONG TempLength,Length2=Length;
1327
1328 /* Locate the first cluster of the file */
1329 assert(FileObject);
1330 pCcb=(PVfatCCB)(FileObject->FsContext2);
1331 assert(pCcb);
1332 Fcb = pCcb->pFcb;
1333 assert(Fcb);
1334 if (DeviceExt->FatType == FAT32)
1335 CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
1336 else
1337 CurrentCluster = Fcb->entry.FirstCluster;
1338 FirstCluster=CurrentCluster;
1339 /* Allocate a buffer to hold 1 cluster of data */
1340
1341 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1342 assert(Temp);
1343
1344 /* Find the cluster according to the offset in the file */
1345
1346 if (CurrentCluster==1)
1347 { //root of FAT16 or FAT12
1348 CurrentCluster=DeviceExt->rootStart+WriteOffset
1349 /DeviceExt->BytesPerCluster*DeviceExt->Boot->SectorsPerCluster;
1350 }
1351 else
1352 if (CurrentCluster==0)
1353 {// file of size 0 : allocate first cluster
1354 CurrentCluster=GetNextWriteCluster(DeviceExt,0);
1355 if (DeviceExt->FatType == FAT32)
1356 {
1357 Fcb->entry.FirstClusterHigh=CurrentCluster>>16;
1358 Fcb->entry.FirstCluster=CurrentCluster;
1359 }
1360 else
1361 Fcb->entry.FirstCluster=CurrentCluster;
1362 }
1363 else
1364 for (FileOffset=0; FileOffset < WriteOffset / DeviceExt->BytesPerCluster; FileOffset++)
1365 {
1366 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1367 }
1368 CHECKPOINT;
1369
1370 /*
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
1373 */
1374
1375 if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
1376 {
1377 CHECKPOINT;
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);
1384 else
1385 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1386
1387 /* Overwrite the last parts of the data as necessary */
1388 memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster), Buffer,
1389 TempLength);
1390
1391 /* Write the cluster back */
1392 if (FirstCluster==1)
1393 {
1394 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1395 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1396 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1397 }
1398 else
1399 {
1400 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1401 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1402 }
1403 Length2 -= TempLength;
1404 Buffer = Buffer + TempLength;
1405 }
1406 CHECKPOINT;
1407
1408 /* Write the buffer in chunks of 1 cluster */
1409
1410 while (Length2 >= DeviceExt->BytesPerCluster)
1411 {
1412 CHECKPOINT;
1413 if (CurrentCluster == 0)
1414 {
1415 ExFreePool(Temp);
1416 return(STATUS_UNSUCCESSFUL);
1417 }
1418 if (FirstCluster==1)
1419 {
1420 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1421 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1422 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1423 }
1424 else
1425 {
1426 VFATWriteCluster(DeviceExt,Buffer,CurrentCluster);
1427 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1428 }
1429 Buffer = Buffer + DeviceExt->BytesPerCluster;
1430 Length2 -= DeviceExt->BytesPerCluster;
1431 }
1432 CHECKPOINT;
1433
1434 /* Write the remainder */
1435
1436 if (Length2 > 0)
1437 {
1438 CHECKPOINT;
1439 if (CurrentCluster == 0)
1440 {
1441 ExFreePool(Temp);
1442 return(STATUS_UNSUCCESSFUL);
1443 }
1444 CHECKPOINT;
1445 /* Read in the existing cluster data */
1446 if (FirstCluster==1)
1447 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1448 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1449 else
1450 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1451 CHECKPOINT;
1452 memcpy(Temp, Buffer, Length2);
1453 CHECKPOINT;
1454 if (FirstCluster==1)
1455 {
1456 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1457 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1458 }
1459 else
1460 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1461 }
1462 CHECKPOINT;
1463 //FIXME : set last write time and date
1464 if(Fcb->entry.FileSize<WriteOffset+Length
1465 && !(Fcb->entry.Attrib &FILE_ATTRIBUTE_DIRECTORY))
1466 {
1467 Fcb->entry.FileSize=WriteOffset+Length;
1468 // update entry in directory
1469 updEntry(DeviceExt,FileObject);
1470 }
1471 ExFreePool(Temp);
1472 return(STATUS_SUCCESS);
1473 }
1474
1475 NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1476 /*
1477 * FUNCTION: Close a file
1478 */
1479 {
1480 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1481 PFILE_OBJECT FileObject = Stack->FileObject;
1482 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1483 NTSTATUS Status;
1484
1485 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject, Irp);
1486
1487 Status = FsdCloseFile(DeviceExtension,FileObject);
1488
1489 Irp->IoStatus.Status = Status;
1490 Irp->IoStatus.Information = 0;
1491
1492 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1493 return(Status);
1494 }
1495
1496
1497 NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1498 /*
1499 * FUNCTION: Create or open a file
1500 */
1501 {
1502 PIO_STACK_LOCATION Stack;
1503 PFILE_OBJECT FileObject;
1504 NTSTATUS Status=STATUS_SUCCESS;
1505 PDEVICE_EXTENSION DeviceExt;
1506 ULONG RequestedDisposition,RequestedOptions;
1507 PVfatCCB pCcb;
1508 PVfatFCB pFcb;
1509
1510 assert(DeviceObject);
1511 assert(Irp);
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);
1518 return(Status);
1519 }
1520 Stack = IoGetCurrentIrpStackLocation(Irp);
1521 assert(Stack);
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;
1526 assert(DeviceExt);
1527 ExAcquireResourceExclusiveLite(&(DeviceExt->Resource),TRUE);
1528 Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
1529 CHECKPOINT;
1530 Irp->IoStatus.Information = 0;
1531 if(!NT_SUCCESS(Status))
1532 {
1533 if(RequestedDisposition==FILE_CREATE
1534 ||RequestedDisposition==FILE_OPEN_IF
1535 ||RequestedDisposition==FILE_OVERWRITE_IF)
1536 {
1537 CHECKPOINT;
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);
1547 }
1548 }
1549 else
1550 {
1551 if(RequestedDisposition==FILE_CREATE)
1552 {
1553 Irp->IoStatus.Information = FILE_EXISTS;
1554 Status=STATUS_OBJECT_NAME_COLLISION;
1555 }
1556 pCcb=FileObject->FsContext2;
1557 pFcb=pCcb->pFcb;
1558 if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
1559 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1560 {
1561 Status=STATUS_FILE_IS_A_DIRECTORY;
1562 }
1563 if( (RequestedOptions&FILE_DIRECTORY_FILE)
1564 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1565 {
1566 Status=STATUS_NOT_A_DIRECTORY;
1567 }
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
1574 }
1575 CHECKPOINT;
1576 Irp->IoStatus.Status = Status;
1577
1578 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1579 ExReleaseResourceForThreadLite(&(DeviceExt->Resource),ExGetCurrentResourceThread());
1580 return Status;
1581 }
1582
1583
1584 NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1585 /*
1586 * FUNCTION: Write to a file
1587 */
1588 {
1589 ULONG Length;
1590 PVOID Buffer;
1591 ULONG Offset;
1592 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1593 PFILE_OBJECT FileObject = Stack->FileObject;
1594 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1595 NTSTATUS Status;
1596
1597 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
1598
1599 Length = Stack->Parameters.Write.Length;
1600 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1601 Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
1602
1603 Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
1604
1605 Irp->IoStatus.Status = Status;
1606 Irp->IoStatus.Information = Length;
1607 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1608
1609 return(Status);
1610 }
1611
1612 NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1613 /*
1614 * FUNCTION: Read from a file
1615 */
1616 {
1617 ULONG Length;
1618 PVOID Buffer;
1619 ULONG Offset;
1620 PIO_STACK_LOCATION Stack;
1621 PFILE_OBJECT FileObject;
1622 PDEVICE_EXTENSION DeviceExt;
1623 NTSTATUS Status;
1624 ULONG LengthRead;
1625
1626 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
1627
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);
1636
1637 Length = Stack->Parameters.Read.Length;
1638 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1639 Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
1640
1641 Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
1642 &LengthRead);
1643
1644 Irp->IoStatus.Status = Status;
1645 Irp->IoStatus.Information = LengthRead;
1646 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1647
1648 return(Status);
1649 }
1650
1651
1652 NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
1653 /*
1654 * FUNCTION: Mount the filesystem
1655 */
1656 {
1657 PDEVICE_OBJECT DeviceObject;
1658 PDEVICE_EXTENSION DeviceExt;
1659
1660 IoCreateDevice(VFATDriverObject,
1661 sizeof(DEVICE_EXTENSION),
1662 NULL,
1663 FILE_DEVICE_FILE_SYSTEM,
1664 0,
1665 FALSE,
1666 &DeviceObject);
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,
1674 DeviceToMount);
1675
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;
1683
1684 /* read volume label */
1685 ReadVolumeLabel (DeviceExt, DeviceObject->Vpb);
1686
1687 return(STATUS_SUCCESS);
1688 }
1689
1690 NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1691 /*
1692 * FUNCTION: File system control
1693 */
1694 {
1695 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1696 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1697 PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
1698 NTSTATUS Status;
1699
1700 // DPRINT("VFAT FSC\n");
1701 DbgPrint("VFAT FSC\n");
1702
1703 /* FIXME: should make sure that this is actually a mount request! */
1704
1705 if (FsdHasFileSystem(DeviceToMount))
1706 {
1707 Status = FsdMount(DeviceToMount);
1708 }
1709 else
1710 {
1711 DPRINT("VFAT: Unrecognized Volume\n");
1712 Status = STATUS_UNRECOGNIZED_VOLUME;
1713 }
1714 DPRINT("VFAT File system successfully mounted\n");
1715
1716 Irp->IoStatus.Status = Status;
1717 Irp->IoStatus.Information = 0;
1718
1719 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1720 return(Status);
1721 }
1722
1723 NTSTATUS FsdGetStandardInformation(PVfatFCB FCB, PDEVICE_OBJECT DeviceObject,
1724 PFILE_STANDARD_INFORMATION StandardInfo)
1725 /*
1726 * FUNCTION: Retrieve the standard file information
1727 */
1728 {
1729 PDEVICE_EXTENSION DeviceExtension;
1730 unsigned long AllocSize;
1731
1732 DeviceExtension = DeviceObject->DeviceExtension;
1733 /* PRECONDITION */
1734 assert(DeviceExtension != NULL);
1735 assert(DeviceExtension->BytesPerCluster != 0);
1736 assert(StandardInfo != NULL);
1737 assert(FCB != NULL);
1738
1739 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
1740
1741 /* Make allocsize a rounded up multiple of BytesPerCluster */
1742 AllocSize = ((FCB->entry.FileSize + DeviceExtension->BytesPerCluster - 1) /
1743 DeviceExtension->BytesPerCluster) *
1744 DeviceExtension->BytesPerCluster;
1745
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;
1752 } else {
1753 StandardInfo->Directory = FALSE;
1754 }
1755
1756 return STATUS_SUCCESS;
1757 }
1758
1759 NTSTATUS FsdSetPositionInformation(PFILE_OBJECT FileObject,
1760 PVfatFCB FCB,
1761 PDEVICE_OBJECT DeviceObject,
1762 PFILE_POSITION_INFORMATION PositionInfo)
1763 {
1764 DPRINT("FsdSetPositionInformation()\n");
1765
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));
1770
1771 return(STATUS_SUCCESS);
1772 }
1773
1774 NTSTATUS FsdGetPositionInformation(PFILE_OBJECT FileObject,
1775 PVfatFCB FCB,
1776 PDEVICE_OBJECT DeviceObject,
1777 PFILE_POSITION_INFORMATION PositionInfo)
1778 {
1779 DPRINT("FsdGetPositionInformation()\n");
1780
1781 memcpy(&PositionInfo->CurrentByteOffset, &FileObject->CurrentByteOffset,
1782 sizeof(LARGE_INTEGER));
1783 DPRINT("Getting position %x\n", PositionInfo->CurrentByteOffset.u.LowPart);
1784 return(STATUS_SUCCESS);
1785 }
1786
1787 NTSTATUS FsdGetBasicInformation(PFILE_OBJECT FileObject,
1788 PVfatFCB FCB,
1789 PDEVICE_OBJECT DeviceObject,
1790 PFILE_BASIC_INFORMATION BasicInfo)
1791 {
1792 DPRINT("FsdGetBasicInformation()\n");
1793
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);
1802
1803 BasicInfo->FileAttributes = FCB->entry.Attrib;
1804
1805 DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
1806
1807 return(STATUS_SUCCESS);
1808 }
1809
1810
1811 NTSTATUS FsdSetDispositionInformation(PFILE_OBJECT FileObject,
1812 PVfatFCB FCB,
1813 PDEVICE_OBJECT DeviceObject,
1814 PFILE_DISPOSITION_INFORMATION DispositionInfo)
1815 {
1816 DPRINT("FsdSetDispositionInformation()\n");
1817
1818 FileObject->DeletePending = DispositionInfo->DeleteFile;
1819
1820 return(STATUS_SUCCESS);
1821 }
1822
1823
1824 NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1825 /*
1826 * FUNCTION: Retrieve the specified file information
1827 */
1828 {
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;
1835
1836 NTSTATUS RC = STATUS_SUCCESS;
1837 void *SystemBuffer;
1838
1839 /* PRECONDITION */
1840 assert(DeviceObject != NULL);
1841 assert(Irp != NULL);
1842
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;
1850
1851 // FIXME : determine Buffer for result :
1852 if (Irp->MdlAddress)
1853 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1854 else
1855 SystemBuffer = Irp->UserBuffer;
1856 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1857
1858 switch(FileInformationClass) {
1859 case FileStandardInformation:
1860 RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
1861 break;
1862 case FilePositionInformation:
1863 RC = FsdGetPositionInformation(FileObject,
1864 FCB,
1865 DeviceObject,
1866 SystemBuffer);
1867 break;
1868 case FileBasicInformation:
1869 RC = FsdGetBasicInformation(FileObject,
1870 FCB,
1871 DeviceObject,
1872 SystemBuffer);
1873 break;
1874 default:
1875 RC=STATUS_NOT_IMPLEMENTED;
1876 }
1877
1878 Irp->IoStatus.Status = RC;
1879 Irp->IoStatus.Information = 0;
1880 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1881
1882 return RC;
1883 }
1884
1885 NTSTATUS FsdSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1886 /*
1887 * FUNCTION: Retrieve the specified file information
1888 */
1889 {
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;
1896 PVOID SystemBuffer;
1897
1898 /* PRECONDITION */
1899 assert(DeviceObject != NULL);
1900 assert(Irp != NULL);
1901
1902 DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
1903 DeviceObject,Irp);
1904
1905 /* INITIALIZATION */
1906 Stack = IoGetCurrentIrpStackLocation(Irp);
1907 FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
1908 FileObject = Stack->FileObject;
1909 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1910
1911 // FIXME : determine Buffer for result :
1912 if (Irp->MdlAddress)
1913 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1914 else
1915 SystemBuffer = Irp->UserBuffer;
1916 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1917
1918 DPRINT("FileInformationClass %d\n",FileInformationClass);
1919 DPRINT("SystemBuffer %x\n",SystemBuffer);
1920
1921 switch(FileInformationClass)
1922 {
1923 case FilePositionInformation:
1924 RC = FsdSetPositionInformation(FileObject,
1925 FCB,
1926 DeviceObject,
1927 SystemBuffer);
1928 break;
1929 case FileDispositionInformation:
1930 RC = FsdSetDispositionInformation(FileObject,
1931 FCB,
1932 DeviceObject,
1933 SystemBuffer);
1934 break;
1935 default:
1936 RC = STATUS_NOT_IMPLEMENTED;
1937 }
1938
1939 Irp->IoStatus.Status = RC;
1940 Irp->IoStatus.Information = 0;
1941 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1942
1943 return RC;
1944 }
1945
1946
1947
1948 NTSTATUS FsdGetFsVolumeInformation(PFILE_OBJECT FileObject,
1949 PVfatFCB FCB,
1950 PDEVICE_OBJECT DeviceObject,
1951 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo)
1952 {
1953 DPRINT("FsdGetFsVolumeInformation()\n");
1954 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
1955
1956 if (!FsVolumeInfo)
1957 return(STATUS_SUCCESS);
1958
1959
1960 /* valid entries */
1961 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
1962 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
1963 wcscpy (FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel);
1964
1965 /* dummy entries */
1966 FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
1967 FsVolumeInfo->SupportsObjects = FALSE;
1968
1969 DPRINT("Finished FsdGetFsVolumeInformation()\n");
1970
1971 return(STATUS_SUCCESS);
1972 }
1973
1974
1975 NTSTATUS FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo)
1976 {
1977 DPRINT("FsdGetFsAttributeInformation()\n");
1978 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
1979
1980 if (!FsAttributeInfo)
1981 return(STATUS_SUCCESS);
1982
1983 FsAttributeInfo->FileSystemAttributes = FS_CASE_IS_PRESERVED;
1984 FsAttributeInfo->MaximumComponentNameLength = 255;
1985 FsAttributeInfo->FileSystemNameLength = 3;
1986 wcscpy (FsAttributeInfo->FileSystemName, L"FAT");
1987
1988 DPRINT("Finished FsdGetFsAttributeInformation()\n");
1989
1990 return(STATUS_SUCCESS);
1991 }
1992
1993 NTSTATUS FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
1994 PFILE_FS_SIZE_INFORMATION FsSizeInfo)
1995 {
1996 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1997
1998 DPRINT("FsdGetFsSizeInformation()\n");
1999 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
2000
2001 if (!FsSizeInfo)
2002 return(STATUS_SUCCESS);
2003
2004 if (DeviceExt->FatType == FAT32)
2005 {
2006 struct _BootSector32 *BootSect = (struct _BootSector32 *)DeviceExt->Boot;
2007
2008 if (BootSect->Sectors)
2009 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
2010 else
2011 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
2012
2013 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2014 FAT32CountAvailableClusters(DeviceExt);
2015
2016 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
2017 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
2018 }
2019 else
2020 {
2021 struct _BootSector *BootSect = (struct _BootSector *)DeviceExt->Boot;
2022
2023 if (BootSect->Sectors)
2024 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
2025 else
2026 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
2027
2028 if (DeviceExt->FatType == FAT16)
2029 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2030 FAT16CountAvailableClusters(DeviceExt);
2031 else
2032 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2033 FAT12CountAvailableClusters(DeviceExt);
2034
2035 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
2036 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
2037 }
2038
2039 DPRINT("Finished FsdGetFsSizeInformation()\n");
2040
2041 return(STATUS_SUCCESS);
2042 }
2043
2044
2045 NTSTATUS FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
2046 /*
2047 * FUNCTION: Retrieve the specified file information
2048 */
2049 {
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;
2056
2057 NTSTATUS RC = STATUS_SUCCESS;
2058 void *SystemBuffer;
2059
2060 /* PRECONDITION */
2061 assert(DeviceObject != NULL);
2062 assert(Irp != NULL);
2063
2064 DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
2065 DeviceObject,Irp);
2066
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;
2074
2075 // FIXME : determine Buffer for result :
2076 if (Irp->MdlAddress)
2077 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2078 else
2079 SystemBuffer = Irp->UserBuffer;
2080 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
2081
2082 DPRINT("FileInformationClass %d\n",FileInformationClass);
2083 DPRINT("SystemBuffer %x\n",SystemBuffer);
2084
2085 switch (FileInformationClass)
2086 {
2087 case FileFsVolumeInformation:
2088 RC = FsdGetFsVolumeInformation(FileObject,
2089 FCB,
2090 DeviceObject,
2091 SystemBuffer);
2092 break;
2093
2094 case FileFsAttributeInformation:
2095 RC = FsdGetFsAttributeInformation(SystemBuffer);
2096 break;
2097
2098 case FileFsSizeInformation:
2099 RC = FsdGetFsSizeInformation(DeviceObject, SystemBuffer);
2100 break;
2101
2102 default:
2103 RC=STATUS_NOT_IMPLEMENTED;
2104 }
2105
2106 Irp->IoStatus.Status = RC;
2107 Irp->IoStatus.Information = 0;
2108 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2109
2110 return RC;
2111 }
2112
2113
2114 NTSTATUS STDCALL
2115 DriverEntry(PDRIVER_OBJECT _DriverObject, PUNICODE_STRING RegistryPath)
2116 /*
2117 * FUNCTION: Called by the system to initalize the driver
2118 * ARGUMENTS:
2119 * DriverObject = object describing this driver
2120 * RegistryPath = path to our configuration entries
2121 * RETURNS: Success or failure
2122 */
2123 {
2124 PDEVICE_OBJECT DeviceObject;
2125 NTSTATUS ret;
2126 UNICODE_STRING ustr;
2127 ANSI_STRING astr;
2128
2129 DbgPrint("VFAT 0.0.6\n");
2130 pFirstFcb=NULL;
2131 VFATDriverObject = _DriverObject;
2132
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)
2138 {
2139 return(ret);
2140 }
2141
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] =
2152 FsdSetInformation;
2153 VFATDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
2154 FsdDirectoryControl;
2155 VFATDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
2156 FsdQueryVolumeInformation;
2157
2158 VFATDriverObject->DriverUnload = NULL;
2159
2160 IoRegisterFileSystem(DeviceObject);
2161
2162 return(STATUS_SUCCESS);
2163 }
2164