source: rtems/cpukit/libfs/src/dosfs/fat_fat_operations.c @ 01c5b9d7

Last change on this file since 01c5b9d7 was 01c5b9d7, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 25, 2003 at 5:01:56 PM

2003-03-25 Thomas Doerfler <Thomas.Doerfler@…>

PR 367/filesystem

  • src/dosfs/Makefile.am, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_file.c, src/dosfs/msdos.h, src/dosfs/msdos_dir.c: Some bugs were still present in the DOSFS implementation:
    • FAT12 did not work properly on Big-Endian machines
    • Some synchronization and error handling problems were present
    • Some legal codings for EOC were not recognized
  • Property mode set to 100644
File size: 14.3 KB
Line 
1/*
2 *  fat_fat_operations.c
3 *
4 *  General operations on File Allocation Table
5 *
6 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
7 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
8 *
9 *  @(#) $Id$
10 */
11
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <errno.h>
17#include <stdlib.h>
18#include <assert.h>
19
20#include <rtems/libio_.h>
21
22#include "fat.h"
23#include "fat_fat_operations.h"
24
25/* fat_scan_fat_for_free_clusters --
26 *     Allocate chain of free clusters from Files Allocation Table
27 *
28 * PARAMETERS:
29 *     mt_entry - mount table entry
30 *     chain    - the number of the first allocated cluster (first cluster
31 *                in  the chain)
32 *     count    - count of clusters to allocate (chain length)
33 *
34 * RETURNS:
35 *     RC_OK on success, or error code if error occured (errno set
36 *     appropriately)
37 *
38 *     
39 */
40int 
41fat_scan_fat_for_free_clusters(
42    rtems_filesystem_mount_table_entry_t *mt_entry,
43    unsigned32                           *chain,
44    unsigned32                            count,
45    unsigned32                           *cls_added,
46    unsigned32                           *last_cl
47    )
48{
49    int            rc = RC_OK;
50    fat_fs_info_t *fs_info = mt_entry->fs_info;
51    unsigned32     cl4find = 2;
52    unsigned32     next_cln = 0;
53    unsigned32     save_cln = 0; 
54    unsigned32     data_cls_val = fs_info->vol.data_cls + 2;
55    unsigned32     i = 2;
56 
57    *cls_added = 0;   
58
59    if (count == 0)
60        return rc;
61       
62    if ((fs_info->vol.type & FAT_FAT32) && 
63        (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE)) 
64        cl4find = fs_info->vol.next_cl; 
65
66    /*
67     * fs_info->vol.data_cls is exactly the count of data clusters
68     * starting at cluster 2, so the maximum valid cluster number is
69     * (fs_info->vol.data_cls + 1)
70     */
71    while (i < data_cls_val)
72    {
73        rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);
74        if ( rc != RC_OK )
75        {
76            if (*cls_added != 0)
77                fat_free_fat_clusters_chain(mt_entry, (*chain));
78            return rc;
79        }   
80
81        /*if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)*/
82        if (next_cln == FAT_GENFAT_FREE)
83        {
84            /*
85             * We are enforced to process allocation of the first free cluster
86             * by separate 'if' statement because otherwise undo function
87             * wouldn't work properly
88             */
89            if (*cls_added == 0)
90            {
91                *chain = cl4find;
92                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
93                if ( rc != RC_OK )
94                {
95                    /*
96                     * this is the first cluster we tried to allocate so no
97                     * cleanup activity needed
98                     */
99                     return rc; 
100                }
101            }
102            else
103            { 
104                /* set EOC value to new allocated cluster */
105                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
106                if ( rc != RC_OK )
107                {
108                    /* cleanup activity */
109                    fat_free_fat_clusters_chain(mt_entry, (*chain));
110                    return rc; 
111                }
112
113                rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
114                if ( rc != RC_OK )
115                {
116                    /* cleanup activity */
117                    fat_free_fat_clusters_chain(mt_entry, (*chain));
118                    /* trying to save last allocated cluster for future use */
119                    fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
120                    fat_buf_release(fs_info);
121                    return rc; 
122                }
123            } 
124
125            save_cln = cl4find;
126            (*cls_added)++;
127
128            /* have we satisfied request ? */
129            if (*cls_added == count)
130            {
131                if (fs_info->vol.type & FAT_FAT32) 
132                {
133                    fs_info->vol.next_cl = save_cln;
134                    if (fs_info->vol.free_cls != 0xFFFFFFFF)
135                        fs_info->vol.free_cls -= (*cls_added);
136                }       
137                *last_cl = save_cln;   
138                fat_buf_release(fs_info);
139                return rc; 
140            } 
141        }
142        i++;
143        cl4find++; 
144        if (cl4find >= data_cls_val)
145            cl4find = 2;
146    }
147
148    if (fs_info->vol.type & FAT_FAT32)
149    { 
150        fs_info->vol.next_cl = save_cln;
151        if (fs_info->vol.free_cls != 0xFFFFFFFF)
152            fs_info->vol.free_cls -= (*cls_added);   
153    }       
154    *last_cl = save_cln;
155    fat_buf_release(fs_info);
156    return RC_OK;   
157} 
158
159/* fat_free_fat_clusters_chain --
160 *     Free chain of clusters in Files Allocation Table.
161 *
162 * PARAMETERS:
163 *     mt_entry - mount table entry
164 *     chain    - number of the first cluster in  the chain
165 *
166 * RETURNS:
167 *     RC_OK on success, or -1 if error occured (errno set appropriately)
168 */
169int 
170fat_free_fat_clusters_chain(
171    rtems_filesystem_mount_table_entry_t *mt_entry,
172    unsigned32                            chain
173    )
174{
175    int            rc = RC_OK, rc1 = RC_OK;
176    fat_fs_info_t *fs_info = mt_entry->fs_info;
177    unsigned32     cur_cln = chain; 
178    unsigned32     next_cln = 0; 
179    unsigned32     freed_cls_cnt = 0;
180   
181    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
182    {
183        rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
184        if ( rc != RC_OK )
185        {
186            if ((fs_info->vol.type & FAT_FAT32) && 
187                (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))
188                fs_info->vol.free_cls += freed_cls_cnt;
189            fat_buf_release(fs_info);   
190            return rc;
191        }   
192
193        rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
194        if ( rc != RC_OK )
195            rc1 = rc;
196
197        freed_cls_cnt++;
198        cur_cln = next_cln;
199    }
200
201    if (fs_info->vol.type & FAT_FAT32)
202    {
203        fs_info->vol.next_cl = chain;
204        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
205            fs_info->vol.free_cls += freed_cls_cnt;
206    }   
207
208    fat_buf_release(fs_info);
209    if (rc1 != RC_OK)
210        return rc1;
211
212    return RC_OK; 
213}
214
215/* fat_get_fat_cluster --
216 *     Fetches the contents of the cluster (link to next cluster in the chain)
217 *     from Files Allocation Table.
218 *
219 * PARAMETERS:
220 *     mt_entry - mount table entry
221 *     cln      - number of cluster to fetch the contents from
222 *     ret_val  - contents of the cluster 'cln' (link to next cluster in
223 *                the chain)
224 *
225 * RETURNS:
226 *     RC_OK on success, or -1 if error occured
227 *     and errno set appropriately
228 */
229int
230fat_get_fat_cluster(
231    rtems_filesystem_mount_table_entry_t *mt_entry,
232    unsigned32                            cln,
233    unsigned32                           *ret_val
234    )
235{
236    int                     rc = RC_OK;
237    register fat_fs_info_t *fs_info = mt_entry->fs_info;
238    bdbuf_buffer           *block0 = NULL;
239    unsigned32              sec = 0;
240    unsigned32              ofs = 0;
241
242    /* sanity check */
243    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
244        set_errno_and_return_minus_one(EIO);
245
246    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + 
247          fs_info->vol.afat_loc;
248    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
249
250    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
251    if (rc != RC_OK)
252        return rc;
253
254    switch ( fs_info->vol.type )
255    {
256        case FAT_FAT12:
257            /*
258             * we are enforced in complex computations for FAT12 to escape CPU
259             * align problems for some architectures
260             */
261            *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
262            if ( ofs == (fs_info->vol.bps - 1) )
263            {
264                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
265                                    &block0);
266                if (rc != RC_OK)
267                    return rc;
268
269                *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
270            }
271            else
272            { 
273                *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
274            }
275
276            if ( FAT_CLUSTER_IS_ODD(cln) )
277                *ret_val = (*ret_val) >> FAT12_SHIFT;
278            else
279                *ret_val = (*ret_val) & FAT_FAT12_MASK;
280            break;
281
282        case FAT_FAT16:
283            *ret_val = *((unsigned16 *)(block0->buffer + ofs));
284            *ret_val = CF_LE_W(*ret_val);
285            break;
286
287        case FAT_FAT32:
288            *ret_val = *((unsigned32 *)(block0->buffer + ofs));
289            *ret_val = CF_LE_L(*ret_val);
290            break;
291
292        default:
293            set_errno_and_return_minus_one(EIO);
294            break;
295    }
296
297    return RC_OK;
298}
299
300/* fat_set_fat_cluster --
301 *     Set the contents of the cluster (link to next cluster in the chain)
302 *     from Files Allocation Table.
303 *
304 * PARAMETERS:
305 *     mt_entry - mount table entry
306 *     cln      - number of cluster to set contents to
307 *     in_val   - value to set
308 *
309 * RETURNS:
310 *     RC_OK on success, or -1 if error occured
311 *     and errno set appropriately
312 */
313int
314fat_set_fat_cluster(
315    rtems_filesystem_mount_table_entry_t *mt_entry,
316    unsigned32                            cln,
317    unsigned32                            in_val
318    )
319{
320    int                rc = RC_OK;
321    fat_fs_info_t     *fs_info = mt_entry->fs_info;
322    unsigned32         sec = 0;
323    unsigned32         ofs = 0;
324    unsigned16         fat16_clv = 0;
325    unsigned32         fat32_clv = 0;
326    bdbuf_buffer      *block0 = NULL; 
327
328    /* sanity check */
329    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
330        set_errno_and_return_minus_one(EIO);
331
332    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + 
333          fs_info->vol.afat_loc;
334    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
335 
336    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
337    if (rc != RC_OK)
338        return rc;
339
340    switch ( fs_info->vol.type )
341    {
342        case FAT_FAT12:
343            if ( FAT_CLUSTER_IS_ODD(cln) )
344            {
345#if 0
346              /*
347               * do not perform endian conversion explicitely,
348               * because following code will enforce little
349               * endian format implicitly!
350               */               
351                fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
352#else
353                fat16_clv = ((unsigned16)in_val) << FAT_FAT12_SHIFT;
354#endif
355                *((unsigned8 *)(block0->buffer + ofs)) = 
356                        (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
357
358                *((unsigned8 *)(block0->buffer + ofs)) = 
359                        (*((unsigned8 *)(block0->buffer + ofs))) | 
360                        (unsigned8)(fat16_clv & 0x00FF);
361
362                fat_buf_mark_modified(fs_info);
363               
364                if ( ofs == (fs_info->vol.bps - 1) )
365                {
366                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
367                                        &block0);
368                    if (rc != RC_OK)
369                        return rc;
370
371                     *((unsigned8 *)(block0->buffer)) &= 0x00;
372 
373                     *((unsigned8 *)(block0->buffer)) = 
374                            (*((unsigned8 *)(block0->buffer))) | 
375                            (unsigned8)((fat16_clv & 0xFF00)>>8);
376                     
377                     fat_buf_mark_modified(fs_info);
378                }
379                else
380                {
381                    *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
382             
383                    *((unsigned8 *)(block0->buffer + ofs + 1)) = 
384                            (*((unsigned8 *)(block0->buffer + ofs + 1))) | 
385                            (unsigned8)((fat16_clv & 0xFF00)>>8);
386                } 
387            }
388            else
389            {
390#if 0
391              /*
392               * do not perform endian conversion explicitely,
393               * because following code will enforce little
394               * endian format implicitly!
395               */               
396                fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
397#else
398                fat16_clv = ((unsigned16)in_val) & FAT_FAT12_MASK;
399#endif
400                *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
401
402                *((unsigned8 *)(block0->buffer + ofs)) = 
403                        (*((unsigned8 *)(block0->buffer + ofs))) | 
404                        (unsigned8)(fat16_clv & 0x00FF);
405                       
406                fat_buf_mark_modified(fs_info);         
407 
408                if ( ofs == (fs_info->vol.bps - 1) )
409                {
410                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ, 
411                                        &block0);
412                    if (rc != RC_OK)
413                        return rc;
414
415                    *((unsigned8 *)(block0->buffer)) = 
416                            (*((unsigned8 *)(block0->buffer))) & 0xF0;
417 
418                    *((unsigned8 *)(block0->buffer)) = 
419                            (*((unsigned8 *)(block0->buffer))) | 
420                            (unsigned8)((fat16_clv & 0xFF00)>>8);
421                           
422                    fat_buf_mark_modified(fs_info);       
423                }
424                else
425                {
426                    *((unsigned8 *)(block0->buffer + ofs + 1)) =   
427                      (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
428
429                    *((unsigned8 *)(block0->buffer + ofs+1)) = 
430                           (*((unsigned8 *)(block0->buffer + ofs+1))) | 
431                           (unsigned8)((fat16_clv & 0xFF00)>>8);
432                } 
433            }
434            break;
435
436        case FAT_FAT16:
437            *((unsigned16 *)(block0->buffer + ofs)) = 
438                    (unsigned16)(CT_LE_W(in_val));
439            fat_buf_mark_modified(fs_info);       
440            break;
441
442        case FAT_FAT32:
443            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
444
445            *((unsigned32 *)(block0->buffer + ofs)) = 
446            (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
447
448            *((unsigned32 *)(block0->buffer + ofs)) = 
449                   fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
450           
451            fat_buf_mark_modified(fs_info);
452            break;
453
454        default:
455            set_errno_and_return_minus_one(EIO);
456            break;
457
458    }
459
460    return RC_OK;
461}
Note: See TracBrowser for help on using the repository browser.