Lots of changes to the kernel
[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 TempStr[0] = (WCHAR)'.';
781 TempStr[1] = 0;
782 FileToFind=&TempStr;
783 }
784 if (Parent != NULL)
785 {
786 DPRINT("Parent->entry.FirstCluster %d\n",Parent->entry.FirstCluster);
787 }
788
789 if (Parent == NULL||Parent->entry.FirstCluster==1)
790 {
791 Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
792 StartingSector = DeviceExt->rootStart;
793 NextCluster=0;
794 if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0) ||
795 (FileToFind[0]=='.' && FileToFind[1]==0))
796 {// it's root : complete essentials fields then return ok
797 memset(Fcb,0,sizeof(VfatFCB));
798 memset(Fcb->entry.Filename,' ',11);
799 Fcb->entry.FileSize=DeviceExt->rootDirectorySectors*BLOCKSIZE;
800 Fcb->entry.Attrib=FILE_ATTRIBUTE_DIRECTORY;
801 if (DeviceExt->FatType == FAT32)
802 Fcb->entry.FirstCluster=2;
803 else Fcb->entry.FirstCluster=1;//FIXME : is 1 the good value for mark root?
804 if(StartSector) *StartSector=StartingSector;
805 if(Entry) *Entry=0;
806 return(STATUS_SUCCESS);
807 }
808 }
809 else
810 {
811 DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
812
813 Size = ULONG_MAX;
814 if (DeviceExt->FatType == FAT32)
815 NextCluster = Parent->entry.FirstCluster
816 +Parent->entry.FirstClusterHigh*65536;
817 else
818 NextCluster = Parent->entry.FirstCluster;
819 StartingSector = ClusterToSector(DeviceExt, NextCluster);
820 if(Parent->entry.FirstCluster==1 && DeviceExt->FatType!=FAT32)
821 {// read of root directory in FAT16 or FAT12
822 StartingSector=DeviceExt->rootStart;
823 }
824 }
825 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
826 if (StartSector && (*StartSector)) StartingSector=*StartSector;
827 i=(Entry)?(*Entry):0;
828 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
829 for (j=0; j<Size; j++)
830 {
831 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
832
833 for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
834 {
835 if (IsVolEntry((PVOID)block,i))
836 continue;
837 if (IsLastEntry((PVOID)block,i))
838 {
839 ExFreePool(block);
840 if(StartSector) *StartSector=StartingSector;
841 if(Entry) *Entry=i;
842 return(STATUS_UNSUCCESSFUL);
843 }
844 if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
845 {
846 DPRINT("Comparing '%w' '%w'\n",name,FileToFind);
847 if (wstrcmpjoki(name,FileToFind))
848 {
849 /* In the case of a long filename, the firstcluster is stored in
850 the next record -- where it's short name is */
851 if(((FATDirEntry *)block)[i].Attrib==0x0f) i++;
852 if( i==(ENTRIES_PER_SECTOR))
853 {// entry is in next sector
854 StartingSector++;
855 //FIXME : treat case of next sector fragmented
856 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
857 i=0;
858 }
859 memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
860 sizeof(FATDirEntry));
861 vfat_wcsncpy(Fcb->ObjectName,name,MAX_PATH);
862 ExFreePool(block);
863 if(StartSector) *StartSector=StartingSector;
864 if(Entry) *Entry=i;
865 return(STATUS_SUCCESS);
866 }
867 }
868 }
869 // not found in this sector, try next :
870
871 /* directory can be fragmented although it is best to keep them
872 unfragmented */
873 if(Entry) *Entry=0;
874 StartingSector++;
875 if ((Parent != NULL && Parent->entry.FirstCluster!=1)
876 || DeviceExt->FatType ==FAT32)
877 {
878 if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
879 {
880 NextCluster = GetNextCluster(DeviceExt,NextCluster);
881 if (NextCluster == 0||NextCluster==0xffffffff)
882 {
883 if(StartSector) *StartSector=StartingSector;
884 if(Entry) *Entry=i;
885 ExFreePool(block);
886 return(STATUS_UNSUCCESSFUL);
887 }
888 StartingSector = ClusterToSector(DeviceExt,NextCluster);
889 }
890 }
891 }
892 ExFreePool(block);
893 if(StartSector) *StartSector=StartingSector;
894 if(Entry) *Entry=i;
895 return(STATUS_UNSUCCESSFUL);
896 }
897
898
899 NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
900 /*
901 * FUNCTION: Closes a file
902 */
903 {
904 PVfatFCB pFcb;
905 PVfatCCB pCcb;
906
907 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
908 DeviceExt,FileObject);
909
910 //FIXME : update entry in directory ?
911 pCcb = (PVfatCCB)(FileObject->FsContext2);
912
913 DPRINT("pCcb %x\n",pCcb);
914 if (pCcb == NULL)
915 {
916 return(STATUS_SUCCESS);
917 }
918
919 pFcb = pCcb->pFcb;
920
921 pFcb->RefCount--;
922 if(pFcb->RefCount<=0)
923 {
924 if(pFcb->prevFcb)
925 pFcb->prevFcb->nextFcb=pFcb->nextFcb;
926 else
927 pFirstFcb=pFcb->nextFcb;
928 if(pFcb->nextFcb)
929 pFcb->nextFcb->prevFcb=pFcb->prevFcb;
930 ExFreePool(pFcb);
931 }
932 ExFreePool(pCcb);
933 return STATUS_SUCCESS;
934 }
935
936 NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
937 PWSTR FileName)
938 /*
939 * FUNCTION: Opens a file
940 */
941 {
942 PWSTR current;
943 PWSTR next;
944 PWSTR string;
945 PVfatFCB ParentFcb;
946 PVfatFCB Fcb,pRelFcb;
947 PVfatFCB Temp;
948 PVfatCCB newCCB,pRelCcb;
949 NTSTATUS Status;
950 PFILE_OBJECT pRelFileObject;
951 PWSTR AbsFileName=NULL;
952 short i,j;
953
954 DPRINT("FsdOpenFile(%08lx, %08lx, %w)\n",
955 DeviceExt,
956 FileObject,
957 FileName);
958
959 //FIXME : treat relative name
960 if(FileObject->RelatedFileObject)
961 {
962 DbgPrint("try related for %w\n",FileName);
963 pRelFileObject=FileObject->RelatedFileObject;
964 pRelCcb=pRelFileObject->FsContext2;
965 assert(pRelCcb);
966 pRelFcb=pRelCcb->pFcb;
967 assert(pRelFcb);
968 // verify related object is a directory and target name don't start with \.
969 if( !(pRelFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
970 || (FileName[0]!= '\\') )
971 {
972 Status=STATUS_INVALID_PARAMETER;
973 return Status;
974 }
975 // construct absolute path name
976 AbsFileName=ExAllocatePool(NonPagedPool,MAX_PATH);
977 for (i=0;pRelFcb->PathName[i];i++)
978 AbsFileName[i]=pRelFcb->PathName[i];
979 AbsFileName[i++]='\\';
980 for (j=0;FileName[j]&&i<MAX_PATH;j++)
981 AbsFileName[i++]=FileName[j];
982 assert(i<MAX_PATH);
983 AbsFileName[i]=0;
984 FileName=AbsFileName;
985 }
986 // try first to find an existing FCB in memory
987 for (Fcb=pFirstFcb;Fcb; Fcb=Fcb->nextFcb)
988 {
989 if (DeviceExt==Fcb->pDevExt
990 && wstrcmpi(FileName,Fcb->PathName))
991 {
992 Fcb->RefCount++;
993 FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
994 newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
995 memset(newCCB,0,sizeof(VfatCCB));
996 FileObject->FsContext2 = newCCB;
997 newCCB->pFcb=Fcb;
998 newCCB->PtrFileObject=FileObject;
999 if(AbsFileName)ExFreePool(AbsFileName);
1000 return(STATUS_SUCCESS);
1001 }
1002 }
1003 string = FileName;
1004 ParentFcb = NULL;
1005 Fcb = ExAllocatePool(NonPagedPool, sizeof(VfatFCB));
1006 memset(Fcb,0,sizeof(VfatFCB));
1007 Fcb->ObjectName=Fcb->PathName;
1008 next = &string[0];
1009
1010 while (next!=NULL)
1011 {
1012 *next = '\\';
1013 current = next+1;
1014 next = wcschr(next+1,'\\');
1015 if (next!=NULL)
1016 {
1017 *next=0;
1018 }
1019 DPRINT("current '%w'\n",current);
1020 Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
1021 if (Status != STATUS_SUCCESS)
1022 {
1023 if (Fcb != NULL)
1024 ExFreePool(Fcb);
1025 if (ParentFcb != NULL)
1026 ExFreePool(ParentFcb);
1027 if(AbsFileName)ExFreePool(AbsFileName);
1028 return(Status);
1029 }
1030 Temp = Fcb;
1031 if (ParentFcb == NULL)
1032 {
1033 Fcb = ExAllocatePool(NonPagedPool,sizeof(VfatFCB));
1034 memset(Fcb,0,sizeof(VfatFCB));
1035 Fcb->ObjectName=Fcb->PathName;
1036 }
1037 else Fcb = ParentFcb;
1038 ParentFcb = Temp;
1039 }
1040 FileObject->FsContext =(PVOID) &ParentFcb->NTRequiredFCB;
1041 newCCB = ExAllocatePool(NonPagedPool,sizeof(VfatCCB));
1042 memset(newCCB,0,sizeof(VfatCCB));
1043 FileObject->FsContext2 = newCCB;
1044 newCCB->pFcb=ParentFcb;
1045 newCCB->PtrFileObject=FileObject;
1046 ParentFcb->RefCount++;
1047 //FIXME : initialize all fields in FCB and CCB
1048 ParentFcb->nextFcb=pFirstFcb;
1049 pFirstFcb=ParentFcb;
1050 vfat_wcsncpy(ParentFcb->PathName,FileName,MAX_PATH);
1051 ParentFcb->ObjectName=ParentFcb->PathName+(current-FileName);
1052 ParentFcb->pDevExt=DeviceExt;
1053 DPRINT("file open, fcb=%x\n",ParentFcb);
1054 DPRINT("FileSize %d\n",ParentFcb->entry.FileSize);
1055 if(Fcb) ExFreePool(Fcb);
1056 if(AbsFileName)ExFreePool(AbsFileName);
1057 return(STATUS_SUCCESS);
1058 }
1059
1060
1061 BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount)
1062 /*
1063 * FUNCTION: Tests if the device contains a filesystem that can be mounted
1064 * by this fsd
1065 */
1066 {
1067 BootSector* Boot;
1068
1069 Boot = ExAllocatePool(NonPagedPool,512);
1070
1071 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)Boot);
1072
1073 if (strncmp(Boot->SysType,"FAT12",5)==0 ||
1074 strncmp(Boot->SysType,"FAT16",5)==0 ||
1075 strncmp(((struct _BootSector32 *)(Boot))->SysType,"FAT32",5)==0)
1076 {
1077 ExFreePool(Boot);
1078 return(TRUE);
1079 }
1080 ExFreePool(Boot);
1081 return(FALSE);
1082 }
1083
1084 NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt,
1085 PDEVICE_OBJECT DeviceToMount)
1086 /*
1087 * FUNCTION: Mounts the device
1088 */
1089 {
1090 DPRINT("Mounting VFAT device...");
1091 DPRINT("DeviceExt %x\n",DeviceExt);
1092
1093 DeviceExt->Boot = ExAllocatePool(NonPagedPool,512);
1094 VFATReadSectors(DeviceToMount, 0, 1, (UCHAR *)DeviceExt->Boot);
1095
1096 DPRINT("DeviceExt->Boot->BytesPerSector %x\n",
1097 DeviceExt->Boot->BytesPerSector);
1098
1099 DeviceExt->FATStart=DeviceExt->Boot->ReservedSectors;
1100 DeviceExt->rootDirectorySectors=
1101 (DeviceExt->Boot->RootEntries*32)/DeviceExt->Boot->BytesPerSector;
1102 DeviceExt->rootStart=
1103 DeviceExt->FATStart+DeviceExt->Boot->FATCount*DeviceExt->Boot->FATSectors;
1104 DeviceExt->dataStart=DeviceExt->rootStart+DeviceExt->rootDirectorySectors;
1105 DeviceExt->FATEntriesPerSector=DeviceExt->Boot->BytesPerSector/32;
1106 DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster *
1107 DeviceExt->Boot->BytesPerSector;
1108
1109 if (strncmp(DeviceExt->Boot->SysType,"FAT12",5)==0)
1110 {
1111 DeviceExt->FatType = FAT12;
1112 }
1113 else if (strncmp(((struct _BootSector32 *)(DeviceExt->Boot))->SysType,"FAT32",5)==0)
1114 {
1115 DeviceExt->FatType = FAT32;
1116 DeviceExt->rootDirectorySectors=DeviceExt->Boot->SectorsPerCluster;
1117 DeviceExt->rootStart=
1118 DeviceExt->FATStart+DeviceExt->Boot->FATCount
1119 * ((struct _BootSector32 *)( DeviceExt->Boot))->FATSectors32;
1120 DeviceExt->dataStart=DeviceExt->rootStart;
1121 }
1122 else
1123 {
1124 DeviceExt->FatType = FAT16;
1125 }
1126
1127 // with FAT32 it's not a good idea to load always fat in memory
1128 // because on a 8GB partition with 2 KO clusters, the fat = 8 MO
1129 if(DeviceExt->FatType!=FAT32)
1130 {
1131 DeviceExt->FAT = ExAllocatePool(NonPagedPool, BLOCKSIZE*DeviceExt->Boot->FATSectors);
1132 VFATReadSectors(DeviceToMount, DeviceExt->FATStart, DeviceExt->Boot->FATSectors, (UCHAR *)DeviceExt->FAT);
1133 }
1134 return STATUS_SUCCESS;
1135 }
1136
1137 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
1138 /*
1139 * FUNCTION: Load a cluster from the physical device
1140 */
1141 {
1142 ULONG Sector;
1143
1144 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1145 DeviceExt,Buffer,Cluster);
1146
1147 Sector = ClusterToSector(DeviceExt, Cluster);
1148
1149 VFATReadSectors(DeviceExt->StorageDevice,
1150 Sector,
1151 DeviceExt->Boot->SectorsPerCluster,
1152 Buffer);
1153 }
1154
1155 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
1156 /*
1157 * FUNCTION: Write a cluster to the physical device
1158 */
1159 {
1160 ULONG Sector;
1161 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
1162 DeviceExt,Buffer,Cluster);
1163
1164 Sector = ClusterToSector(DeviceExt, Cluster);
1165
1166 VFATWriteSectors(DeviceExt->StorageDevice,
1167 Sector,
1168 DeviceExt->Boot->SectorsPerCluster,
1169 Buffer);
1170 }
1171
1172 NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1173 PVOID Buffer, ULONG Length, ULONG ReadOffset,
1174 PULONG LengthRead)
1175 /*
1176 * FUNCTION: Reads data from a file
1177 */
1178 {
1179 ULONG CurrentCluster;
1180 ULONG FileOffset;
1181 ULONG FirstCluster;
1182 PVfatFCB Fcb;
1183 PVOID Temp;
1184 ULONG TempLength;
1185
1186 /* PRECONDITION */
1187 assert(DeviceExt != NULL);
1188 assert(DeviceExt->BytesPerCluster != 0);
1189 assert(FileObject != NULL);
1190 assert(FileObject->FsContext != NULL);
1191
1192 DPRINT("FsdReadFile(DeviceExt %x, FileObject %x, Buffer %x, "
1193 "Length %d, ReadOffset %d)\n",DeviceExt,FileObject,Buffer,
1194 Length,ReadOffset);
1195
1196 Fcb = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1197 if (DeviceExt->FatType == FAT32)
1198 CurrentCluster = Fcb->entry.FirstCluster
1199 +Fcb->entry.FirstClusterHigh*65536;
1200 else
1201 CurrentCluster = Fcb->entry.FirstCluster;
1202 FirstCluster=CurrentCluster;
1203 DPRINT("DeviceExt->BytesPerCluster %x\n",DeviceExt->BytesPerCluster);
1204
1205 if (ReadOffset >= Fcb->entry.FileSize
1206 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1207 {
1208 return(STATUS_END_OF_FILE);
1209 }
1210 if ((ReadOffset + Length) > Fcb->entry.FileSize
1211 && !(Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1212 {
1213 Length = Fcb->entry.FileSize - ReadOffset;
1214 }
1215 *LengthRead = 0;
1216 /* FIXME: optimize by remembering the last cluster read and using if possible */
1217 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1218 if(!Temp) return STATUS_UNSUCCESSFUL;
1219 if (FirstCluster==1)
1220 { //root of FAT16 or FAT12
1221 CurrentCluster=DeviceExt->rootStart+ReadOffset
1222 /(DeviceExt->BytesPerCluster)*DeviceExt->Boot->SectorsPerCluster;
1223 }
1224 else
1225 for (FileOffset=0; FileOffset < ReadOffset / DeviceExt->BytesPerCluster
1226 ; FileOffset++)
1227 {
1228 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1229 }
1230 CHECKPOINT;
1231 if ((ReadOffset % DeviceExt->BytesPerCluster)!=0)
1232 {
1233 if (FirstCluster==1)
1234 {
1235 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1236 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1237 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1238 }
1239 else
1240 {
1241 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1242 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1243 }
1244 TempLength = min(Length,DeviceExt->BytesPerCluster -
1245 (ReadOffset % DeviceExt->BytesPerCluster));
1246
1247 memcpy(Buffer, Temp + ReadOffset % DeviceExt->BytesPerCluster,
1248 TempLength);
1249
1250 (*LengthRead) = (*LengthRead) + TempLength;
1251 Length = Length - TempLength;
1252 Buffer = Buffer + TempLength;
1253 }
1254 CHECKPOINT;
1255 while (Length >= DeviceExt->BytesPerCluster)
1256 {
1257 if (FirstCluster==1)
1258 {
1259 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1260 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1261 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1262 }
1263 else
1264 {
1265 VFATLoadCluster(DeviceExt,Buffer,CurrentCluster);
1266 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1267 }
1268 if (CurrentCluster == 0xffffffff)
1269 {
1270 ExFreePool(Temp);
1271 return(STATUS_SUCCESS);
1272 }
1273
1274 (*LengthRead) = (*LengthRead) + DeviceExt->BytesPerCluster;
1275 Buffer = Buffer + DeviceExt->BytesPerCluster;
1276 Length = Length - DeviceExt->BytesPerCluster;
1277 }
1278 CHECKPOINT;
1279 if (Length > 0)
1280 {
1281 (*LengthRead) = (*LengthRead) + Length;
1282 if (FirstCluster==1)
1283 {
1284 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1285 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1286 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1287 }
1288 else
1289 {
1290 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1291 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1292 }
1293 memcpy(Buffer, Temp, Length);
1294 }
1295 ExFreePool(Temp);
1296 return(STATUS_SUCCESS);
1297 }
1298
1299 NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
1300 PVOID Buffer, ULONG Length, ULONG WriteOffset)
1301 /*
1302 * FUNCTION: Writes data to file
1303 */
1304 {
1305 ULONG CurrentCluster;
1306 ULONG FileOffset;
1307 ULONG FirstCluster;
1308 PVfatFCB Fcb;
1309 PVfatCCB pCcb;
1310 PVOID Temp;
1311 ULONG TempLength,Length2=Length;
1312
1313 /* Locate the first cluster of the file */
1314 assert(FileObject);
1315 pCcb=(PVfatCCB)(FileObject->FsContext2);
1316 assert(pCcb);
1317 Fcb = pCcb->pFcb;
1318 assert(Fcb);
1319 if (DeviceExt->FatType == FAT32)
1320 CurrentCluster = Fcb->entry.FirstCluster+Fcb->entry.FirstClusterHigh*65536;
1321 else
1322 CurrentCluster = Fcb->entry.FirstCluster;
1323 FirstCluster=CurrentCluster;
1324 /* Allocate a buffer to hold 1 cluster of data */
1325
1326 Temp = ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
1327 assert(Temp);
1328
1329 /* Find the cluster according to the offset in the file */
1330
1331 if (CurrentCluster==1)
1332 { //root of FAT16 or FAT12
1333 CurrentCluster=DeviceExt->rootStart+WriteOffset
1334 /DeviceExt->BytesPerCluster*DeviceExt->Boot->SectorsPerCluster;
1335 }
1336 else
1337 if (CurrentCluster==0)
1338 {// file of size 0 : allocate first cluster
1339 CurrentCluster=GetNextWriteCluster(DeviceExt,0);
1340 if (DeviceExt->FatType == FAT32)
1341 {
1342 Fcb->entry.FirstClusterHigh=CurrentCluster>>16;
1343 Fcb->entry.FirstCluster=CurrentCluster;
1344 }
1345 else
1346 Fcb->entry.FirstCluster=CurrentCluster;
1347 }
1348 else
1349 for (FileOffset=0; FileOffset < WriteOffset / DeviceExt->BytesPerCluster; FileOffset++)
1350 {
1351 CurrentCluster = GetNextCluster(DeviceExt,CurrentCluster);
1352 }
1353 CHECKPOINT;
1354
1355 /*
1356 If the offset in the cluster doesn't fall on the cluster boundary then
1357 we have to write only from the specified offset
1358 */
1359
1360 if ((WriteOffset % DeviceExt->BytesPerCluster)!=0)
1361 {
1362 CHECKPOINT;
1363 TempLength = min(Length,DeviceExt->BytesPerCluster -
1364 (WriteOffset % DeviceExt->BytesPerCluster));
1365 /* Read in the existing cluster data */
1366 if (FirstCluster==1)
1367 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1368 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1369 else
1370 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1371
1372 /* Overwrite the last parts of the data as necessary */
1373 memcpy(Temp + (WriteOffset % DeviceExt->BytesPerCluster), Buffer,
1374 TempLength);
1375
1376 /* Write the cluster back */
1377 if (FirstCluster==1)
1378 {
1379 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1380 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1381 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1382 }
1383 else
1384 {
1385 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1386 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1387 }
1388 Length2 -= TempLength;
1389 Buffer = Buffer + TempLength;
1390 }
1391 CHECKPOINT;
1392
1393 /* Write the buffer in chunks of 1 cluster */
1394
1395 while (Length2 >= DeviceExt->BytesPerCluster)
1396 {
1397 CHECKPOINT;
1398 if (CurrentCluster == 0)
1399 {
1400 ExFreePool(Temp);
1401 return(STATUS_UNSUCCESSFUL);
1402 }
1403 if (FirstCluster==1)
1404 {
1405 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1406 ,DeviceExt->Boot->SectorsPerCluster,Buffer);
1407 CurrentCluster += DeviceExt->Boot->SectorsPerCluster;
1408 }
1409 else
1410 {
1411 VFATWriteCluster(DeviceExt,Buffer,CurrentCluster);
1412 CurrentCluster = GetNextCluster(DeviceExt, CurrentCluster);
1413 }
1414 Buffer = Buffer + DeviceExt->BytesPerCluster;
1415 Length2 -= DeviceExt->BytesPerCluster;
1416 }
1417 CHECKPOINT;
1418
1419 /* Write the remainder */
1420
1421 if (Length2 > 0)
1422 {
1423 CHECKPOINT;
1424 if (CurrentCluster == 0)
1425 {
1426 ExFreePool(Temp);
1427 return(STATUS_UNSUCCESSFUL);
1428 }
1429 CHECKPOINT;
1430 /* Read in the existing cluster data */
1431 if (FirstCluster==1)
1432 VFATReadSectors(DeviceExt->StorageDevice,CurrentCluster
1433 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1434 else
1435 VFATLoadCluster(DeviceExt,Temp,CurrentCluster);
1436 CHECKPOINT;
1437 memcpy(Temp, Buffer, Length2);
1438 CHECKPOINT;
1439 if (FirstCluster==1)
1440 {
1441 VFATWriteSectors(DeviceExt->StorageDevice,CurrentCluster
1442 ,DeviceExt->Boot->SectorsPerCluster,Temp);
1443 }
1444 else
1445 VFATWriteCluster(DeviceExt,Temp,CurrentCluster);
1446 }
1447 CHECKPOINT;
1448 //FIXME : set last write time and date
1449 if(Fcb->entry.FileSize<WriteOffset+Length
1450 && !(Fcb->entry.Attrib &FILE_ATTRIBUTE_DIRECTORY))
1451 {
1452 Fcb->entry.FileSize=WriteOffset+Length;
1453 // update entry in directory
1454 updEntry(DeviceExt,FileObject);
1455 }
1456 ExFreePool(Temp);
1457 return(STATUS_SUCCESS);
1458 }
1459
1460 NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1461 /*
1462 * FUNCTION: Close a file
1463 */
1464 {
1465 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1466 PFILE_OBJECT FileObject = Stack->FileObject;
1467 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1468 NTSTATUS Status;
1469
1470 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject, Irp);
1471
1472 Status = FsdCloseFile(DeviceExtension,FileObject);
1473
1474 Irp->IoStatus.Status = Status;
1475 Irp->IoStatus.Information = 0;
1476
1477 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1478 return(Status);
1479 }
1480
1481 NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1482 /*
1483 * FUNCTION: Create or open a file
1484 */
1485 {
1486 PIO_STACK_LOCATION Stack;
1487 PFILE_OBJECT FileObject;
1488 NTSTATUS Status=STATUS_SUCCESS;
1489 PDEVICE_EXTENSION DeviceExt;
1490 ULONG RequestedDisposition,RequestedOptions;
1491 PVfatCCB pCcb;
1492 PVfatFCB pFcb;
1493
1494 assert(DeviceObject);
1495 assert(Irp);
1496 if(DeviceObject->Size==sizeof(DEVICE_OBJECT))
1497 {// DevieObject represent FileSystem instead of logical volume
1498 DbgPrint("FsdCreate called with file system\n");
1499 Irp->IoStatus.Status=Status;
1500 Irp->IoStatus.Information=FILE_OPENED;
1501 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1502 return(Status);
1503 }
1504 Stack = IoGetCurrentIrpStackLocation(Irp);
1505 assert(Stack);
1506 RequestedDisposition = ((Stack->Parameters.Create.Options>>24)&0xff);
1507 RequestedOptions=Stack->Parameters.Create.Options&FILE_VALID_OPTION_FLAGS;
1508 FileObject = Stack->FileObject;
1509 DeviceExt = DeviceObject->DeviceExtension;
1510 assert(DeviceExt);
1511 ExAcquireResourceExclusiveLite(&(DeviceExt->Resource),TRUE);
1512 Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
1513 Irp->IoStatus.Information = 0;
1514 if(!NT_SUCCESS(Status))
1515 {
1516 if(RequestedDisposition==FILE_CREATE
1517 ||RequestedDisposition==FILE_OPEN_IF
1518 ||RequestedDisposition==FILE_OVERWRITE_IF)
1519 {
1520 Status=addEntry(DeviceExt,FileObject,RequestedOptions
1521 ,(Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
1522 if(NT_SUCCESS(Status))
1523 Irp->IoStatus.Information = FILE_CREATED;
1524 // FIXME set size if AllocationSize requested
1525 // FIXME set extended attributes ?
1526 // FIXME set share access
1527 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
1528 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
1529 }
1530 }
1531 else
1532 {
1533 if(RequestedDisposition==FILE_CREATE)
1534 {
1535 Irp->IoStatus.Information = FILE_EXISTS;
1536 Status=STATUS_OBJECT_NAME_COLLISION;
1537 }
1538 pCcb=FileObject->FsContext2;
1539 pFcb=pCcb->pFcb;
1540 if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
1541 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1542 {
1543 Status=STATUS_FILE_IS_A_DIRECTORY;
1544 }
1545 if( (RequestedOptions&FILE_DIRECTORY_FILE)
1546 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
1547 {
1548 Status=STATUS_NOT_A_DIRECTORY;
1549 }
1550 // FIXME : test share access
1551 // FIXME : test write access if requested
1552 if(!NT_SUCCESS(Status))
1553 FsdCloseFile(DeviceExt,FileObject);
1554 else Irp->IoStatus.Information = FILE_OPENED;
1555 // FIXME : make supersed or overwrite if requested
1556 }
1557
1558 Irp->IoStatus.Status = Status;
1559
1560 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1561 ExReleaseResourceForThreadLite(&(DeviceExt->Resource),ExGetCurrentResourceThread());
1562 return Status;
1563 }
1564
1565
1566 NTSTATUS FsdWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1567 /*
1568 * FUNCTION: Write to a file
1569 */
1570 {
1571 ULONG Length;
1572 PVOID Buffer;
1573 ULONG Offset;
1574 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1575 PFILE_OBJECT FileObject = Stack->FileObject;
1576 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1577 NTSTATUS Status;
1578
1579 DPRINT("FsdWrite(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
1580
1581 Length = Stack->Parameters.Write.Length;
1582 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1583 Offset = Stack->Parameters.Write.ByteOffset.u.LowPart;
1584
1585 Status = FsdWriteFile(DeviceExt,FileObject,Buffer,Length,Offset);
1586
1587 Irp->IoStatus.Status = Status;
1588 Irp->IoStatus.Information = Length;
1589 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1590
1591 return(Status);
1592 }
1593
1594 NTSTATUS FsdRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1595 /*
1596 * FUNCTION: Read from a file
1597 */
1598 {
1599 ULONG Length;
1600 PVOID Buffer;
1601 ULONG Offset;
1602 PIO_STACK_LOCATION Stack;
1603 PFILE_OBJECT FileObject;
1604 PDEVICE_EXTENSION DeviceExt;
1605 NTSTATUS Status;
1606 ULONG LengthRead;
1607
1608 DPRINT("FsdRead(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
1609
1610 /* Precondition / Initialization */
1611 assert(Irp != NULL);
1612 Stack = IoGetCurrentIrpStackLocation(Irp);
1613 assert(Stack != NULL);
1614 FileObject = Stack->FileObject;
1615 assert(FileObject != NULL);
1616 DeviceExt = DeviceObject->DeviceExtension;
1617 assert(DeviceExt != NULL);
1618
1619 Length = Stack->Parameters.Read.Length;
1620 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1621 Offset = Stack->Parameters.Read.ByteOffset.u.LowPart;
1622
1623 Status = FsdReadFile(DeviceExt,FileObject,Buffer,Length,Offset,
1624 &LengthRead);
1625
1626 Irp->IoStatus.Status = Status;
1627 Irp->IoStatus.Information = LengthRead;
1628 IoCompleteRequest(Irp,IO_NO_INCREMENT);
1629
1630 return(Status);
1631 }
1632
1633
1634 NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount)
1635 /*
1636 * FUNCTION: Mount the filesystem
1637 */
1638 {
1639 PDEVICE_OBJECT DeviceObject;
1640 PDEVICE_EXTENSION DeviceExt;
1641
1642 IoCreateDevice(VFATDriverObject,
1643 sizeof(DEVICE_EXTENSION),
1644 NULL,
1645 FILE_DEVICE_FILE_SYSTEM,
1646 0,
1647 FALSE,
1648 &DeviceObject);
1649 DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
1650 DeviceExt = (PVOID)DeviceObject->DeviceExtension;
1651 // use same vpb as device disk
1652 DeviceObject->Vpb=DeviceToMount->Vpb;
1653 FsdMountDevice(DeviceExt,DeviceToMount);
1654 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
1655 DeviceExt->StorageDevice = IoAttachDeviceToDeviceStack(DeviceObject,
1656 DeviceToMount);
1657
1658 /* read serial number */
1659 if (DeviceExt->FatType == FAT12 || DeviceExt->FatType == FAT16)
1660 DeviceObject->Vpb->SerialNumber =
1661 ((struct _BootSector *)(DeviceExt->Boot))->VolumeID;
1662 else if (DeviceExt->FatType == FAT32)
1663 DeviceObject->Vpb->SerialNumber =
1664 ((struct _BootSector32 *)(DeviceExt->Boot))->VolumeID;
1665
1666 /* read volume label */
1667 ReadVolumeLabel (DeviceExt, DeviceObject->Vpb);
1668
1669 return(STATUS_SUCCESS);
1670 }
1671
1672 NTSTATUS FsdFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1673 /*
1674 * FUNCTION: File system control
1675 */
1676 {
1677 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1678 // PVPB vpb = Stack->Parameters.Mount.Vpb;
1679 PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject;
1680 NTSTATUS Status;
1681
1682 // DPRINT("VFAT FSC\n");
1683 DbgPrint("VFAT FSC\n");
1684
1685 /* FIXME: should make sure that this is actually a mount request! */
1686
1687 if (FsdHasFileSystem(DeviceToMount))
1688 {
1689 Status = FsdMount(DeviceToMount);
1690 }
1691 else
1692 {
1693 DPRINT("VFAT: Unrecognized Volume\n");
1694 Status = STATUS_UNRECOGNIZED_VOLUME;
1695 }
1696 DPRINT("VFAT File system successfully mounted\n");
1697
1698 Irp->IoStatus.Status = Status;
1699 Irp->IoStatus.Information = 0;
1700
1701 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1702 return(Status);
1703 }
1704
1705 NTSTATUS FsdGetStandardInformation(PVfatFCB FCB, PDEVICE_OBJECT DeviceObject,
1706 PFILE_STANDARD_INFORMATION StandardInfo)
1707 /*
1708 * FUNCTION: Retrieve the standard file information
1709 */
1710 {
1711 PDEVICE_EXTENSION DeviceExtension;
1712 unsigned long AllocSize;
1713
1714 DeviceExtension = DeviceObject->DeviceExtension;
1715 /* PRECONDITION */
1716 assert(DeviceExtension != NULL);
1717 assert(DeviceExtension->BytesPerCluster != 0);
1718 assert(StandardInfo != NULL);
1719 assert(FCB != NULL);
1720
1721 RtlZeroMemory(StandardInfo, sizeof(FILE_STANDARD_INFORMATION));
1722
1723 /* Make allocsize a rounded up multiple of BytesPerCluster */
1724 AllocSize = ((FCB->entry.FileSize + DeviceExtension->BytesPerCluster - 1) /
1725 DeviceExtension->BytesPerCluster) *
1726 DeviceExtension->BytesPerCluster;
1727
1728 StandardInfo->AllocationSize = RtlConvertUlongToLargeInteger(AllocSize);
1729 StandardInfo->EndOfFile = RtlConvertUlongToLargeInteger(FCB->entry.FileSize);
1730 StandardInfo->NumberOfLinks = 0;
1731 StandardInfo->DeletePending = FALSE;
1732 if((FCB->entry.Attrib & 0x10)>0) {
1733 StandardInfo->Directory = TRUE;
1734 } else {
1735 StandardInfo->Directory = FALSE;
1736 }
1737
1738 return STATUS_SUCCESS;
1739 }
1740
1741 NTSTATUS FsdSetPositionInformation(PFILE_OBJECT FileObject,
1742 PVfatFCB FCB,
1743 PDEVICE_OBJECT DeviceObject,
1744 PFILE_POSITION_INFORMATION PositionInfo)
1745 {
1746 DPRINT("FsdSetPositionInformation()\n");
1747
1748 DPRINT("PositionInfo %x\n", PositionInfo);
1749 DPRINT("Setting position %d\n", PositionInfo->CurrentByteOffset.LowPart);
1750 memcpy(&FileObject->CurrentByteOffset,&PositionInfo->CurrentByteOffset,
1751 sizeof(LARGE_INTEGER));
1752
1753 return(STATUS_SUCCESS);
1754 }
1755
1756 NTSTATUS FsdGetPositionInformation(PFILE_OBJECT FileObject,
1757 PVfatFCB FCB,
1758 PDEVICE_OBJECT DeviceObject,
1759 PFILE_POSITION_INFORMATION PositionInfo)
1760 {
1761 DPRINT("FsdGetPositionInformation()\n");
1762
1763 memcpy(&PositionInfo->CurrentByteOffset, &FileObject->CurrentByteOffset,
1764 sizeof(LARGE_INTEGER));
1765 DPRINT("Getting position %x\n", PositionInfo->CurrentByteOffset.LowPart);
1766 return(STATUS_SUCCESS);
1767 }
1768
1769 NTSTATUS FsdGetBasicInformation(PFILE_OBJECT FileObject,
1770 PVfatFCB FCB,
1771 PDEVICE_OBJECT DeviceObject,
1772 PFILE_BASIC_INFORMATION BasicInfo)
1773 {
1774 DPRINT("FsdGetBasicInformation()\n");
1775
1776 FsdDosDateTimeToFileTime(FCB->entry.CreationDate,FCB->entry.CreationTime,
1777 &BasicInfo->CreationTime);
1778 FsdDosDateTimeToFileTime(FCB->entry.AccessDate,0,
1779 &BasicInfo->LastAccessTime);
1780 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
1781 &BasicInfo->LastWriteTime);
1782 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,FCB->entry.UpdateTime,
1783 &BasicInfo->ChangeTime);
1784
1785 BasicInfo->FileAttributes = FCB->entry.Attrib;
1786
1787 DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
1788
1789 return(STATUS_SUCCESS);
1790 }
1791
1792
1793 NTSTATUS FsdQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1794 /*
1795 * FUNCTION: Retrieve the specified file information
1796 */
1797 {
1798 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1799 FILE_INFORMATION_CLASS FileInformationClass =
1800 Stack->Parameters.QueryFile.FileInformationClass;
1801 PFILE_OBJECT FileObject = NULL;
1802 PVfatFCB FCB = NULL;
1803 // PVfatCCB CCB = NULL;
1804
1805 NTSTATUS RC = STATUS_SUCCESS;
1806 void *SystemBuffer;
1807
1808 /* PRECONDITION */
1809 assert(DeviceObject != NULL);
1810 assert(Irp != NULL);
1811
1812 /* INITIALIZATION */
1813 Stack = IoGetCurrentIrpStackLocation(Irp);
1814 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
1815 FileObject = Stack->FileObject;
1816 // CCB = (PVfatCCB)(FileObject->FsContext2);
1817 // FCB = CCB->Buffer; // Should be CCB->FCB???
1818 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1819
1820 // FIXME : determine Buffer for result :
1821 if (Irp->MdlAddress)
1822 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1823 else
1824 SystemBuffer = Irp->UserBuffer;
1825 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1826
1827 switch(FileInformationClass) {
1828 case FileStandardInformation:
1829 RC = FsdGetStandardInformation(FCB, DeviceObject, SystemBuffer);
1830 break;
1831 case FilePositionInformation:
1832 RC = FsdGetPositionInformation(FileObject,
1833 FCB,
1834 DeviceObject,
1835 SystemBuffer);
1836 break;
1837 case FileBasicInformation:
1838 RC = FsdGetBasicInformation(FileObject,
1839 FCB,
1840 DeviceObject,
1841 SystemBuffer);
1842 break;
1843 default:
1844 RC=STATUS_NOT_IMPLEMENTED;
1845 }
1846
1847 Irp->IoStatus.Status = RC;
1848 Irp->IoStatus.Information = 0;
1849 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1850
1851 return RC;
1852 }
1853
1854 NTSTATUS FsdSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1855 /*
1856 * FUNCTION: Retrieve the specified file information
1857 */
1858 {
1859 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1860 FILE_INFORMATION_CLASS FileInformationClass;
1861 PFILE_OBJECT FileObject = NULL;
1862 PVfatFCB FCB = NULL;
1863 // PVfatCCB CCB = NULL;
1864 NTSTATUS RC = STATUS_SUCCESS;
1865 PVOID SystemBuffer;
1866
1867 /* PRECONDITION */
1868 assert(DeviceObject != NULL);
1869 assert(Irp != NULL);
1870
1871 DPRINT("FsdSetInformation(DeviceObject %x, Irp %x)\n",
1872 DeviceObject,Irp);
1873
1874 /* INITIALIZATION */
1875 Stack = IoGetCurrentIrpStackLocation(Irp);
1876 FileInformationClass = Stack->Parameters.SetFile.FileInformationClass;
1877 FileObject = Stack->FileObject;
1878 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
1879
1880 // FIXME : determine Buffer for result :
1881 if (Irp->MdlAddress)
1882 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
1883 else
1884 SystemBuffer = Irp->UserBuffer;
1885 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
1886
1887 DPRINT("FileInformationClass %d\n",FileInformationClass);
1888 DPRINT("SystemBuffer %x\n",SystemBuffer);
1889
1890 switch(FileInformationClass)
1891 {
1892 case FilePositionInformation:
1893 RC = FsdSetPositionInformation(FileObject,
1894 FCB,
1895 DeviceObject,
1896 SystemBuffer);
1897 break;
1898 default:
1899 RC = STATUS_NOT_IMPLEMENTED;
1900 }
1901
1902 Irp->IoStatus.Status = RC;
1903 Irp->IoStatus.Information = 0;
1904 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1905
1906 return RC;
1907 }
1908
1909
1910
1911 NTSTATUS FsdGetFsVolumeInformation(PFILE_OBJECT FileObject,
1912 PVfatFCB FCB,
1913 PDEVICE_OBJECT DeviceObject,
1914 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo)
1915 {
1916 DPRINT("FsdGetFsVolumeInformation()\n");
1917 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
1918
1919 if (!FsVolumeInfo)
1920 return(STATUS_SUCCESS);
1921
1922
1923 /* valid entries */
1924 FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
1925 FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
1926 wcscpy (FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel);
1927
1928 /* dummy entries */
1929 FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
1930 FsVolumeInfo->SupportsObjects = FALSE;
1931
1932 DPRINT("Finished FsdGetFsVolumeInformation()\n");
1933
1934 return(STATUS_SUCCESS);
1935 }
1936
1937
1938 NTSTATUS FsdGetFsAttributeInformation(PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo)
1939 {
1940 DPRINT("FsdGetFsAttributeInformation()\n");
1941 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
1942
1943 if (!FsAttributeInfo)
1944 return(STATUS_SUCCESS);
1945
1946 FsAttributeInfo->FileSystemAttributes = FS_CASE_IS_PRESERVED;
1947 FsAttributeInfo->MaximumComponentNameLength = 255;
1948 FsAttributeInfo->FileSystemNameLength = 3;
1949 wcscpy (FsAttributeInfo->FileSystemName, L"FAT");
1950
1951 DPRINT("Finished FsdGetFsAttributeInformation()\n");
1952
1953 return(STATUS_SUCCESS);
1954 }
1955
1956 NTSTATUS FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
1957 PFILE_FS_SIZE_INFORMATION FsSizeInfo)
1958 {
1959 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
1960
1961 DPRINT("FsdGetFsSizeInformation()\n");
1962 DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
1963
1964 if (!FsSizeInfo)
1965 return(STATUS_SUCCESS);
1966
1967 if (DeviceExt->FatType == FAT32)
1968 {
1969 struct _BootSector32 *BootSect = (struct _BootSector32 *)DeviceExt->Boot;
1970
1971 if (BootSect->Sectors)
1972 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
1973 else
1974 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
1975
1976 FsSizeInfo->AvailableAllocationUnits.QuadPart =
1977 FAT32CountAvailableClusters(DeviceExt);
1978
1979 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
1980 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
1981 }
1982 else
1983 {
1984 struct _BootSector *BootSect = (struct _BootSector *)DeviceExt->Boot;
1985
1986 if (BootSect->Sectors)
1987 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->Sectors;
1988 else
1989 FsSizeInfo->TotalAllocationUnits.QuadPart = BootSect->SectorsHuge;
1990
1991 if (DeviceExt->FatType == FAT16)
1992 FsSizeInfo->AvailableAllocationUnits.QuadPart =
1993 FAT16CountAvailableClusters(DeviceExt);
1994 else
1995 FsSizeInfo->AvailableAllocationUnits.QuadPart =
1996 FAT12CountAvailableClusters(DeviceExt);
1997
1998 FsSizeInfo->SectorsPerAllocationUnit = BootSect->SectorsPerCluster;
1999 FsSizeInfo->BytesPerSector = BootSect->BytesPerSector;
2000 }
2001
2002 DPRINT("Finished FsdGetFsSizeInformation()\n");
2003
2004 return(STATUS_SUCCESS);
2005 }
2006
2007
2008 NTSTATUS FsdQueryVolumeInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
2009 /*
2010 * FUNCTION: Retrieve the specified file information
2011 */
2012 {
2013 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
2014 FILE_INFORMATION_CLASS FileInformationClass =
2015 Stack->Parameters.QueryVolume.FileInformationClass;
2016 PFILE_OBJECT FileObject = NULL;
2017 PVfatFCB FCB = NULL;
2018 // PVfatCCB CCB = NULL;
2019
2020 NTSTATUS RC = STATUS_SUCCESS;
2021 void *SystemBuffer;
2022
2023 /* PRECONDITION */
2024 assert(DeviceObject != NULL);
2025 assert(Irp != NULL);
2026
2027 DPRINT("FsdQueryVolumeInformation(DeviceObject %x, Irp %x)\n",
2028 DeviceObject,Irp);
2029
2030 /* INITIALIZATION */
2031 Stack = IoGetCurrentIrpStackLocation(Irp);
2032 FileInformationClass = Stack->Parameters.QueryVolume.FileInformationClass;
2033 FileObject = Stack->FileObject;
2034 // CCB = (PVfatCCB)(FileObject->FsContext2);
2035 // FCB = CCB->Buffer; // Should be CCB->FCB???
2036 FCB = ((PVfatCCB)(FileObject->FsContext2))->pFcb;
2037
2038 // FIXME : determine Buffer for result :
2039 if (Irp->MdlAddress)
2040 SystemBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2041 else
2042 SystemBuffer = Irp->UserBuffer;
2043 // SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
2044
2045 DPRINT("FileInformationClass %d\n",FileInformationClass);
2046 DPRINT("SystemBuffer %x\n",SystemBuffer);
2047
2048 switch (FileInformationClass)
2049 {
2050 case FileFsVolumeInformation:
2051 RC = FsdGetFsVolumeInformation(FileObject,
2052 FCB,
2053 DeviceObject,
2054 SystemBuffer);
2055 break;
2056
2057 case FileFsAttributeInformation:
2058 RC = FsdGetFsAttributeInformation(SystemBuffer);
2059 break;
2060
2061 case FileFsSizeInformation:
2062 RC = FsdGetFsSizeInformation(DeviceObject, SystemBuffer);
2063 break;
2064
2065 default:
2066 RC=STATUS_NOT_IMPLEMENTED;
2067 }
2068
2069 Irp->IoStatus.Status = RC;
2070 Irp->IoStatus.Information = 0;
2071 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2072
2073 return RC;
2074 }
2075
2076
2077 STDCALL NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject,
2078 PUNICODE_STRING RegistryPath)
2079 /*
2080 * FUNCTION: Called by the system to initalize the driver
2081 * ARGUMENTS:
2082 * DriverObject = object describing this driver
2083 * RegistryPath = path to our configuration entries
2084 * RETURNS: Success or failure
2085 */
2086 {
2087 PDEVICE_OBJECT DeviceObject;
2088 NTSTATUS ret;
2089 UNICODE_STRING ustr;
2090 ANSI_STRING astr;
2091
2092 DbgPrint("VFAT 0.0.6\n");
2093 pFirstFcb=NULL;
2094 VFATDriverObject = _DriverObject;
2095
2096 RtlInitAnsiString(&astr,"\\Device\\VFAT");
2097 RtlAnsiStringToUnicodeString(&ustr,&astr,TRUE);
2098 ret = IoCreateDevice(VFATDriverObject,0,&ustr,
2099 FILE_DEVICE_FILE_SYSTEM,0,FALSE,&DeviceObject);
2100 if (ret!=STATUS_SUCCESS)
2101 {
2102 return(ret);
2103 }
2104
2105 DeviceObject->Flags = DO_DIRECT_IO;
2106 VFATDriverObject->MajorFunction[IRP_MJ_CLOSE] = FsdClose;
2107 VFATDriverObject->MajorFunction[IRP_MJ_CREATE] = FsdCreate;
2108 VFATDriverObject->MajorFunction[IRP_MJ_READ] = FsdRead;
2109 VFATDriverObject->MajorFunction[IRP_MJ_WRITE] = FsdWrite;
2110 VFATDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
2111 FsdFileSystemControl;
2112 VFATDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
2113 FsdQueryInformation;
2114 VFATDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
2115 FsdSetInformation;
2116 VFATDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
2117 FsdDirectoryControl;
2118 VFATDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
2119 FsdQueryVolumeInformation;
2120
2121 VFATDriverObject->DriverUnload = NULL;
2122
2123 IoRegisterFileSystem(DeviceObject);
2124
2125 return(STATUS_SUCCESS);
2126 }
2127