7bf62efc6c89b57311a8bc10fc17f5d005eaeb30
[tpg/acess2.git] / KernelLand / Modules / Filesystems / FAT / fatio.c
1 /*
2  * Acess2 FAT12/16/32 Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * fatio.c
6  * - FAT Manipulation and Cluster IO
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <vfs.h>
11 #include "common.h"
12
13 // === CODE ===
14 /**
15  * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
16  * \brief Fetches a value from the FAT
17  */
18 Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
19 {
20         Uint32  val = 0;
21         Uint32  ofs;
22         ENTER("pDisk xCluster", Disk, cluster);
23         
24         Mutex_Acquire( &Disk->lFAT );
25         #if CACHE_FAT
26         if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
27         {
28                 val = Disk->FATCache[cluster];
29                 if(Disk->type == FAT12 && val == EOC_FAT12)     val = GETFATVALUE_EOC;
30                 if(Disk->type == FAT16 && val == EOC_FAT16)     val = GETFATVALUE_EOC;
31                 if(Disk->type == FAT32 && val == EOC_FAT32)     val = GETFATVALUE_EOC;
32         }
33         else
34         {
35         #endif
36                 ofs = Disk->bootsect.resvSectCount*512;
37                 if(Disk->type == FAT12) {
38                         VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);
39                         LOG("3 bytes at 0x%x are (Uint32)0x%x", ofs+(cluster/2)*3, val);
40                         val = (cluster & 1) ? (val>>12) : (val & 0xFFF);
41                         if(val == EOC_FAT12)    val = GETFATVALUE_EOC;
42                 } else if(Disk->type == FAT16) {
43                         VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);
44                         if(val == EOC_FAT16)    val = GETFATVALUE_EOC;
45                 } else {
46                         VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);
47                         if(val == EOC_FAT32)    val = GETFATVALUE_EOC;
48                 }
49         #if CACHE_FAT
50         }
51         #endif /*CACHE_FAT*/
52         Mutex_Release( &Disk->lFAT );
53         LEAVE('x', val);
54         return val;
55 }
56
57 #if SUPPORT_WRITE
58 /**
59  * \brief Allocate a new cluster
60  */
61 Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)
62 {
63         Uint32  ret = -1;
64         
65         #if CACHE_FAT
66         if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
67         {
68                  int    bFoundCluster = 0;
69                 Uint32  eoc;
70
71                 switch(Disk->type)
72                 {
73                 case FAT12:     eoc = EOC_FAT12;        break;
74                 case FAT16:     eoc = EOC_FAT16;        break;
75                 case FAT32:     eoc = EOC_FAT32;        break;
76                         default:        return 0;
77                 }
78                 
79                 Mutex_Acquire(&Disk->lFAT);
80                 if( Previous != -1 )
81                 {
82                         for(ret = Previous; ret < Disk->ClusterCount; ret++)
83                         {
84                                 if(Disk->FATCache[ret] != 0) {
85                                         bFoundCluster = 1;
86                                         break;
87                                 }
88                         }
89                 }
90                 if( !bFoundCluster )
91                 {
92                         for(ret = 0; ret < Previous; ret++)
93                         {
94                                 if(Disk->FATCache[ret] == 0) {
95                                         bFoundCluster = 1;
96                                         break;
97                                 }
98                         }
99                 }
100                 
101                 if(bFoundCluster)
102                 { 
103                         Disk->FATCache[ret] = eoc;
104                         if( Previous != -1 )
105                                 Disk->FATCache[Previous] = ret;
106                 }
107                 else
108                 {
109                         ret = 0;
110                 }
111                         
112                 Mutex_Release(&Disk->lFAT);
113                 LOG("Allocated cluster %x", ret);
114                 return ret;
115         }
116         else
117         {
118         #endif
119                 Uint32  val = 0;
120                 Uint32  base = Disk->bootsect.resvSectCount*512;
121                  int    block = 0, block_ofs = 0;
122                  int    first_block;
123                 const int       block_size = 512*3;
124                 const int       ents_per_block_12 = block_size * 2 / 3; // 1.5 bytes per entry
125 //              const int       ents_per_block_16 = block_size / 2;     // 2 bytes per entry
126 //              const int       ents_per_block_32 = block_size / 4;     // 4 bytes per entry
127                  int    block_count_12 = DivUp(Disk->ClusterCount, ents_per_block_12);
128                 Uint8   sector_data[block_size+1];
129                 sector_data[block_size] = 0;
130                 
131                 Mutex_Acquire(&Disk->lFAT);
132                 switch(Disk->type)
133                 {
134                 case FAT12:
135                         if( Previous != -1 )
136                                 block = Previous / ents_per_block_12;
137                         else
138                                 block = 0;
139                         first_block = block;
140                         
141                         // Search within the same block as the previous cluster first
142                         do {
143                                 VFS_ReadAt(Disk->fileHandle, base + block*block_size, block_size, sector_data);
144                                 for( block_ofs = 0; block_ofs < ents_per_block_12; block_ofs ++ )
145                                 {
146                                         Uint32  *valptr = (void*)( sector_data + block_ofs / 2 * 3 );
147                                          int    bitofs = 12 * (block_ofs % 2);
148 //                                      LOG("%i:%i - FAT Ent 0x%03x", block, block_ofs, (*valptr>>bitofs) & 0xFFF);
149                                         if( ((*valptr >> bitofs) & 0xFFF) == 0 ) {
150                                                 // Found a free cluster
151                                                 *valptr |= EOC_FAT12 << bitofs;
152                                                 ret = block * ents_per_block_12 + block_ofs;
153                                                 break;
154                                         }
155                                 }
156                                 // Check for early break from the above loop
157                                 if( block_ofs != ents_per_block_12 )
158                                         break;
159
160                                 // Next block please
161                                 block ++;
162                                 if( block == block_count_12 )
163                                         block = 0;
164                         } while( block != first_block );
165                         
166                         if( ret != 0 )  // TODO: Could cluster 0 be valid?
167                         {
168                                 // Write back changes to this part of the FAT
169                                 VFS_WriteAt(Disk->fileHandle, base + block, block_size, sector_data);
170         
171                                 // Note the new cluster in the chain
172                                 if( Previous != -1 )
173                                 {
174                                         LOG("Updating cluster %x to point to %x (offset %x)", Previous, ret,
175                                                 base + (Previous>>1)*3);
176                                         VFS_ReadAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val); 
177                                         if( Previous & 1 ) {
178                                                 val &= 0x000FFF;
179                                                 val |= ret << 12;
180                                         }
181                                         else {
182                                                 val &= 0xFFF000;
183                                                 val |= ret << 0;
184                                         }
185                                         VFS_WriteAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
186                                 }
187                         }
188                         break;
189                 case FAT16:
190                         Log_Warning("FAT", "TODO: Implement cluster allocation with FAT16");
191 //                      VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);
192 //                      VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);
193                         break;
194                 case FAT32:
195                         Log_Warning("FAT", "TODO: Implement cluster allocation with FAT32");
196 //                      VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);
197 //                      VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);
198                         break;
199                 }
200                 Mutex_Release(&Disk->lFAT);
201                 LOG("Allocated cluster %x", ret);
202                 return ret;
203         #if CACHE_FAT
204         }
205         #endif
206 }
207
208 /**
209  * \brief Free's a cluster
210  * \return The original contents of the cluster
211  */
212 Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)
213 {
214         Uint32  ret;
215
216         if( Cluster < 2 || Cluster > Disk->ClusterCount )       // oops?
217         {
218                 Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)", 
219                         Cluster, Disk->ClusterCount-1);
220                 return -1;
221         }
222         
223         Mutex_Acquire(&Disk->lFAT);
224         #if CACHE_FAT
225         if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
226         {
227                 
228                 ret = Disk->FATCache[Cluster];
229                 Disk->FATCache[Cluster] = 0;
230         }
231         else
232         {
233         #endif
234                 Uint32  val = 0;
235                 Uint32  ofs = Disk->bootsect.resvSectCount*512;
236                 switch(Disk->type)
237                 {
238                 case FAT12:
239                         VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
240                         val = LittleEndian32(val);
241                         if( Cluster & 1 ) {
242                                 ret = (val >> 12) & 0xFFF;
243                                 val &= 0xFFF;
244                         }
245                         else {
246                                 ret = val & 0xFFF;
247                                 val &= 0xFFF000;
248                         }
249                         val = LittleEndian32(val);
250                         VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
251                         break;
252                 case FAT16:
253                         VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret);
254                         ret = LittleEndian16(ret);
255                         val = 0;
256                         VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);
257                         break;
258                 case FAT32:
259                         VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret);
260                         ret = LittleEndian32(ret);
261                         val = 0;
262                         VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val);
263                         break;
264                 }
265         #if CACHE_FAT
266         }
267         #endif
268         Mutex_Release(&Disk->lFAT);
269         LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12);
270         if(ret == 0) {
271                 Log_Notice("FAT", "Cluster 0x%x was already free", Cluster);
272                 return -1;
273         }
274         if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;
275         if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;
276         if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;
277         LOG("ret = %07x", ret);
278         return ret;
279 }
280 #endif
281
282 /*
283  * ====================
284  *      Cluster IO
285  * ====================
286  */
287 /**
288  * \brief Read a cluster
289  * \param Disk  Disk (Volume) to read from
290  * \param Length        Length to read
291  * \param Buffer        Destination for read data
292  */
293 void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)
294 {
295         ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);
296         VFS_ReadAt(
297                 Disk->fileHandle,
298                 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
299                         * Disk->bootsect.bps,
300                 Length,
301                 Buffer
302                 );
303         LEAVE('-');
304 }
305
306 #if SUPPORT_WRITE
307 /**
308  * \brief Write a cluster to disk
309  */
310 void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer)
311 {
312         ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);
313         VFS_WriteAt(
314                 Disk->fileHandle,
315                 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
316                         * Disk->bootsect.bps,
317                 Disk->BytesPerCluster,
318                 Buffer
319                 );
320         LEAVE('-');
321 }
322 #endif

UCC git Repository :: git.ucc.asn.au