6a35b7a436eb240466ec89c086d71742cc92a179
[reactos.git] / reactos / drivers / fs / vfat / fat.c
1 /*
2 * $Id: fat.c,v 1.7 2000/12/07 16:58:42 jean Exp $
3 *
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS kernel
6 * FILE: services/fs/vfat/fat.c
7 * PURPOSE: VFAT Filesystem
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 *
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <wchar.h>
16 #include <ddk/cctypes.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /* FUNCTIONS ****************************************************************/
24
25 ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
26 /*
27 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
28 * disk read
29 */
30 {
31 ULONG FATsector;
32 ULONG FATeis;
33 PULONG Block;
34
35 Block = ExAllocatePool(NonPagedPool,1024);
36 FATsector=CurrentCluster/(512/sizeof(ULONG));
37 FATeis=CurrentCluster-(FATsector*(512/sizeof(ULONG)));
38 VFATReadSectors(DeviceExt->StorageDevice
39 ,(ULONG)(DeviceExt->FATStart+FATsector), 1,(UCHAR*) Block);
40 CurrentCluster = Block[FATeis];
41 if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
42 CurrentCluster = 0xffffffff;
43 ExFreePool(Block);
44 return(CurrentCluster);
45 }
46
47 ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
48 /*
49 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table from the
50 * in-memory FAT
51 */
52 {
53 PUSHORT Block;
54 Block=(PUSHORT)DeviceExt->FAT;
55 CurrentCluster = Block[CurrentCluster];
56 if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
57 CurrentCluster = 0xffffffff;
58 DPRINT("Returning %x\n",CurrentCluster);
59 return(CurrentCluster);
60 }
61
62 ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
63 /*
64 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table from the
65 * in-memory FAT
66 */
67 {
68 unsigned char* CBlock;
69 ULONG FATOffset;
70 ULONG Entry;
71 CBlock = DeviceExt->FAT;
72 FATOffset = (CurrentCluster * 12)/ 8;//first byte containing value
73 if ((CurrentCluster % 2) == 0)
74 {
75 Entry = CBlock[FATOffset];
76 Entry |= ((CBlock[FATOffset+1] & 0xf)<<8);
77 }
78 else
79 {
80 Entry = (CBlock[FATOffset] >> 4);
81 Entry |= (CBlock[FATOffset+1] << 4);
82 }
83 DPRINT("Entry %x\n",Entry);
84 if (Entry >= 0xff8 && Entry <= 0xfff)
85 Entry = 0xffffffff;
86 DPRINT("Returning %x\n",Entry);
87 return(Entry);
88 }
89
90 ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
91 /*
92 * FUNCTION: Retrieve the next cluster depending on the FAT type
93 */
94 {
95 ULONG NextCluster;
96
97 DPRINT("GetNextCluster(DeviceExt %x, CurrentCluster %x)\n",
98 DeviceExt,CurrentCluster);
99
100 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
101
102 if (DeviceExt->FatType == FAT16)
103 {
104 NextCluster = Fat16GetNextCluster(DeviceExt, CurrentCluster);
105 }
106 else if (DeviceExt->FatType == FAT32)
107 {
108 NextCluster = Fat32GetNextCluster(DeviceExt, CurrentCluster);
109 }
110 else
111 {
112 NextCluster = Fat12GetNextCluster(DeviceExt, CurrentCluster);
113 }
114
115 ExReleaseResourceLite(&DeviceExt->FatResource);
116
117 return(NextCluster);
118 }
119
120 ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
121 /*
122 * FUNCTION: Finds the first available cluster in a FAT16 table
123 */
124 {
125 PUSHORT Block;
126 int i;
127 Block=(PUSHORT)DeviceExt->FAT;
128 for(i=2;i<(DeviceExt->Boot->FATSectors*256) ;i++)
129 if(Block[i]==0)
130 return (i);
131 /* Give an error message (out of disk space) if we reach here) */
132 return 0;
133 }
134
135 ULONG FAT12FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
136 /*
137 * FUNCTION: Finds the first available cluster in a FAT12 table
138 */
139 {
140 ULONG FATOffset;
141 ULONG Entry;
142 PUCHAR CBlock=DeviceExt->FAT;
143 ULONG i;
144 for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
145 {
146 FATOffset = (i * 12)/8;
147 if ((i % 2) == 0)
148 {
149 Entry = CBlock[FATOffset];
150 Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
151 }
152 else
153 {
154 Entry = (CBlock[FATOffset] >> 4);
155 Entry |= (CBlock[FATOffset + 1] << 4);
156 }
157 if(Entry==0)
158 return (i);
159 }
160 /* Give an error message (out of disk space) if we reach here) */
161 DbgPrint("Disk full, %d clusters used\n",i);
162 return 0;
163 }
164
165 ULONG FAT32FindAvailableCluster(PDEVICE_EXTENSION DeviceExt)
166 /*
167 * FUNCTION: Finds the first available cluster in a FAT32 table
168 */
169 {
170 ULONG sector;
171 PULONG Block;
172 int i;
173 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
174 for(sector=0
175 ;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
176 ;sector++)
177 {
178 VFATReadSectors(DeviceExt->StorageDevice
179 ,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
180
181 for(i=0; i<512; i++)
182 {
183 if(Block[i]==0)
184 {
185 ExFreePool(Block);
186 return (i+sector*128);
187 }
188 }
189 }
190 /* Give an error message (out of disk space) if we reach here) */
191 ExFreePool(Block);
192 return 0;
193 }
194
195 ULONG FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
196 /*
197 * FUNCTION: Counts free cluster in a FAT12 table
198 */
199 {
200 ULONG FATOffset;
201 ULONG Entry;
202 PUCHAR CBlock=DeviceExt->FAT;
203 ULONG ulCount = 0;
204 ULONG i;
205
206 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
207
208 for(i=2;i<((DeviceExt->Boot->FATSectors*512*8)/12) ;i++)
209 {
210 FATOffset = (i * 12)/8;
211 if ((i % 2) == 0)
212 {
213 Entry = CBlock[FATOffset];
214 Entry |= ((CBlock[FATOffset + 1] & 0xf)<<8);
215 }
216 else
217 {
218 Entry = (CBlock[FATOffset] >> 4);
219 Entry |= (CBlock[FATOffset + 1] << 4);
220 }
221 if(Entry==0)
222 ulCount++;
223 }
224
225 ExReleaseResourceLite(&DeviceExt->FatResource);
226
227 return ulCount;
228 }
229
230 ULONG FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
231 /*
232 * FUNCTION: Counts free clusters in a FAT16 table
233 */
234 {
235 PUSHORT Block;
236 ULONG ulCount = 0;
237 ULONG i;
238
239 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
240
241 Block=(PUSHORT)DeviceExt->FAT;
242 for(i=2;i<(DeviceExt->Boot->FATSectors*256);i++)
243 {
244 if(Block[i]==0)
245 ulCount++;
246 }
247
248 ExReleaseResourceLite(&DeviceExt->FatResource);
249
250 return ulCount;
251 }
252
253 ULONG FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
254 /*
255 * FUNCTION: Counts free clusters in a FAT32 table
256 */
257 {
258 ULONG sector;
259 PULONG Block;
260 ULONG ulCount = 0;
261 ULONG i;
262
263 ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
264
265 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
266 for(sector=0
267 ;sector< ((struct _BootSector32*)(DeviceExt->Boot))->FATSectors32
268 ;sector++)
269 {
270 VFATReadSectors(DeviceExt->StorageDevice
271 ,(ULONG)(DeviceExt->FATStart+sector), 1,(UCHAR*) Block);
272
273 for(i=0; i<512; i++)
274 {
275 if(Block[i]==0)
276 ulCount++;
277 }
278 }
279 /* Give an error message (out of disk space) if we reach here) */
280 ExFreePool(Block);
281 ExReleaseResourceLite(&DeviceExt->FatResource);
282 return ulCount;
283 }
284
285 void FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
286 ULONG NewValue)
287 /*
288 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
289 */
290 {
291 ULONG FATsector;
292 ULONG FATOffset;
293 PUCHAR CBlock=DeviceExt->FAT;
294 int i;
295 FATOffset = (ClusterToWrite * 12)/8;
296 if ((ClusterToWrite % 2) == 0)
297 {
298 CBlock[FATOffset]=NewValue;
299 CBlock[FATOffset + 1] &=0xf0;
300 CBlock[FATOffset + 1]
301 |= (NewValue&0xf00)>>8;
302 }
303 else
304 {
305 CBlock[FATOffset] &=0x0f;
306 CBlock[FATOffset]
307 |= (NewValue&0xf)<<4;
308 CBlock[FATOffset+1]=NewValue>>4;
309 }
310 /* Write the changed FAT sector(s) to disk */
311 FATsector=FATOffset/BLOCKSIZE;
312 for(i=0;i<DeviceExt->Boot->FATCount;i++)
313 {
314 if( (FATOffset%BLOCKSIZE)==(BLOCKSIZE-1))//entry is on 2 sectors
315 {
316 VFATWriteSectors(DeviceExt->StorageDevice,
317 DeviceExt->FATStart+FATsector
318 +i*DeviceExt->Boot->FATSectors,
319 2,
320 CBlock+FATsector*512);
321 }
322 else
323 {
324 VFATWriteSectors(DeviceExt->StorageDevice,
325 DeviceExt->FATStart+FATsector
326 +i*DeviceExt->Boot->FATSectors,
327 1,
328 CBlock+FATsector*512);
329 }
330 }
331 }
332
333 void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
334 ULONG NewValue)
335 /*
336 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
337 */
338 {
339 ULONG FATsector;
340 PUSHORT Block;
341 ULONG Start;
342 int i;
343
344 DbgPrint("FAT16WriteCluster %u : %u\n", ClusterToWrite, NewValue);
345
346 Block=(PUSHORT)DeviceExt->FAT;
347 FATsector=ClusterToWrite/(512/sizeof(USHORT));
348
349 /* Update the in-memory FAT */
350 Block[ClusterToWrite] = NewValue;
351
352 /* Write the changed FAT sector to disk (all FAT's) */
353 Start = DeviceExt->FATStart + FATsector;
354 for (i = 0; i < DeviceExt->Boot->FATCount; i++)
355 {
356 VFATWriteSectors(DeviceExt->StorageDevice,
357 Start,
358 1,
359 ((UCHAR *)Block)+FATsector*512);
360 Start += DeviceExt->Boot->FATSectors;
361 }
362 }
363
364 void FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
365 ULONG NewValue)
366 /*
367 * FUNCTION: Writes a cluster to the FAT32 physical tables
368 */
369 {
370 ULONG FATsector;
371 ULONG FATeis;
372 PUSHORT Block;
373 ULONG Start;
374 int i;
375 struct _BootSector32 *pBoot;
376 DbgPrint("FAT32WriteCluster %u : %u\n",ClusterToWrite,NewValue);
377 Block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
378 FATsector=ClusterToWrite/128;
379 FATeis=ClusterToWrite-(FATsector*128);
380 /* load sector, change value, then rewrite sector */
381 VFATReadSectors(DeviceExt->StorageDevice,
382 DeviceExt->FATStart+FATsector,
383 1,
384 (UCHAR *)Block);
385 Block[FATeis] = NewValue;
386 /* Write the changed FAT sector to disk (all FAT's) */
387 Start = DeviceExt->FATStart + FATsector;
388 pBoot = (struct _BootSector32*) DeviceExt->Boot;
389 for (i = 0; i < pBoot->FATCount; i++)
390 {
391 VFATWriteSectors(DeviceExt->StorageDevice,
392 Start,
393 1,
394 (UCHAR *)Block);
395 Start += pBoot->FATSectors;
396 }
397 ExFreePool(Block);
398 }
399
400 void WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite,
401 ULONG NewValue)
402 /*
403 * FUNCTION: Write a changed FAT entry
404 */
405 {
406 if (DeviceExt->FatType==FAT16)
407 {
408 FAT16WriteCluster(DeviceExt, ClusterToWrite, NewValue);
409 }
410 else if (DeviceExt->FatType==FAT32)
411 {
412 FAT32WriteCluster(DeviceExt, ClusterToWrite, NewValue);
413 }
414 else
415 {
416 FAT12WriteCluster(DeviceExt, ClusterToWrite, NewValue);
417 }
418 }
419
420 ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster)
421 /*
422 * FUNCTION: Determines the next cluster to be written
423 */
424 {
425 ULONG LastCluster, NewCluster;
426 UCHAR *Buffer2;
427
428 DPRINT("GetNextWriteCluster(DeviceExt %x, CurrentCluster %x)\n",
429 DeviceExt,CurrentCluster);
430
431 /* Find out what was happening in the last cluster's AU */
432 LastCluster=GetNextCluster(DeviceExt,
433 CurrentCluster);
434 /* Check to see if we must append or overwrite */
435 if (LastCluster == 0xffffffff)
436 {
437 /* we are after last existing cluster : we must add one to file */
438 /* Append */
439 /* Firstly, find the next available open allocation unit */
440 if (DeviceExt->FatType == FAT16)
441 {
442 NewCluster = FAT16FindAvailableCluster(DeviceExt);
443 DPRINT1("NewCluster %x\n", NewCluster);
444 }
445 else if (DeviceExt->FatType == FAT32)
446 {
447 NewCluster = FAT32FindAvailableCluster(DeviceExt);
448 }
449 else
450 {
451 NewCluster = FAT12FindAvailableCluster(DeviceExt);
452 DPRINT( "NewFat12Cluster: %x\n", NewCluster );
453 }
454 /* Mark the new AU as the EOF */
455 WriteCluster(DeviceExt, NewCluster, 0xFFFFFFFF);
456 /* Now, write the AU of the LastCluster with the value of the newly
457 found AU */
458 if(CurrentCluster)
459 {
460 WriteCluster(DeviceExt, CurrentCluster, NewCluster);
461 }
462 // fill cluster with zero
463 Buffer2=ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
464 memset(Buffer2,0,DeviceExt->BytesPerCluster);
465 VFATWriteCluster(DeviceExt,Buffer2,NewCluster);
466 ExFreePool(Buffer2);
467 /* Return NewCluster as CurrentCluster */
468 return NewCluster;
469 }
470 else
471 {
472 /* Overwrite: Return LastCluster as CurrentCluster */
473 return LastCluster;
474 }
475 }
476
477 ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt,
478 unsigned long Cluster)
479 /*
480 * FUNCTION: Converts the cluster number to a sector number for this physical
481 * device
482 */
483 {
484 return DeviceExt->dataStart+((Cluster-2)*DeviceExt->Boot->SectorsPerCluster);
485 }
486
487 void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
488 /*
489 * FUNCTION: Load a cluster from the physical device
490 */
491 {
492 ULONG Sector;
493
494 DPRINT("VFATLoadCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
495 DeviceExt,Buffer,Cluster);
496
497 Sector = ClusterToSector(DeviceExt, Cluster);
498
499 VFATReadSectors(DeviceExt->StorageDevice,
500 Sector,
501 DeviceExt->Boot->SectorsPerCluster,
502 Buffer);
503 DPRINT("Finished VFATReadSectors\n");
504 }
505
506 void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster)
507 /*
508 * FUNCTION: Write a cluster to the physical device
509 */
510 {
511 ULONG Sector;
512 DPRINT("VFATWriteCluster(DeviceExt %x, Buffer %x, Cluster %d)\n",
513 DeviceExt,Buffer,Cluster);
514
515 Sector = ClusterToSector(DeviceExt, Cluster);
516
517 VFATWriteSectors(DeviceExt->StorageDevice,
518 Sector,
519 DeviceExt->Boot->SectorsPerCluster,
520 Buffer);
521 }
522