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