All:
[reactos.git] / reactos / drivers / fs / vfat / fat.c
1 /*
2 * $Id: fat.c,v 1.36 2002/03/18 22:37:12 hbirr Exp $
3 *
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/fat.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 *
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <wchar.h>
16 #include <ntos/minmax.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /* GLOBALS ******************************************************************/
24
25 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
26
27 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGESIZE ? \
28 (pDeviceExt)->FatInfo.BytesPerCluster : PAGESIZE)
29
30 /* FUNCTIONS ****************************************************************/
31
32 NTSTATUS
33 Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt,
34 ULONG CurrentCluster,
35 PULONG NextCluster)
36 /*
37 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
38 * disk read
39 */
40 {
41 PVOID BaseAddress;
42 NTSTATUS Status;
43 ULONG FATOffset;
44 ULONG ChunkSize;
45 PVOID Context;
46 LARGE_INTEGER Offset;
47
48 ChunkSize = CACHEPAGESIZE(DeviceExt);
49 FATOffset = CurrentCluster * sizeof(ULONG);
50 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
51 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
52 {
53 return STATUS_UNSUCCESSFUL;
54 }
55 CurrentCluster = (*(PULONG)(BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
56 if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
57 CurrentCluster = 0xffffffff;
58 CcUnpinData(Context);
59 *NextCluster = CurrentCluster;
60 return (STATUS_SUCCESS);
61 }
62
63 NTSTATUS
64 Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt,
65 ULONG CurrentCluster,
66 PULONG NextCluster)
67 /*
68 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
69 */
70 {
71 PVOID BaseAddress;
72 NTSTATUS Status;
73 ULONG FATOffset;
74 ULONG ChunkSize;
75 PVOID Context;
76 LARGE_INTEGER Offset;
77
78 ChunkSize = CACHEPAGESIZE(DeviceExt);
79 FATOffset = CurrentCluster * 2;
80 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
81 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
82 {
83 return STATUS_UNSUCCESSFUL;
84 }
85 CurrentCluster = *((PUSHORT)(BaseAddress + (FATOffset % ChunkSize)));
86 if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
87 CurrentCluster = 0xffffffff;
88 CcUnpinData(Context);
89 *NextCluster = CurrentCluster;
90 return (STATUS_SUCCESS);
91 }
92
93 NTSTATUS
94 Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt,
95 ULONG CurrentCluster,
96 PULONG NextCluster)
97 /*
98 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
99 */
100 {
101 PUSHORT CBlock;
102 ULONG FATOffset;
103 ULONG Entry;
104 NTSTATUS Status;
105 PVOID BaseAddress;
106 PVOID Context;
107 LARGE_INTEGER Offset;
108
109
110 *NextCluster = 0;
111
112 Offset.QuadPart = 0;
113 if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * BLOCKSIZE, 1, &Context, &BaseAddress))
114 {
115 return STATUS_UNSUCCESSFUL;
116 }
117 CBlock = (PUSHORT)(BaseAddress + (CurrentCluster * 12) / 8);
118 if ((CurrentCluster % 2) == 0)
119 {
120 Entry = *CBlock & 0x0fff;
121 }
122 else
123 {
124 Entry = *CBlock >> 4;
125 }
126 // DPRINT("Entry %x\n",Entry);
127 if (Entry >= 0xff8 && Entry <= 0xfff)
128 Entry = 0xffffffff;
129 // DPRINT("Returning %x\n",Entry);
130 *NextCluster = Entry;
131 CcUnpinData(Context);
132 // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
133 return STATUS_SUCCESS;
134 }
135
136 NTSTATUS
137 FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt,
138 PULONG Cluster)
139 /*
140 * FUNCTION: Finds the first available cluster in a FAT16 table
141 */
142 {
143 ULONG FatLength;
144 ULONG StartCluster;
145 ULONG i, j;
146 NTSTATUS Status;
147 PVOID BaseAddress;
148 ULONG ChunkSize;
149 PVOID Context = 0;
150 LARGE_INTEGER Offset;
151 PUSHORT Block;
152
153 ChunkSize = CACHEPAGESIZE(DeviceExt);
154 FatLength = (DeviceExt->FatInfo.NumberOfClusters +2 ) * 2;
155 *Cluster = 0;
156 StartCluster = DeviceExt->LastAvailableCluster;
157
158 for (j = 0; j < 2; j++)
159 {
160 for (i = StartCluster * 2; i < FatLength; i += 2, Block++)
161 {
162 if ((i % ChunkSize) == 0 || Context == NULL)
163 {
164 Offset.QuadPart = ROUND_DOWN(i, ChunkSize);
165 if (Context != NULL)
166 {
167 CcUnpinData(Context);
168 }
169 CHECKPOINT;
170 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
171 {
172 DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
173 return STATUS_UNSUCCESSFUL;
174 }
175 CHECKPOINT;
176 Block = (PUSHORT)(BaseAddress + i % ChunkSize);
177 }
178
179 if (*Block == 0)
180 {
181 DPRINT("Found available cluster 0x%x\n", i / 2);
182 DeviceExt->LastAvailableCluster = *Cluster = i / 2;
183 CcUnpinData(Context);
184 return(STATUS_SUCCESS);
185 }
186 }
187 FatLength = StartCluster * 2;
188 StartCluster = 2;
189 if (Context != NULL)
190 {
191 CcUnpinData(Context);
192 Context =NULL;
193 }
194 }
195 return(STATUS_DISK_FULL);
196 }
197
198 NTSTATUS
199 FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
200 /*
201 * FUNCTION: Finds the first available cluster in a FAT12 table
202 */
203 {
204 ULONG FatLength;
205 ULONG FATOffset;
206 ULONG StartCluster;
207 ULONG Entry;
208 PUSHORT CBlock;
209 ULONG i, j;
210 PVOID BaseAddress;
211 NTSTATUS Status;
212 PVOID Context;
213 LARGE_INTEGER Offset;
214
215 FatLength = DeviceExt->FatInfo.NumberOfClusters + 2;
216 *Cluster = 0;
217 StartCluster = DeviceExt->LastAvailableCluster;
218 Offset.QuadPart = 0;
219 if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * BLOCKSIZE, 1, &Context, &BaseAddress))
220 {
221 DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * BLOCKSIZE);
222 return STATUS_UNSUCCESSFUL;
223 }
224
225 for (j = 0; j < 2; j++)
226 {
227 for (i = StartCluster; i < FatLength; i++)
228 {
229 CBlock = (PUSHORT)(BaseAddress + (i * 12) / 8);
230 if ((i % 2) == 0)
231 {
232 Entry = *CBlock & 0xfff;
233 }
234 else
235 {
236 Entry = *CBlock >> 4;
237 }
238 if (Entry == 0)
239 {
240 DPRINT("Found available cluster 0x%x\n", i);
241 DeviceExt->LastAvailableCluster = *Cluster = i;
242 CcUnpinData(Context);
243 return(STATUS_SUCCESS);
244 }
245 }
246 FatLength = StartCluster;
247 StartCluster = 2;
248 }
249 CcUnpinData(Context);
250 return (STATUS_DISK_FULL);
251 }
252
253 NTSTATUS
254 FAT32FindAvailableCluster (PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
255 /*
256 * FUNCTION: Finds the first available cluster in a FAT32 table
257 */
258 {
259 ULONG FatLength;
260 ULONG StartCluster;
261 ULONG i, j;
262 NTSTATUS Status;
263 PVOID BaseAddress;
264 ULONG ChunkSize;
265 PVOID Context = 0;
266 LARGE_INTEGER Offset;
267 PULONG Block;
268
269 ChunkSize = CACHEPAGESIZE(DeviceExt);
270 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2) * 4;
271 *Cluster = 0;
272 StartCluster = DeviceExt->LastAvailableCluster;
273
274 for (j = 0; j < 2; j++)
275 {
276 for (i = StartCluster * 4; i < FatLength; i += 4, Block++)
277 {
278 if ((i % ChunkSize) == 0 || Context == NULL)
279 {
280 Offset.QuadPart = ROUND_DOWN(i, ChunkSize);
281 if (Context != NULL)
282 {
283 CcUnpinData(Context);
284 }
285 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
286 {
287 DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
288 return STATUS_UNSUCCESSFUL;
289 }
290 Block = (PULONG)(BaseAddress + i % ChunkSize);
291 }
292
293 if ((*Block & 0x0fffffff) == 0)
294 {
295 DPRINT("Found available cluster 0x%x\n", i / 4);
296 DeviceExt->LastAvailableCluster = *Cluster = i / 4;
297 CcUnpinData(Context);
298 return(STATUS_SUCCESS);
299 }
300 }
301 FatLength = StartCluster * 4;
302 StartCluster = 2;
303 if (Context != NULL)
304 {
305 CcUnpinData(Context);
306 Context=NULL;
307 }
308 }
309 return (STATUS_DISK_FULL);
310 }
311
312
313 NTSTATUS
314 FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
315 /*
316 * FUNCTION: Counts free cluster in a FAT12 table
317 */
318 {
319 ULONG FATOffset;
320 ULONG Entry;
321 PVOID BaseAddress;
322 ULONG ulCount = 0;
323 ULONG i;
324 NTSTATUS Status;
325 ULONG numberofclusters;
326 LARGE_INTEGER Offset;
327 PVOID Context;
328 PUSHORT CBlock;
329
330 Offset.QuadPart = 0;
331 if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * BLOCKSIZE, 1, &Context, &BaseAddress))
332 {
333 return STATUS_UNSUCCESSFUL;
334 }
335
336 numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;
337
338 for (i = 2; i < numberofclusters; i++)
339 {
340 CBlock = (PUSHORT)(BaseAddress + (i * 12) / 8);
341 if ((i % 2) == 0)
342 {
343 Entry = *CBlock & 0x0fff;
344 }
345 else
346 {
347 Entry = *CBlock >> 4;
348 }
349 if (Entry == 0)
350 ulCount++;
351 }
352
353 CcUnpinData(Context);
354 DeviceExt->AvailableClusters = ulCount;
355 DeviceExt->AvailableClustersValid = TRUE;
356
357 return(STATUS_SUCCESS);
358 }
359
360
361 NTSTATUS
362 FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
363 /*
364 * FUNCTION: Counts free clusters in a FAT16 table
365 */
366 {
367 PUSHORT Block;
368 PVOID BaseAddress = NULL;
369 ULONG ulCount = 0;
370 ULONG i;
371 ULONG ChunkSize;
372 NTSTATUS Status;
373 PVOID Context = NULL;
374 LARGE_INTEGER Offset;
375 ULONG FatLength;
376
377 ChunkSize = CACHEPAGESIZE(DeviceExt);
378 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2) * 2;
379
380 for (i = 4; i< FatLength; i += 2, Block++)
381 {
382 if ((i % ChunkSize) == 0 || Context == NULL)
383 {
384 DPRINT("%d\n", i/2);
385 if (Context)
386 {
387 CcUnpinData(Context);
388 }
389 Offset.QuadPart = ROUND_DOWN(i, ChunkSize);
390 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
391 {
392 return STATUS_UNSUCCESSFUL;
393 }
394 Block = (PUSHORT)(BaseAddress + i % ChunkSize);
395 }
396 if (*Block == 0)
397 ulCount++;
398 }
399
400 DeviceExt->AvailableClusters = ulCount;
401 DeviceExt->AvailableClustersValid = TRUE;
402 CcUnpinData(Context);
403
404 return(STATUS_SUCCESS);
405 }
406
407
408 NTSTATUS
409 FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
410 /*
411 * FUNCTION: Counts free clusters in a FAT32 table
412 */
413 {
414 PULONG Block;
415 PVOID BaseAddress = NULL;
416 ULONG ulCount = 0;
417 ULONG i;
418 ULONG ChunkSize;
419 NTSTATUS Status;
420 PVOID Context = NULL;
421 LARGE_INTEGER Offset;
422 ULONG FatLength;
423
424 ChunkSize = CACHEPAGESIZE(DeviceExt);
425 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2) * 4;
426
427 for (i = 8; i< FatLength; i += 4, Block++)
428 {
429 if ((i % ChunkSize) == 0 || Context == NULL)
430 {
431 if (Context)
432 {
433 CcUnpinData(Context);
434 }
435 Offset.QuadPart = ROUND_DOWN(i, ChunkSize);
436 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
437 {
438 return STATUS_UNSUCCESSFUL;
439 }
440 Block = (PULONG)(BaseAddress + i % ChunkSize);
441 }
442 if ((*Block & 0x0fffffff) == 0)
443 ulCount++;
444 }
445
446 DeviceExt->AvailableClusters = ulCount;
447 DeviceExt->AvailableClustersValid = TRUE;
448 CcUnpinData(Context);
449
450 return(STATUS_SUCCESS);
451 }
452
453 NTSTATUS
454 CountAvailableClusters(PDEVICE_EXTENSION DeviceExt,
455 PLARGE_INTEGER Clusters)
456 {
457 NTSTATUS Status = STATUS_SUCCESS;
458 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
459 if (!DeviceExt->AvailableClustersValid)
460 {
461 if (DeviceExt->FatInfo.FatType == FAT12)
462 Status = FAT12CountAvailableClusters(DeviceExt);
463 else if (DeviceExt->FatInfo.FatType == FAT16)
464 Status = FAT16CountAvailableClusters(DeviceExt);
465 else
466 Status = FAT32CountAvailableClusters(DeviceExt);
467 }
468 Clusters->QuadPart = DeviceExt->AvailableClusters;
469 ExReleaseResourceLite (&DeviceExt->FatResource);
470
471 return Status;
472 }
473
474
475
476
477
478 NTSTATUS
479 FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt,
480 ULONG ClusterToWrite,
481 ULONG NewValue,
482 PULONG OldValue)
483 /*
484 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
485 */
486 {
487 ULONG FATsector;
488 ULONG FATOffset;
489 PUCHAR CBlock;
490 int i;
491 NTSTATUS Status;
492 PVOID BaseAddress;
493 PVOID Context;
494 LARGE_INTEGER Offset;
495
496 Offset.QuadPart = 0;
497 if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * BLOCKSIZE, 1, &Context, &BaseAddress))
498 {
499 return STATUS_UNSUCCESSFUL;
500 }
501 CBlock = (PUCHAR)BaseAddress;
502
503 FATOffset = (ClusterToWrite * 12) / 8;
504 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
505 NewValue, ClusterToWrite, FATOffset);
506 if ((ClusterToWrite % 2) == 0)
507 {
508 *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
509 CBlock[FATOffset] = NewValue;
510 CBlock[FATOffset + 1] &= 0xf0;
511 CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
512 }
513 else
514 {
515 *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
516 CBlock[FATOffset] &= 0x0f;
517 CBlock[FATOffset] |= (NewValue & 0xf) << 4;
518 CBlock[FATOffset + 1] = NewValue >> 4;
519 }
520 /* Write the changed FAT sector(s) to disk */
521 FATsector = FATOffset / BLOCKSIZE;
522 CcSetDirtyPinnedData(Context, NULL);
523 CcUnpinData(Context);
524 return(STATUS_SUCCESS);
525 }
526
527 NTSTATUS
528 FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt,
529 ULONG ClusterToWrite,
530 ULONG NewValue,
531 PULONG OldValue)
532 /*
533 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
534 */
535 {
536 PVOID BaseAddress;
537 NTSTATUS Status;
538 ULONG FATOffset;
539 ULONG i;
540 ULONG ChunkSize;
541 PVOID Context;
542 LARGE_INTEGER Offset;
543 PUSHORT Cluster;
544
545 ChunkSize = CACHEPAGESIZE(DeviceExt);
546 FATOffset = ClusterToWrite * 2;
547 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
548 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
549 {
550 return STATUS_UNSUCCESSFUL;
551 }
552 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
553 ClusterToWrite);
554 Cluster = ((PUSHORT)(BaseAddress + (FATOffset % ChunkSize)));
555 *OldValue = *Cluster;
556 *Cluster = NewValue;
557 CcSetDirtyPinnedData(Context, NULL);
558 CcUnpinData(Context);
559 return(STATUS_SUCCESS);
560 }
561
562 NTSTATUS
563 FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt,
564 ULONG ClusterToWrite,
565 ULONG NewValue,
566 PULONG OldValue)
567 /*
568 * FUNCTION: Writes a cluster to the FAT32 physical tables
569 */
570 {
571 PVOID BaseAddress;
572 NTSTATUS Status;
573 ULONG FATOffset;
574 ULONG i;
575 ULONG ChunkSize;
576 PVOID Context;
577 LARGE_INTEGER Offset;
578 PULONG Cluster;
579
580 ChunkSize = CACHEPAGESIZE(DeviceExt);
581
582 FATOffset = (ClusterToWrite * 4);
583 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
584 if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
585 {
586 return STATUS_UNSUCCESSFUL;
587 }
588 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
589 ClusterToWrite);
590 Cluster = ((PULONG)(BaseAddress + (FATOffset % ChunkSize)));
591 *OldValue = *Cluster & 0x0fffffff;
592 *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
593
594 CcSetDirtyPinnedData(Context, NULL);
595 CcUnpinData(Context);
596
597 return(STATUS_SUCCESS);
598 }
599
600
601 NTSTATUS
602 WriteCluster(PDEVICE_EXTENSION DeviceExt,
603 ULONG ClusterToWrite,
604 ULONG NewValue)
605 /*
606 * FUNCTION: Write a changed FAT entry
607 */
608 {
609 NTSTATUS Status;
610 ULONG OldValue;
611 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
612 if (DeviceExt->FatInfo.FatType == FAT16)
613 {
614 Status = FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
615 }
616 else if (DeviceExt->FatInfo.FatType == FAT32)
617 {
618 Status = FAT32WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
619 }
620 else
621 {
622 Status = FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
623 }
624 if (DeviceExt->AvailableClustersValid)
625 {
626 if (OldValue && NewValue == 0)
627 InterlockedIncrement(&DeviceExt->AvailableClusters);
628 else if (OldValue == 0 && NewValue)
629 InterlockedDecrement(&DeviceExt->AvailableClusters);
630 }
631 ExReleaseResourceLite(&DeviceExt->FatResource);
632 return(Status);
633 }
634
635 ULONG
636 ClusterToSector(PDEVICE_EXTENSION DeviceExt,
637 ULONG Cluster)
638 /*
639 * FUNCTION: Converts the cluster number to a sector number for this physical
640 * device
641 */
642 {
643 return DeviceExt->FatInfo.dataStart +
644 ((Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
645 }
646
647 NTSTATUS
648 VfatRawReadCluster(PDEVICE_EXTENSION DeviceExt,
649 ULONG FirstCluster,
650 PVOID Buffer,
651 ULONG Cluster,
652 ULONG Count)
653 /*
654 * FUNCTION: Load one ore more continus clusters from the physical device
655 */
656 {
657
658 if (FirstCluster == 1)
659 {
660 return VfatReadSectors(DeviceExt->StorageDevice, Cluster,
661 DeviceExt->FatInfo.SectorsPerCluster * Count, Buffer);
662 }
663 else
664 {
665 ULONG Sector;
666
667 Sector = ClusterToSector(DeviceExt, Cluster);
668 return VfatReadSectors(DeviceExt->StorageDevice, Sector,
669 DeviceExt->FatInfo.SectorsPerCluster * Count, Buffer);
670 }
671 }
672
673 NTSTATUS
674 VfatRawWriteCluster(PDEVICE_EXTENSION DeviceExt,
675 ULONG FirstCluster,
676 PVOID Buffer,
677 ULONG Cluster,
678 ULONG Count)
679 /*
680 * FUNCTION: Write a cluster to the physical device
681 */
682 {
683 ULONG Sector;
684 NTSTATUS Status;
685
686 DPRINT("VfatWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
687 DeviceExt, Buffer, Cluster);
688
689 if (FirstCluster == 1)
690 {
691 Status = VfatWriteSectors(DeviceExt->StorageDevice, Cluster,
692 DeviceExt->FatInfo.SectorsPerCluster * Count, Buffer);
693 }
694 else
695 {
696 Sector = ClusterToSector(DeviceExt, Cluster);
697
698 Status = VfatWriteSectors(DeviceExt->StorageDevice, Sector,
699 DeviceExt->FatInfo.SectorsPerCluster * Count, Buffer);
700 }
701 return(Status);
702 }
703
704 NTSTATUS
705 GetNextCluster(PDEVICE_EXTENSION DeviceExt,
706 ULONG CurrentCluster,
707 PULONG NextCluster,
708 BOOLEAN Extend)
709 /*
710 * FUNCTION: Retrieve the next cluster depending on the FAT type
711 */
712 {
713 NTSTATUS Status;
714
715 DPRINT ("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
716 DeviceExt, CurrentCluster);
717
718 if (!Extend)
719 {
720 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
721 }
722 else
723 {
724 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
725 }
726 CHECKPOINT;
727 /*
728 * If the file hasn't any clusters allocated then we need special
729 * handling
730 */
731 if (CurrentCluster == 0 && Extend)
732 {
733 ULONG NewCluster;
734
735 if (DeviceExt->FatInfo.FatType == FAT16)
736 {
737 CHECKPOINT;
738 Status = FAT16FindAvailableCluster(DeviceExt, &NewCluster);
739 CHECKPOINT;
740 if (!NT_SUCCESS(Status))
741 {
742 ExReleaseResourceLite(&DeviceExt->FatResource);
743 return(Status);
744 }
745 }
746 else if (DeviceExt->FatInfo.FatType == FAT32)
747 {
748 Status = FAT32FindAvailableCluster(DeviceExt, &NewCluster);
749 if (!NT_SUCCESS(Status))
750 {
751 ExReleaseResourceLite(&DeviceExt->FatResource);
752 return(Status);
753 }
754 }
755 else
756 {
757 Status = FAT12FindAvailableCluster(DeviceExt, &NewCluster);
758 if (!NT_SUCCESS(Status))
759 {
760 ExReleaseResourceLite(&DeviceExt->FatResource);
761 return(Status);
762 }
763 }
764 /* Mark the new AU as the EOF */
765 WriteCluster (DeviceExt, NewCluster, 0xFFFFFFFF);
766 *NextCluster = NewCluster;
767 ExReleaseResourceLite(&DeviceExt->FatResource);
768 return(STATUS_SUCCESS);
769 }
770 else if (CurrentCluster == 0)
771 {
772 ExReleaseResourceLite(&DeviceExt->FatResource);
773 return(STATUS_UNSUCCESSFUL);
774 }
775
776 if (DeviceExt->FatInfo.FatType == FAT16)
777 {
778 Status = Fat16GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
779 }
780 else if (DeviceExt->FatInfo.FatType == FAT32)
781 {
782 Status = Fat32GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
783 }
784 else
785 {
786 Status = Fat12GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
787 }
788 if (Extend && (*NextCluster) == 0xFFFFFFFF)
789 {
790 ULONG NewCluster;
791
792 /* We are after last existing cluster, we must add one to file */
793 /* Firstly, find the next available open allocation unit */
794 if (DeviceExt->FatInfo.FatType == FAT16)
795 {
796 Status = FAT16FindAvailableCluster(DeviceExt, &NewCluster);
797 if (!NT_SUCCESS(Status))
798 {
799 ExReleaseResourceLite(&DeviceExt->FatResource);
800 return(Status);
801 }
802 }
803 else if (DeviceExt->FatInfo.FatType == FAT32)
804 {
805 Status = FAT32FindAvailableCluster(DeviceExt, &NewCluster);
806 if (!NT_SUCCESS(Status))
807 {
808 ExReleaseResourceLite(&DeviceExt->FatResource);
809 return(Status);
810 }
811 }
812 else
813 {
814 Status = FAT12FindAvailableCluster(DeviceExt, &NewCluster);
815 if (!NT_SUCCESS(Status))
816 {
817 ExReleaseResourceLite(&DeviceExt->FatResource);
818 return(Status);
819 }
820 }
821 /* Mark the new AU as the EOF */
822 WriteCluster(DeviceExt, NewCluster, 0xFFFFFFFF);
823 /* Now, write the AU of the LastCluster with the value of the newly
824 found AU */
825 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
826 *NextCluster = NewCluster;
827 }
828
829 ExReleaseResourceLite(&DeviceExt->FatResource);
830
831 return(Status);
832 }
833
834
835 NTSTATUS
836 GetNextSector(PDEVICE_EXTENSION DeviceExt,
837 ULONG CurrentSector,
838 PULONG NextSector,
839 BOOLEAN Extend)
840 /* Some functions don't have access to the cluster they're really reading from.
841 Maybe this is a dirty solution, but it will allow them to handle fragmentation. */
842 {
843 NTSTATUS Status;
844
845 DPRINT("GetNextSector(DeviceExt %x, CurrentSector %x)\n",
846 DeviceExt,
847 CurrentSector);
848 if (CurrentSector<DeviceExt->FatInfo.dataStart || ((CurrentSector - DeviceExt->FatInfo.dataStart + 1) % DeviceExt->FatInfo.SectorsPerCluster))
849 /* Basically, if the next sequential sector would be on a cluster border, then we'll need to check in the FAT */
850 {
851 (*NextSector)=CurrentSector+1;
852 return (STATUS_SUCCESS);
853 }
854 else
855 {
856 CurrentSector = (CurrentSector - DeviceExt->FatInfo.dataStart) / DeviceExt->FatInfo.SectorsPerCluster + 2;
857
858 Status = GetNextCluster(DeviceExt, CurrentSector, NextSector, Extend);
859 if (!NT_SUCCESS(Status))
860 {
861 return(Status);
862 }
863 if ((*NextSector) == 0 || (*NextSector) == 0xffffffff)
864 {
865 /* The caller wants to know a sector. These FAT codes don't correspond to any sector. */
866 return(STATUS_UNSUCCESSFUL);
867 }
868
869 (*NextSector) = ClusterToSector(DeviceExt,(*NextSector));
870 return(STATUS_SUCCESS);
871 }
872 }
873
874 /* EOF */