1 /*
2 * PROJECT: VFAT Filesystem
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: File Allocation Table routines
5 * COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
6 * Copyright 2015-2018 Pierre Schweitzer <pierre@reactos.org>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "vfat.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
19 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
20
21 /* FUNCTIONS ****************************************************************/
22
23 /*
24 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
25 * disk read
26 */
27 NTSTATUS
FAT32GetNextCluster(PDEVICE_EXTENSION DeviceExt,ULONG CurrentCluster,PULONG NextCluster)28 FAT32GetNextCluster(
29 PDEVICE_EXTENSION DeviceExt,
30 ULONG CurrentCluster,
31 PULONG NextCluster)
32 {
33 NTSTATUS Status = STATUS_SUCCESS;
34 PVOID BaseAddress;
35 ULONG FATOffset;
36 ULONG ChunkSize;
37 PVOID Context = NULL;
38 LARGE_INTEGER Offset;
39
40 ChunkSize = CACHEPAGESIZE(DeviceExt);
41 FATOffset = CurrentCluster * sizeof(ULONG);
42 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
43 _SEH2_TRY
44 {
45 if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress))
46 {
47 NT_ASSERT(FALSE);
48 return STATUS_UNSUCCESSFUL;
49 }
50 }
51 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
52 {
53 _SEH2_YIELD(return _SEH2_GetExceptionCode());
54 }
55 _SEH2_END;
56
57 CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
58 if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
59 CurrentCluster = 0xffffffff;
60
61 if (CurrentCluster == 0)
62 {
63 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
64 Status = STATUS_FILE_CORRUPT_ERROR;
65 if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
66 ASSERT(CurrentCluster != 0);
67 }
68 CcUnpinData(Context);
69 *NextCluster = CurrentCluster;
70 return Status;
71 }
72
73 /*
74 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
75 */
76 NTSTATUS
FAT16GetNextCluster(PDEVICE_EXTENSION DeviceExt,ULONG CurrentCluster,PULONG NextCluster)77 FAT16GetNextCluster(
78 PDEVICE_EXTENSION DeviceExt,
79 ULONG CurrentCluster,
80 PULONG NextCluster)
81 {
82 NTSTATUS Status = STATUS_SUCCESS;
83 PVOID BaseAddress;
84 ULONG FATOffset;
85 ULONG ChunkSize;
86 PVOID Context;
87 LARGE_INTEGER Offset;
88
89 ChunkSize = CACHEPAGESIZE(DeviceExt);
90 FATOffset = CurrentCluster * 2;
91 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
92 _SEH2_TRY
93 {
94 CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
95 }
96 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
97 {
98 _SEH2_YIELD(return _SEH2_GetExceptionCode());
99 }
100 _SEH2_END;
101
102 CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
103 if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
104 CurrentCluster = 0xffffffff;
105
106 if (CurrentCluster == 0)
107 {
108 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
109 Status = STATUS_FILE_CORRUPT_ERROR;
110 if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
111 ASSERT(CurrentCluster != 0);
112 }
113
114 CcUnpinData(Context);
115 *NextCluster = CurrentCluster;
116 return Status;
117 }
118
119 /*
120 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
121 */
122 NTSTATUS
FAT12GetNextCluster(PDEVICE_EXTENSION DeviceExt,ULONG CurrentCluster,PULONG NextCluster)123 FAT12GetNextCluster(
124 PDEVICE_EXTENSION DeviceExt,
125 ULONG CurrentCluster,
126 PULONG NextCluster)
127 {
128 PUSHORT CBlock;
129 ULONG Entry;
130 PVOID BaseAddress;
131 PVOID Context;
132 LARGE_INTEGER Offset;
133
134 *NextCluster = 0;
135
136 Offset.QuadPart = 0;
137 _SEH2_TRY
138 {
139 CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, MAP_WAIT, &Context, &BaseAddress);
140 }
141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
142 {
143 _SEH2_YIELD(return _SEH2_GetExceptionCode());
144 }
145 _SEH2_END;
146
147 CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
148 if ((CurrentCluster % 2) == 0)
149 {
150 Entry = *CBlock & 0x0fff;
151 }
152 else
153 {
154 Entry = *CBlock >> 4;
155 }
156
157 // DPRINT("Entry %x\n",Entry);
158 if (Entry >= 0xff8 && Entry <= 0xfff)
159 Entry = 0xffffffff;
160
161 // DPRINT("Returning %x\n",Entry);
162 ASSERT(Entry != 0);
163 *NextCluster = Entry;
164 CcUnpinData(Context);
165 // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
166 return STATUS_SUCCESS;
167 }
168
169 /*
170 * FUNCTION: Finds the first available cluster in a FAT16 table
171 */
172 NTSTATUS
FAT16FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt,PULONG Cluster)173 FAT16FindAndMarkAvailableCluster(
174 PDEVICE_EXTENSION DeviceExt,
175 PULONG Cluster)
176 {
177 ULONG FatLength;
178 ULONG StartCluster;
179 ULONG i, j;
180 PVOID BaseAddress;
181 ULONG ChunkSize;
182 PVOID Context = 0;
183 LARGE_INTEGER Offset;
184 PUSHORT Block;
185 PUSHORT BlockEnd;
186
187 ChunkSize = CACHEPAGESIZE(DeviceExt);
188 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
189 *Cluster = 0;
190 StartCluster = DeviceExt->LastAvailableCluster;
191
192 for (j = 0; j < 2; j++)
193 {
194 for (i = StartCluster; i < FatLength;)
195 {
196 Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
197 _SEH2_TRY
198 {
199 CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
200 }
201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
202 {
203 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
204 _SEH2_YIELD(return _SEH2_GetExceptionCode());
205 }
206 _SEH2_END;
207
208 Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
209 BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
210
211 /* Now process the whole block */
212 while (Block < BlockEnd && i < FatLength)
213 {
214 if (*Block == 0)
215 {
216 DPRINT("Found available cluster 0x%x\n", i);
217 DeviceExt->LastAvailableCluster = *Cluster = i;
218 *Block = 0xffff;
219 CcSetDirtyPinnedData(Context, NULL);
220 CcUnpinData(Context);
221 if (DeviceExt->AvailableClustersValid)
222 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
223 return STATUS_SUCCESS;
224 }
225
226 Block++;
227 i++;
228 }
229
230 CcUnpinData(Context);
231 }
232
233 FatLength = StartCluster;
234 StartCluster = 2;
235 }
236
237 return STATUS_DISK_FULL;
238 }
239
240 /*
241 * FUNCTION: Finds the first available cluster in a FAT12 table
242 */
243 NTSTATUS
FAT12FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt,PULONG Cluster)244 FAT12FindAndMarkAvailableCluster(
245 PDEVICE_EXTENSION DeviceExt,
246 PULONG Cluster)
247 {
248 ULONG FatLength;
249 ULONG StartCluster;
250 ULONG Entry;
251 PUSHORT CBlock;
252 ULONG i, j;
253 PVOID BaseAddress;
254 PVOID Context;
255 LARGE_INTEGER Offset;
256
257 FatLength = DeviceExt->FatInfo.NumberOfClusters + 2;
258 *Cluster = 0;
259 StartCluster = DeviceExt->LastAvailableCluster;
260 Offset.QuadPart = 0;
261 _SEH2_TRY
262 {
263 CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, PIN_WAIT, &Context, &BaseAddress);
264 }
265 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
266 {
267 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
268 _SEH2_YIELD(return _SEH2_GetExceptionCode());
269 }
270 _SEH2_END;
271
272 for (j = 0; j < 2; j++)
273 {
274 for (i = StartCluster; i < FatLength; i++)
275 {
276 CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
277 if ((i % 2) == 0)
278 {
279 Entry = *CBlock & 0xfff;
280 }
281 else
282 {
283 Entry = *CBlock >> 4;
284 }
285
286 if (Entry == 0)
287 {
288 DPRINT("Found available cluster 0x%x\n", i);
289 DeviceExt->LastAvailableCluster = *Cluster = i;
290 if ((i % 2) == 0)
291 *CBlock = (*CBlock & 0xf000) | 0xfff;
292 else
293 *CBlock = (*CBlock & 0xf) | 0xfff0;
294 CcSetDirtyPinnedData(Context, NULL);
295 CcUnpinData(Context);
296 if (DeviceExt->AvailableClustersValid)
297 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
298 return STATUS_SUCCESS;
299 }
300 }
301 FatLength = StartCluster;
302 StartCluster = 2;
303 }
304 CcUnpinData(Context);
305 return STATUS_DISK_FULL;
306 }
307
308 /*
309 * FUNCTION: Finds the first available cluster in a FAT32 table
310 */
311 NTSTATUS
FAT32FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt,PULONG Cluster)312 FAT32FindAndMarkAvailableCluster(
313 PDEVICE_EXTENSION DeviceExt,
314 PULONG Cluster)
315 {
316 ULONG FatLength;
317 ULONG StartCluster;
318 ULONG i, j;
319 PVOID BaseAddress;
320 ULONG ChunkSize;
321 PVOID Context;
322 LARGE_INTEGER Offset;
323 PULONG Block;
324 PULONG BlockEnd;
325
326 ChunkSize = CACHEPAGESIZE(DeviceExt);
327 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
328 *Cluster = 0;
329 StartCluster = DeviceExt->LastAvailableCluster;
330
331 for (j = 0; j < 2; j++)
332 {
333 for (i = StartCluster; i < FatLength;)
334 {
335 Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
336 _SEH2_TRY
337 {
338 CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
339 }
340 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
341 {
342 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
343 _SEH2_YIELD(return _SEH2_GetExceptionCode());
344 }
345 _SEH2_END;
346 Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
347 BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
348
349 /* Now process the whole block */
350 while (Block < BlockEnd && i < FatLength)
351 {
352 if ((*Block & 0x0fffffff) == 0)
353 {
354 DPRINT("Found available cluster 0x%x\n", i);
355 DeviceExt->LastAvailableCluster = *Cluster = i;
356 *Block = 0x0fffffff;
357 CcSetDirtyPinnedData(Context, NULL);
358 CcUnpinData(Context);
359 if (DeviceExt->AvailableClustersValid)
360 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
361 return STATUS_SUCCESS;
362 }
363
364 Block++;
365 i++;
366 }
367
368 CcUnpinData(Context);
369 }
370 FatLength = StartCluster;
371 StartCluster = 2;
372 }
373 return STATUS_DISK_FULL;
374 }
375
376 /*
377 * FUNCTION: Counts free cluster in a FAT12 table
378 */
379 static
380 NTSTATUS
FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)381 FAT12CountAvailableClusters(
382 PDEVICE_EXTENSION DeviceExt)
383 {
384 ULONG Entry;
385 PVOID BaseAddress;
386 ULONG ulCount = 0;
387 ULONG i;
388 ULONG numberofclusters;
389 LARGE_INTEGER Offset;
390 PVOID Context;
391 PUSHORT CBlock;
392
393 Offset.QuadPart = 0;
394 _SEH2_TRY
395 {
396 CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, MAP_WAIT, &Context, &BaseAddress);
397 }
398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
399 {
400 _SEH2_YIELD(return _SEH2_GetExceptionCode());
401 }
402 _SEH2_END;
403
404 numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;
405
406 for (i = 2; i < numberofclusters; i++)
407 {
408 CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
409 if ((i % 2) == 0)
410 {
411 Entry = *CBlock & 0x0fff;
412 }
413 else
414 {
415 Entry = *CBlock >> 4;
416 }
417
418 if (Entry == 0)
419 ulCount++;
420 }
421
422 CcUnpinData(Context);
423 DeviceExt->AvailableClusters = ulCount;
424 DeviceExt->AvailableClustersValid = TRUE;
425
426 return STATUS_SUCCESS;
427 }
428
429
430 /*
431 * FUNCTION: Counts free clusters in a FAT16 table
432 */
433 static
434 NTSTATUS
FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)435 FAT16CountAvailableClusters(
436 PDEVICE_EXTENSION DeviceExt)
437 {
438 PUSHORT Block;
439 PUSHORT BlockEnd;
440 PVOID BaseAddress = NULL;
441 ULONG ulCount = 0;
442 ULONG i;
443 ULONG ChunkSize;
444 PVOID Context = NULL;
445 LARGE_INTEGER Offset;
446 ULONG FatLength;
447
448 ChunkSize = CACHEPAGESIZE(DeviceExt);
449 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
450
451 for (i = 2; i < FatLength; )
452 {
453 Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
454 _SEH2_TRY
455 {
456 CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
457 }
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
459 {
460 _SEH2_YIELD(return _SEH2_GetExceptionCode());
461 }
462 _SEH2_END;
463 Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
464 BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
465
466 /* Now process the whole block */
467 while (Block < BlockEnd && i < FatLength)
468 {
469 if (*Block == 0)
470 ulCount++;
471 Block++;
472 i++;
473 }
474
475 CcUnpinData(Context);
476 }
477
478 DeviceExt->AvailableClusters = ulCount;
479 DeviceExt->AvailableClustersValid = TRUE;
480
481 return STATUS_SUCCESS;
482 }
483
484
485 /*
486 * FUNCTION: Counts free clusters in a FAT32 table
487 */
488 static
489 NTSTATUS
FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)490 FAT32CountAvailableClusters(
491 PDEVICE_EXTENSION DeviceExt)
492 {
493 PULONG Block;
494 PULONG BlockEnd;
495 PVOID BaseAddress = NULL;
496 ULONG ulCount = 0;
497 ULONG i;
498 ULONG ChunkSize;
499 PVOID Context = NULL;
500 LARGE_INTEGER Offset;
501 ULONG FatLength;
502
503 ChunkSize = CACHEPAGESIZE(DeviceExt);
504 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
505
506 for (i = 2; i < FatLength; )
507 {
508 Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
509 _SEH2_TRY
510 {
511 CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
512 }
513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
514 {
515 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
516 _SEH2_YIELD(return _SEH2_GetExceptionCode());
517 }
518 _SEH2_END;
519 Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
520 BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
521
522 /* Now process the whole block */
523 while (Block < BlockEnd && i < FatLength)
524 {
525 if ((*Block & 0x0fffffff) == 0)
526 ulCount++;
527 Block++;
528 i++;
529 }
530
531 CcUnpinData(Context);
532 }
533
534 DeviceExt->AvailableClusters = ulCount;
535 DeviceExt->AvailableClustersValid = TRUE;
536
537 return STATUS_SUCCESS;
538 }
539
540 NTSTATUS
CountAvailableClusters(PDEVICE_EXTENSION DeviceExt,PLARGE_INTEGER Clusters)541 CountAvailableClusters(
542 PDEVICE_EXTENSION DeviceExt,
543 PLARGE_INTEGER Clusters)
544 {
545 NTSTATUS Status = STATUS_SUCCESS;
546 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
547 if (!DeviceExt->AvailableClustersValid)
548 {
549 if (DeviceExt->FatInfo.FatType == FAT12)
550 Status = FAT12CountAvailableClusters(DeviceExt);
551 else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16)
552 Status = FAT16CountAvailableClusters(DeviceExt);
553 else
554 Status = FAT32CountAvailableClusters(DeviceExt);
555 }
556 if (Clusters != NULL)
557 {
558 Clusters->QuadPart = DeviceExt->AvailableClusters;
559 }
560 ExReleaseResourceLite (&DeviceExt->FatResource);
561
562 return Status;
563 }
564
565
566 /*
567 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
568 */
569 NTSTATUS
FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt,ULONG ClusterToWrite,ULONG NewValue,PULONG OldValue)570 FAT12WriteCluster(
571 PDEVICE_EXTENSION DeviceExt,
572 ULONG ClusterToWrite,
573 ULONG NewValue,
574 PULONG OldValue)
575 {
576 ULONG FATOffset;
577 PUCHAR CBlock;
578 PVOID BaseAddress;
579 PVOID Context;
580 LARGE_INTEGER Offset;
581
582 Offset.QuadPart = 0;
583 _SEH2_TRY
584 {
585 CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, PIN_WAIT, &Context, &BaseAddress);
586 }
587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
588 {
589 _SEH2_YIELD(return _SEH2_GetExceptionCode());
590 }
591 _SEH2_END;
592 CBlock = (PUCHAR)BaseAddress;
593
594 FATOffset = (ClusterToWrite * 12) / 8;
595 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
596 NewValue, ClusterToWrite, FATOffset);
597 if ((ClusterToWrite % 2) == 0)
598 {
599 *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
600 CBlock[FATOffset] = (UCHAR)NewValue;
601 CBlock[FATOffset + 1] &= 0xf0;
602 CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
603 }
604 else
605 {
606 *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
607 CBlock[FATOffset] &= 0x0f;
608 CBlock[FATOffset] |= (NewValue & 0xf) << 4;
609 CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4);
610 }
611 /* Write the changed FAT sector(s) to disk */
612 CcSetDirtyPinnedData(Context, NULL);
613 CcUnpinData(Context);
614 return STATUS_SUCCESS;
615 }
616
617 /*
618 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
619 */
620 NTSTATUS
FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt,ULONG ClusterToWrite,ULONG NewValue,PULONG OldValue)621 FAT16WriteCluster(
622 PDEVICE_EXTENSION DeviceExt,
623 ULONG ClusterToWrite,
624 ULONG NewValue,
625 PULONG OldValue)
626 {
627 PVOID BaseAddress;
628 ULONG FATOffset;
629 ULONG ChunkSize;
630 PVOID Context;
631 LARGE_INTEGER Offset;
632 PUSHORT Cluster;
633
634 ChunkSize = CACHEPAGESIZE(DeviceExt);
635 FATOffset = ClusterToWrite * 2;
636 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
637 _SEH2_TRY
638 {
639 CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
640 }
641 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
642 {
643 _SEH2_YIELD(return _SEH2_GetExceptionCode());
644 }
645 _SEH2_END;
646
647 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
648 ClusterToWrite);
649 Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
650 *OldValue = *Cluster;
651 *Cluster = (USHORT)NewValue;
652 CcSetDirtyPinnedData(Context, NULL);
653 CcUnpinData(Context);
654 return STATUS_SUCCESS;
655 }
656
657 /*
658 * FUNCTION: Writes a cluster to the FAT32 physical tables
659 */
660 NTSTATUS
FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt,ULONG ClusterToWrite,ULONG NewValue,PULONG OldValue)661 FAT32WriteCluster(
662 PDEVICE_EXTENSION DeviceExt,
663 ULONG ClusterToWrite,
664 ULONG NewValue,
665 PULONG OldValue)
666 {
667 PVOID BaseAddress;
668 ULONG FATOffset;
669 ULONG ChunkSize;
670 PVOID Context;
671 LARGE_INTEGER Offset;
672 PULONG Cluster;
673
674 ChunkSize = CACHEPAGESIZE(DeviceExt);
675
676 FATOffset = (ClusterToWrite * 4);
677 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
678 _SEH2_TRY
679 {
680 CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
681 }
682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
683 {
684 _SEH2_YIELD(return _SEH2_GetExceptionCode());
685 }
686 _SEH2_END;
687
688 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
689 ClusterToWrite);
690 Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize)));
691 *OldValue = *Cluster & 0x0fffffff;
692 *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
693
694 CcSetDirtyPinnedData(Context, NULL);
695 CcUnpinData(Context);
696
697 return STATUS_SUCCESS;
698 }
699
700
701 /*
702 * FUNCTION: Write a changed FAT entry
703 */
704 NTSTATUS
WriteCluster(PDEVICE_EXTENSION DeviceExt,ULONG ClusterToWrite,ULONG NewValue)705 WriteCluster(
706 PDEVICE_EXTENSION DeviceExt,
707 ULONG ClusterToWrite,
708 ULONG NewValue)
709 {
710 NTSTATUS Status;
711 ULONG OldValue;
712
713 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
714 Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
715 if (DeviceExt->AvailableClustersValid)
716 {
717 if (OldValue && NewValue == 0)
718 InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters);
719 else if (OldValue == 0 && NewValue)
720 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
721 }
722 ExReleaseResourceLite(&DeviceExt->FatResource);
723 return Status;
724 }
725
726 /*
727 * FUNCTION: Converts the cluster number to a sector number for this physical
728 * device
729 */
730 ULONGLONG
ClusterToSector(PDEVICE_EXTENSION DeviceExt,ULONG Cluster)731 ClusterToSector(
732 PDEVICE_EXTENSION DeviceExt,
733 ULONG Cluster)
734 {
735 return DeviceExt->FatInfo.dataStart +
736 ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
737
738 }
739
740 /*
741 * FUNCTION: Retrieve the next cluster depending on the FAT type
742 */
743 NTSTATUS
GetNextCluster(PDEVICE_EXTENSION DeviceExt,ULONG CurrentCluster,PULONG NextCluster)744 GetNextCluster(
745 PDEVICE_EXTENSION DeviceExt,
746 ULONG CurrentCluster,
747 PULONG NextCluster)
748 {
749 NTSTATUS Status;
750
751 DPRINT("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
752 DeviceExt, CurrentCluster);
753
754 if (CurrentCluster == 0)
755 {
756 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
757 if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
758 ASSERT(CurrentCluster != 0);
759 return STATUS_FILE_CORRUPT_ERROR;
760 }
761
762 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
763 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
764 ExReleaseResourceLite(&DeviceExt->FatResource);
765
766 return Status;
767 }
768
769 /*
770 * FUNCTION: Retrieve the next cluster depending on the FAT type
771 */
772 NTSTATUS
GetNextClusterExtend(PDEVICE_EXTENSION DeviceExt,ULONG CurrentCluster,PULONG NextCluster)773 GetNextClusterExtend(
774 PDEVICE_EXTENSION DeviceExt,
775 ULONG CurrentCluster,
776 PULONG NextCluster)
777 {
778 ULONG NewCluster;
779 NTSTATUS Status;
780
781 DPRINT("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
782 DeviceExt, CurrentCluster);
783
784 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
785 /*
786 * If the file hasn't any clusters allocated then we need special
787 * handling
788 */
789 if (CurrentCluster == 0)
790 {
791 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
792 if (!NT_SUCCESS(Status))
793 {
794 ExReleaseResourceLite(&DeviceExt->FatResource);
795 return Status;
796 }
797
798 *NextCluster = NewCluster;
799 ExReleaseResourceLite(&DeviceExt->FatResource);
800 return STATUS_SUCCESS;
801 }
802
803 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
804
805 if ((*NextCluster) == 0xFFFFFFFF)
806 {
807 /* We are after last existing cluster, we must add one to file */
808 /* Firstly, find the next available open allocation unit and
809 mark it as end of file */
810 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
811 if (!NT_SUCCESS(Status))
812 {
813 ExReleaseResourceLite(&DeviceExt->FatResource);
814 return Status;
815 }
816
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 return Status;
825 }
826
827 /*
828 * FUNCTION: Retrieve the dirty status
829 */
830 NTSTATUS
GetDirtyStatus(PDEVICE_EXTENSION DeviceExt,PBOOLEAN DirtyStatus)831 GetDirtyStatus(
832 PDEVICE_EXTENSION DeviceExt,
833 PBOOLEAN DirtyStatus)
834 {
835 NTSTATUS Status;
836
837 DPRINT("GetDirtyStatus(DeviceExt %p)\n", DeviceExt);
838
839 /* FAT12 has no dirty bit */
840 if (DeviceExt->FatInfo.FatType == FAT12)
841 {
842 *DirtyStatus = FALSE;
843 return STATUS_SUCCESS;
844 }
845
846 /* Not really in the FAT, but share the lock because
847 * we're really low-level and shouldn't happent that often
848 * And call the appropriate function
849 */
850 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
851 Status = DeviceExt->GetDirtyStatus(DeviceExt, DirtyStatus);
852 ExReleaseResourceLite(&DeviceExt->FatResource);
853
854 return Status;
855 }
856
857 NTSTATUS
FAT16GetDirtyStatus(PDEVICE_EXTENSION DeviceExt,PBOOLEAN DirtyStatus)858 FAT16GetDirtyStatus(
859 PDEVICE_EXTENSION DeviceExt,
860 PBOOLEAN DirtyStatus)
861 {
862 LARGE_INTEGER Offset;
863 ULONG Length;
864 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
865 NTSTATUS Status;
866 #else
867 PVOID Context;
868 #endif
869 struct _BootSector * Sector;
870
871 /* We'll read the bootsector at 0 */
872 Offset.QuadPart = 0;
873 Length = DeviceExt->FatInfo.BytesPerSector;
874 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
875 /* Go through Cc for this */
876 _SEH2_TRY
877 {
878 CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
879 }
880 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
881 {
882 _SEH2_YIELD(return _SEH2_GetExceptionCode());
883 }
884 _SEH2_END;
885 #else
886 /* No Cc, do it the old way:
887 * - Allocate a big enough buffer
888 * - And read the disk
889 */
890 Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
891 if (Sector == NULL)
892 {
893 *DirtyStatus = TRUE;
894 return STATUS_INSUFFICIENT_RESOURCES;
895 }
896
897 Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
898 if (!NT_SUCCESS(Status))
899 {
900 *DirtyStatus = TRUE;
901 ExFreePoolWithTag(Sector, TAG_BUFFER);
902 return Status;
903 }
904 #endif
905
906 /* Make sure we have a boot sector...
907 * FIXME: This check is a bit lame and should be improved
908 */
909 if (Sector->Signatur1 != 0xaa55)
910 {
911 /* Set we are dirty so that we don't attempt anything */
912 *DirtyStatus = TRUE;
913 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
914 CcUnpinData(Context);
915 #else
916 ExFreePoolWithTag(Sector, TAG_BUFFER);
917 #endif
918 return STATUS_DISK_CORRUPT_ERROR;
919 }
920
921 /* Return the status of the dirty bit */
922 if (Sector->Res1 & FAT_DIRTY_BIT)
923 *DirtyStatus = TRUE;
924 else
925 *DirtyStatus = FALSE;
926
927 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
928 CcUnpinData(Context);
929 #else
930 ExFreePoolWithTag(Sector, TAG_BUFFER);
931 #endif
932 return STATUS_SUCCESS;
933 }
934
935 NTSTATUS
FAT32GetDirtyStatus(PDEVICE_EXTENSION DeviceExt,PBOOLEAN DirtyStatus)936 FAT32GetDirtyStatus(
937 PDEVICE_EXTENSION DeviceExt,
938 PBOOLEAN DirtyStatus)
939 {
940 LARGE_INTEGER Offset;
941 ULONG Length;
942 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
943 NTSTATUS Status;
944 #else
945 PVOID Context;
946 #endif
947 struct _BootSector32 * Sector;
948
949 /* We'll read the bootsector at 0 */
950 Offset.QuadPart = 0;
951 Length = DeviceExt->FatInfo.BytesPerSector;
952 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
953 /* Go through Cc for this */
954 _SEH2_TRY
955 {
956 CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
957 }
958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
959 {
960 _SEH2_YIELD(return _SEH2_GetExceptionCode());
961 }
962 _SEH2_END;
963 #else
964 /* No Cc, do it the old way:
965 * - Allocate a big enough buffer
966 * - And read the disk
967 */
968 Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
969 if (Sector == NULL)
970 {
971 *DirtyStatus = TRUE;
972 return STATUS_INSUFFICIENT_RESOURCES;
973 }
974
975 Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
976 if (!NT_SUCCESS(Status))
977 {
978 *DirtyStatus = TRUE;
979 ExFreePoolWithTag(Sector, TAG_BUFFER);
980 return Status;
981 }
982 #endif
983
984 /* Make sure we have a boot sector...
985 * FIXME: This check is a bit lame and should be improved
986 */
987 if (Sector->Signature1 != 0xaa55)
988 {
989 /* Set we are dirty so that we don't attempt anything */
990 *DirtyStatus = TRUE;
991 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
992 CcUnpinData(Context);
993 #else
994 ExFreePoolWithTag(Sector, TAG_BUFFER);
995 #endif
996 return STATUS_DISK_CORRUPT_ERROR;
997 }
998
999 /* Return the status of the dirty bit */
1000 if (Sector->Res4 & FAT_DIRTY_BIT)
1001 *DirtyStatus = TRUE;
1002 else
1003 *DirtyStatus = FALSE;
1004
1005 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1006 CcUnpinData(Context);
1007 #else
1008 ExFreePoolWithTag(Sector, TAG_BUFFER);
1009 #endif
1010 return STATUS_SUCCESS;
1011 }
1012
1013 /*
1014 * FUNCTION: Set the dirty status
1015 */
1016 NTSTATUS
SetDirtyStatus(PDEVICE_EXTENSION DeviceExt,BOOLEAN DirtyStatus)1017 SetDirtyStatus(
1018 PDEVICE_EXTENSION DeviceExt,
1019 BOOLEAN DirtyStatus)
1020 {
1021 NTSTATUS Status;
1022
1023 DPRINT("SetDirtyStatus(DeviceExt %p, DirtyStatus %d)\n", DeviceExt, DirtyStatus);
1024
1025 /* FAT12 has no dirty bit */
1026 if (DeviceExt->FatInfo.FatType == FAT12)
1027 {
1028 return STATUS_SUCCESS;
1029 }
1030
1031 /* Not really in the FAT, but share the lock because
1032 * we're really low-level and shouldn't happent that often
1033 * And call the appropriate function
1034 * Acquire exclusive because we will modify ondisk value
1035 */
1036 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
1037 Status = DeviceExt->SetDirtyStatus(DeviceExt, DirtyStatus);
1038 ExReleaseResourceLite(&DeviceExt->FatResource);
1039
1040 return Status;
1041 }
1042
1043 NTSTATUS
FAT16SetDirtyStatus(PDEVICE_EXTENSION DeviceExt,BOOLEAN DirtyStatus)1044 FAT16SetDirtyStatus(
1045 PDEVICE_EXTENSION DeviceExt,
1046 BOOLEAN DirtyStatus)
1047 {
1048 LARGE_INTEGER Offset;
1049 ULONG Length;
1050 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1051 NTSTATUS Status;
1052 #else
1053 PVOID Context;
1054 #endif
1055 struct _BootSector * Sector;
1056
1057 /* We'll read (and then write) the bootsector at 0 */
1058 Offset.QuadPart = 0;
1059 Length = DeviceExt->FatInfo.BytesPerSector;
1060 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1061 /* Go through Cc for this */
1062 _SEH2_TRY
1063 {
1064 CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
1065 }
1066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1067 {
1068 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1069 }
1070 _SEH2_END;
1071 #else
1072 /* No Cc, do it the old way:
1073 * - Allocate a big enough buffer
1074 * - And read the disk
1075 */
1076 Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
1077 if (Sector == NULL)
1078 {
1079 return STATUS_INSUFFICIENT_RESOURCES;
1080 }
1081
1082 Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1083 if (!NT_SUCCESS(Status))
1084 {
1085 ExFreePoolWithTag(Sector, TAG_BUFFER);
1086 return Status;
1087 }
1088 #endif
1089
1090 /* Make sure we have a boot sector...
1091 * FIXME: This check is a bit lame and should be improved
1092 */
1093 if (Sector->Signatur1 != 0xaa55)
1094 {
1095 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1096 CcUnpinData(Context);
1097 #else
1098 ExFreePoolWithTag(Sector, TAG_BUFFER);
1099 #endif
1100 return STATUS_DISK_CORRUPT_ERROR;
1101 }
1102
1103 /* Modify the dirty bit status according
1104 * to caller needs
1105 */
1106 if (!DirtyStatus)
1107 {
1108 Sector->Res1 &= ~FAT_DIRTY_BIT;
1109 }
1110 else
1111 {
1112 Sector->Res1 |= FAT_DIRTY_BIT;
1113 }
1114
1115 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1116 /* Mark boot sector dirty so that it gets written to the disk */
1117 CcSetDirtyPinnedData(Context, NULL);
1118 CcUnpinData(Context);
1119 return STATUS_SUCCESS;
1120 #else
1121 /* Write back the boot sector to the disk */
1122 Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1123 ExFreePoolWithTag(Sector, TAG_BUFFER);
1124 return Status;
1125 #endif
1126 }
1127
1128 NTSTATUS
FAT32SetDirtyStatus(PDEVICE_EXTENSION DeviceExt,BOOLEAN DirtyStatus)1129 FAT32SetDirtyStatus(
1130 PDEVICE_EXTENSION DeviceExt,
1131 BOOLEAN DirtyStatus)
1132 {
1133 LARGE_INTEGER Offset;
1134 ULONG Length;
1135 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1136 NTSTATUS Status;
1137 #else
1138 PVOID Context;
1139 #endif
1140 struct _BootSector32 * Sector;
1141
1142 /* We'll read (and then write) the bootsector at 0 */
1143 Offset.QuadPart = 0;
1144 Length = DeviceExt->FatInfo.BytesPerSector;
1145 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1146 /* Go through Cc for this */
1147 _SEH2_TRY
1148 {
1149 CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
1150 }
1151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1152 {
1153 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1154 }
1155 _SEH2_END;
1156 #else
1157 /* No Cc, do it the old way:
1158 * - Allocate a big enough buffer
1159 * - And read the disk
1160 */
1161 Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
1162 if (Sector == NULL)
1163 {
1164 return STATUS_INSUFFICIENT_RESOURCES;
1165 }
1166
1167 Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1168 if (!NT_SUCCESS(Status))
1169 {
1170 ExFreePoolWithTag(Sector, TAG_BUFFER);
1171 return Status;
1172 }
1173 #endif
1174
1175 /* Make sure we have a boot sector...
1176 * FIXME: This check is a bit lame and should be improved
1177 */
1178 if (Sector->Signature1 != 0xaa55)
1179 {
1180 ASSERT(FALSE);
1181 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1182 CcUnpinData(Context);
1183 #else
1184 ExFreePoolWithTag(Sector, TAG_BUFFER);
1185 #endif
1186 return STATUS_DISK_CORRUPT_ERROR;
1187 }
1188
1189 /* Modify the dirty bit status according
1190 * to caller needs
1191 */
1192 if (!DirtyStatus)
1193 {
1194 Sector->Res4 &= ~FAT_DIRTY_BIT;
1195 }
1196 else
1197 {
1198 Sector->Res4 |= FAT_DIRTY_BIT;
1199 }
1200
1201 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1202 /* Mark boot sector dirty so that it gets written to the disk */
1203 CcSetDirtyPinnedData(Context, NULL);
1204 CcUnpinData(Context);
1205 return STATUS_SUCCESS;
1206 #else
1207 /* Write back the boot sector to the disk */
1208 Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1209 ExFreePoolWithTag(Sector, TAG_BUFFER);
1210 return Status;
1211 #endif
1212 }
1213
1214 NTSTATUS
FAT32UpdateFreeClustersCount(PDEVICE_EXTENSION DeviceExt)1215 FAT32UpdateFreeClustersCount(
1216 PDEVICE_EXTENSION DeviceExt)
1217 {
1218 LARGE_INTEGER Offset;
1219 ULONG Length;
1220 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1221 NTSTATUS Status;
1222 #else
1223 PVOID Context;
1224 #endif
1225 struct _FsInfoSector * Sector;
1226
1227 if (!DeviceExt->AvailableClustersValid)
1228 {
1229 return STATUS_INVALID_PARAMETER;
1230 }
1231
1232 /* We'll read (and then write) the fsinfo sector */
1233 Offset.QuadPart = DeviceExt->FatInfo.FSInfoSector * DeviceExt->FatInfo.BytesPerSector;
1234 Length = DeviceExt->FatInfo.BytesPerSector;
1235 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1236 /* Go through Cc for this */
1237 _SEH2_TRY
1238 {
1239 CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
1240 }
1241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1242 {
1243 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1244 }
1245 _SEH2_END;
1246 #else
1247 /* No Cc, do it the old way:
1248 * - Allocate a big enough buffer
1249 * - And read the disk
1250 */
1251 Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
1252 if (Sector == NULL)
1253 {
1254 return STATUS_INSUFFICIENT_RESOURCES;
1255 }
1256
1257 Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1258 if (!NT_SUCCESS(Status))
1259 {
1260 ExFreePoolWithTag(Sector, TAG_BUFFER);
1261 return Status;
1262 }
1263 #endif
1264
1265 /* Make sure we have a FSINFO sector */
1266 if (Sector->ExtBootSignature2 != 0x41615252 ||
1267 Sector->FSINFOSignature != 0x61417272 ||
1268 Sector->Signatur2 != 0xaa550000)
1269 {
1270 ASSERT(FALSE);
1271 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1272 CcUnpinData(Context);
1273 #else
1274 ExFreePoolWithTag(Sector, TAG_BUFFER);
1275 #endif
1276 return STATUS_DISK_CORRUPT_ERROR;
1277 }
1278
1279 /* Update the free clusters count */
1280 Sector->FreeCluster = InterlockedCompareExchange((PLONG)&DeviceExt->AvailableClusters, 0, 0);
1281
1282 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1283 /* Mark FSINFO sector dirty so that it gets written to the disk */
1284 CcSetDirtyPinnedData(Context, NULL);
1285 CcUnpinData(Context);
1286 return STATUS_SUCCESS;
1287 #else
1288 /* Write back the FSINFO sector to the disk */
1289 Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
1290 ExFreePoolWithTag(Sector, TAG_BUFFER);
1291 return Status;
1292 #endif
1293 }
1294
1295 /* EOF */
1296