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

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