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