Fix merge r65567.
[reactos.git] / drivers / filesystems / fastfat / fat.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/fat.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "vfat.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
20 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
21
22 /* FUNCTIONS ****************************************************************/
23
24 /*
25 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
26 * disk read
27 */
28 NTSTATUS
29 FAT32GetNextCluster(
30 PDEVICE_EXTENSION DeviceExt,
31 ULONG CurrentCluster,
32 PULONG NextCluster)
33 {
34 PVOID BaseAddress;
35 ULONG FATOffset;
36 ULONG ChunkSize;
37 PVOID Context;
38 LARGE_INTEGER Offset;
39
40 ChunkSize = CACHEPAGESIZE(DeviceExt);
41 FATOffset = CurrentCluster * sizeof(ULONG);
42 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
43 if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
44 {
45 return STATUS_UNSUCCESSFUL;
46 }
47
48 CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
49 if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
50 CurrentCluster = 0xffffffff;
51
52 CcUnpinData(Context);
53 *NextCluster = CurrentCluster;
54 return STATUS_SUCCESS;
55 }
56
57 /*
58 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
59 */
60 NTSTATUS
61 FAT16GetNextCluster(
62 PDEVICE_EXTENSION DeviceExt,
63 ULONG CurrentCluster,
64 PULONG NextCluster)
65 {
66 PVOID BaseAddress;
67 ULONG FATOffset;
68 ULONG ChunkSize;
69 PVOID Context;
70 LARGE_INTEGER Offset;
71
72 ChunkSize = CACHEPAGESIZE(DeviceExt);
73 FATOffset = CurrentCluster * 2;
74 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
75 if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress))
76 {
77 return STATUS_UNSUCCESSFUL;
78 }
79
80 CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
81 if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
82 CurrentCluster = 0xffffffff;
83 CcUnpinData(Context);
84 *NextCluster = CurrentCluster;
85 return STATUS_SUCCESS;
86 }
87
88 /*
89 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
90 */
91 NTSTATUS
92 FAT12GetNextCluster(
93 PDEVICE_EXTENSION DeviceExt,
94 ULONG CurrentCluster,
95 PULONG NextCluster)
96 {
97 PUSHORT CBlock;
98 ULONG Entry;
99 PVOID BaseAddress;
100 PVOID Context;
101 LARGE_INTEGER Offset;
102
103 *NextCluster = 0;
104
105 Offset.QuadPart = 0;
106 if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
107 {
108 return STATUS_UNSUCCESSFUL;
109 }
110
111 CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
112 if ((CurrentCluster % 2) == 0)
113 {
114 Entry = *CBlock & 0x0fff;
115 }
116 else
117 {
118 Entry = *CBlock >> 4;
119 }
120
121 // DPRINT("Entry %x\n",Entry);
122 if (Entry >= 0xff8 && Entry <= 0xfff)
123 Entry = 0xffffffff;
124
125 // DPRINT("Returning %x\n",Entry);
126 *NextCluster = Entry;
127 CcUnpinData(Context);
128 // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
129 return STATUS_SUCCESS;
130 }
131
132 /*
133 * FUNCTION: Finds the first available cluster in a FAT16 table
134 */
135 NTSTATUS
136 FAT16FindAndMarkAvailableCluster(
137 PDEVICE_EXTENSION DeviceExt,
138 PULONG Cluster)
139 {
140 ULONG FatLength;
141 ULONG StartCluster;
142 ULONG i, j;
143 PVOID BaseAddress;
144 ULONG ChunkSize;
145 PVOID Context = 0;
146 LARGE_INTEGER Offset;
147 PUSHORT Block;
148 PUSHORT BlockEnd;
149
150 ChunkSize = CACHEPAGESIZE(DeviceExt);
151 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
152 *Cluster = 0;
153 StartCluster = DeviceExt->LastAvailableCluster;
154
155 for (j = 0; j < 2; j++)
156 {
157 for (i = StartCluster; i < FatLength;)
158 {
159 Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
160 if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
161 {
162 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
163 return STATUS_UNSUCCESSFUL;
164 }
165
166 Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
167 BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
168
169 /* Now process the whole block */
170 while (Block < BlockEnd && i < FatLength)
171 {
172 if (*Block == 0)
173 {
174 DPRINT("Found available cluster 0x%x\n", i);
175 DeviceExt->LastAvailableCluster = *Cluster = i;
176 *Block = 0xffff;
177 CcSetDirtyPinnedData(Context, NULL);
178 CcUnpinData(Context);
179 if (DeviceExt->AvailableClustersValid)
180 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
181 return STATUS_SUCCESS;
182 }
183
184 Block++;
185 i++;
186 }
187
188 CcUnpinData(Context);
189 }
190
191 FatLength = StartCluster;
192 StartCluster = 2;
193 }
194
195 return STATUS_DISK_FULL;
196 }
197
198 /*
199 * FUNCTION: Finds the first available cluster in a FAT12 table
200 */
201 NTSTATUS
202 FAT12FindAndMarkAvailableCluster(
203 PDEVICE_EXTENSION DeviceExt,
204 PULONG Cluster)
205 {
206 ULONG FatLength;
207 ULONG StartCluster;
208 ULONG Entry;
209 PUSHORT CBlock;
210 ULONG i, j;
211 PVOID BaseAddress;
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 (!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
220 {
221 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
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)((char*)BaseAddress + (i * 12) / 8);
230 if ((i % 2) == 0)
231 {
232 Entry = *CBlock & 0xfff;
233 }
234 else
235 {
236 Entry = *CBlock >> 4;
237 }
238
239 if (Entry == 0)
240 {
241 DPRINT("Found available cluster 0x%x\n", i);
242 DeviceExt->LastAvailableCluster = *Cluster = i;
243 if ((i % 2) == 0)
244 *CBlock = (*CBlock & 0xf000) | 0xfff;
245 else
246 *CBlock = (*CBlock & 0xf) | 0xfff0;
247 CcSetDirtyPinnedData(Context, NULL);
248 CcUnpinData(Context);
249 if (DeviceExt->AvailableClustersValid)
250 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
251 return STATUS_SUCCESS;
252 }
253 }
254 FatLength = StartCluster;
255 StartCluster = 2;
256 }
257 CcUnpinData(Context);
258 return STATUS_DISK_FULL;
259 }
260
261 /*
262 * FUNCTION: Finds the first available cluster in a FAT32 table
263 */
264 NTSTATUS
265 FAT32FindAndMarkAvailableCluster(
266 PDEVICE_EXTENSION DeviceExt,
267 PULONG Cluster)
268 {
269 ULONG FatLength;
270 ULONG StartCluster;
271 ULONG i, j;
272 PVOID BaseAddress;
273 ULONG ChunkSize;
274 PVOID Context;
275 LARGE_INTEGER Offset;
276 PULONG Block;
277 PULONG BlockEnd;
278
279 ChunkSize = CACHEPAGESIZE(DeviceExt);
280 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
281 *Cluster = 0;
282 StartCluster = DeviceExt->LastAvailableCluster;
283
284 for (j = 0; j < 2; j++)
285 {
286 for (i = StartCluster; i < FatLength;)
287 {
288 Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
289 if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
290 {
291 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
292 return STATUS_UNSUCCESSFUL;
293 }
294 Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
295 BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
296
297 /* Now process the whole block */
298 while (Block < BlockEnd && i < FatLength)
299 {
300 if ((*Block & 0x0fffffff) == 0)
301 {
302 DPRINT("Found available cluster 0x%x\n", i);
303 DeviceExt->LastAvailableCluster = *Cluster = i;
304 *Block = 0x0fffffff;
305 CcSetDirtyPinnedData(Context, NULL);
306 CcUnpinData(Context);
307 if (DeviceExt->AvailableClustersValid)
308 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
309 return STATUS_SUCCESS;
310 }
311
312 Block++;
313 i++;
314 }
315
316 CcUnpinData(Context);
317 }
318 FatLength = StartCluster;
319 StartCluster = 2;
320 }
321 return STATUS_DISK_FULL;
322 }
323
324 /*
325 * FUNCTION: Counts free cluster in a FAT12 table
326 */
327 static
328 NTSTATUS
329 FAT12CountAvailableClusters(
330 PDEVICE_EXTENSION DeviceExt)
331 {
332 ULONG Entry;
333 PVOID BaseAddress;
334 ULONG ulCount = 0;
335 ULONG i;
336 ULONG numberofclusters;
337 LARGE_INTEGER Offset;
338 PVOID Context;
339 PUSHORT CBlock;
340
341 Offset.QuadPart = 0;
342 if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
343 {
344 return STATUS_UNSUCCESSFUL;
345 }
346
347 numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;
348
349 for (i = 2; i < numberofclusters; i++)
350 {
351 CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
352 if ((i % 2) == 0)
353 {
354 Entry = *CBlock & 0x0fff;
355 }
356 else
357 {
358 Entry = *CBlock >> 4;
359 }
360
361 if (Entry == 0)
362 ulCount++;
363 }
364
365 CcUnpinData(Context);
366 DeviceExt->AvailableClusters = ulCount;
367 DeviceExt->AvailableClustersValid = TRUE;
368
369 return STATUS_SUCCESS;
370 }
371
372
373 /*
374 * FUNCTION: Counts free clusters in a FAT16 table
375 */
376 static
377 NTSTATUS
378 FAT16CountAvailableClusters(
379 PDEVICE_EXTENSION DeviceExt)
380 {
381 PUSHORT Block;
382 PUSHORT BlockEnd;
383 PVOID BaseAddress = NULL;
384 ULONG ulCount = 0;
385 ULONG i;
386 ULONG ChunkSize;
387 PVOID Context = NULL;
388 LARGE_INTEGER Offset;
389 ULONG FatLength;
390
391 ChunkSize = CACHEPAGESIZE(DeviceExt);
392 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
393
394 for (i = 2; i < FatLength; )
395 {
396 Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
397 if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
398 {
399 return STATUS_UNSUCCESSFUL;
400 }
401 Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
402 BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
403
404 /* Now process the whole block */
405 while (Block < BlockEnd && i < FatLength)
406 {
407 if (*Block == 0)
408 ulCount++;
409 Block++;
410 i++;
411 }
412
413 CcUnpinData(Context);
414 }
415
416 DeviceExt->AvailableClusters = ulCount;
417 DeviceExt->AvailableClustersValid = TRUE;
418
419 return STATUS_SUCCESS;
420 }
421
422
423 /*
424 * FUNCTION: Counts free clusters in a FAT32 table
425 */
426 static
427 NTSTATUS
428 FAT32CountAvailableClusters(
429 PDEVICE_EXTENSION DeviceExt)
430 {
431 PULONG Block;
432 PULONG BlockEnd;
433 PVOID BaseAddress = NULL;
434 ULONG ulCount = 0;
435 ULONG i;
436 ULONG ChunkSize;
437 PVOID Context = NULL;
438 LARGE_INTEGER Offset;
439 ULONG FatLength;
440
441 ChunkSize = CACHEPAGESIZE(DeviceExt);
442 FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
443
444 for (i = 2; i < FatLength; )
445 {
446 Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
447 if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
448 {
449 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
450 return STATUS_UNSUCCESSFUL;
451 }
452 Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
453 BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
454
455 /* Now process the whole block */
456 while (Block < BlockEnd && i < FatLength)
457 {
458 if ((*Block & 0x0fffffff) == 0)
459 ulCount++;
460 Block++;
461 i++;
462 }
463
464 CcUnpinData(Context);
465 }
466
467 DeviceExt->AvailableClusters = ulCount;
468 DeviceExt->AvailableClustersValid = TRUE;
469
470 return STATUS_SUCCESS;
471 }
472
473 NTSTATUS
474 CountAvailableClusters(
475 PDEVICE_EXTENSION DeviceExt,
476 PLARGE_INTEGER Clusters)
477 {
478 NTSTATUS Status = STATUS_SUCCESS;
479 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
480 if (!DeviceExt->AvailableClustersValid)
481 {
482 if (DeviceExt->FatInfo.FatType == FAT12)
483 Status = FAT12CountAvailableClusters(DeviceExt);
484 else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16)
485 Status = FAT16CountAvailableClusters(DeviceExt);
486 else
487 Status = FAT32CountAvailableClusters(DeviceExt);
488 }
489 Clusters->QuadPart = DeviceExt->AvailableClusters;
490 ExReleaseResourceLite (&DeviceExt->FatResource);
491
492 return Status;
493 }
494
495
496 /*
497 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
498 */
499 NTSTATUS
500 FAT12WriteCluster(
501 PDEVICE_EXTENSION DeviceExt,
502 ULONG ClusterToWrite,
503 ULONG NewValue,
504 PULONG OldValue)
505 {
506 ULONG FATOffset;
507 PUCHAR CBlock;
508 PVOID BaseAddress;
509 PVOID Context;
510 LARGE_INTEGER Offset;
511
512 Offset.QuadPart = 0;
513 if (!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
514 {
515 return STATUS_UNSUCCESSFUL;
516 }
517 CBlock = (PUCHAR)BaseAddress;
518
519 FATOffset = (ClusterToWrite * 12) / 8;
520 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
521 NewValue, ClusterToWrite, FATOffset);
522 if ((ClusterToWrite % 2) == 0)
523 {
524 *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
525 CBlock[FATOffset] = (UCHAR)NewValue;
526 CBlock[FATOffset + 1] &= 0xf0;
527 CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
528 }
529 else
530 {
531 *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
532 CBlock[FATOffset] &= 0x0f;
533 CBlock[FATOffset] |= (NewValue & 0xf) << 4;
534 CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4);
535 }
536 /* Write the changed FAT sector(s) to disk */
537 CcSetDirtyPinnedData(Context, NULL);
538 CcUnpinData(Context);
539 return STATUS_SUCCESS;
540 }
541
542 /*
543 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
544 */
545 NTSTATUS
546 FAT16WriteCluster(
547 PDEVICE_EXTENSION DeviceExt,
548 ULONG ClusterToWrite,
549 ULONG NewValue,
550 PULONG OldValue)
551 {
552 PVOID BaseAddress;
553 ULONG FATOffset;
554 ULONG ChunkSize;
555 PVOID Context;
556 LARGE_INTEGER Offset;
557 PUSHORT Cluster;
558
559 ChunkSize = CACHEPAGESIZE(DeviceExt);
560 FATOffset = ClusterToWrite * 2;
561 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
562 if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
563 {
564 return STATUS_UNSUCCESSFUL;
565 }
566
567 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
568 ClusterToWrite);
569 Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
570 *OldValue = *Cluster;
571 *Cluster = (USHORT)NewValue;
572 CcSetDirtyPinnedData(Context, NULL);
573 CcUnpinData(Context);
574 return STATUS_SUCCESS;
575 }
576
577 /*
578 * FUNCTION: Writes a cluster to the FAT32 physical tables
579 */
580 NTSTATUS
581 FAT32WriteCluster(
582 PDEVICE_EXTENSION DeviceExt,
583 ULONG ClusterToWrite,
584 ULONG NewValue,
585 PULONG OldValue)
586 {
587 PVOID BaseAddress;
588 ULONG FATOffset;
589 ULONG ChunkSize;
590 PVOID Context;
591 LARGE_INTEGER Offset;
592 PULONG Cluster;
593
594 ChunkSize = CACHEPAGESIZE(DeviceExt);
595
596 FATOffset = (ClusterToWrite * 4);
597 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
598 if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
599 {
600 return STATUS_UNSUCCESSFUL;
601 }
602
603 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
604 ClusterToWrite);
605 Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize)));
606 *OldValue = *Cluster & 0x0fffffff;
607 *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
608
609 CcSetDirtyPinnedData(Context, NULL);
610 CcUnpinData(Context);
611
612 return STATUS_SUCCESS;
613 }
614
615
616 /*
617 * FUNCTION: Write a changed FAT entry
618 */
619 NTSTATUS
620 WriteCluster(
621 PDEVICE_EXTENSION DeviceExt,
622 ULONG ClusterToWrite,
623 ULONG NewValue)
624 {
625 NTSTATUS Status;
626 ULONG OldValue;
627
628 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
629 Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
630 if (DeviceExt->AvailableClustersValid)
631 {
632 if (OldValue && NewValue == 0)
633 InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters);
634 else if (OldValue == 0 && NewValue)
635 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
636 }
637 ExReleaseResourceLite(&DeviceExt->FatResource);
638 return Status;
639 }
640
641 /*
642 * FUNCTION: Converts the cluster number to a sector number for this physical
643 * device
644 */
645 ULONGLONG
646 ClusterToSector(
647 PDEVICE_EXTENSION DeviceExt,
648 ULONG Cluster)
649 {
650 return DeviceExt->FatInfo.dataStart +
651 ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
652
653 }
654
655 /*
656 * FUNCTION: Retrieve the next cluster depending on the FAT type
657 */
658 NTSTATUS
659 GetNextCluster(
660 PDEVICE_EXTENSION DeviceExt,
661 ULONG CurrentCluster,
662 PULONG NextCluster)
663 {
664 NTSTATUS Status;
665
666 DPRINT("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
667 DeviceExt, CurrentCluster);
668
669 if (CurrentCluster == 0)
670 return STATUS_INVALID_PARAMETER;
671
672 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
673 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
674 ExReleaseResourceLite(&DeviceExt->FatResource);
675
676 return Status;
677 }
678
679 /*
680 * FUNCTION: Retrieve the next cluster depending on the FAT type
681 */
682 NTSTATUS
683 GetNextClusterExtend(
684 PDEVICE_EXTENSION DeviceExt,
685 ULONG CurrentCluster,
686 PULONG NextCluster)
687 {
688 ULONG NewCluster;
689 NTSTATUS Status;
690
691 DPRINT("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
692 DeviceExt, CurrentCluster);
693
694 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
695 /*
696 * If the file hasn't any clusters allocated then we need special
697 * handling
698 */
699 if (CurrentCluster == 0)
700 {
701 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
702 if (!NT_SUCCESS(Status))
703 {
704 ExReleaseResourceLite(&DeviceExt->FatResource);
705 return Status;
706 }
707
708 *NextCluster = NewCluster;
709 ExReleaseResourceLite(&DeviceExt->FatResource);
710 return STATUS_SUCCESS;
711 }
712
713 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
714
715 if ((*NextCluster) == 0xFFFFFFFF)
716 {
717 /* We are after last existing cluster, we must add one to file */
718 /* Firstly, find the next available open allocation unit and
719 mark it as end of file */
720 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
721 if (!NT_SUCCESS(Status))
722 {
723 ExReleaseResourceLite(&DeviceExt->FatResource);
724 return Status;
725 }
726
727 /* Now, write the AU of the LastCluster with the value of the newly
728 found AU */
729 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
730 *NextCluster = NewCluster;
731 }
732
733 ExReleaseResourceLite(&DeviceExt->FatResource);
734 return Status;
735 }
736
737 /* EOF */