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

4.115
Last change on this file since ba386a6 was ba386a6, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/14 at 18:28:47

dosfs/fat.c: Remove use of register keyword

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