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