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

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