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