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

5
Last change on this file since 06331e4 was 06331e4, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 27, 2018 at 10:56:01 AM

dosfs: Fix device identifier

Update #3358.

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