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

5
Last change on this file since cfe8f7a was cfe8f7a, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/20 at 14:14:06

doxygen: Switch @brief and @ingroup

This order change fixes the Latex documentation build via Doxygen.

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