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

4.11
Last change on this file since 8863338 was 8863338, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 8, 2012 at 1:45:27 PM

dosfs: Use FAT_UNDEFINED_VALUE

  • Property mode set to 100644
File size: 24.8 KB
Line 
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
10#if HAVE_CONFIG_H
11#include "config.h"
12#endif
13
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
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;
32    bool              sec_of_fat;
33
34
35    if (fs_info->c.state == FAT_CACHE_EMPTY)
36    {
37        if (op_type == FAT_OP_TYPE_READ)
38            sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
39        else
40            sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
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                {
71                    sc = rtems_bdbuf_get(fs_info->vol.dd,
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)
93            sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
94        else
95            sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
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;
110    bool              sec_of_fat;
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            {
134                sc = rtems_bdbuf_get(fs_info->vol.dd,
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
157/* _fat_block_read --
158 *     This function reads 'count' bytes from device filesystem is mounted on,
159 *     starts at 'start+offset' position where 'start' computed in sectors
160 *     and 'offset' is offset inside sector (reading may cross sectors
161 *     boundary; in this case assumed we want to read sequential sector(s))
162 *
163 * PARAMETERS:
164 *     fs_info  - FS info
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(
176    fat_fs_info_t                        *fs_info,
177    uint32_t                              start,
178    uint32_t                              offset,
179    uint32_t                              count,
180    void                                 *buff
181    )
182{
183    int                     rc = RC_OK;
184    ssize_t                 cmpltd = 0;
185    uint32_t                blk = start;
186    uint32_t                ofs = offset;
187    rtems_bdbuf_buffer     *block = NULL;
188    uint32_t                c = 0;
189
190    while (count > 0)
191    {
192        rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
193        if (rc != RC_OK)
194            return -1;
195
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 --
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
211 *     boundary; in this case assumed we want to write sequential sector(s))
212 *
213 * PARAMETERS:
214 *     fs_info  - FS info
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(
226    fat_fs_info_t                        *fs_info,
227    uint32_t                              start,
228    uint32_t                              offset,
229    uint32_t                              count,
230    const void                           *buff)
231{
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;
238
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)
248            return -1;
249
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
262int
263_fat_block_zero(
264    fat_fs_info_t                        *fs_info,
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
297/* _fat_block_release --
298 *     This function works around the hack that hold a bdbuf and does
299 *     not release it.
300 *
301 * PARAMETERS:
302 *     fs_info  - FS info
303 *
304 * RETURNS:
305 *     0 on success, or -1 if error occured and errno set appropriately
306 */
307int
308_fat_block_release(fat_fs_info_t *fs_info)
309{
310    return fat_buf_release(fs_info);
311}
312
313/* fat_cluster_read --
314 *     wrapper for reading a whole cluster at once
315 *
316 * PARAMETERS:
317 *     fs_info  - FS info
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 */
325ssize_t
326fat_cluster_read(
327    fat_fs_info_t                        *fs_info,
328    uint32_t                              cln,
329    void                                 *buff
330    )
331{
332    uint32_t       fsec = 0;
333
334    fsec = fat_cluster_num_to_sector_num(fs_info, cln);
335
336    return _fat_block_read(fs_info, fsec, 0,
337                           fs_info->vol.spc << fs_info->vol.sec_log2, buff);
338}
339
340/* fat_cluster_write --
341 *     wrapper for writting a whole cluster at once
342 *
343 * PARAMETERS:
344 *     fs_info  - FS info
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 */
352ssize_t
353fat_cluster_write(
354    fat_fs_info_t                        *fs_info,
355    uint32_t                              cln,
356    const void                           *buff
357    )
358{
359    uint32_t       fsec = 0;
360
361    fsec = fat_cluster_num_to_sector_num(fs_info, cln);
362
363    return _fat_block_write(fs_info, fsec, 0,
364                          fs_info->vol.spc << fs_info->vol.sec_log2, buff);
365}
366
367/* fat_init_volume_info --
368 *     Get inforamtion about volume on which filesystem is mounted on
369 *
370 * PARAMETERS:
371 *     fs_info  - FS info
372 *
373 * RETURNS:
374 *     RC_OK on success, or -1 if error occured
375 *     and errno set appropriately
376 */
377int
378fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
379{
380    rtems_status_code   sc = RTEMS_SUCCESSFUL;
381    int                 rc = RC_OK;
382    register fat_vol_t *vol = &fs_info->vol;
383    uint32_t            data_secs = 0;
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;
389    rtems_bdbuf_buffer *block = NULL;
390
391    vol->fd = open(device, O_RDWR);
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    }
403
404    /* Must be a block device. */
405    if (!S_ISBLK(stat_buf.st_mode))
406    {
407        close(vol->fd);
408        rtems_set_errno_and_return_minus_one(ENXIO);
409    }
410
411    /* check that device is registred as block device and lock it */
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    }
417
418    /* Read boot record */
419    /* FIXME: Asserts FAT_MAX_BPB_SIZE < bdbuf block size */
420    sc = rtems_bdbuf_read( vol->dd, 0, &block);
421    if (sc != RTEMS_SUCCESSFUL)
422    {
423        close(vol->fd);
424        rtems_set_errno_and_return_minus_one( EIO);
425    }
426
427    memcpy( boot_rec, block->buffer, FAT_MAX_BPB_SIZE);
428
429    sc = rtems_bdbuf_release( block);
430    if (sc != RTEMS_SUCCESSFUL)
431    {
432        close(vol->fd);
433        rtems_set_errno_and_return_minus_one( EIO );
434    }
435
436    /* Evaluate boot record */
437    vol->bps = FAT_GET_BR_BYTES_PER_SECTOR(boot_rec);
438
439    if ( (vol->bps != 512)  &&
440         (vol->bps != 1024) &&
441         (vol->bps != 2048) &&
442         (vol->bps != 4096))
443    {
444        close(vol->fd);
445        rtems_set_errno_and_return_minus_one( EINVAL );
446    }
447
448    for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
449         i >>= 1, vol->sec_mul++);
450    for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
451         i >>= 1, vol->sec_log2++);
452
453    vol->spc = FAT_GET_BR_SECTORS_PER_CLUSTER(boot_rec);
454    /*
455     * "sectors per cluster" of zero is invalid
456     * (and would hang the following loop)
457     */
458    if (vol->spc == 0)
459    {
460        close(vol->fd);
461        rtems_set_errno_and_return_minus_one(EINVAL);
462    }
463
464    for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
465         i >>= 1, vol->spc_log2++);
466
467    /*
468     * "bytes per cluster" value greater than 32K is invalid
469     */
470    if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
471    {
472        close(vol->fd);
473        rtems_set_errno_and_return_minus_one(EINVAL);
474    }
475
476    for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
477         i >>= 1, vol->bpc_log2++);
478
479    vol->fats = FAT_GET_BR_FAT_NUM(boot_rec);
480    vol->fat_loc = FAT_GET_BR_RESERVED_SECTORS_NUM(boot_rec);
481
482    vol->rdir_entrs = FAT_GET_BR_FILES_PER_ROOT_DIR(boot_rec);
483
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
490    if ( (FAT_GET_BR_SECTORS_PER_FAT(boot_rec)) != 0)
491        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT(boot_rec);
492    else
493        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT32(boot_rec);
494
495    vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
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;
500
501    if ( (FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
502        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec);
503    else
504        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM32(boot_rec);
505
506    data_secs = vol->tot_secs - vol->data_fsec;
507
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    }
517    else
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    }
532
533    if (vol->type == FAT_FAT32)
534    {
535        vol->rdir_cl = FAT_GET_BR_FAT32_ROOT_CLUSTER(boot_rec);
536
537        vol->mirror = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
538        if (vol->mirror)
539            vol->afat = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
540        else
541            vol->afat = 0;
542
543        vol->info_sec = FAT_GET_BR_FAT32_FS_INFO_SECTOR(boot_rec);
544        if( vol->info_sec == 0 )
545        {
546            close(vol->fd);
547            rtems_set_errno_and_return_minus_one( EINVAL );
548        }
549        else
550        {
551            ret = _fat_block_read(fs_info, vol->info_sec , 0,
552                                  FAT_FSI_LEADSIG_SIZE, fs_info_sector);
553            if ( ret < 0 )
554            {
555                close(vol->fd);
556                return -1;
557            }
558
559            if (FAT_GET_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
560                FAT_FSINFO_LEAD_SIGNATURE_VALUE)
561            {
562                _fat_block_release(fs_info);
563                close(vol->fd);
564                rtems_set_errno_and_return_minus_one( EINVAL );
565            }
566            else
567            {
568                ret = _fat_block_read(fs_info, vol->info_sec , FAT_FSI_INFO,
569                                      FAT_USEFUL_INFO_SIZE, fs_info_sector);
570                if ( ret < 0 )
571                {
572                    _fat_block_release(fs_info);
573                    close(vol->fd);
574                    return -1;
575                }
576
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);
579                rc = fat_fat32_update_fsinfo_sector(fs_info, FAT_UNDEFINED_VALUE,
580                                                    FAT_UNDEFINED_VALUE);
581                if ( rc != RC_OK )
582                {
583                    _fat_block_release(fs_info);
584                    close(vol->fd);
585                    return rc;
586                }
587            }
588        }
589    }
590    else
591    {
592        vol->rdir_cl = 0;
593        vol->mirror = 0;
594        vol->afat = 0;
595        vol->free_cls = FAT_UNDEFINED_VALUE;
596        vol->next_cl = FAT_UNDEFINED_VALUE;
597    }
598
599    _fat_block_release(fs_info);
600
601    vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
602
603    /* set up collection of fat-files fd */
604    fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
605    if ( fs_info->vhash == NULL )
606    {
607        close(vol->fd);
608        rtems_set_errno_and_return_minus_one( ENOMEM );
609    }
610
611    for (i = 0; i < FAT_HASH_SIZE; i++)
612        rtems_chain_initialize_empty(fs_info->vhash + i);
613
614    fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
615    if ( fs_info->rhash == NULL )
616    {
617        close(vol->fd);
618        free(fs_info->vhash);
619        rtems_set_errno_and_return_minus_one( ENOMEM );
620    }
621    for (i = 0; i < FAT_HASH_SIZE; i++)
622        rtems_chain_initialize_empty(fs_info->rhash + i);
623
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    {
630        close(vol->fd);
631        free(fs_info->vhash);
632        free(fs_info->rhash);
633        rtems_set_errno_and_return_minus_one( ENOMEM );
634    }
635    fs_info->sec_buf = (uint8_t *)calloc(vol->bps, sizeof(uint8_t));
636    if (fs_info->sec_buf == NULL)
637    {
638        close(vol->fd);
639        free(fs_info->vhash);
640        free(fs_info->rhash);
641        free(fs_info->uino);
642        rtems_set_errno_and_return_minus_one( ENOMEM );
643    }
644
645    return RC_OK;
646}
647
648/* fat_shutdown_drive --
649 *     Free all allocated resources and synchronize all necessary data
650 *
651 * PARAMETERS:
652 *     fs_info  - FS info
653 *
654 * RETURNS:
655 *     RC_OK on success, or -1 if error occured
656 *     and errno set appropriately
657 */
658int
659fat_shutdown_drive(fat_fs_info_t *fs_info)
660{
661    int            rc = RC_OK;
662    int            i = 0;
663
664    if (fs_info->vol.type & FAT_FAT32)
665    {
666        rc = fat_fat32_update_fsinfo_sector(fs_info, fs_info->vol.free_cls,
667                                            fs_info->vol.next_cl);
668        if ( rc != RC_OK )
669            rc = -1;
670    }
671
672    fat_buf_release(fs_info);
673
674    if (rtems_bdbuf_syncdev(fs_info->vol.dd) != RTEMS_SUCCESSFUL)
675        rc = -1;
676
677    for (i = 0; i < FAT_HASH_SIZE; i++)
678    {
679        rtems_chain_node    *node = NULL;
680        rtems_chain_control *the_chain = fs_info->vhash + i;
681
682        while ( (node = rtems_chain_get(the_chain)) != NULL )
683            free(node);
684    }
685
686    for (i = 0; i < FAT_HASH_SIZE; i++)
687    {
688        rtems_chain_node    *node = NULL;
689        rtems_chain_control *the_chain = fs_info->rhash + i;
690
691        while ( (node = rtems_chain_get(the_chain)) != NULL )
692            free(node);
693    }
694
695    free(fs_info->vhash);
696    free(fs_info->rhash);
697
698    free(fs_info->uino);
699    free(fs_info->sec_buf);
700    close(fs_info->vol.fd);
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:
711 *     fs_info           - FS info
712 *     start_cluster_num - num of first cluster in the chain
713 *
714 * RETURNS:
715 *     RC_OK on success, or -1 if error occured
716 *     and errno set appropriately
717 */
718int
719fat_init_clusters_chain(
720    fat_fs_info_t                        *fs_info,
721    uint32_t                              start_cln
722    )
723{
724    int                     rc = RC_OK;
725    ssize_t                 ret = 0;
726    uint32_t                cur_cln = start_cln;
727    char                   *buf;
728
729    buf = calloc(fs_info->vol.bpc, sizeof(char));
730    if ( buf == NULL )
731        rtems_set_errno_and_return_minus_one( EIO );
732
733    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
734    {
735        ret = fat_cluster_write(fs_info, cur_cln, buf);
736        if ( ret == -1 )
737        {
738            free(buf);
739            return -1;
740        }
741
742        rc  = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
743        if ( rc != RC_OK )
744        {
745            free(buf);
746            return rc;
747        }
748
749    }
750    free(buf);
751    return rc;
752}
753
754#define FAT_UNIQ_INO_BASE 0x0FFFFF00
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:
769 *     fs_info  - FS info
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 !!!
777 *
778 */
779uint32_t
780fat_get_unique_ino(fat_fs_info_t *fs_info)
781{
782    uint32_t                j = 0;
783    bool                    resrc_unsuff = false;
784
785    while (!resrc_unsuff)
786    {
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);
792                return (fs_info->uino_base + fs_info->index);
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;
805            else
806                resrc_unsuff = true;
807        }
808        else
809            resrc_unsuff = true;
810    }
811    return 0;
812}
813
814/* fat_free_unique_ino --
815 *     Return unique ino to unique ino pool
816 *
817 * PARAMETERS:
818 *     fs_info  - FS info
819 *     ino      - inode number to free
820 *
821 * RETURNS:
822 *     None
823 */
824void
825fat_free_unique_ino(
826    fat_fs_info_t                        *fs_info,
827    uint32_t                              ino
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:
837 *     fs_info  - FS info
838 *     ino   - ino to be tested
839 *
840 * RETURNS:
841 *     true if ino is allocated from unique ino pool, false otherwise
842 */
843inline bool
844fat_ino_is_unique(
845    fat_fs_info_t                        *fs_info,
846    uint32_t                              ino
847    )
848{
849
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:
857 *     fs_info    - FS info
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(
866    fat_fs_info_t                        *fs_info,
867    uint32_t                              free_count,
868    uint32_t                              next_free
869    )
870{
871    ssize_t                 ret1 = 0, ret2 = 0;
872    uint32_t                le_free_count = 0;
873    uint32_t                le_next_free = 0;
874
875    le_free_count = CT_LE_L(free_count);
876    le_next_free = CT_LE_L(next_free);
877
878    ret1 = _fat_block_write(fs_info,
879                            fs_info->vol.info_sec,
880                            FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
881                            4,
882                            (char *)(&le_free_count));
883
884    ret2 = _fat_block_write(fs_info,
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.