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