source: rtems/cpukit/libfs/src/dosfs/fat_fat_operations.c @ 2742cc3

Last change on this file since 2742cc3 was f36a7bfc, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/02 at 20:43:50

2002-02-28 Victor V. Vengerov <vvv@…>

  • DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
  • src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in, src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c, src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c, src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c, src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c, src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c, src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c, src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c, src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
  • configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to reflect addition.
  • Property mode set to 100644
File size: 13.7 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        {
83            /*
84             * We are enforced to process allocation of the first free cluster
85             * by separate 'if' statement because otherwise undo function
86             * wouldn't work properly
87             */
88            if (*cls_added == 0)
89            {
90                *chain = cl4find;
91                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
92                if ( rc != RC_OK )
93                {
94                    /*
95                     * this is the first cluster we tried to allocate so no
96                     * cleanup activity needed
97                     */
98                     return rc;
99                }
100            }
101            else
102            { 
103                /* set EOC value to new allocated cluster */
104                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
105                if ( rc != RC_OK )
106                {
107                    /* cleanup activity */
108                    fat_free_fat_clusters_chain(mt_entry, (*chain));
109                    return rc;
110                }
111
112                rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
113                if ( rc != RC_OK )
114                {
115                    /* cleanup activity */
116                    fat_free_fat_clusters_chain(mt_entry, (*chain));
117                    /* trying to save last allocated cluster for future use */
118                    fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
119                    fat_buf_release(fs_info);
120                    return rc;
121                }
122            } 
123
124            save_cln = cl4find;
125            (*cls_added)++;
126
127            /* have we satisfied request ? */
128            if (*cls_added == count)
129            {
130                if (fs_info->vol.type & FAT_FAT32)
131                {
132                    fs_info->vol.next_cl = save_cln;
133                    if (fs_info->vol.free_cls != 0xFFFFFFFF)
134                        fs_info->vol.free_cls -= (*cls_added);
135                }       
136                *last_cl = save_cln;   
137                fat_buf_release(fs_info);
138                return rc; 
139            } 
140        }
141        i++;
142        cl4find++; 
143        if (cl4find >= data_cls_val)
144            cl4find = 2;
145    }
146
147    if (fs_info->vol.type & FAT_FAT32)
148    {
149        fs_info->vol.next_cl = save_cln;
150        if (fs_info->vol.free_cls != 0xFFFFFFFF)
151            fs_info->vol.free_cls -= (*cls_added);   
152    }       
153    *last_cl = save_cln;
154    fat_buf_release(fs_info);
155    return RC_OK;   
156}
157
158/* fat_free_fat_clusters_chain --
159 *     Free chain of clusters in Files Allocation Table.
160 *
161 * PARAMETERS:
162 *     mt_entry - mount table entry
163 *     chain    - number of the first cluster in  the chain
164 *
165 * RETURNS:
166 *     RC_OK on success, or -1 if error occured (errno set appropriately)
167 */
168int
169fat_free_fat_clusters_chain(
170    rtems_filesystem_mount_table_entry_t *mt_entry,
171    unsigned32                            chain
172    )
173{
174    int            rc = RC_OK, rc1 = RC_OK;
175    fat_fs_info_t *fs_info = mt_entry->fs_info;
176    unsigned32     cur_cln = chain;
177    unsigned32     next_cln = 0;
178    unsigned32     freed_cls_cnt = 0;
179   
180    while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
181    {
182        rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
183        if ( rc != RC_OK )
184        {
185            if ((fs_info->vol.type & FAT_FAT32) &&
186                (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))
187                fs_info->vol.free_cls += freed_cls_cnt;
188            fat_buf_release(fs_info);   
189            return rc;
190        }   
191
192        rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
193        if ( rc != RC_OK )
194            rc1 = rc;
195
196        freed_cls_cnt++;
197        cur_cln = next_cln;
198    }
199
200    if (fs_info->vol.type & FAT_FAT32)
201    {
202        fs_info->vol.next_cl = chain;
203        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
204            fs_info->vol.free_cls += freed_cls_cnt;
205    }   
206
207    fat_buf_release(fs_info);
208    if (rc1 != RC_OK)
209        return rc1;
210
211    return RC_OK;
212}
213
214/* fat_get_fat_cluster --
215 *     Fetches the contents of the cluster (link to next cluster in the chain)
216 *     from Files Allocation Table.
217 *
218 * PARAMETERS:
219 *     mt_entry - mount table entry
220 *     cln      - number of cluster to fetch the contents from
221 *     ret_val  - contents of the cluster 'cln' (link to next cluster in
222 *                the chain)
223 *
224 * RETURNS:
225 *     RC_OK on success, or -1 if error occured
226 *     and errno set appropriately
227 */
228int
229fat_get_fat_cluster(
230    rtems_filesystem_mount_table_entry_t *mt_entry,
231    unsigned32                            cln,
232    unsigned32                           *ret_val
233    )
234{
235    int                     rc = RC_OK;
236    register fat_fs_info_t *fs_info = mt_entry->fs_info;
237    bdbuf_buffer           *block0 = NULL;
238    unsigned32              sec = 0;
239    unsigned32              ofs = 0;
240
241    /* sanity check */
242    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
243        set_errno_and_return_minus_one(EIO);
244
245    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
246          fs_info->vol.afat_loc;
247    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
248
249    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
250    if (rc != RC_OK)
251        return rc;
252
253    switch ( fs_info->vol.type )
254    {
255        case FAT_FAT12:
256            /*
257             * we are enforced in complex computations for FAT12 to escape CPU
258             * align problems for some architectures
259             */
260            *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
261            if ( ofs == (fs_info->vol.bps - 1) )
262            {
263                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
264                                    &block0);
265                if (rc != RC_OK)
266                    return rc;
267
268                *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
269            }
270            else
271            { 
272                *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
273            }
274
275            if ( FAT_CLUSTER_IS_ODD(cln) )
276                *ret_val = (*ret_val) >> FAT12_SHIFT;
277            else
278                *ret_val = (*ret_val) & FAT_FAT12_MASK;
279
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                fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
346
347                *((unsigned8 *)(block0->buffer + ofs)) =
348                        (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
349
350                *((unsigned8 *)(block0->buffer + ofs)) =
351                        (*((unsigned8 *)(block0->buffer + ofs))) |
352                        (unsigned8)(fat16_clv & 0x00FF);
353
354                fat_buf_mark_modified(fs_info);
355               
356                if ( ofs == (fs_info->vol.bps - 1) )
357                {
358                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
359                                        &block0);
360                    if (rc != RC_OK)
361                        return rc;
362
363                     *((unsigned8 *)(block0->buffer)) &= 0x00;
364 
365                     *((unsigned8 *)(block0->buffer)) =
366                            (*((unsigned8 *)(block0->buffer))) |
367                            (unsigned8)((fat16_clv & 0xFF00)>>8);
368                     
369                     fat_buf_mark_modified(fs_info);
370                }
371                else
372                {
373                    *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
374             
375                    *((unsigned8 *)(block0->buffer + ofs + 1)) =
376                            (*((unsigned8 *)(block0->buffer + ofs + 1))) |
377                            (unsigned8)((fat16_clv & 0xFF00)>>8);
378                } 
379            }
380            else
381            {
382                fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
383
384                *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
385
386                *((unsigned8 *)(block0->buffer + ofs)) =
387                        (*((unsigned8 *)(block0->buffer + ofs))) |
388                        (unsigned8)(fat16_clv & 0x00FF);
389                       
390                fat_buf_mark_modified(fs_info);         
391 
392                if ( ofs == (fs_info->vol.bps - 1) )
393                {
394                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
395                                        &block0);
396                    if (rc != RC_OK)
397                        return rc;
398
399                    *((unsigned8 *)(block0->buffer)) =
400                            (*((unsigned8 *)(block0->buffer))) & 0xF0;
401 
402                    *((unsigned8 *)(block0->buffer)) =
403                            (*((unsigned8 *)(block0->buffer))) |
404                            (unsigned8)((fat16_clv & 0xFF00)>>8);
405                           
406                    fat_buf_mark_modified(fs_info);       
407                }
408                else
409                {
410                    *((unsigned8 *)(block0->buffer + ofs + 1)) =   
411                      (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
412
413                    *((unsigned8 *)(block0->buffer + ofs+1)) =
414                           (*((unsigned8 *)(block0->buffer + ofs+1))) |
415                           (unsigned8)((fat16_clv & 0xFF00)>>8);
416                } 
417            }
418            break;
419
420        case FAT_FAT16:
421            *((unsigned16 *)(block0->buffer + ofs)) =
422                    (unsigned16)(CT_LE_W(in_val));
423            fat_buf_mark_modified(fs_info);       
424            break;
425
426        case FAT_FAT32:
427            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
428
429            *((unsigned32 *)(block0->buffer + ofs)) =
430            (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
431
432            *((unsigned32 *)(block0->buffer + ofs)) =
433                   fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
434           
435            fat_buf_mark_modified(fs_info);
436            break;
437
438        default:
439            set_errno_and_return_minus_one(EIO);
440            break;
441
442    }
443
444    return RC_OK;
445}
Note: See TracBrowser for help on using the repository browser.