/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @brief RTEMS File Systems Block Position and Size Management * * @ingroup rtems_rfs * * RTEMS File Systems Block Position and Size Management. * * These functions manage the position in a block map as well as a size of data * held in a block map. The position is the block count plus the offset into * the last block where a block position of 0 and an offset of 0 is the start * of a map. The size has a block count plus an offset, but the offset into the * last block gives the actual size of the data in the map. This means a size * will always have a block count greater than 0 when the file is not empty. A * size offset of 0 and a non-zero block count means the length if aligned to * the end of the block. For this reason there are 2 similar types so we know * which set of rules are in use and the reason for this file. */ /* * COPYRIGHT (c) 2010 Chris Johns * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if !defined (_RTEMS_RFS_BLOCK_POS_H_) #define _RTEMS_RFS_BLOCK_POS_H_ #include #include /** * The block number is the same type as the inode block number. This makes sure * the sizes of the types match. */ typedef rtems_rfs_inode_block rtems_rfs_block_no; /** * The offset into a block. */ typedef uint32_t rtems_rfs_block_off; /** * A block position is a block number times the block size plus the offset. The * block field can be used hold a block number for the position as a look up * cache. */ typedef struct rtems_rfs_block_pos_s { /** * The block index in the map. Range is from 0 to the maps block count minus * 1. */ rtems_rfs_block_no bno; /** * The offset into the block. Must be less than the block size. */ rtems_rfs_block_off boff; /** * The block number that the bpos + boff map to. The 0 value is invalid and * means no block number has been set. */ rtems_rfs_block_no block; } rtems_rfs_block_pos; /** * Copy a block position. * * @param[in] _lhs is the left hand side. * @param[in] _rhs is the right hand side. */ #define rtems_rfs_block_copy_bpos(_lhs, _rhs) \ do { (_lhs)->bno = (_rhs)->bno; \ (_lhs)->boff = (_rhs)->boff; \ (_lhs)->block = (_rhs)->block; } while (0) /** * Zero a block position. * * @param[in] bpos is a pointer to the block position. */ static inline void rtems_rfs_block_set_bpos_zero (rtems_rfs_block_pos* bpos) { bpos->bno = 0; bpos->boff = 0; bpos->block = 0; } /** * Given a position compute the block number and block offset. * * @param[in] fs is the file system data. * @param[in] pos is the position as an absolute offset from the start. * @param[out] bpos is a pointer to the block position to fill in. */ void rtems_rfs_block_get_bpos (rtems_rfs_file_system* fs, rtems_rfs_pos pos, rtems_rfs_block_pos* bpos); /** * Given a block position compute the absolute offset. * * @param[in] fs is the file system data. * @param[out] bpos is a pointer to the block position to fill in. * * @retval offset The absolute offset. */ rtems_rfs_pos rtems_rfs_block_get_pos (rtems_rfs_file_system* fs, rtems_rfs_block_pos* bpos); /** * Add the relative position to the block position. The relative position is * signed. * * @param[in] fs is the file system data. * @param[in] offset is the relative offset add to the block position. * @param[out] bpos is a pointer to the block position to fill in. */ static inline void rtems_rfs_block_add_pos (rtems_rfs_file_system* fs, rtems_rfs_pos_rel offset, rtems_rfs_block_pos* bpos) { rtems_rfs_block_get_bpos (fs, rtems_rfs_block_get_pos (fs, bpos) + offset, bpos); bpos->block = 0; } /** * A block size is the number of blocks less one plus the offset where the * offset must be less than the block size. */ typedef struct rtems_rfs_block_size_s { /** * The count of blocks in a map. A 0 means no blocks and a zero length and * the offset should also be 0. */ rtems_rfs_block_no count; /** * The offset into the block. An offset of 0 means block size, ie the first * byte of the next block which is not allocated. */ rtems_rfs_block_off offset; } rtems_rfs_block_size; /** * Copy a block size. * * @param[in] _lhs is the left hand side. * @param[in] _rhs is the right hand side. */ #define rtems_rfs_block_copy_size(_lhs, _rhs) \ do { (_lhs)->count = (_rhs)->count; \ (_lhs)->offset = (_rhs)->offset; } while (0) /** * Last block ? */ #define rtems_rfs_block_pos_last_block(_p, _s) \ ((((_p)->bno == 0) && ((_s)->count == 0)) || ((_p)->bno == ((_s)->count - 1))) /** * Last block ? */ #define rtems_rfs_block_pos_past_end(_p, _s) \ (((_p)->bno && ((_s)->count == 0)) || \ ((_p)->bno >= (_s)->count) || \ (((_p)->bno == ((_s)->count - 1)) && ((_p)->boff > (_s)->offset))) /** * Is the block position past the end. */ #define rtems_rfs_block_pos_block_past_end(_p, _s) \ (((_p)->bno && ((_s)->count == 0)) || ((_p)->bno >= (_s)->count)) /** * Copy the size to the block position. Note the block position and the size * have different block counts. */ #define rtems_rfs_block_size_get_bpos(_s, _b) \ do { (_b)->bno = (_s)->count; \ (_b)->boff = (_s)->offset; \ (_b)->block = 0; \ if ((_b)->boff) --(_b)->bno; } while (0) /** * Do the sizes match ? */ #define rtems_rfs_block_size_equal(_lhs, _rhs) \ (((_lhs)->count == (_rhs)->count) && ((_lhs)->offset == (_rhs)->offset)) /** * Zero a block size. * * @param[in] size is a pointer to the block size. */ static inline void rtems_rfs_block_set_size_zero (rtems_rfs_block_size* size) { size->count = 0; size->offset = 0; } /** * Set the size given a position. * * @param[in] fs is the file system data. * @param[in] pos is the position as an absolute offset from the start. * @param[out] size is a pointer to the block size to fill in. */ void rtems_rfs_block_get_block_size (rtems_rfs_file_system* fs, rtems_rfs_pos pos, rtems_rfs_block_size* size); /** * Calculate the position given the number of blocks and the offset. If the * block count is 0 the size is 0. If the block is greater than 0 and the * offset is 0 the size is number of blocks multipled by the block size and if * the offset is not 0 it is the offset into the last block. For example if * blocks is 1 and offset is 0 the size is the block size. If the block count * is 1 and size is 100 the size is 100. * * @param[in] fs is the file system data. * @param[in] size The size in blocks and offset. * * @retval size The size in bytes. */ rtems_rfs_pos rtems_rfs_block_get_size (rtems_rfs_file_system* fs, rtems_rfs_block_size* size); #endif