]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-FAT-SL/fat_sl/common/fat.c
Slight modification to license blub text in header comments.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-FAT-SL / fat_sl / common / fat.c
1 /*\r
2  * FreeRTOS+FAT FS V1.0.0 (C) 2013 HCC Embedded\r
3  *\r
4  * The FreeRTOS+FAT SL license terms are different to the FreeRTOS license \r
5  * terms.\r
6  * \r
7  * FreeRTOS+FAT SL uses a dual license model that allows the software to be used \r
8  * under a standard GPL open source license, or a commercial license.  The \r
9  * standard GPL license (unlike the modified GPL license under which FreeRTOS \r
10  * itself is distributed) requires that all software statically linked with \r
11  * FreeRTOS+FAT SL is also distributed under the same GPL V2 license terms.  \r
12  * Details of both license options follow:\r
13  * \r
14  * - Open source licensing -\r
15  * FreeRTOS+FAT SL is a free download and may be used, modified, evaluated and\r
16  * distributed without charge provided the user adheres to version two of the \r
17  * GNU General Public License (GPL) and does not remove the copyright notice or \r
18  * this text.  The GPL V2 text is available on the gnu.org web site, and on the\r
19  * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.\r
20  * \r
21  * - Commercial licensing -\r
22  * Businesses and individuals who for commercial or other reasons cannot comply\r
23  * with the terms of the GPL V2 license must obtain a commercial license before \r
24  * incorporating FreeRTOS+FAT SL into proprietary software for distribution in \r
25  * any form.  Commercial licenses can be purchased from \r
26  * http://shop.freertos.org/fat_sl and do not require any source files to be \r
27  * changed.\r
28  *\r
29  * FreeRTOS+FAT SL is distributed in the hope that it will be useful.  You\r
30  * cannot use FreeRTOS+FAT SL unless you agree that you use the software 'as\r
31  * is'.  FreeRTOS+FAT SL is provided WITHOUT ANY WARRANTY; without even the\r
32  * implied warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A\r
33  * PARTICULAR PURPOSE. Real Time Engineers Ltd. and HCC Embedded disclaims all\r
34  * conditions and terms, be they implied, expressed, or statutory.\r
35  *\r
36  * http://www.FreeRTOS.org\r
37  * http://www.FreeRTOS.org/FreeRTOS-Plus\r
38  *\r
39  */\r
40 #include "../../api/fat_sl.h"\r
41 \r
42 #include "fat.h"\r
43 #include "util.h"\r
44 #include "volume.h"\r
45 #include "drv.h"\r
46 \r
47 #include "../../version/ver_fat_sl.h"\r
48 #if VER_FAT_SL_MAJOR != 3 || VER_FAT_SL_MINOR != 2\r
49  #error Incompatible FAT_SL version number!\r
50 #endif\r
51 \r
52 /****************************************************************************\r
53  *\r
54  * _f_writefatsector\r
55  *\r
56  * writing fat sector into volume, this function check if fat was modified\r
57  * and writes data\r
58  *\r
59  * RETURNS\r
60  *\r
61  * error code or zero if successful\r
62  *\r
63  ***************************************************************************/\r
64 unsigned char _f_writefatsector ( void )\r
65 {\r
66   unsigned char  a;\r
67 \r
68   if ( gl_volume.modified )\r
69   {\r
70     unsigned long  fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;\r
71 \r
72     if ( gl_volume.fatsector >= gl_volume.firstfat.num )\r
73     {\r
74       return F_ERR_INVALIDSECTOR;\r
75     }\r
76 \r
77     for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )\r
78     {\r
79       unsigned char  ret;\r
80       ret = _f_writeglsector( fatsector );\r
81       if ( ret )\r
82       {\r
83         return ret;\r
84       }\r
85 \r
86       fatsector += gl_volume.firstfat.num;\r
87     }\r
88 \r
89     gl_volume.modified = 0;\r
90   }\r
91 \r
92   return F_NO_ERROR;\r
93 } /* _f_writefatsector */\r
94 \r
95 \r
96 \r
97 /****************************************************************************\r
98  *\r
99  * _f_getfatsector\r
100  *\r
101  * read a fat sector from media\r
102  *\r
103  * INPUTS\r
104  *\r
105  * sector - which fat sector is needed, this sector number is zero based\r
106  *\r
107  * RETURNS\r
108  *\r
109  * error code or zero if successful\r
110  *\r
111  ***************************************************************************/\r
112 unsigned char _f_getfatsector ( unsigned long sector )\r
113 {\r
114   unsigned char  a;\r
115 \r
116   if ( gl_volume.fatsector != sector )\r
117   {\r
118     unsigned long  fatsector;\r
119 \r
120     gl_volume.fatsector = sector;\r
121 \r
122     if ( gl_volume.fatsector >= gl_volume.firstfat.num )\r
123     {\r
124       return F_ERR_INVALIDSECTOR;\r
125     }\r
126 \r
127     fatsector = gl_volume.firstfat.sector + gl_volume.fatsector;\r
128 \r
129     for ( a = 0 ; a < gl_volume.bootrecord.number_of_FATs ; a++ )\r
130     {\r
131       if ( !_f_readglsector( fatsector ) )\r
132       {\r
133         return F_NO_ERROR;\r
134       }\r
135 \r
136       fatsector += gl_volume.firstfat.num;\r
137     }\r
138 \r
139     return F_ERR_READ;\r
140   }\r
141 \r
142   return F_NO_ERROR;\r
143 } /* _f_getfatsector */\r
144 \r
145 \r
146 \r
147 /****************************************************************************\r
148  *\r
149  * _f_setclustervalue\r
150  *\r
151  * set a cluster value in the FAT\r
152  *\r
153  * INPUTS\r
154  *\r
155  * cluster - which cluster's value need to be modified\r
156  * data - new value of the cluster\r
157  *\r
158  * RETURNS\r
159  *\r
160  * error code or zero if successful\r
161  *\r
162  ***************************************************************************/\r
163 unsigned char _f_setclustervalue ( unsigned long cluster, unsigned long _tdata )\r
164 {\r
165   unsigned char  ret;\r
166 \r
167   switch ( gl_volume.mediatype )\r
168   {\r
169     case F_FAT16_MEDIA:\r
170     {\r
171       unsigned long   sector = cluster;\r
172       unsigned short  s_data = (unsigned short)( _tdata & 0xffff ); /*keep 16 bit only*/\r
173 \r
174       sector /= ( F_SECTOR_SIZE / 2 );\r
175       cluster -= sector * ( F_SECTOR_SIZE / 2 );\r
176 \r
177       ret = _f_getfatsector( sector );\r
178       if ( ret )\r
179       {\r
180         return ret;\r
181       }\r
182 \r
183       if ( _f_getword( &gl_sector[cluster << 1] ) != s_data )\r
184       {\r
185         _f_setword( &gl_sector[cluster << 1], s_data );\r
186         gl_volume.modified = 1;\r
187       }\r
188     }\r
189     break;\r
190 \r
191     case F_FAT12_MEDIA:\r
192     {\r
193       unsigned char   f12new[2];\r
194       unsigned long   sector = cluster;\r
195       unsigned short  pos;\r
196       unsigned short  s_data = (unsigned short)( _tdata & 0x0fff ); /*keep 12 bit only*/\r
197 \r
198       if ( cluster & 1 )\r
199       {\r
200         s_data <<= 4;\r
201       }\r
202 \r
203       _f_setword( f12new, s_data ); /*create new data*/\r
204 \r
205       sector += sector / 2;       /*1.5 bytes*/\r
206       pos = (unsigned short)( sector % F_SECTOR_SIZE );\r
207       sector /= F_SECTOR_SIZE;\r
208 \r
209       ret = _f_getfatsector( sector );\r
210       if ( ret )\r
211       {\r
212         return ret;\r
213       }\r
214 \r
215       if ( cluster & 1 )\r
216       {\r
217         f12new[0] |= gl_sector[pos] & 0x0f;\r
218       }\r
219 \r
220       if ( gl_sector[pos] != f12new[0] )\r
221       {\r
222         gl_sector[pos] = f12new[0];\r
223         gl_volume.modified = 1;\r
224       }\r
225 \r
226       pos++;\r
227       if ( pos >= 512 )\r
228       {\r
229         ret = _f_getfatsector( sector + 1 );\r
230         if ( ret )\r
231         {\r
232           return ret;\r
233         }\r
234 \r
235         pos = 0;\r
236       }\r
237 \r
238       if ( !( cluster & 1 ) )\r
239       {\r
240         f12new[1] |= gl_sector[pos] & 0xf0;\r
241       }\r
242 \r
243       if ( gl_sector[pos] != f12new[1] )\r
244       {\r
245         gl_sector[pos] = f12new[1];\r
246         gl_volume.modified = 1;\r
247       }\r
248     }\r
249     break;\r
250 \r
251     case F_FAT32_MEDIA:\r
252     {\r
253       unsigned long  sector = cluster;\r
254       unsigned long  oldv;\r
255 \r
256       sector /= ( F_SECTOR_SIZE / 4 );\r
257       cluster -= sector * ( F_SECTOR_SIZE / 4 );\r
258 \r
259       ret = _f_getfatsector( sector );\r
260       if ( ret )\r
261       {\r
262         return ret;\r
263       }\r
264 \r
265       oldv = _f_getlong( &gl_sector[cluster << 2] );\r
266 \r
267       _tdata &= 0x0fffffff;\r
268       _tdata |= oldv & 0xf0000000; /*keep 4 top bits*/\r
269 \r
270       if ( _tdata != oldv )\r
271       {\r
272         _f_setlong( &gl_sector[cluster << 2], _tdata );\r
273         gl_volume.modified = 1;\r
274       }\r
275     }\r
276     break;\r
277 \r
278     default:\r
279       return F_ERR_INVALIDMEDIA;\r
280   } /* switch */\r
281 \r
282   return F_NO_ERROR;\r
283 } /* _f_setclustervalue */\r
284 \r
285 \r
286 /****************************************************************************\r
287  *\r
288  * _f_getclustervalue\r
289  *\r
290  * get a cluster value from FAT\r
291  *\r
292  * INPUTS\r
293  *\r
294  * cluster - which cluster value is requested\r
295  * pvalue - where to store data\r
296  *\r
297  * RETURNS\r
298  *\r
299  * error code or zero if successful\r
300  *\r
301  ***************************************************************************/\r
302 unsigned char _f_getclustervalue ( unsigned long cluster, unsigned long * pvalue )\r
303 {\r
304   unsigned long  val;\r
305   unsigned char  ret;\r
306 \r
307   switch ( gl_volume.mediatype )\r
308   {\r
309     case F_FAT16_MEDIA:\r
310     {\r
311       unsigned long  sector = cluster;\r
312       sector /= ( F_SECTOR_SIZE / 2 );\r
313       cluster -= sector * ( F_SECTOR_SIZE / 2 );\r
314 \r
315       ret = _f_getfatsector( sector );\r
316       if ( ret )\r
317       {\r
318         return ret;\r
319       }\r
320 \r
321       val = _f_getword( &gl_sector[cluster << 1] );\r
322       if ( val >= ( F_CLUSTER_RESERVED & 0xffff ) )\r
323       {\r
324         val |= 0x0ffff000;                                       /*extends it*/\r
325       }\r
326 \r
327       if ( pvalue )\r
328       {\r
329         *pvalue = val;\r
330       }\r
331     }\r
332     break;\r
333 \r
334     case F_FAT12_MEDIA:\r
335     {\r
336       unsigned char   dataf12[2];\r
337       unsigned long   sector = cluster;\r
338       unsigned short  pos;\r
339 \r
340       sector += sector / 2;       /*1.5 bytes*/\r
341       pos = (unsigned short)( sector % F_SECTOR_SIZE );\r
342       sector /= F_SECTOR_SIZE;\r
343 \r
344       ret = _f_getfatsector( sector );\r
345       if ( ret )\r
346       {\r
347         return ret;\r
348       }\r
349 \r
350       dataf12[0] = gl_sector[pos++];\r
351 \r
352       if ( pos >= 512 )\r
353       {\r
354         ret = _f_getfatsector( sector + 1 );\r
355         if ( ret )\r
356         {\r
357           return ret;\r
358         }\r
359 \r
360         pos = 0;\r
361       }\r
362 \r
363       dataf12[1] = gl_sector[pos];\r
364 \r
365       val = _f_getword( dataf12 );\r
366 \r
367       if ( cluster & 1 )\r
368       {\r
369         val = val >> 4;\r
370       }\r
371       else\r
372       {\r
373         val = val & 0xfff;\r
374       }\r
375 \r
376       if ( val >= ( F_CLUSTER_RESERVED & 0xfff ) )\r
377       {\r
378         val |= 0x0ffff000;                                      /*extends it*/\r
379       }\r
380 \r
381       if ( pvalue )\r
382       {\r
383         *pvalue = val;\r
384       }\r
385     }\r
386     break;\r
387 \r
388     case F_FAT32_MEDIA:\r
389     {\r
390       unsigned long  sector = cluster;\r
391       sector /= ( F_SECTOR_SIZE / 4 );\r
392       cluster -= sector * ( F_SECTOR_SIZE / 4 );\r
393 \r
394       ret = _f_getfatsector( sector );\r
395       if ( ret )\r
396       {\r
397         return ret;\r
398       }\r
399 \r
400       if ( pvalue )\r
401       {\r
402         *pvalue = _f_getlong( &gl_sector[cluster << 2] ) & 0x0fffffff;       /*28bit*/\r
403       }\r
404     }\r
405     break;\r
406 \r
407     default:\r
408       return F_ERR_INVALIDMEDIA;\r
409   } /* switch */\r
410 \r
411   return F_NO_ERROR;\r
412 } /* _f_getclustervalue */\r
413 \r
414 \r
415 \r
416 \r
417 \r
418 \r
419 /****************************************************************************\r
420  *\r
421  * _f_clustertopos\r
422  *\r
423  * convert a cluster position into physical sector position\r
424  *\r
425  * INPUTS\r
426  *\r
427  * cluster - original cluster position\r
428  * pos - position structure to fills the position\r
429  *\r
430  ***************************************************************************/\r
431 void _f_clustertopos ( unsigned long cluster, F_POS * pos )\r
432 {\r
433   pos->cluster = cluster;\r
434 \r
435   if ( !cluster )\r
436   {\r
437     pos->sector = gl_volume.root.sector;\r
438     pos->sectorend = pos->sector + gl_volume.root.num;\r
439   }\r
440   else\r
441   {\r
442     unsigned long  sectorcou = gl_volume.bootrecord.sector_per_cluster;\r
443     pos->sector = ( pos->cluster - 2 ) * sectorcou + gl_volume._tdata.sector;\r
444     pos->sectorend = pos->sector + sectorcou;\r
445   }\r
446 \r
447   if ( cluster >= F_CLUSTER_RESERVED )\r
448   {\r
449     pos->sectorend = 0;\r
450   }\r
451 \r
452   pos->pos = 0;\r
453 } /* _f_clustertopos */\r
454 \r
455 \r
456 \r
457 \r
458 /****************************************************************************\r
459  *\r
460  * _f_getcurrsector\r
461  *\r
462  * read current sector according in file structure\r
463  *\r
464  * INPUTS\r
465  * f - internal file pointer\r
466  *\r
467  * RETURNS\r
468  * error code or zero if successful\r
469  *\r
470  ***************************************************************************/\r
471 unsigned char _f_getcurrsector ( void )\r
472 {\r
473   unsigned char  ret;\r
474   unsigned long  cluster;\r
475 \r
476   if ( gl_file.pos.sector == gl_file.pos.sectorend )\r
477   {\r
478     gl_volume.fatsector = (unsigned long)-1;\r
479     ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );\r
480     if ( ret )\r
481     {\r
482       return ret;\r
483     }\r
484 \r
485     if ( cluster >= F_CLUSTER_RESERVED )\r
486     {\r
487       return F_ERR_EOF;\r
488     }\r
489 \r
490     gl_file.prevcluster = gl_file.pos.cluster;\r
491     _f_clustertopos( cluster, &gl_file.pos );\r
492   }\r
493 \r
494   return _f_readglsector( gl_file.pos.sector );\r
495 } /* _f_getcurrsector */\r
496 \r
497 \r
498 \r
499 /****************************************************************************\r
500  *\r
501  * _f_alloccluster\r
502  *\r
503  * allocate cluster from FAT\r
504  *\r
505  * INPUTS\r
506  * pcluster - where to store the allocated cluster number\r
507  *\r
508  * RETURNS\r
509  *\r
510  * error code or zero if successful\r
511  *\r
512  ***************************************************************************/\r
513 \r
514 unsigned char _f_alloccluster ( unsigned long * pcluster )\r
515 {\r
516   unsigned long  maxcluster = gl_volume.maxcluster;\r
517   unsigned long  cou;\r
518   unsigned long  cluster = gl_volume.lastalloccluster;\r
519   unsigned long  value;\r
520   unsigned char  ret;\r
521 \r
522   for ( cou = 0 ; cou < maxcluster ; cou++ )\r
523   {\r
524     if ( cluster >= maxcluster )\r
525     {\r
526       cluster = 0;\r
527     }\r
528 \r
529     ret = _f_getclustervalue( cluster, &value );\r
530     if ( ret )\r
531     {\r
532       return ret;\r
533     }\r
534 \r
535     if ( !value )\r
536     {\r
537       gl_volume.lastalloccluster = cluster + 1;   /*set next one*/\r
538       *pcluster = cluster;\r
539 \r
540       return F_NO_ERROR;\r
541     }\r
542 \r
543     cluster++;\r
544   }\r
545 \r
546   return F_ERR_NOMOREENTRY;\r
547 } /* _f_alloccluster */\r
548 \r
549 \r
550 \r
551 \r
552 /****************************************************************************\r
553  *\r
554  * _f_removechain\r
555  *\r
556  * remove cluster chain from fat\r
557  *\r
558  * INPUTS\r
559  * cluster - first cluster in the cluster chain\r
560  *\r
561  * RETURNS\r
562  *\r
563  * error code or zero if successful\r
564  *\r
565  ***************************************************************************/\r
566 \r
567 unsigned char _f_removechain ( unsigned long cluster )\r
568 {\r
569   gl_volume.fatsector = (unsigned long)-1;\r
570 \r
571   if ( cluster < gl_volume.lastalloccluster ) /*this could be the begining of alloc*/\r
572   {\r
573     gl_volume.lastalloccluster = cluster;\r
574   }\r
575 \r
576   while ( cluster < F_CLUSTER_RESERVED && cluster >= 2 )\r
577   {\r
578     unsigned long  nextcluster;\r
579 \r
580     unsigned char  ret = _f_getclustervalue( cluster, &nextcluster );\r
581     if ( ret )\r
582     {\r
583       return ret;\r
584     }\r
585 \r
586     ret = _f_setclustervalue( cluster, F_CLUSTER_FREE );\r
587     if ( ret )\r
588     {\r
589       return ret;\r
590     }\r
591 \r
592     cluster = nextcluster;\r
593   }\r
594 \r
595   return _f_writefatsector();\r
596 } /* _f_removechain */\r
597 \r
598 \r
599 \r
600 \r