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

4.115
Last change on this file since c65afce4 was c65afce4, checked in by Sebastian Huber <sebastian.huber@…>, on 07/07/12 at 13:46:33

dosfs: Use fs_info instead of mt_entry

  • Property mode set to 100644
File size: 13.2 KB
RevLine 
[f36a7bfc]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
[ffc144e]10#if HAVE_CONFIG_H
11#include "config.h"
12#endif
13
[f36a7bfc]14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <unistd.h>
18#include <errno.h>
19#include <stdlib.h>
20
21#include <rtems/libio_.h>
22
23#include "fat.h"
24#include "fat_fat_operations.h"
25
26/* fat_scan_fat_for_free_clusters --
27 *     Allocate chain of free clusters from Files Allocation Table
28 *
29 * PARAMETERS:
[c65afce4]30 *     fs_info  - FS info
[a5305f6b]31 *     chain    - the number of the first allocated cluster (first cluster
[f36a7bfc]32 *                in  the chain)
33 *     count    - count of clusters to allocate (chain length)
34 *
35 * RETURNS:
[a5305f6b]36 *     RC_OK on success, or error code if error occured (errno set
[f36a7bfc]37 *     appropriately)
38 *
[a5305f6b]39 *
[f36a7bfc]40 */
[a5305f6b]41int
[f36a7bfc]42fat_scan_fat_for_free_clusters(
[c65afce4]43    fat_fs_info_t                        *fs_info,
[f91bbe64]44    uint32_t                             *chain,
45    uint32_t                              count,
46    uint32_t                             *cls_added,
[3d0c96c7]47    uint32_t                             *last_cl,
48    bool                                  zero_fill
[f36a7bfc]49    )
50{
51    int            rc = RC_OK;
[f91bbe64]52    uint32_t       cl4find = 2;
53    uint32_t       next_cln = 0;
[a5305f6b]54    uint32_t       save_cln = 0;
[f91bbe64]55    uint32_t       data_cls_val = fs_info->vol.data_cls + 2;
56    uint32_t       i = 2;
[a5305f6b]57
58    *cls_added = 0;
[f36a7bfc]59
60    if (count == 0)
61        return rc;
[a5305f6b]62
[471feaf]63    if (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE)
[a5305f6b]64        cl4find = fs_info->vol.next_cl;
[f36a7bfc]65
[a5305f6b]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
[f36a7bfc]69     * (fs_info->vol.data_cls + 1)
70     */
71    while (i < data_cls_val)
72    {
[c65afce4]73        rc = fat_get_fat_cluster(fs_info, cl4find, &next_cln);
[f36a7bfc]74        if ( rc != RC_OK )
75        {
76            if (*cls_added != 0)
[c65afce4]77                fat_free_fat_clusters_chain(fs_info, (*chain));
[f36a7bfc]78            return rc;
[a5305f6b]79        }
[f36a7bfc]80
[c151cfc3]81        if (next_cln == FAT_GENFAT_FREE)
[f36a7bfc]82        {
83            /*
84             * We are enforced to process allocation of the first free cluster
[a5305f6b]85             * by separate 'if' statement because otherwise undo function
[f36a7bfc]86             * wouldn't work properly
87             */
88            if (*cls_added == 0)
89            {
90                *chain = cl4find;
[c65afce4]91                rc = fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_EOC);
[f36a7bfc]92                if ( rc != RC_OK )
93                {
[a5305f6b]94                    /*
95                     * this is the first cluster we tried to allocate so no
96                     * cleanup activity needed
[f36a7bfc]97                     */
[a5305f6b]98                     return rc;
[f36a7bfc]99                }
100            }
101            else
[a5305f6b]102            {
[f36a7bfc]103                /* set EOC value to new allocated cluster */
[c65afce4]104                rc = fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_EOC);
[f36a7bfc]105                if ( rc != RC_OK )
106                {
107                    /* cleanup activity */
[c65afce4]108                    fat_free_fat_clusters_chain(fs_info, (*chain));
[a5305f6b]109                    return rc;
[f36a7bfc]110                }
111
[c65afce4]112                rc = fat_set_fat_cluster(fs_info, save_cln, cl4find);
[f36a7bfc]113                if ( rc != RC_OK )
[3d0c96c7]114                    goto cleanup;
115            }
116
117            if (zero_fill) {
[c65afce4]118                uint32_t sec = fat_cluster_num_to_sector_num(fs_info,
[3d0c96c7]119                                                             cl4find);
120
[c65afce4]121                rc = _fat_block_zero(fs_info, sec, 0, fs_info->vol.bpc);
[3d0c96c7]122                if ( rc != RC_OK )
123                    goto cleanup;
[a5305f6b]124            }
[f36a7bfc]125
126            save_cln = cl4find;
127            (*cls_added)++;
128
129            /* have we satisfied request ? */
130            if (*cls_added == count)
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);
[a5305f6b]135                *last_cl = save_cln;
[f36a7bfc]136                fat_buf_release(fs_info);
[a5305f6b]137                return rc;
138            }
[f36a7bfc]139        }
140        i++;
[a5305f6b]141        cl4find++;
[f36a7bfc]142        if (cl4find >= data_cls_val)
143            cl4find = 2;
144    }
145
146        fs_info->vol.next_cl = save_cln;
147        if (fs_info->vol.free_cls != 0xFFFFFFFF)
[a5305f6b]148            fs_info->vol.free_cls -= (*cls_added);
[471feaf]149
[f36a7bfc]150    *last_cl = save_cln;
151    fat_buf_release(fs_info);
[a5305f6b]152    return RC_OK;
[3d0c96c7]153
154cleanup:
155
156    /* cleanup activity */
[c65afce4]157    fat_free_fat_clusters_chain(fs_info, (*chain));
[3d0c96c7]158    /* trying to save last allocated cluster for future use */
[c65afce4]159    fat_set_fat_cluster(fs_info, cl4find, FAT_GENFAT_FREE);
[3d0c96c7]160    fat_buf_release(fs_info);
161    return rc;
[a5305f6b]162}
[f36a7bfc]163
164/* fat_free_fat_clusters_chain --
165 *     Free chain of clusters in Files Allocation Table.
166 *
167 * PARAMETERS:
[c65afce4]168 *     fs_info  - FS info
[a5305f6b]169 *     chain    - number of the first cluster in  the chain
[f36a7bfc]170 *
171 * RETURNS:
172 *     RC_OK on success, or -1 if error occured (errno set appropriately)
173 */
[a5305f6b]174int
[f36a7bfc]175fat_free_fat_clusters_chain(
[c65afce4]176    fat_fs_info_t                        *fs_info,
[f91bbe64]177    uint32_t                              chain
[f36a7bfc]178    )
179{
180    int            rc = RC_OK, rc1 = RC_OK;
[a5305f6b]181    uint32_t       cur_cln = chain;
182    uint32_t       next_cln = 0;
[f91bbe64]183    uint32_t       freed_cls_cnt = 0;
[a5305f6b]184
[c151cfc3]185    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
[f36a7bfc]186    {
[c65afce4]187        rc = fat_get_fat_cluster(fs_info, cur_cln, &next_cln);
[f36a7bfc]188        if ( rc != RC_OK )
189        {
[471feaf]190              if(fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
[f36a7bfc]191                fs_info->vol.free_cls += freed_cls_cnt;
[471feaf]192
[a5305f6b]193            fat_buf_release(fs_info);
[f36a7bfc]194            return rc;
[a5305f6b]195        }
[f36a7bfc]196
[c65afce4]197        rc = fat_set_fat_cluster(fs_info, cur_cln, FAT_GENFAT_FREE);
[f36a7bfc]198        if ( rc != RC_OK )
199            rc1 = rc;
200
201        freed_cls_cnt++;
202        cur_cln = next_cln;
203    }
204
205        fs_info->vol.next_cl = chain;
206        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
207            fs_info->vol.free_cls += freed_cls_cnt;
208
209    fat_buf_release(fs_info);
210    if (rc1 != RC_OK)
211        return rc1;
212
[a5305f6b]213    return RC_OK;
[f36a7bfc]214}
215
216/* fat_get_fat_cluster --
[a5305f6b]217 *     Fetches the contents of the cluster (link to next cluster in the chain)
[f36a7bfc]218 *     from Files Allocation Table.
219 *
220 * PARAMETERS:
[c65afce4]221 *     fs_info  - FS info
[f36a7bfc]222 *     cln      - number of cluster to fetch the contents from
[a5305f6b]223 *     ret_val  - contents of the cluster 'cln' (link to next cluster in
224 *                the chain)
[f36a7bfc]225 *
226 * RETURNS:
227 *     RC_OK on success, or -1 if error occured
228 *     and errno set appropriately
229 */
230int
231fat_get_fat_cluster(
[c65afce4]232    fat_fs_info_t                        *fs_info,
[f91bbe64]233    uint32_t                              cln,
234    uint32_t                             *ret_val
[f36a7bfc]235    )
236{
237    int                     rc = RC_OK;
[3899a537]238    rtems_bdbuf_buffer     *block0 = NULL;
[f91bbe64]239    uint32_t                sec = 0;
240    uint32_t                ofs = 0;
[f36a7bfc]241
242    /* sanity check */
243    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
[3899a537]244        rtems_set_errno_and_return_minus_one(EIO);
[f36a7bfc]245
[a5305f6b]246    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
[f36a7bfc]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:
[a5305f6b]257            /*
[f36a7bfc]258             * we are enforced in complex computations for FAT12 to escape CPU
259             * align problems for some architectures
260             */
[f91bbe64]261            *ret_val = (*((uint8_t   *)(block0->buffer + ofs)));
[f36a7bfc]262            if ( ofs == (fs_info->vol.bps - 1) )
263            {
[a5305f6b]264                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
[f36a7bfc]265                                    &block0);
266                if (rc != RC_OK)
267                    return rc;
268
[f91bbe64]269                *ret_val |= (*((uint8_t   *)(block0->buffer)))<<8;
[f36a7bfc]270            }
271            else
[a5305f6b]272            {
[f91bbe64]273                *ret_val |= (*((uint8_t   *)(block0->buffer + ofs + 1)))<<8;
[f36a7bfc]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:
[f91bbe64]283            *ret_val = *((uint16_t   *)(block0->buffer + ofs));
[f36a7bfc]284            *ret_val = CF_LE_W(*ret_val);
285            break;
286
287        case FAT_FAT32:
[f91bbe64]288            *ret_val = *((uint32_t   *)(block0->buffer + ofs));
[f36a7bfc]289            *ret_val = CF_LE_L(*ret_val);
290            break;
291
292        default:
[3899a537]293            rtems_set_errno_and_return_minus_one(EIO);
[f36a7bfc]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:
[c65afce4]305 *     fs_info  - FS info
[f36a7bfc]306 *     cln      - number of cluster to set contents to
[a5305f6b]307 *     in_val   - value to set
[f36a7bfc]308 *
309 * RETURNS:
310 *     RC_OK on success, or -1 if error occured
311 *     and errno set appropriately
312 */
313int
314fat_set_fat_cluster(
[c65afce4]315    fat_fs_info_t                        *fs_info,
[f91bbe64]316    uint32_t                              cln,
317    uint32_t                              in_val
[f36a7bfc]318    )
319{
[3899a537]320    int                 rc = RC_OK;
321    uint32_t            sec = 0;
322    uint32_t            ofs = 0;
323    uint16_t            fat16_clv = 0;
324    uint32_t            fat32_clv = 0;
325    rtems_bdbuf_buffer *block0 = NULL;
[f36a7bfc]326
327    /* sanity check */
328    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
[3899a537]329        rtems_set_errno_and_return_minus_one(EIO);
[f36a7bfc]330
[a5305f6b]331    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
[f36a7bfc]332          fs_info->vol.afat_loc;
333    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
[a5305f6b]334
[f36a7bfc]335    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
336    if (rc != RC_OK)
337        return rc;
338
339    switch ( fs_info->vol.type )
340    {
341        case FAT_FAT12:
342            if ( FAT_CLUSTER_IS_ODD(cln) )
343            {
[f91bbe64]344                fat16_clv = ((uint16_t  )in_val) << FAT_FAT12_SHIFT;
[a5305f6b]345                *((uint8_t   *)(block0->buffer + ofs)) =
[f91bbe64]346                        (*((uint8_t   *)(block0->buffer + ofs))) & 0x0F;
[f36a7bfc]347
[a5305f6b]348                *((uint8_t   *)(block0->buffer + ofs)) =
349                        (*((uint8_t   *)(block0->buffer + ofs))) |
[f91bbe64]350                        (uint8_t  )(fat16_clv & 0x00FF);
[f36a7bfc]351
352                fat_buf_mark_modified(fs_info);
[a5305f6b]353
[f36a7bfc]354                if ( ofs == (fs_info->vol.bps - 1) )
355                {
[a5305f6b]356                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
[f36a7bfc]357                                        &block0);
358                    if (rc != RC_OK)
359                        return rc;
360
[f91bbe64]361                     *((uint8_t   *)(block0->buffer)) &= 0x00;
[a5305f6b]362
363                     *((uint8_t   *)(block0->buffer)) =
364                            (*((uint8_t   *)(block0->buffer))) |
[f91bbe64]365                            (uint8_t  )((fat16_clv & 0xFF00)>>8);
[a5305f6b]366
[f36a7bfc]367                     fat_buf_mark_modified(fs_info);
368                }
369                else
370                {
[f91bbe64]371                    *((uint8_t   *)(block0->buffer + ofs + 1)) &= 0x00;
[a5305f6b]372
373                    *((uint8_t   *)(block0->buffer + ofs + 1)) =
374                            (*((uint8_t   *)(block0->buffer + ofs + 1))) |
[f91bbe64]375                            (uint8_t  )((fat16_clv & 0xFF00)>>8);
[a5305f6b]376                }
[f36a7bfc]377            }
378            else
379            {
[f91bbe64]380                fat16_clv = ((uint16_t  )in_val) & FAT_FAT12_MASK;
381                *((uint8_t   *)(block0->buffer + ofs)) &= 0x00;
[f36a7bfc]382
[a5305f6b]383                *((uint8_t   *)(block0->buffer + ofs)) =
384                        (*((uint8_t   *)(block0->buffer + ofs))) |
[f91bbe64]385                        (uint8_t  )(fat16_clv & 0x00FF);
[a5305f6b]386
387                fat_buf_mark_modified(fs_info);
388
[f36a7bfc]389                if ( ofs == (fs_info->vol.bps - 1) )
390                {
[a5305f6b]391                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
[f36a7bfc]392                                        &block0);
393                    if (rc != RC_OK)
394                        return rc;
395
[a5305f6b]396                    *((uint8_t   *)(block0->buffer)) =
[f91bbe64]397                            (*((uint8_t   *)(block0->buffer))) & 0xF0;
[a5305f6b]398
399                    *((uint8_t   *)(block0->buffer)) =
400                            (*((uint8_t   *)(block0->buffer))) |
[f91bbe64]401                            (uint8_t  )((fat16_clv & 0xFF00)>>8);
[a5305f6b]402
403                    fat_buf_mark_modified(fs_info);
[f36a7bfc]404                }
405                else
406                {
[a5305f6b]407                    *((uint8_t   *)(block0->buffer + ofs + 1)) =
[f91bbe64]408                      (*((uint8_t   *)(block0->buffer + ofs + 1))) & 0xF0;
[f36a7bfc]409
[a5305f6b]410                    *((uint8_t   *)(block0->buffer + ofs+1)) =
411                           (*((uint8_t   *)(block0->buffer + ofs+1))) |
[f91bbe64]412                           (uint8_t  )((fat16_clv & 0xFF00)>>8);
[a5305f6b]413                }
[f36a7bfc]414            }
415            break;
416
417        case FAT_FAT16:
[a5305f6b]418            *((uint16_t   *)(block0->buffer + ofs)) =
[f91bbe64]419                    (uint16_t  )(CT_LE_W(in_val));
[a5305f6b]420            fat_buf_mark_modified(fs_info);
[f36a7bfc]421            break;
422
423        case FAT_FAT32:
424            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
425
[a5305f6b]426            *((uint32_t   *)(block0->buffer + ofs)) =
[f91bbe64]427            (*((uint32_t   *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
[f36a7bfc]428
[a5305f6b]429            *((uint32_t   *)(block0->buffer + ofs)) =
[f91bbe64]430                   fat32_clv | (*((uint32_t   *)(block0->buffer + ofs)));
[a5305f6b]431
[f36a7bfc]432            fat_buf_mark_modified(fs_info);
433            break;
434
435        default:
[3899a537]436            rtems_set_errno_and_return_minus_one(EIO);
[f36a7bfc]437            break;
438
439    }
440
441    return RC_OK;
442}
Note: See TracBrowser for help on using the repository browser.