Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /**
0002  * @file
0003  *
0004  * @ingroup DOSFS
0005  *
0006  * @brief Low-level Operations on a Volume with a DOSFS FAT filesystem
0007  */
0008 
0009 /*
0010  * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0011  * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
0012  */
0013 
0014 #ifdef HAVE_CONFIG_H
0015 #include "config.h"
0016 #endif
0017 
0018 #include <sys/types.h>
0019 #include <sys/stat.h>
0020 #include <fcntl.h>
0021 #include <unistd.h>
0022 #include <errno.h>
0023 #include <stdlib.h>
0024 #include <stdint.h>
0025 
0026 #include <rtems/libio_.h>
0027 
0028 #include "fat.h"
0029 #include "fat_fat_operations.h"
0030 
0031 static int
0032  _fat_block_release(fat_fs_info_t *fs_info);
0033 
0034 static inline uint32_t
0035 fat_cluster_num_to_block_num (const fat_fs_info_t *fs_info,
0036                               uint32_t             cln)
0037 {
0038     uint32_t blk;
0039 
0040     if ( (cln == 0) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)) )
0041         blk = fat_sector_num_to_block_num(fs_info, fs_info->vol.rdir_loc);
0042     else
0043     {
0044         cln -= FAT_RSRVD_CLN;
0045         blk = cln << (fs_info->vol.bpc_log2 - fs_info->vol.bytes_per_block_log2);
0046         blk += fat_sector_num_to_block_num(fs_info, fs_info->vol.data_fsec);
0047     }
0048 
0049     return blk;
0050 }
0051 
0052 int
0053 fat_buf_access(fat_fs_info_t   *fs_info,
0054                const uint32_t   sec_num,
0055                const int        op_type,
0056                uint8_t        **sec_buf)
0057 {
0058     rtems_status_code sc = RTEMS_SUCCESSFUL;
0059     uint32_t          blk = fat_sector_num_to_block_num (fs_info,
0060                                                          sec_num);
0061     uint32_t          blk_ofs = fat_sector_offset_to_block_offset (fs_info,
0062                                                                    sec_num,
0063                                                                    0);
0064 
0065     if (fs_info->c.state == FAT_CACHE_EMPTY || fs_info->c.blk_num != sec_num)
0066     {
0067         fat_buf_release(fs_info);
0068 
0069         if (op_type == FAT_OP_TYPE_READ)
0070             sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
0071         else
0072             sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
0073         if (sc != RTEMS_SUCCESSFUL)
0074             rtems_set_errno_and_return_minus_one(EIO);
0075         fs_info->c.blk_num = sec_num;
0076         fs_info->c.modified = 0;
0077         fs_info->c.state = FAT_CACHE_ACTUAL;
0078     }
0079     *sec_buf = &fs_info->c.buf->buffer[blk_ofs];
0080     return RC_OK;
0081 }
0082 
0083 int
0084 fat_buf_release(fat_fs_info_t *fs_info)
0085 {
0086     rtems_status_code sc = RTEMS_SUCCESSFUL;
0087 
0088     if (fs_info->c.state == FAT_CACHE_EMPTY)
0089         return RC_OK;
0090 
0091     if (fs_info->c.modified)
0092     {
0093         uint32_t sec_num = fs_info->c.blk_num;
0094         bool     sec_of_fat = ((sec_num >= fs_info->vol.fat_loc) &&
0095                               (sec_num < fs_info->vol.rdir_loc));
0096         uint32_t blk_ofs = fat_sector_offset_to_block_offset(fs_info,
0097                                                              sec_num,
0098                                                              0);
0099 
0100         if (sec_of_fat && !fs_info->vol.mirror)
0101             memcpy(fs_info->sec_buf,
0102                    fs_info->c.buf->buffer + blk_ofs,
0103                    fs_info->vol.bps);
0104 
0105         sc = rtems_bdbuf_release_modified(fs_info->c.buf);
0106         if (sc != RTEMS_SUCCESSFUL)
0107             rtems_set_errno_and_return_minus_one(EIO);
0108         fs_info->c.modified = 0;
0109 
0110         if (sec_of_fat && !fs_info->vol.mirror)
0111         {
0112             uint8_t i;
0113 
0114             for (i = 1; i < fs_info->vol.fats; i++)
0115             {
0116                 rtems_bdbuf_buffer *bd;
0117                 uint32_t blk;
0118 
0119                 sec_num = fs_info->c.blk_num + fs_info->vol.fat_length * i,
0120                 blk = fat_sector_num_to_block_num(fs_info, sec_num);
0121                 blk_ofs = fat_sector_offset_to_block_offset(fs_info,
0122                                                             sec_num,
0123                                                             0);
0124 
0125                 if (blk_ofs == 0
0126                     && fs_info->vol.bps == fs_info->vol.bytes_per_block)
0127                 {
0128                     sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &bd);
0129                 }
0130                 else
0131                 {
0132                     sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &bd);
0133                 }
0134                 if ( sc != RTEMS_SUCCESSFUL)
0135                     rtems_set_errno_and_return_minus_one(ENOMEM);
0136                 memcpy(bd->buffer + blk_ofs, fs_info->sec_buf, fs_info->vol.bps);
0137                 sc = rtems_bdbuf_release_modified(bd);
0138                 if ( sc != RTEMS_SUCCESSFUL)
0139                     rtems_set_errno_and_return_minus_one(ENOMEM);
0140             }
0141         }
0142     }
0143     else
0144     {
0145         sc = rtems_bdbuf_release(fs_info->c.buf);
0146         if (sc != RTEMS_SUCCESSFUL)
0147             rtems_set_errno_and_return_minus_one(EIO);
0148     }
0149     fs_info->c.state = FAT_CACHE_EMPTY;
0150     return RC_OK;
0151 }
0152 
0153 /* _fat_block_read --
0154  *     This function reads 'count' bytes from device filesystem is mounted on,
0155  *     starts at 'start+offset' position where 'start' computed in sectors
0156  *     and 'offset' is offset inside sector (reading may cross sectors
0157  *     boundary; in this case assumed we want to read sequential sector(s))
0158  *
0159  * PARAMETERS:
0160  *     fs_info  - FS info
0161  *     start    - sector num to start read from
0162  *     offset   - offset inside sector 'start'
0163  *     count    - count of bytes to read
0164  *     buff     - buffer provided by user
0165  *
0166  * RETURNS:
0167  *     bytes read on success, or -1 if error occurred
0168  *     and errno set appropriately
0169  */
0170 ssize_t
0171 _fat_block_read(
0172     fat_fs_info_t                        *fs_info,
0173     uint32_t                              start,
0174     uint32_t                              offset,
0175     uint32_t                              count,
0176     void                                 *buff
0177     )
0178 {
0179     int                     rc = RC_OK;
0180     ssize_t                 cmpltd = 0;
0181     uint32_t                sec_num = start;
0182     uint32_t                ofs = offset;
0183     uint8_t                *sec_buf;
0184     uint32_t                c = 0;
0185 
0186     while (count > 0)
0187     {
0188         rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
0189         if (rc != RC_OK)
0190             return -1;
0191 
0192         c = MIN(count, (fs_info->vol.bps - ofs));
0193         memcpy((buff + cmpltd), (sec_buf + ofs), c);
0194 
0195         count -= c;
0196         cmpltd += c;
0197         sec_num++;
0198         ofs = 0;
0199     }
0200     return cmpltd;
0201 }
0202 
0203 void
0204 fat_block_peek(
0205     fat_fs_info_t                        *fs_info,
0206     const uint32_t                        blk,
0207     const uint32_t                        blk_cnt
0208     )
0209 {
0210     rtems_bdbuf_peek(fs_info->vol.dd, blk, blk_cnt);
0211 }
0212 
0213 static ssize_t
0214 fat_block_write(
0215     fat_fs_info_t                        *fs_info,
0216     const uint32_t                        start_blk,
0217     const uint32_t                        offset,
0218     const uint32_t                        count,
0219     const void                           *buf)
0220 {
0221     int                 rc             = RC_OK;
0222     uint32_t            bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
0223     uint8_t            *blk_buf;
0224     uint32_t            sec_num        = fat_block_num_to_sector_num(fs_info, start_blk);
0225 
0226     if (0 < bytes_to_write)
0227     {
0228         if (bytes_to_write == fs_info->vol.bytes_per_block)
0229         {
0230             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
0231         }
0232         else
0233             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &blk_buf);
0234 
0235         if (RC_OK == rc)
0236         {
0237             memcpy(blk_buf + offset, buf, bytes_to_write);
0238 
0239             fat_buf_mark_modified(fs_info);
0240         }
0241     }
0242     if (RC_OK != rc)
0243         return rc;
0244     else
0245         return bytes_to_write;
0246 }
0247 
0248 /* fat_sector_write --
0249  *     This function write 'count' bytes to device filesystem is mounted on,
0250  *     starts at 'start+offset' position where 'start' computed in sectors
0251  *     and 'offset' is offset inside sector (writing may cross sectors
0252  *     boundary; in this case assumed we want to write sequential sector(s))
0253  *
0254  * PARAMETERS:
0255  *     fs_info  - FS info
0256  *     start    - sector num to start read from
0257  *     offset   - offset inside sector 'start'
0258  *     count    - count of bytes to write
0259  *     buff     - buffer provided by user
0260  *
0261  * RETURNS:
0262  *     bytes written on success, or -1 if error occurred
0263  *     and errno set appropriately
0264  */
0265 ssize_t
0266 fat_sector_write(
0267     fat_fs_info_t                        *fs_info,
0268     uint32_t                              start,
0269     uint32_t                              offset,
0270     uint32_t                              count,
0271     const void                           *buff)
0272 {
0273     int                 rc = RC_OK;
0274     ssize_t             cmpltd = 0;
0275     uint32_t            sec_num = start;
0276     uint32_t            ofs = offset;
0277     uint8_t            *sec_buf;
0278     uint32_t            c = 0;
0279 
0280     while(count > 0)
0281     {
0282         c = MIN(count, (fs_info->vol.bps - ofs));
0283 
0284         if (c == fs_info->vol.bytes_per_block)
0285             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &sec_buf);
0286         else
0287             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
0288         if (rc != RC_OK)
0289             return -1;
0290 
0291         memcpy((sec_buf + ofs), (buff + cmpltd), c);
0292 
0293         fat_buf_mark_modified(fs_info);
0294 
0295         count -= c;
0296         cmpltd +=c;
0297         sec_num++;
0298         ofs = 0;
0299     }
0300     return cmpltd;
0301 }
0302 
0303 static ssize_t
0304  fat_block_set (
0305      fat_fs_info_t                        *fs_info,
0306      const uint32_t                        start_blk,
0307      const uint32_t                        offset,
0308      const uint32_t                        count,
0309      const uint8_t                         pattern)
0310 {
0311     int                 rc             = RC_OK;
0312     uint32_t            bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
0313     uint8_t            *blk_buf;
0314     uint32_t            sec_num        = fat_block_num_to_sector_num(fs_info, start_blk);
0315 
0316     if (0 < bytes_to_write)
0317     {
0318         if (bytes_to_write == fs_info->vol.bytes_per_block)
0319         {
0320             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
0321         }
0322         else
0323             rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &blk_buf);
0324 
0325         if (RC_OK == rc)
0326         {
0327             memset(blk_buf + offset, pattern, bytes_to_write);
0328 
0329             fat_buf_mark_modified(fs_info);
0330         }
0331     }
0332     if (RC_OK != rc)
0333         return rc;
0334     else
0335         return bytes_to_write;
0336 }
0337 
0338 ssize_t
0339 fat_cluster_set(
0340      fat_fs_info_t                        *fs_info,
0341      const uint32_t                        start_cln,
0342      const uint32_t                        offset,
0343      const uint32_t                        count,
0344      const uint8_t                         pattern)
0345 {
0346   ssize_t             rc               = RC_OK;
0347   uint32_t            bytes_to_write   = MIN(count, (fs_info->vol.bpc - offset));
0348   uint32_t            cur_blk          = fat_cluster_num_to_block_num(fs_info, start_cln);
0349   uint32_t            blocks_in_offset = offset >> fs_info->vol.bytes_per_block_log2;
0350   uint32_t            ofs_blk          = offset - (blocks_in_offset << fs_info->vol.bytes_per_block_log2);
0351   ssize_t             bytes_written    = 0;
0352   ssize_t             ret;
0353 
0354   cur_blk += blocks_in_offset;
0355 
0356   while (   (RC_OK == rc)
0357          && (0 < bytes_to_write))
0358   {
0359     uint32_t c = MIN(bytes_to_write, (fs_info->vol.bytes_per_block - ofs_blk));
0360 
0361     ret = fat_block_set(
0362         fs_info,
0363         cur_blk,
0364         ofs_blk,
0365         c,
0366         pattern);
0367     if (c != ret)
0368       rc = -1;
0369     else
0370     {
0371         bytes_to_write -= ret;
0372         bytes_written  += ret;
0373         ++cur_blk;
0374     }
0375     ofs_blk = 0;
0376   }
0377   if (RC_OK != rc)
0378     return rc;
0379   else
0380     return bytes_written;
0381 }
0382 
0383 /* _fat_block_release --
0384  *     This function works around the hack that hold a bdbuf and does
0385  *     not release it.
0386  *
0387  * PARAMETERS:
0388  *     fs_info  - FS info
0389  *
0390  * RETURNS:
0391  *     0 on success, or -1 if error occurred and errno set appropriately
0392  */
0393 int
0394 _fat_block_release(fat_fs_info_t *fs_info)
0395 {
0396     return fat_buf_release(fs_info);
0397 }
0398 
0399 /* fat_cluster_write --
0400  *     This function write 'count' bytes to device filesystem is mounted on,
0401  *     starts at 'start+offset' position where 'start' computed in clusters
0402  *     and 'offset' is offset inside cluster.
0403  *     Writing will NOT cross cluster boundaries!
0404  *
0405  * PARAMETERS:
0406  *     fs_info            - FS info
0407  *     start_cln          - cluster number to start writing to
0408  *     offset             - offset inside cluster 'start'
0409  *     count              - count of bytes to write
0410  *     buff               - buffer provided by user
0411  *
0412  * RETURNS:
0413  *     bytes written on success, or -1 if error occurred
0414  *     and errno set appropriately
0415  */
0416 ssize_t
0417 fat_cluster_write(
0418     fat_fs_info_t                        *fs_info,
0419     const uint32_t                        start_cln,
0420     const uint32_t                        offset,
0421     const uint32_t                        count,
0422     const void                           *buff)
0423 {
0424     ssize_t             rc               = RC_OK;
0425     uint32_t            bytes_to_write   = MIN(count, (fs_info->vol.bpc - offset));
0426     uint32_t            cur_blk          = fat_cluster_num_to_block_num(fs_info, start_cln);
0427     uint32_t            blocks_in_offset = (offset >> fs_info->vol.bytes_per_block_log2);
0428     uint32_t            ofs_blk          = offset - (blocks_in_offset << fs_info->vol.bytes_per_block_log2);
0429     ssize_t             bytes_written    = 0;
0430     uint8_t             *buffer          = (uint8_t*)buff;
0431     ssize_t             ret;
0432     uint32_t            c;
0433 
0434     cur_blk += blocks_in_offset;
0435 
0436     while (   (RC_OK == rc)
0437            && (0 < bytes_to_write))
0438     {
0439       c = MIN(bytes_to_write, (fs_info->vol.bytes_per_block - ofs_blk));
0440 
0441       ret = fat_block_write(
0442           fs_info,
0443           cur_blk,
0444           ofs_blk,
0445           c,
0446           &buffer[bytes_written]);
0447       if (c != ret)
0448         rc = -1;
0449       else
0450       {
0451           bytes_to_write -= ret;
0452           bytes_written  += ret;
0453           ++cur_blk;
0454       }
0455       ofs_blk = 0;
0456     }
0457     if (RC_OK != rc)
0458       return rc;
0459     else
0460       return bytes_written;
0461 }
0462 
0463 static bool is_cluster_aligned(const fat_vol_t *vol, uint32_t sec_num)
0464 {
0465     return (sec_num & (vol->spc - 1)) == 0;
0466 }
0467 
0468 /* fat_init_volume_info --
0469  *     Get inforamtion about volume on which filesystem is mounted on
0470  *
0471  * PARAMETERS:
0472  *     fs_info  - FS info
0473  *
0474  * RETURNS:
0475  *     RC_OK on success, or -1 if error occurred
0476  *     and errno set appropriately
0477  */
0478 int
0479 fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
0480 {
0481     rtems_status_code   sc = RTEMS_SUCCESSFUL;
0482     int                 rc = RC_OK;
0483     fat_vol_t          *vol = &fs_info->vol;
0484     uint32_t            data_secs = 0;
0485     char                boot_rec[FAT_MAX_BPB_SIZE];
0486     char                fs_info_sector[FAT_USEFUL_INFO_SIZE];
0487     ssize_t             ret = 0;
0488     struct stat         stat_buf;
0489     int                 i = 0;
0490     rtems_bdbuf_buffer *block = NULL;
0491 
0492     vol->fd = open(device, O_RDWR);
0493     if (vol->fd < 0)
0494     {
0495         rtems_set_errno_and_return_minus_one(ENXIO);
0496     }
0497 
0498     rc = fstat(vol->fd, &stat_buf);
0499     if (rc != 0)
0500     {
0501         close(vol->fd);
0502         rtems_set_errno_and_return_minus_one(ENXIO);
0503     }
0504 
0505     /* Must be a block device. */
0506     if (!S_ISBLK(stat_buf.st_mode))
0507     {
0508         close(vol->fd);
0509         rtems_set_errno_and_return_minus_one(ENXIO);
0510     }
0511 
0512     /* check that device is registred as block device and lock it */
0513     rc = rtems_disk_fd_get_disk_device(vol->fd, &vol->dd);
0514     if (rc != 0) {
0515         close(vol->fd);
0516         rtems_set_errno_and_return_minus_one(ENXIO);
0517     }
0518 
0519     vol->dev = stat_buf.st_rdev;
0520 
0521     /* Read boot record */
0522     /* FIXME: Asserts FAT_MAX_BPB_SIZE < bdbuf block size */
0523     sc = rtems_bdbuf_read( vol->dd, 0, &block);
0524     if (sc != RTEMS_SUCCESSFUL)
0525     {
0526         close(vol->fd);
0527         rtems_set_errno_and_return_minus_one( EIO);
0528     }
0529 
0530     memcpy( boot_rec, block->buffer, FAT_MAX_BPB_SIZE);
0531 
0532     sc = rtems_bdbuf_release( block);
0533     if (sc != RTEMS_SUCCESSFUL)
0534     {
0535         close(vol->fd);
0536         rtems_set_errno_and_return_minus_one( EIO );
0537     }
0538 
0539     /* Evaluate boot record */
0540     vol->bps = FAT_GET_BR_BYTES_PER_SECTOR(boot_rec);
0541 
0542     if ( (vol->bps != 512)  &&
0543          (vol->bps != 1024) &&
0544          (vol->bps != 2048) &&
0545          (vol->bps != 4096))
0546     {
0547         close(vol->fd);
0548         rtems_set_errno_and_return_minus_one( EINVAL );
0549     }
0550     for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
0551          i >>= 1, vol->sec_mul++);
0552     for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
0553          i >>= 1, vol->sec_log2++);
0554 
0555     /* Assign the sector size as bdbuf block size for now.
0556      * If possible the bdbuf block size will get increased to the cluster
0557      * size at the end of this method for better performance */
0558     sc = rtems_bdbuf_set_block_size (vol->dd, vol->bps, true);
0559     if (sc != RTEMS_SUCCESSFUL)
0560     {
0561       close(vol->fd);
0562       rtems_set_errno_and_return_minus_one( EINVAL );
0563     }
0564     vol->bytes_per_block = vol->bps;
0565     vol->bytes_per_block_log2 = vol->sec_log2;
0566     vol->sectors_per_block = 1;
0567 
0568     vol->spc = FAT_GET_BR_SECTORS_PER_CLUSTER(boot_rec);
0569     /*
0570      * "sectors per cluster" of zero is invalid
0571      * (and would hang the following loop)
0572      */
0573     if (vol->spc == 0)
0574     {
0575         close(vol->fd);
0576         rtems_set_errno_and_return_minus_one(EINVAL);
0577     }
0578 
0579     for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
0580          i >>= 1, vol->spc_log2++);
0581 
0582     /* Sectors per cluster must be a power of two */
0583     if (vol->spc != UINT32_C(1) << vol->spc_log2)
0584     {
0585         close(vol->fd);
0586         rtems_set_errno_and_return_minus_one(EINVAL);
0587     }
0588 
0589     vol->bpc = ((uint32_t) vol->bps) << vol->spc_log2;
0590 
0591     for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
0592          i >>= 1, vol->bpc_log2++);
0593 
0594     vol->fats = FAT_GET_BR_FAT_NUM(boot_rec);
0595     vol->fat_loc = FAT_GET_BR_RESERVED_SECTORS_NUM(boot_rec);
0596 
0597     vol->rdir_entrs = FAT_GET_BR_FILES_PER_ROOT_DIR(boot_rec);
0598 
0599     /* calculate the count of sectors occupied by the root directory */
0600     vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
0601                      vol->bps;
0602 
0603     vol->rdir_size = vol->rdir_secs << vol->sec_log2;
0604 
0605     if ( (FAT_GET_BR_SECTORS_PER_FAT(boot_rec)) != 0)
0606         vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT(boot_rec);
0607     else
0608         vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT32(boot_rec);
0609 
0610     vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
0611                      vol->rdir_secs;
0612 
0613     /* for  FAT12/16 root dir starts at(sector) */
0614     vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
0615 
0616     if ( (FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
0617         vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec);
0618     else
0619         vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM32(boot_rec);
0620 
0621     data_secs = vol->tot_secs - vol->data_fsec;
0622 
0623     vol->data_cls = data_secs / vol->spc;
0624 
0625     /* determine FAT type at least */
0626     if ( vol->data_cls < FAT_FAT12_MAX_CLN)
0627     {
0628         vol->type = FAT_FAT12;
0629         vol->mask = FAT_FAT12_MASK;
0630         vol->eoc_val = FAT_FAT12_EOC;
0631     }
0632     else
0633     {
0634         if ( vol->data_cls < FAT_FAT16_MAX_CLN)
0635         {
0636             vol->type = FAT_FAT16;
0637             vol->mask = FAT_FAT16_MASK;
0638             vol->eoc_val = FAT_FAT16_EOC;
0639         }
0640         else if ( vol->data_cls < FAT_FAT32_MASK - 1 )
0641         {
0642             vol->type = FAT_FAT32;
0643             vol->mask = FAT_FAT32_MASK;
0644             vol->eoc_val = FAT_FAT32_EOC;
0645         }
0646         else
0647         {
0648             close(vol->fd);
0649             rtems_set_errno_and_return_minus_one( EINVAL );
0650         }
0651     }
0652 
0653     if (vol->type == FAT_FAT32)
0654     {
0655         vol->rdir_cl = FAT_GET_BR_FAT32_ROOT_CLUSTER(boot_rec);
0656 
0657         vol->mirror = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
0658         if (vol->mirror)
0659             vol->afat = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
0660         else
0661             vol->afat = 0;
0662 
0663         vol->info_sec = FAT_GET_BR_FAT32_FS_INFO_SECTOR(boot_rec);
0664         if( vol->info_sec == 0 )
0665         {
0666             close(vol->fd);
0667             rtems_set_errno_and_return_minus_one( EINVAL );
0668         }
0669         else
0670         {
0671             ret = _fat_block_read(fs_info, vol->info_sec , 0,
0672                                   FAT_FSI_LEADSIG_SIZE, fs_info_sector);
0673             if ( ret < 0 )
0674             {
0675                 close(vol->fd);
0676                 return -1;
0677             }
0678 
0679             if (FAT_GET_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
0680                 FAT_FSINFO_LEAD_SIGNATURE_VALUE)
0681             {
0682                 _fat_block_release(fs_info);
0683                 close(vol->fd);
0684                 rtems_set_errno_and_return_minus_one( EINVAL );
0685             }
0686             else
0687             {
0688                 ret = _fat_block_read(fs_info, vol->info_sec , FAT_FSI_INFO,
0689                                       FAT_USEFUL_INFO_SIZE, fs_info_sector);
0690                 if ( ret < 0 )
0691                 {
0692                     _fat_block_release(fs_info);
0693                     close(vol->fd);
0694                     return -1;
0695                 }
0696 
0697                 vol->free_cls_in_fs_info =
0698                   FAT_GET_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
0699                 vol->free_cls = vol->free_cls_in_fs_info;
0700                 vol->next_cl_in_fs_info =
0701                   FAT_GET_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
0702                 vol->next_cl = vol->next_cl_in_fs_info;
0703             }
0704         }
0705     }
0706     else
0707     {
0708         vol->rdir_cl = 0;
0709         vol->mirror = 0;
0710         vol->afat = 0;
0711         vol->free_cls = FAT_UNDEFINED_VALUE;
0712         vol->next_cl = FAT_UNDEFINED_VALUE;
0713     }
0714 
0715     _fat_block_release(fs_info);
0716 
0717     vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
0718 
0719     /* set up collection of fat-files fd */
0720     fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
0721     if ( fs_info->vhash == NULL )
0722     {
0723         close(vol->fd);
0724         rtems_set_errno_and_return_minus_one( ENOMEM );
0725     }
0726 
0727     for (i = 0; i < FAT_HASH_SIZE; i++)
0728         rtems_chain_initialize_empty(fs_info->vhash + i);
0729 
0730     fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
0731     if ( fs_info->rhash == NULL )
0732     {
0733         close(vol->fd);
0734         free(fs_info->vhash);
0735         rtems_set_errno_and_return_minus_one( ENOMEM );
0736     }
0737     for (i = 0; i < FAT_HASH_SIZE; i++)
0738         rtems_chain_initialize_empty(fs_info->rhash + i);
0739 
0740     fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
0741     fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
0742     fs_info->index = 0;
0743     fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
0744     if ( fs_info->uino == NULL )
0745     {
0746         close(vol->fd);
0747         free(fs_info->vhash);
0748         free(fs_info->rhash);
0749         rtems_set_errno_and_return_minus_one( ENOMEM );
0750     }
0751     fs_info->sec_buf = (uint8_t *)calloc(vol->bps, sizeof(uint8_t));
0752     if (fs_info->sec_buf == NULL)
0753     {
0754         close(vol->fd);
0755         free(fs_info->vhash);
0756         free(fs_info->rhash);
0757         free(fs_info->uino);
0758         rtems_set_errno_and_return_minus_one( ENOMEM );
0759     }
0760 
0761     /*
0762      * If possible we will use the cluster size as bdbuf block size for faster
0763      * file access. This requires that certain sectors are aligned to cluster
0764      * borders.
0765      */
0766     if (is_cluster_aligned(vol, vol->data_fsec)
0767         && (FAT_FAT32 == vol->type || is_cluster_aligned(vol, vol->rdir_loc)))
0768     {
0769         sc = rtems_bdbuf_set_block_size (vol->dd, vol->bpc, true);
0770         if (sc == RTEMS_SUCCESSFUL)
0771         {
0772             vol->bytes_per_block = vol->bpc;
0773             vol->bytes_per_block_log2 = vol->bpc_log2;
0774             vol->sectors_per_block = vol->spc;
0775         }
0776     }
0777 
0778     return RC_OK;
0779 }
0780 
0781 /* fat_fat32_update_fsinfo_sector --
0782  *     Synchronize fsinfo sector for FAT32 volumes
0783  *
0784  * PARAMETERS:
0785  *     fs_info    - FS info
0786  *
0787  * RETURNS:
0788  *     RC_OK on success, or -1 if error occurred (errno set appropriately)
0789  */
0790 static int
0791 fat_fat32_update_fsinfo_sector(fat_fs_info_t *fs_info)
0792 {
0793     ssize_t ret1 = 0, ret2 = 0;
0794 
0795     if (fs_info->vol.type == FAT_FAT32)
0796     {
0797         uint32_t free_count = fs_info->vol.free_cls;
0798         uint32_t next_free = fs_info->vol.next_cl;
0799 
0800         if (free_count != fs_info->vol.free_cls_in_fs_info)
0801         {
0802             uint32_t le_free_count = CT_LE_L(free_count);
0803 
0804             fs_info->vol.free_cls_in_fs_info = free_count;
0805 
0806             ret1 = fat_sector_write(fs_info,
0807                                     fs_info->vol.info_sec,
0808                                     FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
0809                                     sizeof(le_free_count),
0810                                     &le_free_count);
0811         }
0812 
0813         if (next_free != fs_info->vol.next_cl_in_fs_info)
0814         {
0815             uint32_t le_next_free = CT_LE_L(next_free);
0816 
0817             fs_info->vol.next_cl_in_fs_info = next_free;
0818 
0819             ret2 = fat_sector_write(fs_info,
0820                                     fs_info->vol.info_sec,
0821                                     FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
0822                                     sizeof(le_next_free),
0823                                     &le_next_free);
0824         }
0825     }
0826 
0827     if ( (ret1 < 0) || (ret2 < 0) )
0828         return -1;
0829 
0830     return RC_OK;
0831 }
0832 
0833 int
0834 fat_sync(fat_fs_info_t *fs_info)
0835 {
0836     int rc = RC_OK;
0837 
0838     rc = fat_fat32_update_fsinfo_sector(fs_info);
0839     if ( rc != RC_OK )
0840         rc = -1;
0841 
0842     fat_buf_release(fs_info);
0843 
0844     if (rtems_bdbuf_syncdev(fs_info->vol.dd) != RTEMS_SUCCESSFUL)
0845         rc = -1;
0846 
0847     return rc;
0848 }
0849 
0850 /* fat_shutdown_drive --
0851  *     Free all allocated resources and synchronize all necessary data
0852  *
0853  * PARAMETERS:
0854  *     fs_info  - FS info
0855  *
0856  * RETURNS:
0857  *     RC_OK on success, or -1 if error occurred
0858  *     and errno set appropriately
0859  */
0860 int
0861 fat_shutdown_drive(fat_fs_info_t *fs_info)
0862 {
0863     int            rc = RC_OK;
0864     int            i = 0;
0865 
0866     rc = fat_sync(fs_info);
0867     if ( rc != RC_OK )
0868         rc = -1;
0869 
0870     for (i = 0; i < FAT_HASH_SIZE; i++)
0871     {
0872         rtems_chain_node    *node = NULL;
0873         rtems_chain_control *the_chain = fs_info->vhash + i;
0874 
0875         while ( (node = rtems_chain_get_unprotected(the_chain)) != NULL )
0876             free(node);
0877     }
0878 
0879     for (i = 0; i < FAT_HASH_SIZE; i++)
0880     {
0881         rtems_chain_node    *node = NULL;
0882         rtems_chain_control *the_chain = fs_info->rhash + i;
0883 
0884         while ( (node = rtems_chain_get_unprotected(the_chain)) != NULL )
0885             free(node);
0886     }
0887 
0888     free(fs_info->vhash);
0889     free(fs_info->rhash);
0890 
0891     free(fs_info->uino);
0892     free(fs_info->sec_buf);
0893     close(fs_info->vol.fd);
0894 
0895     if (rc)
0896         errno = EIO;
0897     return rc;
0898 }
0899 
0900 /* fat_init_clusters_chain --
0901  *     Zeroing contents of all clusters in the chain
0902  *
0903  * PARAMETERS:
0904  *     fs_info           - FS info
0905  *     start_cluster_num - num of first cluster in the chain
0906  *
0907  * RETURNS:
0908  *     RC_OK on success, or -1 if error occurred
0909  *     and errno set appropriately
0910  */
0911 int
0912 fat_init_clusters_chain(
0913     fat_fs_info_t                        *fs_info,
0914     uint32_t                              start_cln
0915     )
0916 {
0917     int                     rc = RC_OK;
0918     ssize_t                 ret = 0;
0919     uint32_t                cur_cln = start_cln;
0920 
0921     while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
0922     {
0923         ret = fat_cluster_set(fs_info, cur_cln, 0, fs_info->vol.bpc, 0);
0924         if ( ret != fs_info->vol.bpc )
0925         {
0926             return -1;
0927         }
0928 
0929         rc  = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
0930         if ( rc != RC_OK )
0931         {
0932             return rc;
0933         }
0934 
0935     }
0936 
0937     return rc;
0938 }
0939 
0940 #define FAT_UNIQ_INO_BASE 0x0FFFFF00
0941 
0942 #define FAT_UNIQ_INO_IS_BUSY(index, arr) \
0943   (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
0944 
0945 #define FAT_SET_UNIQ_INO_BUSY(index, arr) \
0946   ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
0947 
0948 #define FAT_SET_UNIQ_INO_FREE(index, arr) \
0949   ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
0950 
0951 /* fat_get_unique_ino --
0952  *     Allocate unique ino from unique ino pool
0953  *
0954  * PARAMETERS:
0955  *     fs_info  - FS info
0956  *
0957  * RETURNS:
0958  *     unique inode number on success, or 0 if there is no free unique inode
0959  *     number in the pool
0960  *
0961  * ATTENTION:
0962  *     0 means FAILED !!!
0963  *
0964  */
0965 uint32_t
0966 fat_get_unique_ino(fat_fs_info_t *fs_info)
0967 {
0968     uint32_t                j = 0;
0969     bool                    resrc_unsuff = false;
0970 
0971     while (!resrc_unsuff)
0972     {
0973         for (j = 0; j < fs_info->uino_pool_size; j++)
0974         {
0975             if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
0976             {
0977                 FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
0978                 return (fs_info->uino_base + fs_info->index);
0979             }
0980             fs_info->index++;
0981             if (fs_info->index >= fs_info->uino_pool_size)
0982                 fs_info->index = 0;
0983         }
0984 
0985         if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
0986         {
0987             fs_info->uino_pool_size <<= 1;
0988             fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
0989             if (fs_info->uino != NULL)
0990                 fs_info->index = fs_info->uino_pool_size;
0991             else
0992                 resrc_unsuff = true;
0993         }
0994         else
0995             resrc_unsuff = true;
0996     }
0997     return 0;
0998 }
0999 
1000 /* fat_free_unique_ino --
1001  *     Return unique ino to unique ino pool
1002  *
1003  * PARAMETERS:
1004  *     fs_info  - FS info
1005  *     ino      - inode number to free
1006  *
1007  * RETURNS:
1008  *     None
1009  */
1010 void
1011 fat_free_unique_ino(
1012     fat_fs_info_t                        *fs_info,
1013     uint32_t                              ino
1014     )
1015 {
1016     FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
1017 }
1018 
1019 /* fat_ino_is_unique --
1020  *     Test whether ino is from unique ino pool
1021  *
1022  * PARAMETERS:
1023  *     fs_info  - FS info
1024  *     ino   - ino to be tested
1025  *
1026  * RETURNS:
1027  *     true if ino is allocated from unique ino pool, false otherwise
1028  */
1029 inline bool
1030 fat_ino_is_unique(
1031     fat_fs_info_t                        *fs_info,
1032     uint32_t                              ino
1033     )
1034 {
1035 
1036     return (ino >= fs_info->uino_base);
1037 }