summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/rfs/rtems-rfs-block-pos.h
blob: 3a3aab6b9708e2d8d9fbb3f8104cf83d45640421 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/**
 * @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 <chrisj@rtems.org>
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#if !defined (_RTEMS_RFS_BLOCK_POS_H_)
#define _RTEMS_RFS_BLOCK_POS_H_

#include <rtems/rfs/rtems-rfs-file-system.h>
#include <rtems/rfs/rtems-rfs-inode.h>

/**
 * 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