source: rtems/cpukit/libfs/src/dosfs/fat.c @ 8863338

4.115
Last change on this file since 8863338 was 8863338, checked in by Sebastian Huber <sebastian.huber@…>, on 11/08/12 at 13:45:27

dosfs: Use FAT_UNDEFINED_VALUE

  • Property mode set to 100644
File size: 24.8 KB
RevLine 
[f36a7bfc]1/*
2 * fat.c
3 *
4 * Low-level operations on a volume with FAT filesystem
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"
[d32359a7]24#include "fat_fat_operations.h"
[f36a7bfc]25
[3899a537]26int
27fat_buf_access(fat_fs_info_t *fs_info, uint32_t   blk, int op_type,
28               rtems_bdbuf_buffer **buf)
29{
30    rtems_status_code sc = RTEMS_SUCCESSFUL;
31    uint8_t           i;
[0a896eb]32    bool              sec_of_fat;
[3899a537]33
34
35    if (fs_info->c.state == FAT_CACHE_EMPTY)
36    {
37        if (op_type == FAT_OP_TYPE_READ)
[796967c]38            sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
[3899a537]39        else
[796967c]40            sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
[3899a537]41        if (sc != RTEMS_SUCCESSFUL)
42            rtems_set_errno_and_return_minus_one(EIO);
43        fs_info->c.blk_num = blk;
44        fs_info->c.modified = 0;
45        fs_info->c.state = FAT_CACHE_ACTUAL;
46    }
47
48    sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
49                  (fs_info->c.blk_num < fs_info->vol.rdir_loc));
50
51    if (fs_info->c.blk_num != blk)
52    {
53        if (fs_info->c.modified)
54        {
55            if (sec_of_fat && !fs_info->vol.mirror)
56                memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
57                       fs_info->vol.bps);
58
59            sc = rtems_bdbuf_release_modified(fs_info->c.buf);
60            fs_info->c.state = FAT_CACHE_EMPTY;
61            fs_info->c.modified = 0;
62            if (sc != RTEMS_SUCCESSFUL)
63                rtems_set_errno_and_return_minus_one(EIO);
64
65            if (sec_of_fat && !fs_info->vol.mirror)
66            {
67                rtems_bdbuf_buffer *b;
68
69                for (i = 1; i < fs_info->vol.fats; i++)
70                {
[796967c]71                    sc = rtems_bdbuf_get(fs_info->vol.dd,
[3899a537]72                                         fs_info->c.blk_num +
73                                         fs_info->vol.fat_length * i,
74                                         &b);
75                    if ( sc != RTEMS_SUCCESSFUL)
76                        rtems_set_errno_and_return_minus_one(ENOMEM);
77                    memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
78                    sc = rtems_bdbuf_release_modified(b);
79                    if ( sc != RTEMS_SUCCESSFUL)
80                        rtems_set_errno_and_return_minus_one(ENOMEM);
81                }
82            }
83        }
84        else
85        {
86            sc = rtems_bdbuf_release(fs_info->c.buf);
87            fs_info->c.state = FAT_CACHE_EMPTY;
88            if (sc != RTEMS_SUCCESSFUL)
89                rtems_set_errno_and_return_minus_one(EIO);
90
91        }
92        if (op_type == FAT_OP_TYPE_READ)
[796967c]93            sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
[3899a537]94        else
[796967c]95            sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
[3899a537]96        if (sc != RTEMS_SUCCESSFUL)
97            rtems_set_errno_and_return_minus_one(EIO);
98        fs_info->c.blk_num = blk;
99        fs_info->c.state = FAT_CACHE_ACTUAL;
100    }
101    *buf = fs_info->c.buf;
102    return RC_OK;
103}
104
105int
106fat_buf_release(fat_fs_info_t *fs_info)
107{
108    rtems_status_code sc = RTEMS_SUCCESSFUL;
109    uint8_t           i;
[0a896eb]110    bool              sec_of_fat;
[3899a537]111
112    if (fs_info->c.state == FAT_CACHE_EMPTY)
113        return RC_OK;
114
115    sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
116                  (fs_info->c.blk_num < fs_info->vol.rdir_loc));
117
118    if (fs_info->c.modified)
119    {
120        if (sec_of_fat && !fs_info->vol.mirror)
121            memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
122
123        sc = rtems_bdbuf_release_modified(fs_info->c.buf);
124        if (sc != RTEMS_SUCCESSFUL)
125            rtems_set_errno_and_return_minus_one(EIO);
126        fs_info->c.modified = 0;
127
128        if (sec_of_fat && !fs_info->vol.mirror)
129        {
130            rtems_bdbuf_buffer *b;
131
132            for (i = 1; i < fs_info->vol.fats; i++)
133            {
[796967c]134                sc = rtems_bdbuf_get(fs_info->vol.dd,
[3899a537]135                                     fs_info->c.blk_num +
136                                     fs_info->vol.fat_length * i,
137                                     &b);
138                if ( sc != RTEMS_SUCCESSFUL)
139                    rtems_set_errno_and_return_minus_one(ENOMEM);
140                memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
141                sc = rtems_bdbuf_release_modified(b);
142                if ( sc != RTEMS_SUCCESSFUL)
143                    rtems_set_errno_and_return_minus_one(ENOMEM);
144            }
145        }
146    }
147    else
148    {
149        sc = rtems_bdbuf_release(fs_info->c.buf);
150        if (sc != RTEMS_SUCCESSFUL)
151            rtems_set_errno_and_return_minus_one(EIO);
152    }
153    fs_info->c.state = FAT_CACHE_EMPTY;
154    return RC_OK;
155}
156
[f36a7bfc]157/* _fat_block_read --
158 *     This function reads 'count' bytes from device filesystem is mounted on,
[a5305f6b]159 *     starts at 'start+offset' position where 'start' computed in sectors
160 *     and 'offset' is offset inside sector (reading may cross sectors
[f36a7bfc]161 *     boundary; in this case assumed we want to read sequential sector(s))
162 *
163 * PARAMETERS:
[c65afce4]164 *     fs_info  - FS info
[f36a7bfc]165 *     start    - sector num to start read from
166 *     offset   - offset inside sector 'start'
167 *     count    - count of bytes to read
168 *     buff     - buffer provided by user
169 *
170 * RETURNS:
171 *     bytes read on success, or -1 if error occured
172 *     and errno set appropriately
173 */
174ssize_t
175_fat_block_read(
[c65afce4]176    fat_fs_info_t                        *fs_info,
[a5305f6b]177    uint32_t                              start,
[f91bbe64]178    uint32_t                              offset,
[a5305f6b]179    uint32_t                              count,
[f36a7bfc]180    void                                 *buff
181    )
182{
183    int                     rc = RC_OK;
184    ssize_t                 cmpltd = 0;
[f91bbe64]185    uint32_t                blk = start;
186    uint32_t                ofs = offset;
[3899a537]187    rtems_bdbuf_buffer     *block = NULL;
[f91bbe64]188    uint32_t                c = 0;
[a5305f6b]189
[f36a7bfc]190    while (count > 0)
191    {
192        rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
193        if (rc != RC_OK)
[08c09e24]194            return -1;
195
[f36a7bfc]196        c = MIN(count, (fs_info->vol.bps - ofs));
197        memcpy((buff + cmpltd), (block->buffer + ofs), c);
198
199        count -= c;
200        cmpltd += c;
201        blk++;
202        ofs = 0;
203    }
204    return cmpltd;
205}
206
207/* _fat_block_write --
[a5305f6b]208 *     This function write 'count' bytes to device filesystem is mounted on,
209 *     starts at 'start+offset' position where 'start' computed in sectors
210 *     and 'offset' is offset inside sector (writing may cross sectors
[f36a7bfc]211 *     boundary; in this case assumed we want to write sequential sector(s))
212 *
213 * PARAMETERS:
[c65afce4]214 *     fs_info  - FS info
[f36a7bfc]215 *     start    - sector num to start read from
216 *     offset   - offset inside sector 'start'
217 *     count    - count of bytes to write
218 *     buff     - buffer provided by user
219 *
220 * RETURNS:
221 *     bytes written on success, or -1 if error occured
222 *     and errno set appropriately
223 */
224ssize_t
225_fat_block_write(
[c65afce4]226    fat_fs_info_t                        *fs_info,
[a5305f6b]227    uint32_t                              start,
[f91bbe64]228    uint32_t                              offset,
[a5305f6b]229    uint32_t                              count,
[f36a7bfc]230    const void                           *buff)
231{
[3899a537]232    int                 rc = RC_OK;
233    ssize_t             cmpltd = 0;
234    uint32_t            blk  = start;
235    uint32_t            ofs = offset;
236    rtems_bdbuf_buffer *block = NULL;
237    uint32_t            c = 0;
[a5305f6b]238
[f36a7bfc]239    while(count > 0)
240    {
241        c = MIN(count, (fs_info->vol.bps - ofs));
242
243        if (c == fs_info->vol.bps)
244            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
245        else
246            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
247        if (rc != RC_OK)
[08c09e24]248            return -1;
[a5305f6b]249
[f36a7bfc]250        memcpy((block->buffer + ofs), (buff + cmpltd), c);
251
252        fat_buf_mark_modified(fs_info);
253
254        count -= c;
255        cmpltd +=c;
256        blk++;
257        ofs = 0;
258    }
259    return cmpltd;
260}
261
[3d0c96c7]262int
263_fat_block_zero(
[c65afce4]264    fat_fs_info_t                        *fs_info,
[3d0c96c7]265    uint32_t                              start,
266    uint32_t                              offset,
267    uint32_t                              count)
268{
269    int                 rc = RC_OK;
270    uint32_t            blk  = start;
271    uint32_t            ofs = offset;
272    rtems_bdbuf_buffer *block = NULL;
273    uint32_t            c = 0;
274
275    while(count > 0)
276    {
277        c = MIN(count, (fs_info->vol.bps - ofs));
278
279        if (c == fs_info->vol.bps)
280            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
281        else
282            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
283        if (rc != RC_OK)
284            return -1;
285
286        memset((block->buffer + ofs), 0, c);
287
288        fat_buf_mark_modified(fs_info);
289
290        count -= c;
291        blk++;
292        ofs = 0;
293    }
294    return 0;
295}
296
[eb649786]297/* _fat_block_release --
298 *     This function works around the hack that hold a bdbuf and does
299 *     not release it.
300 *
301 * PARAMETERS:
[c65afce4]302 *     fs_info  - FS info
[eb649786]303 *
304 * RETURNS:
305 *     0 on success, or -1 if error occured and errno set appropriately
306 */
307int
[c65afce4]308_fat_block_release(fat_fs_info_t *fs_info)
[eb649786]309{
310    return fat_buf_release(fs_info);
311}
[0a7278e]312
[f36a7bfc]313/* fat_cluster_read --
314 *     wrapper for reading a whole cluster at once
315 *
316 * PARAMETERS:
[c65afce4]317 *     fs_info  - FS info
[f36a7bfc]318 *     cln      - number of cluster to read
319 *     buff     - buffer provided by user
320 *
321 * RETURNS:
322 *     bytes read on success, or -1 if error occured
323 *     and errno set appropriately
324 */
[a5305f6b]325ssize_t
[f36a7bfc]326fat_cluster_read(
[c65afce4]327    fat_fs_info_t                        *fs_info,
[f91bbe64]328    uint32_t                              cln,
[f36a7bfc]329    void                                 *buff
330    )
331{
[a5305f6b]332    uint32_t       fsec = 0;
[f36a7bfc]333
[c65afce4]334    fsec = fat_cluster_num_to_sector_num(fs_info, cln);
[a5305f6b]335
[c65afce4]336    return _fat_block_read(fs_info, fsec, 0,
[a5305f6b]337                           fs_info->vol.spc << fs_info->vol.sec_log2, buff);
338}
[f36a7bfc]339
340/* fat_cluster_write --
341 *     wrapper for writting a whole cluster at once
342 *
343 * PARAMETERS:
[c65afce4]344 *     fs_info  - FS info
[f36a7bfc]345 *     cln      - number of cluster to write
346 *     buff     - buffer provided by user
347 *
348 * RETURNS:
349 *     bytes written on success, or -1 if error occured
350 *     and errno set appropriately
351 */
[a5305f6b]352ssize_t
[f36a7bfc]353fat_cluster_write(
[c65afce4]354    fat_fs_info_t                        *fs_info,
[f91bbe64]355    uint32_t                              cln,
[f36a7bfc]356    const void                           *buff
357    )
358{
[f91bbe64]359    uint32_t       fsec = 0;
[a5305f6b]360
[c65afce4]361    fsec = fat_cluster_num_to_sector_num(fs_info, cln);
[a5305f6b]362
[c65afce4]363    return _fat_block_write(fs_info, fsec, 0,
[a5305f6b]364                          fs_info->vol.spc << fs_info->vol.sec_log2, buff);
365}
[f36a7bfc]366
367/* fat_init_volume_info --
368 *     Get inforamtion about volume on which filesystem is mounted on
369 *
370 * PARAMETERS:
[c65afce4]371 *     fs_info  - FS info
[f36a7bfc]372 *
373 * RETURNS:
374 *     RC_OK on success, or -1 if error occured
375 *     and errno set appropriately
376 */
377int
[c65afce4]378fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
[f36a7bfc]379{
[bf95ccb5]380    rtems_status_code   sc = RTEMS_SUCCESSFUL;
[f36a7bfc]381    int                 rc = RC_OK;
382    register fat_vol_t *vol = &fs_info->vol;
[f91bbe64]383    uint32_t            data_secs = 0;
[f36a7bfc]384    char                boot_rec[FAT_MAX_BPB_SIZE];
385    char                fs_info_sector[FAT_USEFUL_INFO_SIZE];
386    ssize_t             ret = 0;
387    struct stat         stat_buf;
388    int                 i = 0;
[3899a537]389    rtems_bdbuf_buffer *block = NULL;
[f36a7bfc]390
[c65afce4]391    vol->fd = open(device, O_RDWR);
[796967c]392    if (vol->fd < 0)
393    {
394        rtems_set_errno_and_return_minus_one(ENXIO);
395    }
396
397    rc = fstat(vol->fd, &stat_buf);
398    if (rc != 0)
399    {
400        close(vol->fd);
401        rtems_set_errno_and_return_minus_one(ENXIO);
402    }
[f36a7bfc]403
[5268642]404    /* Must be a block device. */
405    if (!S_ISBLK(stat_buf.st_mode))
[796967c]406    {
407        close(vol->fd);
408        rtems_set_errno_and_return_minus_one(ENXIO);
409    }
[f36a7bfc]410
[3899a537]411    /* check that device is registred as block device and lock it */
[796967c]412    rc = rtems_disk_fd_get_disk_device(vol->fd, &vol->dd);
413    if (rc != 0) {
414        close(vol->fd);
415        rtems_set_errno_and_return_minus_one(ENXIO);
416    }
[f36a7bfc]417
[bf95ccb5]418    /* Read boot record */
419    /* FIXME: Asserts FAT_MAX_BPB_SIZE < bdbuf block size */
[796967c]420    sc = rtems_bdbuf_read( vol->dd, 0, &block);
[bf95ccb5]421    if (sc != RTEMS_SUCCESSFUL)
[f36a7bfc]422    {
[796967c]423        close(vol->fd);
[3899a537]424        rtems_set_errno_and_return_minus_one( EIO);
[a5305f6b]425    }
426
[bf95ccb5]427    memcpy( boot_rec, block->buffer, FAT_MAX_BPB_SIZE);
428
429    sc = rtems_bdbuf_release( block);
430    if (sc != RTEMS_SUCCESSFUL)
[f36a7bfc]431    {
[796967c]432        close(vol->fd);
[3899a537]433        rtems_set_errno_and_return_minus_one( EIO );
[f36a7bfc]434    }
435
[bf95ccb5]436    /* Evaluate boot record */
[c36f885a]437    vol->bps = FAT_GET_BR_BYTES_PER_SECTOR(boot_rec);
[0a7278e]438
439    if ( (vol->bps != 512)  &&
440         (vol->bps != 1024) &&
[f36a7bfc]441         (vol->bps != 2048) &&
442         (vol->bps != 4096))
[a5305f6b]443    {
[796967c]444        close(vol->fd);
[3899a537]445        rtems_set_errno_and_return_minus_one( EINVAL );
[a5305f6b]446    }
[f36a7bfc]447
[a5305f6b]448    for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
[f36a7bfc]449         i >>= 1, vol->sec_mul++);
[a5305f6b]450    for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
[f36a7bfc]451         i >>= 1, vol->sec_log2++);
452
[c36f885a]453    vol->spc = FAT_GET_BR_SECTORS_PER_CLUSTER(boot_rec);
[c151cfc3]454    /*
455     * "sectors per cluster" of zero is invalid
456     * (and would hang the following loop)
457     */
458    if (vol->spc == 0)
459    {
[796967c]460        close(vol->fd);
[3899a537]461        rtems_set_errno_and_return_minus_one(EINVAL);
[a5305f6b]462    }
[c151cfc3]463
[a5305f6b]464    for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
[f36a7bfc]465         i >>= 1, vol->spc_log2++);
[a5305f6b]466
467    /*
[3b44f153]468     * "bytes per cluster" value greater than 32K is invalid
[f36a7bfc]469     */
470    if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
471    {
[796967c]472        close(vol->fd);
[3899a537]473        rtems_set_errno_and_return_minus_one(EINVAL);
[a5305f6b]474    }
[f36a7bfc]475
[a5305f6b]476    for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
[f36a7bfc]477         i >>= 1, vol->bpc_log2++);
478
[c36f885a]479    vol->fats = FAT_GET_BR_FAT_NUM(boot_rec);
480    vol->fat_loc = FAT_GET_BR_RESERVED_SECTORS_NUM(boot_rec);
[a5305f6b]481
[c36f885a]482    vol->rdir_entrs = FAT_GET_BR_FILES_PER_ROOT_DIR(boot_rec);
[0a7278e]483
[f36a7bfc]484    /* calculate the count of sectors occupied by the root directory */
485    vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
486                     vol->bps;
487
488    vol->rdir_size = vol->rdir_secs << vol->sec_log2;
489
[c36f885a]490    if ( (FAT_GET_BR_SECTORS_PER_FAT(boot_rec)) != 0)
491        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT(boot_rec);
[f36a7bfc]492    else
[c36f885a]493        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT32(boot_rec);
[0a7278e]494
495    vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
[f36a7bfc]496                     vol->rdir_secs;
497
498    /* for  FAT12/16 root dir starts at(sector) */
499    vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
[0a7278e]500
[c36f885a]501    if ( (FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
502        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec);
[f36a7bfc]503    else
[c36f885a]504        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM32(boot_rec);
[0a7278e]505
[f36a7bfc]506    data_secs = vol->tot_secs - vol->data_fsec;
[a5305f6b]507
[f36a7bfc]508    vol->data_cls = data_secs / vol->spc;
509
510    /* determine FAT type at least */
511    if ( vol->data_cls < FAT_FAT12_MAX_CLN)
512    {
513        vol->type = FAT_FAT12;
514        vol->mask = FAT_FAT12_MASK;
515        vol->eoc_val = FAT_FAT12_EOC;
516    }
[a5305f6b]517    else
[f36a7bfc]518    {
519        if ( vol->data_cls < FAT_FAT16_MAX_CLN)
520        {
521            vol->type = FAT_FAT16;
522            vol->mask = FAT_FAT16_MASK;
523            vol->eoc_val = FAT_FAT16_EOC;
524        }
525        else
526        {
527            vol->type = FAT_FAT32;
528            vol->mask = FAT_FAT32_MASK;
529            vol->eoc_val = FAT_FAT32_EOC;
530        }
531    }
[a5305f6b]532
[f36a7bfc]533    if (vol->type == FAT_FAT32)
534    {
[c36f885a]535        vol->rdir_cl = FAT_GET_BR_FAT32_ROOT_CLUSTER(boot_rec);
[0a7278e]536
[c36f885a]537        vol->mirror = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
[f36a7bfc]538        if (vol->mirror)
[c36f885a]539            vol->afat = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
[f36a7bfc]540        else
[a5305f6b]541            vol->afat = 0;
[f36a7bfc]542
[c36f885a]543        vol->info_sec = FAT_GET_BR_FAT32_FS_INFO_SECTOR(boot_rec);
[f36a7bfc]544        if( vol->info_sec == 0 )
[a5305f6b]545        {
[796967c]546            close(vol->fd);
[3899a537]547            rtems_set_errno_and_return_minus_one( EINVAL );
[a5305f6b]548        }
549        else
[f36a7bfc]550        {
[c65afce4]551            ret = _fat_block_read(fs_info, vol->info_sec , 0,
[f36a7bfc]552                                  FAT_FSI_LEADSIG_SIZE, fs_info_sector);
553            if ( ret < 0 )
554            {
[796967c]555                close(vol->fd);
[f36a7bfc]556                return -1;
[0a7278e]557            }
558
559            if (FAT_GET_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
[f36a7bfc]560                FAT_FSINFO_LEAD_SIGNATURE_VALUE)
[a5305f6b]561            {
[c65afce4]562                _fat_block_release(fs_info);
[796967c]563                close(vol->fd);
[3899a537]564                rtems_set_errno_and_return_minus_one( EINVAL );
[a5305f6b]565            }
[f36a7bfc]566            else
567            {
[c65afce4]568                ret = _fat_block_read(fs_info, vol->info_sec , FAT_FSI_INFO,
[f36a7bfc]569                                      FAT_USEFUL_INFO_SIZE, fs_info_sector);
570                if ( ret < 0 )
571                {
[c65afce4]572                    _fat_block_release(fs_info);
[796967c]573                    close(vol->fd);
[f36a7bfc]574                    return -1;
[0a7278e]575                }
576
[c36f885a]577                vol->free_cls = FAT_GET_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
578                vol->next_cl = FAT_GET_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
[8863338]579                rc = fat_fat32_update_fsinfo_sector(fs_info, FAT_UNDEFINED_VALUE,
580                                                    FAT_UNDEFINED_VALUE);
[f36a7bfc]581                if ( rc != RC_OK )
582                {
[c65afce4]583                    _fat_block_release(fs_info);
[796967c]584                    close(vol->fd);
[a5305f6b]585                    return rc;
586                }
[f36a7bfc]587            }
588        }
589    }
590    else
591    {
592        vol->rdir_cl = 0;
593        vol->mirror = 0;
594        vol->afat = 0;
[8863338]595        vol->free_cls = FAT_UNDEFINED_VALUE;
596        vol->next_cl = FAT_UNDEFINED_VALUE;
[f36a7bfc]597    }
[eb649786]598
[c65afce4]599    _fat_block_release(fs_info);
[eb649786]600
[f36a7bfc]601    vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
602
603    /* set up collection of fat-files fd */
[3899a537]604    fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
[a5305f6b]605    if ( fs_info->vhash == NULL )
[f36a7bfc]606    {
[796967c]607        close(vol->fd);
[3899a537]608        rtems_set_errno_and_return_minus_one( ENOMEM );
[a5305f6b]609    }
[f36a7bfc]610
611    for (i = 0; i < FAT_HASH_SIZE; i++)
[3899a537]612        rtems_chain_initialize_empty(fs_info->vhash + i);
[f36a7bfc]613
[3899a537]614    fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
[a5305f6b]615    if ( fs_info->rhash == NULL )
[f36a7bfc]616    {
[796967c]617        close(vol->fd);
[f36a7bfc]618        free(fs_info->vhash);
[3899a537]619        rtems_set_errno_and_return_minus_one( ENOMEM );
[f36a7bfc]620    }
621    for (i = 0; i < FAT_HASH_SIZE; i++)
[3899a537]622        rtems_chain_initialize_empty(fs_info->rhash + i);
[a5305f6b]623
[f36a7bfc]624    fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
625    fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
626    fs_info->index = 0;
627    fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
628    if ( fs_info->uino == NULL )
629    {
[796967c]630        close(vol->fd);
[f36a7bfc]631        free(fs_info->vhash);
632        free(fs_info->rhash);
[3899a537]633        rtems_set_errno_and_return_minus_one( ENOMEM );
[f36a7bfc]634    }
[0247c6c]635    fs_info->sec_buf = (uint8_t *)calloc(vol->bps, sizeof(uint8_t));
[f36a7bfc]636    if (fs_info->sec_buf == NULL)
637    {
[796967c]638        close(vol->fd);
[f36a7bfc]639        free(fs_info->vhash);
640        free(fs_info->rhash);
641        free(fs_info->uino);
[3899a537]642        rtems_set_errno_and_return_minus_one( ENOMEM );
[f36a7bfc]643    }
[a5305f6b]644
645    return RC_OK;
[f36a7bfc]646}
647
648/* fat_shutdown_drive --
[a5305f6b]649 *     Free all allocated resources and synchronize all necessary data
[f36a7bfc]650 *
651 * PARAMETERS:
[c65afce4]652 *     fs_info  - FS info
[f36a7bfc]653 *
654 * RETURNS:
655 *     RC_OK on success, or -1 if error occured
656 *     and errno set appropriately
657 */
658int
[c65afce4]659fat_shutdown_drive(fat_fs_info_t *fs_info)
[f36a7bfc]660{
661    int            rc = RC_OK;
662    int            i = 0;
663
664    if (fs_info->vol.type & FAT_FAT32)
665    {
[c65afce4]666        rc = fat_fat32_update_fsinfo_sector(fs_info, fs_info->vol.free_cls,
[f36a7bfc]667                                            fs_info->vol.next_cl);
668        if ( rc != RC_OK )
669            rc = -1;
[a5305f6b]670    }
[f36a7bfc]671
672    fat_buf_release(fs_info);
[a5305f6b]673
[796967c]674    if (rtems_bdbuf_syncdev(fs_info->vol.dd) != RTEMS_SUCCESSFUL)
[f36a7bfc]675        rc = -1;
676
677    for (i = 0; i < FAT_HASH_SIZE; i++)
678    {
[3899a537]679        rtems_chain_node    *node = NULL;
680        rtems_chain_control *the_chain = fs_info->vhash + i;
[a5305f6b]681
[3899a537]682        while ( (node = rtems_chain_get(the_chain)) != NULL )
[f36a7bfc]683            free(node);
[a5305f6b]684    }
[f36a7bfc]685
686    for (i = 0; i < FAT_HASH_SIZE; i++)
687    {
[3899a537]688        rtems_chain_node    *node = NULL;
689        rtems_chain_control *the_chain = fs_info->rhash + i;
[f36a7bfc]690
[3899a537]691        while ( (node = rtems_chain_get(the_chain)) != NULL )
[f36a7bfc]692            free(node);
[a5305f6b]693    }
[f36a7bfc]694
695    free(fs_info->vhash);
[a5305f6b]696    free(fs_info->rhash);
[f36a7bfc]697
698    free(fs_info->uino);
699    free(fs_info->sec_buf);
[796967c]700    close(fs_info->vol.fd);
[f36a7bfc]701
702    if (rc)
703        errno = EIO;
704    return rc;
705}
706
707/* fat_init_clusters_chain --
708 *     Zeroing contents of all clusters in the chain
709 *
710 * PARAMETERS:
[c65afce4]711 *     fs_info           - FS info
[a5305f6b]712 *     start_cluster_num - num of first cluster in the chain
[f36a7bfc]713 *
714 * RETURNS:
715 *     RC_OK on success, or -1 if error occured
716 *     and errno set appropriately
717 */
718int
719fat_init_clusters_chain(
[c65afce4]720    fat_fs_info_t                        *fs_info,
[f91bbe64]721    uint32_t                              start_cln
[f36a7bfc]722    )
723{
724    int                     rc = RC_OK;
725    ssize_t                 ret = 0;
[f91bbe64]726    uint32_t                cur_cln = start_cln;
[f36a7bfc]727    char                   *buf;
[a5305f6b]728
[f36a7bfc]729    buf = calloc(fs_info->vol.bpc, sizeof(char));
730    if ( buf == NULL )
[3899a537]731        rtems_set_errno_and_return_minus_one( EIO );
[f36a7bfc]732
[c151cfc3]733    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
[f36a7bfc]734    {
[c65afce4]735        ret = fat_cluster_write(fs_info, cur_cln, buf);
[f36a7bfc]736        if ( ret == -1 )
737        {
738            free(buf);
739            return -1;
740        }
741
[c65afce4]742        rc  = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
[f36a7bfc]743        if ( rc != RC_OK )
744        {
745            free(buf);
746            return rc;
747        }
[a5305f6b]748
[f36a7bfc]749    }
750    free(buf);
751    return rc;
[a5305f6b]752}
753
754#define FAT_UNIQ_INO_BASE 0x0FFFFF00
[f36a7bfc]755
756#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
757  (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
758
759#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
760  ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
761
762#define FAT_SET_UNIQ_INO_FREE(index, arr) \
763  ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
764
765/* fat_get_unique_ino --
766 *     Allocate unique ino from unique ino pool
767 *
768 * PARAMETERS:
[c65afce4]769 *     fs_info  - FS info
[f36a7bfc]770 *
771 * RETURNS:
772 *     unique inode number on success, or 0 if there is no free unique inode
773 *     number in the pool
774 *
775 * ATTENTION:
776 *     0 means FAILED !!!
[a5305f6b]777 *
[f36a7bfc]778 */
[a5305f6b]779uint32_t
[c65afce4]780fat_get_unique_ino(fat_fs_info_t *fs_info)
[f36a7bfc]781{
[f91bbe64]782    uint32_t                j = 0;
[0a896eb]783    bool                    resrc_unsuff = false;
[f36a7bfc]784
785    while (!resrc_unsuff)
[a5305f6b]786    {
[f36a7bfc]787        for (j = 0; j < fs_info->uino_pool_size; j++)
788        {
789            if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
790            {
791                FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
[a5305f6b]792                return (fs_info->uino_base + fs_info->index);
[f36a7bfc]793            }
794            fs_info->index++;
795            if (fs_info->index >= fs_info->uino_pool_size)
796                fs_info->index = 0;
797        }
798
799        if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
800        {
801            fs_info->uino_pool_size <<= 1;
802            fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
803            if (fs_info->uino != NULL)
804                fs_info->index = fs_info->uino_pool_size;
[a5305f6b]805            else
[0a896eb]806                resrc_unsuff = true;
[f36a7bfc]807        }
808        else
[0a896eb]809            resrc_unsuff = true;
[a5305f6b]810    }
[f36a7bfc]811    return 0;
812}
813
814/* fat_free_unique_ino --
815 *     Return unique ino to unique ino pool
816 *
817 * PARAMETERS:
[c65afce4]818 *     fs_info  - FS info
[f36a7bfc]819 *     ino      - inode number to free
820 *
821 * RETURNS:
822 *     None
823 */
824void
825fat_free_unique_ino(
[c65afce4]826    fat_fs_info_t                        *fs_info,
[f91bbe64]827    uint32_t                              ino
[f36a7bfc]828    )
829{
830    FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
831}
832
833/* fat_ino_is_unique --
834 *     Test whether ino is from unique ino pool
835 *
836 * PARAMETERS:
[c65afce4]837 *     fs_info  - FS info
[f36a7bfc]838 *     ino   - ino to be tested
839 *
840 * RETURNS:
[0a896eb]841 *     true if ino is allocated from unique ino pool, false otherwise
[f36a7bfc]842 */
[0a896eb]843inline bool
[f36a7bfc]844fat_ino_is_unique(
[c65afce4]845    fat_fs_info_t                        *fs_info,
[f91bbe64]846    uint32_t                              ino
[f36a7bfc]847    )
848{
[a5305f6b]849
[f36a7bfc]850    return (ino >= fs_info->uino_base);
851}
852
853/* fat_fat32_update_fsinfo_sector --
854 *     Synchronize fsinfo sector for FAT32 volumes
855 *
856 * PARAMETERS:
[c65afce4]857 *     fs_info    - FS info
[f36a7bfc]858 *     free_count - count of free clusters
859 *     next_free  - the next free cluster num
860 *
861 * RETURNS:
862 *     RC_OK on success, or -1 if error occured (errno set appropriately)
863 */
864int
865fat_fat32_update_fsinfo_sector(
[c65afce4]866    fat_fs_info_t                        *fs_info,
[f91bbe64]867    uint32_t                              free_count,
868    uint32_t                              next_free
[f36a7bfc]869    )
870{
871    ssize_t                 ret1 = 0, ret2 = 0;
[f91bbe64]872    uint32_t                le_free_count = 0;
873    uint32_t                le_next_free = 0;
[f36a7bfc]874
875    le_free_count = CT_LE_L(free_count);
876    le_next_free = CT_LE_L(next_free);
877
[c65afce4]878    ret1 = _fat_block_write(fs_info,
[f36a7bfc]879                            fs_info->vol.info_sec,
880                            FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
881                            4,
882                            (char *)(&le_free_count));
883
[c65afce4]884    ret2 = _fat_block_write(fs_info,
[f36a7bfc]885                            fs_info->vol.info_sec,
886                            FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
887                            4,
888                            (char *)(&le_next_free));
889
890    if ( (ret1 < 0) || (ret2 < 0) )
891        return -1;
892
893    return RC_OK;
894}
Note: See TracBrowser for help on using the repository browser.