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