Create this branch to work on loading of different Kernel-Debugger DLL providers...
[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 FATOffset;
482 PUCHAR CBlock;
483 PVOID BaseAddress;
484 PVOID Context;
485 LARGE_INTEGER Offset;
486
487 Offset.QuadPart = 0;
488 if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
489 {
490 return STATUS_UNSUCCESSFUL;
491 }
492 CBlock = (PUCHAR)BaseAddress;
493
494 FATOffset = (ClusterToWrite * 12) / 8;
495 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
496 NewValue, ClusterToWrite, FATOffset);
497 if ((ClusterToWrite % 2) == 0)
498 {
499 *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
500 CBlock[FATOffset] = (UCHAR)NewValue;
501 CBlock[FATOffset + 1] &= 0xf0;
502 CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
503 }
504 else
505 {
506 *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
507 CBlock[FATOffset] &= 0x0f;
508 CBlock[FATOffset] |= (NewValue & 0xf) << 4;
509 CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4);
510 }
511 /* Write the changed FAT sector(s) to disk */
512 CcSetDirtyPinnedData(Context, NULL);
513 CcUnpinData(Context);
514 return(STATUS_SUCCESS);
515 }
516
517 NTSTATUS
518 FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt,
519 ULONG ClusterToWrite,
520 ULONG NewValue,
521 PULONG OldValue)
522 /*
523 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
524 */
525 {
526 PVOID BaseAddress;
527 ULONG FATOffset;
528 ULONG ChunkSize;
529 PVOID Context;
530 LARGE_INTEGER Offset;
531 PUSHORT Cluster;
532
533 ChunkSize = CACHEPAGESIZE(DeviceExt);
534 FATOffset = ClusterToWrite * 2;
535 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
536 if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
537 {
538 return STATUS_UNSUCCESSFUL;
539 }
540 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
541 ClusterToWrite);
542 Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
543 *OldValue = *Cluster;
544 *Cluster = (USHORT)NewValue;
545 CcSetDirtyPinnedData(Context, NULL);
546 CcUnpinData(Context);
547 return(STATUS_SUCCESS);
548 }
549
550 NTSTATUS
551 FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt,
552 ULONG ClusterToWrite,
553 ULONG NewValue,
554 PULONG OldValue)
555 /*
556 * FUNCTION: Writes a cluster to the FAT32 physical tables
557 */
558 {
559 PVOID BaseAddress;
560 ULONG FATOffset;
561 ULONG ChunkSize;
562 PVOID Context;
563 LARGE_INTEGER Offset;
564 PULONG Cluster;
565
566 ChunkSize = CACHEPAGESIZE(DeviceExt);
567
568 FATOffset = (ClusterToWrite * 4);
569 Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
570 if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
571 {
572 return STATUS_UNSUCCESSFUL;
573 }
574 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
575 ClusterToWrite);
576 Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize)));
577 *OldValue = *Cluster & 0x0fffffff;
578 *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
579
580 CcSetDirtyPinnedData(Context, NULL);
581 CcUnpinData(Context);
582
583 return(STATUS_SUCCESS);
584 }
585
586
587 NTSTATUS
588 WriteCluster(PDEVICE_EXTENSION DeviceExt,
589 ULONG ClusterToWrite,
590 ULONG NewValue)
591 /*
592 * FUNCTION: Write a changed FAT entry
593 */
594 {
595 NTSTATUS Status;
596 ULONG OldValue;
597 ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
598 Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
599 if (DeviceExt->AvailableClustersValid)
600 {
601 if (OldValue && NewValue == 0)
602 InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters);
603 else if (OldValue == 0 && NewValue)
604 InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
605 }
606 ExReleaseResourceLite(&DeviceExt->FatResource);
607 return(Status);
608 }
609
610 ULONGLONG
611 ClusterToSector(PDEVICE_EXTENSION DeviceExt,
612 ULONG Cluster)
613 /*
614 * FUNCTION: Converts the cluster number to a sector number for this physical
615 * device
616 */
617 {
618 return DeviceExt->FatInfo.dataStart +
619 ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
620
621 }
622
623 NTSTATUS
624 GetNextCluster(PDEVICE_EXTENSION DeviceExt,
625 ULONG CurrentCluster,
626 PULONG NextCluster)
627 /*
628 * FUNCTION: Retrieve the next cluster depending on the FAT type
629 */
630 {
631 NTSTATUS Status;
632
633 DPRINT ("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
634 DeviceExt, CurrentCluster);
635
636 if (CurrentCluster == 0)
637 return(STATUS_INVALID_PARAMETER);
638
639 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
640 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
641 ExReleaseResourceLite(&DeviceExt->FatResource);
642
643 return(Status);
644 }
645
646 NTSTATUS
647 GetNextClusterExtend(PDEVICE_EXTENSION DeviceExt,
648 ULONG CurrentCluster,
649 PULONG NextCluster)
650 /*
651 * FUNCTION: Retrieve the next cluster depending on the FAT type
652 */
653 {
654 NTSTATUS Status;
655
656 DPRINT ("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
657 DeviceExt, CurrentCluster);
658
659 ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
660 /*
661 * If the file hasn't any clusters allocated then we need special
662 * handling
663 */
664 if (CurrentCluster == 0)
665 {
666 ULONG NewCluster;
667
668 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
669 if (!NT_SUCCESS(Status))
670 {
671 ExReleaseResourceLite(&DeviceExt->FatResource);
672 return Status;
673 }
674
675 *NextCluster = NewCluster;
676 ExReleaseResourceLite(&DeviceExt->FatResource);
677 return(STATUS_SUCCESS);
678 }
679
680 Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
681
682 if ((*NextCluster) == 0xFFFFFFFF)
683 {
684 ULONG NewCluster;
685
686 /* We are after last existing cluster, we must add one to file */
687 /* Firstly, find the next available open allocation unit and
688 mark it as end of file */
689 Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
690 if (!NT_SUCCESS(Status))
691 {
692 ExReleaseResourceLite(&DeviceExt->FatResource);
693 return Status;
694 }
695
696 /* Now, write the AU of the LastCluster with the value of the newly
697 found AU */
698 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
699 *NextCluster = NewCluster;
700 }
701
702 ExReleaseResourceLite(&DeviceExt->FatResource);
703
704 return(Status);
705 }
706
707 /* EOF */