595cc18599370188a745e5f53de800c3dfe8ada8
[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 (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
1221 {
1222 return(STATUS_FILE_IS_A_DIRECTORY);
1223 }
1224
1225 if (ReadOffset >= Fcb->entry.FileSize
1226 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1227 {
1228 return(STATUS_END_OF_FILE);
1229 }
1230 if ((ReadOffset + Length) > Fcb->entry.FileSize
1231 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1232 {
1233 Length = Fcb->entry.FileSize - ReadOffset;
1234 }
1235 *LengthRead = 0;
1236 /* FIXME: optimize by remembering the last cluster read and using if possible */
1237 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1238 if(!Temp) return STATUS_UNSUCCESSFUL;
1239 if (FirstCluster==1)
1240 { //root of FAT16 or FAT12
1241 CurrentCluster=DeviceExt->rootStart+ReadOffset
1242 /(DeviceExt->BytesPerCluster)*DeviceExt->Boot->SectorsPerCluster;
1243 }
1244 else
1245 for (FileOffset=0; FileOffset < ReadOffset / DeviceExt->BytesPerCluster
1246 ; FileOffset++)
1247 {
1248 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1249 }
1250 CHECKPOINT;
1251 if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
1252 {
1253 if (FirstCluster==1)
1254 {
1255 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1256 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1257 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1258 }
1259 else
1260 {
1261 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1262 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1263 }
1264 TempLength = min(Length,DeviceExt->BytesPerCluster -
1265 (ReadOffset % DeviceExt->BytesPerCluster));
1266
1267 memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
1268 TempLength);
1269
1270 (*LengthRead) = (*LengthRead) + TempLength;
1271 Length = Length - TempLength;
1272 Buffer = Buffer + TempLength;
1273 }
1274 CHECKPOINT;
1275 while (Length >= DeviceExt->BytesPerCluster)
1276 {
1277 if (FirstCluster==1)
1278 {
1279 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1280 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1281 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1282 }
1283 else
1284 {
1285 VFATLoadCluster(DeviceExt,Buffer,CurrentCluster);
1286 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1287 }
1288 if (CurrentCluster == 0xffffffff)
1289 {
1290 ExFreePool(Temp);
1291 return(STATUS_SUCCESS);
1292 }
1293
1294 (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
1295 Buffer = Buffer + DeviceExt->BytesPerCluster;
1296 Length = Length - DeviceExt->BytesPerCluster;
1297 }
1298 CHECKPOINT;
1299 if (Length > 0)
1300 {
1301 (*LengthRead) = (*LengthRead) + Length;
1302 if (FirstCluster==1)
1303 {
1304 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1305 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1306 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1307 }
1308 else
1309 {
1310 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1311 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1312 }
1313 memcpy(Buffer, Temp, Length);
1314 }
1315 ExFreePool(Temp);
1316 return(STATUS_SUCCESS);
1317 }
1318
1319 NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1320 PVOID Buffer, ULONG Length, ULONG WriteOffset)
1321 /*
1322 * FUNCTION: Writes data to file
1323 */
1324 {
1325 ULONG CurrentCluster;
1326 ULONG FileOffset;
1327 ULONG FirstCluster;
1328 PVfatFCB Fcb;
1329 PVfatCCB pCcb;
1330 PVOID Temp;
1331 ULONG TempLength,Length2=Length;
1332
1333 /* Locate the first cluster of the file */
1334 assert(FileObject);
1335 pCcb=(PVfatCCB)(FileObject->FsContext2);
1336 assert(pCcb);
1337 Fcb = pCcb->pFcb;
1338 assert(Fcb);
1339 if (DeviceExt->FatType == FAT32)
1340 CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
1341 else
1342 CurrentCluster = Fcb->entry.FirstCluster;
1343 FirstCluster=CurrentCluster;
1344 /* Allocate a buffer to hold 1 cluster of data */
1345
1346 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1347 assert(Temp);
1348
1349 /* Find the cluster according to the offset in the file */
1350
1351 if (CurrentCluster==1)
1352 { //root of FAT16 or FAT12
1353 CurrentCluster=DeviceExt->rootStart+WriteOffset
1354 /DeviceExt->BytesPerCluster*DeviceExt->Boot->SectorsPerCluster;
1355 }
1356 else
1357 if (CurrentCluster==0)
1358 {// file of size 0 : allocate first cluster
1359 CurrentCluster=GetNextWriteCluster(DeviceExt,0);
1360 if (DeviceExt->FatType == FAT32)
1361 {
1362 Fcb->entry.FirstClusterHigh=CurrentCluster>>16;
1363 Fcb->entry.FirstCluster=CurrentCluster;
1364 }
1365 else
1366 Fcb->entry.FirstCluster=CurrentCluster;
1367 }
1368 else
1369 for (FileOffset=0; FileOffset < WriteOffset / DeviceExt->BytesPerCluster; FileOffset++)
1370 {
1371 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1372 }
1373 CHECKPOINT;
1374
1375 /*
1376 If the offset in the cluster doesn't fall on the cluster boundary then
1377 we have to write only from the specified offset
1378 */
1379
1380 if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
1381 {
1382 CHECKPOINT;
1383 TempLength = min(Length,DeviceExt->BytesPerCluster -
1384 (WriteOffset % DeviceExt->BytesPerCluster));
1385 /* Read in the existing cluster data */
1386 if (FirstCluster==1)
1387 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1388 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1389 else
1390 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1391
1392 /* Overwrite the last parts of the data as necessary */
1393 memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster), Buffer,
1394 TempLength);
1395
1396 /* Write the cluster back */
1397 if (FirstCluster==1)
1398 {
1399 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1400 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1401 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1402 }
1403 else
1404 {
1405 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1406 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1407 }
1408 Length2 -= TempLength;
1409 Buffer = Buffer + TempLength;
1410 }
1411 CHECKPOINT;
1412
1413 /* Write the buffer in chunks of 1 cluster */
1414
1415 while (Length2 >= DeviceExt->BytesPerCluster)
1416 {
1417 CHECKPOINT;
1418 if (CurrentCluster == 0)
1419 {
1420 ExFreePool(Temp);
1421 return(STATUS_UNSUCCESSFUL);
1422 }
1423 if (FirstCluster==1)
1424 {
1425 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1426 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1427 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1428 }
1429 else
1430 {
1431 VFATWriteCluster(DeviceExt,Buffer,CurrentCluster);
1432 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1433 }
1434 Buffer = Buffer + DeviceExt->BytesPerCluster;
1435 Length2 -= DeviceExt->BytesPerCluster;
1436 }
1437 CHECKPOINT;
1438
1439 /* Write the remainder */
1440
1441 if (Length2 > 0)
1442 {
1443 CHECKPOINT;
1444 if (CurrentCluster == 0)
1445 {
1446 ExFreePool(Temp);
1447 return(STATUS_UNSUCCESSFUL);
1448 }
1449 CHECKPOINT;
1450 /* Read in the existing cluster data */
1451 if (FirstCluster==1)
1452 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1453 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1454 else
1455 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1456 CHECKPOINT;
1457 memcpy(Temp, Buffer, Length2);
1458 CHECKPOINT;
1459 if (FirstCluster==1)
1460 {
1461 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1462 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1463 }
1464 else
1465 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1466 }
1467 CHECKPOINT;
1468 //FIXME : set last write time and date
1469 if(Fcb->entry.FileSize<WriteOffset+Length
1470 && !(Fcb->entry.Attrib &FILE_ATTRIBUTE_DIRECTORY))
1471 {
1472 Fcb->entry.FileSize=WriteOffset+Length;
1473 // update entry in directory
1474 updEntry(DeviceExt,FileObject);
1475 }
1476 ExFreePool(Temp);
1477 return(STATUS_SUCCESS);
1478 }
1479
1480 NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1481 /*
1482 * FUNCTION: Close a file
1483 */
1484 {
1485 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1486 PFILE_OBJECT FileObject = Stack->FileObject;
1487 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1488 NTSTATUS Status;
1489
1490 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject, Irp);
1491
1492 Status = FsdCloseFile(DeviceExtension,FileObject);
1493
1494 Irp->IoStatus.Status = Status;
1495 Irp->IoStatus.Information = 0;
1496
1497 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1498 return(Status);
1499 }
1500
1501
1502 NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1503 /*
1504 * FUNCTION: Create or open a file
1505 */
1506 {
1507 PIO_STACK_LOCATION Stack;
1508 PFILE_OBJECT FileObject;
1509 NTSTATUS Status=STATUS_SUCCESS;
1510 PDEVICE_EXTENSION DeviceExt;
1511 ULONG RequestedDisposition,RequestedOptions;
1512 PVfatCCB pCcb;
1513 PVfatFCB pFcb;
1514
1515 assert(DeviceObject);
1516 assert(Irp);
1517 if(DeviceObject->Size==sizeof(DEVICE_OBJECT))
1518 {// DevieObject represent FileSystem instead of logical volume
1519 DbgPrint("FsdCreate called with file system\n");
1520 Irp->IoStatus.Status=Status;
1521 Irp->IoStatus.Information=FILE_OPENED;
1522 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1523 return(Status);
1524 }
1525 Stack = IoGetCurrentIrpStackLocation(Irp);
1526 assert(Stack);
1527 RequestedDisposition = ((Stack->Parameters.Create.Options>>24)&0xff);
1528 RequestedOptions=Stack->Parameters.Create.Options&FILE_VALID_OPTION_FLAGS;
1529 FileObject = Stack->FileObject;
1530 DeviceExt = DeviceObject->DeviceExtension;
1531 assert(DeviceExt);
1532 ExAcquireResourceExclusiveLite(&(DeviceExt->Resource),TRUE);
1533 Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
1534 CHECKPOINT;
1535 Irp->IoStatus.Information = 0;
1536 if(!NT_SUCCESS(Status))
1537 {
1538 if(RequestedDisposition==FILE_CREATE
1539 ||RequestedDisposition==FILE_OPEN_IF
1540 ||RequestedDisposition==FILE_OVERWRITE_IF)
1541 {
1542 CHECKPOINT;
1543 Status=addEntry(DeviceExt,FileObject,RequestedOptions
1544 ,(Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
1545 if(NT_SUCCESS(Status))
1546 Irp->IoStatus.Information = FILE_CREATED;
1547 // FIXME set size if AllocationSize requested
1548 // FIXME set extended attributes ?
1549 // FIXME set share access
1550 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1551 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1552 }
1553 }
1554 else
1555 {
1556 if(RequestedDisposition==FILE_CREATE)
1557 {
1558 Irp->IoStatus.Information = FILE_EXISTS;
1559 Status=STATUS_OBJECT_NAME_COLLISION;
1560 }
1561 pCcb=FileObject->FsContext2;
1562 pFcb=pCcb->pFcb;
1563 if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
1564 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1565 {
1566 Status=STATUS_FILE_IS_A_DIRECTORY;
1567 }
1568 if( (RequestedOptions&FILE_DIRECTORY_FILE)
1569 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1570 {
1571 Status=STATUS_NOT_A_DIRECTORY;
1572 }
1573 // FIXME : test share access
1574 // FIXME : test write access if requested
1575 if(!NT_SUCCESS(Status))
1576 FsdCloseFile(DeviceExt,FileObject);
1577 else Irp->IoStatus.Information = FILE_OPENED;
1578 // FIXME : make supersed or overwrite if requested
1579 }
1580 CHECKPOINT;
1581 Irp->IoStatus.Status = Status;
1582
1583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1584 ExReleaseResourceForThreadLite(&(DeviceExt->Resource),ExGetCurrentResourceThread());
1585 return Status;
1586 }
1587
1588
1589 NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1590 /*
1591 * FUNCTION: Write to a file
1592 */
1593 {
1594 ULONG Length;
1595 PVOID Buffer;
1596 ULONG Offset;
1597 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1598 PFILE_OBJECT FileObject = Stack->FileObject;
1599 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1600 NTSTATUS Status;
1601
1602 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
1603
1604 Length = Stack->Parameters.Write.Length;
1605 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1606 Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
1607
1608 Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
1609
1610 Irp->IoStatus.Status = Status;
1611 Irp->IoStatus.Information = Length;
1612 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1613
1614 return(Status);
1615 }
1616
1617 NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1618 /*
1619 * FUNCTION: Read from a file
1620 */
1621 {
1622 ULONG Length;
1623 PVOID Buffer;
1624 ULONG Offset;
1625 PIO_STACK_LOCATION Stack;
1626 PFILE_OBJECT FileObject;
1627 PDEVICE_EXTENSION DeviceExt;
1628 NTSTATUS Status;
1629 ULONG LengthRead;
1630
1631 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
1632
1633 /* Precondition / Initialization */
1634 assert(Irp != NULL);
1635 Stack = IoGetCurrentIrpStackLocation(Irp);
1636 assert(Stack != NULL);
1637 FileObject = Stack->FileObject;
1638 assert(FileObject != NULL);
1639 DeviceExt = DeviceObject->DeviceExtension;
1640 assert(DeviceExt != NULL);
1641
1642 Length = Stack->Parameters.Read.Length;
1643 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1644 Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
1645
1646 Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
1647 &LengthRead);
1648
1649 Irp->IoStatus.Status = Status;
1650 Irp->IoStatus.Information = LengthRead;
1651 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1652
1653 return(Status);
1654 }
1655
1656
1657 NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
1658 /*
1659 * FUNCTION: Mount the filesystem
1660 */
1661 {
1662 PDEVICE_OBJECT DeviceObject;
1663 PDEVICE_EXTENSION DeviceExt;
1664
1665 IoCreateDevice(VFATDriverObject,
1666 sizeof(DEVICE_EXTENSION),
1667 NULL,
1668 FILE_DEVICE_FILE_SYSTEM,
1669 0,
1670 FALSE,
1671 &DeviceObject);
1672 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
1673 DeviceExt = (PVOID)DeviceObject->DeviceExtension;
1674 // use same vpb as device disk
1675 DeviceObject->Vpb=DeviceToMount->Vpb;
1676 FsdMountDevice(DeviceExt,DeviceToMount);
1677 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
1678 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
1679 DeviceToMount);
1680
1681 /* read serial number */
1682 if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
1683 DeviceObject->Vpb->SerialNumber =
1684 ((struct _BootSector *)(DeviceExt->Boot))->VolumeID;
1685 else if (DeviceExt->FatType == FAT32)
1686 DeviceObject->Vpb->SerialNumber =
1687 ((struct _BootSector32 *)(DeviceExt->Boot))->VolumeID;
1688
1689 /* read volume label */
1690 ReadVolumeLabel (DeviceExt, DeviceObject->Vpb);
1691
1692 return(STATUS_SUCCESS);
1693 }
1694
1695 NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1696 /*
1697 * FUNCTION: File system control
1698 */
1699 {
1700 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1701 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1702 PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
1703 NTSTATUS Status;
1704
1705 // DPRINT("VFAT FSC\n");
1706 DbgPrint("VFAT FSC\n");
1707
1708 /* FIXME: should make sure that this is actually a mount request! */
1709
1710 if (FsdHasFileSystem(DeviceToMount))
1711 {
1712 Status = FsdMount(DeviceToMount);
1713 }
1714 else
1715 {
1716 DPRINT("VFAT: Unrecognized Volume\n");
1717 Status = STATUS_UNRECOGNIZED_VOLUME;
1718 }
1719 DPRINT("VFAT File system successfully mounted\n");
1720
1721 Irp->IoStatus.Status = Status;
1722 Irp->IoStatus.Information = 0;
1723
1724 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1725 return(Status);
1726 }
1727
1728 NTSTATUS FsdGetStandardInformation(PVfatFCB FCB, PDEVICE_OBJECT DeviceObject,
1729 PFILE_STANDARD_INFORMATION StandardInfo)
1730 /*
1731 * FUNCTION: Retrieve the standard file information
1732 */
1733 {
1734 PDEVICE_EXTENSION DeviceExtension;
1735 unsigned long AllocSize;
1736
1737 DeviceExtension = DeviceObject->DeviceExtension;
1738 /* PRECONDITION */
1739 assert(DeviceExtension != NULL);
1740 assert(DeviceExtension->BytesPerCluster != 0);
1741 assert(StandardInfo != NULL);
1742 assert(FCB != NULL);
1743
1744 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
1745
1746 /* Make allocsize a rounded up multiple of BytesPerCluster */
1747 AllocSize = ((FCB->entry.FileSize + DeviceExtension->BytesPerCluster - 1) /
1748 DeviceExtension->BytesPerCluster) *
1749 DeviceExtension->BytesPerCluster;
1750
1751 StandardInfo->AllocationSize = RtlConvertUlongToLargeInteger(AllocSize);
1752 StandardInfo->EndOfFile = RtlConvertUlongToLargeInteger(FCB->entry.FileSize);
1753 StandardInfo->NumberOfLinks = 0;
1754 StandardInfo->DeletePending = FALSE;
1755 if((FCB->entry.Attrib & 0x10)>0) {
1756 StandardInfo->Directory = TRUE;
1757 } else {
1758 StandardInfo->Directory = FALSE;
1759 }
1760
1761 return STATUS_SUCCESS;
1762 }
1763
1764 NTSTATUS FsdSetPositionInformation(PFILE_OBJECT FileObject,
1765 PVfatFCB FCB,
1766 PDEVICE_OBJECT DeviceObject,
1767 PFILE_POSITION_INFORMATION PositionInfo)
1768 {
1769 DPRINT("FsdSetPositionInformation()\n");
1770
1771 DPRINT("PositionInfo %x\n", PositionInfo);
1772 DPRINT("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
1773 memcpy(&FileObject->CurrentByteOffset,&PositionInfo->CurrentByteOffset,
1774 sizeof(LARGE_INTEGER));
1775
1776 return(STATUS_SUCCESS);
1777 }
1778
1779 NTSTATUS FsdGetPositionInformation(PFILE_OBJECT FileObject,
1780 PVfatFCB FCB,
1781 PDEVICE_OBJECT DeviceObject,
1782 PFILE_POSITION_INFORMATION PositionInfo)
1783 {
1784 DPRINT("FsdGetPositionInformation()\n");
1785
1786 memcpy(&PositionInfo->CurrentByteOffset, &FileObject->CurrentByteOffset,
1787 sizeof(LARGE_INTEGER));
1788 DPRINT("Getting position %x\n", PositionInfo->CurrentByteOffset.u.LowPart);
1789 return(STATUS_SUCCESS);
1790 }
1791
1792 NTSTATUS FsdGetBasicInformation(PFILE_OBJECT FileObject,
1793 PVfatFCB FCB,
1794 PDEVICE_OBJECT DeviceObject,
1795 PFILE_BASIC_INFORMATION BasicInfo)
1796 {
1797 DPRINT("FsdGetBasicInformation()\n");
1798
1799 FsdDosDateTimeToFileTime(FCB->entry.CreationDate,FCB->entry.CreationTime,
1800 &BasicInfo->CreationTime);
1801 FsdDosDateTimeToFileTime(FCB->entry.AccessDate,0,
1802 &BasicInfo->LastAccessTime);
1803 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
1804 &BasicInfo->LastWriteTime);
1805 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
1806 &BasicInfo->ChangeTime);
1807
1808 BasicInfo->FileAttributes = FCB->entry.Attrib;
1809
1810 DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
1811
1812 return(STATUS_SUCCESS);
1813 }
1814
1815
1816 NTSTATUS FsdSetDispositionInformation(PFILE_OBJECT FileObject,
1817 PVfatFCB FCB,
1818 PDEVICE_OBJECT DeviceObject,
1819 PFILE_DISPOSITION_INFORMATION DispositionInfo)
1820 {
1821 DPRINT("FsdSetDispositionInformation()\n");
1822
1823 FileObject->DeletePending = DispositionInfo->DeleteFile;
1824
1825 return(STATUS_SUCCESS);
1826 }
1827
1828
1829 NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1830 /*
1831 * FUNCTION: Retrieve the specified file information
1832 */
1833 {
1834 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1835 FILE_INFORMATION_CLASS FileInformationClass =
1836 Stack->Parameters.QueryFile.FileInformationClass;
1837 PFILE_OBJECT FileObject = NULL;
1838 PVfatFCB FCB = NULL;
1839 // PVfatCCB CCB = NULL;
1840
1841 NTSTATUS RC = STATUS_SUCCESS;
1842 void *SystemBuffer;
1843
1844 /* PRECONDITION */
1845 assert(DeviceObject != NULL);
1846 assert(Irp != NULL);
1847
1848 /* INITIALIZATION */
1849 Stack = IoGetCurrentIrpStackLocation(Irp);
1850 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
1851 FileObject = Stack->FileObject;
1852 // CCB = (PVfatCCB)(FileObject->FsContext2);
1853 // FCB = CCB->Buffer; // Should be CCB->FCB???
1854 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1855
1856 // FIXME : determine Buffer for result :
1857 if (Irp->MdlAddress)
1858 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1859 else
1860 SystemBuffer = Irp->UserBuffer;
1861 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1862
1863 switch(FileInformationClass) {
1864 case FileStandardInformation:
1865 RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
1866 break;
1867 case FilePositionInformation:
1868 RC = FsdGetPositionInformation(FileObject,
1869 FCB,
1870 DeviceObject,
1871 SystemBuffer);
1872 break;
1873 case FileBasicInformation:
1874 RC = FsdGetBasicInformation(FileObject,
1875 FCB,
1876 DeviceObject,
1877 SystemBuffer);
1878 break;
1879 default:
1880 RC=STATUS_NOT_IMPLEMENTED;
1881 }
1882
1883 Irp->IoStatus.Status = RC;
1884 Irp->IoStatus.Information = 0;
1885 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1886
1887 return RC;
1888 }
1889
1890 NTSTATUS FsdSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1891 /*
1892 * FUNCTION: Retrieve the specified file information
1893 */
1894 {
1895 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1896 FILE_INFORMATION_CLASS FileInformationClass;
1897 PFILE_OBJECT FileObject = NULL;
1898 PVfatFCB FCB = NULL;
1899 // PVfatCCB CCB = NULL;
1900 NTSTATUS RC = STATUS_SUCCESS;
1901 PVOID SystemBuffer;
1902
1903 /* PRECONDITION */
1904 assert(DeviceObject != NULL);
1905 assert(Irp != NULL);
1906
1907 DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
1908 DeviceObject,Irp);
1909
1910 /* INITIALIZATION */
1911 Stack = IoGetCurrentIrpStackLocation(Irp);
1912 FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
1913 FileObject = Stack->FileObject;
1914 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1915
1916 // FIXME : determine Buffer for result :
1917 if (Irp->MdlAddress)
1918 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1919 else
1920 SystemBuffer = Irp->UserBuffer;
1921 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1922
1923 DPRINT("FileInformationClass %d\n",FileInformationClass);
1924 DPRINT("SystemBuffer %x\n",SystemBuffer);
1925
1926 switch(FileInformationClass)
1927 {
1928 case FilePositionInformation:
1929 RC = FsdSetPositionInformation(FileObject,
1930 FCB,
1931 DeviceObject,
1932 SystemBuffer);
1933 break;
1934 case FileDispositionInformation:
1935 RC = FsdSetDispositionInformation(FileObject,
1936 FCB,
1937 DeviceObject,
1938 SystemBuffer);
1939 break;
1940 default:
1941 RC = STATUS_NOT_IMPLEMENTED;
1942 }
1943
1944 Irp->IoStatus.Status = RC;
1945 Irp->IoStatus.Information = 0;
1946 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1947
1948 return RC;
1949 }
1950
1951
1952
1953 NTSTATUS FsdGetFsVolumeInformation(PFILE_OBJECT FileObject,
1954 PVfatFCB FCB,
1955 PDEVICE_OBJECT DeviceObject,
1956 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo)
1957 {
1958 DPRINT("FsdGetFsVolumeInformation()\n");
1959 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
1960
1961 if (!FsVolumeInfo)
1962 return(STATUS_SUCCESS);
1963
1964
1965 /* valid entries */
1966 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
1967 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
1968 wcscpy (FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel);
1969
1970 /* dummy entries */
1971 FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
1972 FsVolumeInfo->SupportsObjects = FALSE;
1973
1974 DPRINT("Finished FsdGetFsVolumeInformation()\n");
1975
1976 return(STATUS_SUCCESS);
1977 }
1978
1979
1980 NTSTATUS FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo)
1981 {
1982 DPRINT("FsdGetFsAttributeInformation()\n");
1983 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
1984
1985 if (!FsAttributeInfo)
1986 return(STATUS_SUCCESS);
1987
1988 FsAttributeInfo->FileSystemAttributes = FS_CASE_IS_PRESERVED;
1989 FsAttributeInfo->MaximumComponentNameLength = 255;
1990 FsAttributeInfo->FileSystemNameLength = 3;
1991 wcscpy (FsAttributeInfo->FileSystemName, L"FAT");
1992
1993 DPRINT("Finished FsdGetFsAttributeInformation()\n");
1994
1995 return(STATUS_SUCCESS);
1996 }
1997
1998 NTSTATUS FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
1999 PFILE_FS_SIZE_INFORMATION FsSizeInfo)
2000 {
2001 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
2002
2003 DPRINT("FsdGetFsSizeInformation()\n");
2004 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
2005
2006 if (!FsSizeInfo)
2007 return(STATUS_SUCCESS);
2008
2009 if (DeviceExt->FatType == FAT32)
2010 {
2011 struct _BootSector32 *BootSect = (struct _BootSector32 *)DeviceExt->Boot;
2012
2013 if (BootSect->Sectors)
2014 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
2015 else
2016 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
2017
2018 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2019 FAT32CountAvailableClusters(DeviceExt);
2020
2021 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
2022 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
2023 }
2024 else
2025 {
2026 struct _BootSector *BootSect = (struct _BootSector *)DeviceExt->Boot;
2027
2028 if (BootSect->Sectors)
2029 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
2030 else
2031 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
2032
2033 if (DeviceExt->FatType == FAT16)
2034 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2035 FAT16CountAvailableClusters(DeviceExt);
2036 else
2037 FsSizeInfo->AvailableAllocationUnits.QuadPart =
2038 FAT12CountAvailableClusters(DeviceExt);
2039
2040 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
2041 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
2042 }
2043
2044 DPRINT("Finished FsdGetFsSizeInformation()\n");
2045
2046 return(STATUS_SUCCESS);
2047 }
2048
2049
2050 NTSTATUS FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
2051 /*
2052 * FUNCTION: Retrieve the specified file information
2053 */
2054 {
2055 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
2056 FILE_INFORMATION_CLASS FileInformationClass =
2057 Stack->Parameters.QueryVolume.FileInformationClass;
2058 PFILE_OBJECT FileObject = NULL;
2059 PVfatFCB FCB = NULL;
2060 // PVfatCCB CCB = NULL;
2061
2062 NTSTATUS RC = STATUS_SUCCESS;
2063 void *SystemBuffer;
2064
2065 /* PRECONDITION */
2066 assert(DeviceObject != NULL);
2067 assert(Irp != NULL);
2068
2069 DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
2070 DeviceObject,Irp);
2071
2072 /* INITIALIZATION */
2073 Stack = IoGetCurrentIrpStackLocation(Irp);
2074 FileInformationClass = Stack->Parameters.QueryVolume.FileInformationClass;
2075 FileObject = Stack->FileObject;
2076 // CCB = (PVfatCCB)(FileObject->FsContext2);
2077 // FCB = CCB->Buffer; // Should be CCB->FCB???
2078 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
2079
2080 // FIXME : determine Buffer for result :
2081 if (Irp->MdlAddress)
2082 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2083 else
2084 SystemBuffer = Irp->UserBuffer;
2085 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
2086
2087 DPRINT("FileInformationClass %d\n",FileInformationClass);
2088 DPRINT("SystemBuffer %x\n",SystemBuffer);
2089
2090 switch (FileInformationClass)
2091 {
2092 case FileFsVolumeInformation:
2093 RC = FsdGetFsVolumeInformation(FileObject,
2094 FCB,
2095 DeviceObject,
2096 SystemBuffer);
2097 break;
2098
2099 case FileFsAttributeInformation:
2100 RC = FsdGetFsAttributeInformation(SystemBuffer);
2101 break;
2102
2103 case FileFsSizeInformation:
2104 RC = FsdGetFsSizeInformation(DeviceObject, SystemBuffer);
2105 break;
2106
2107 default:
2108 RC=STATUS_NOT_IMPLEMENTED;
2109 }
2110
2111 Irp->IoStatus.Status = RC;
2112 Irp->IoStatus.Information = 0;
2113 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2114
2115 return RC;
2116 }
2117
2118
2119 NTSTATUS STDCALL
2120 DriverEntry(PDRIVER_OBJECT _DriverObject, PUNICODE_STRING RegistryPath)
2121 /*
2122 * FUNCTION: Called by the system to initalize the driver
2123 * ARGUMENTS:
2124 * DriverObject = object describing this driver
2125 * RegistryPath = path to our configuration entries
2126 * RETURNS: Success or failure
2127 */
2128 {
2129 PDEVICE_OBJECT DeviceObject;
2130 NTSTATUS ret;
2131 UNICODE_STRING ustr;
2132 ANSI_STRING astr;
2133
2134 DbgPrint("VFAT 0.0.6\n");
2135 pFirstFcb=NULL;
2136 VFATDriverObject = _DriverObject;
2137
2138 RtlInitAnsiString(&astr,"\\Device\\VFAT");
2139 RtlAnsiStringToUnicodeString(&ustr,&astr,TRUE);
2140 ret = IoCreateDevice(VFATDriverObject,0,&ustr,
2141 FILE_DEVICE_FILE_SYSTEM,0,FALSE,&DeviceObject);
2142 if (ret!=STATUS_SUCCESS)
2143 {
2144 return(ret);
2145 }
2146
2147 DeviceObject->Flags = DO_DIRECT_IO;
2148 VFATDriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
2149 VFATDriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
2150 VFATDriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
2151 VFATDriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
2152 VFATDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
2153 FsdFileSystemControl;
2154 VFATDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
2155 FsdQueryInformation;
2156 VFATDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
2157 FsdSetInformation;
2158 VFATDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
2159 FsdDirectoryControl;
2160 VFATDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
2161 FsdQueryVolumeInformation;
2162
2163 VFATDriverObject->DriverUnload = NULL;
2164
2165 IoRegisterFileSystem(DeviceObject);
2166
2167 return(STATUS_SUCCESS);
2168 }
2169