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