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