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