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

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