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