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

4.115
Last change on this file since 4e59276 was 4e59276, checked in by Mathew Kallada <matkallada@…>, on 12/28/12 at 14:05:20

libfs: Doxygen Enhancement Task #5

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