source: mainline/uspace/lib/ext4/libext4_filesystem.c@ d5a78e28

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d5a78e28 was d5a78e28, checked in by Frantisek Princ <frantisek.princ@…>, 14 years ago

file truncate skeleton, but non functional

  • Property mode set to 100644
File size: 9.4 KB
RevLine 
[6c501f8]1/*
2 * Copyright (c) 2011 Frantisek Princ
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libext4
30 * @{
31 */
32
33/**
34 * @file libext4_filesystem.c
35 * @brief TODO
36 */
37
[9b9d37bb]38#include <byteorder.h>
[6c501f8]39#include <errno.h>
[01ab41b]40#include <malloc.h>
[3711e7e]41#include "libext4.h"
[6c501f8]42
43int ext4_filesystem_init(ext4_filesystem_t *fs, service_id_t service_id)
44{
[01ab41b]45 int rc;
46 ext4_superblock_t *temp_superblock;
47 size_t block_size;
[a9a0982]48 uint32_t block_ids_per_block;
49 int i;
[01ab41b]50
51 fs->device = service_id;
52
[9c0c0e1]53 // TODO what does constant 2048 mean?
[01ab41b]54 rc = block_init(EXCHANGE_SERIALIZE, fs->device, 2048);
55 if (rc != EOK) {
56 return rc;
57 }
58
[9c0c0e1]59 /* Read superblock from device */
[01ab41b]60 rc = ext4_superblock_read_direct(fs->device, &temp_superblock);
61 if (rc != EOK) {
62 block_fini(fs->device);
63 return rc;
64 }
65
[9c0c0e1]66 /* Read block size from superblock and check */
[01ab41b]67 block_size = ext4_superblock_get_block_size(temp_superblock);
68 if (block_size > EXT4_MAX_BLOCK_SIZE) {
69 block_fini(fs->device);
70 return ENOTSUP;
71 }
72
[9c0c0e1]73 /* Initialize block caching */
[01ab41b]74 rc = block_cache_init(service_id, block_size, 0, CACHE_MODE_WT);
75 if (rc != EOK) {
76 block_fini(fs->device);
77 return rc;
78 }
79
[a9a0982]80 block_ids_per_block = block_size / sizeof(uint32_t);
81 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
82 fs->inode_blocks_per_level[0] = 1;
83 for (i = 1; i < 4; i++) {
84 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i-1] *
85 block_ids_per_block;
86 fs->inode_block_limits[i] = fs->inode_block_limits[i-1] +
87 fs->inode_blocks_per_level[i];
88 }
89
[9c0c0e1]90 /* Return loaded superblock */
[01ab41b]91 fs->superblock = temp_superblock;
92
[6c501f8]93 return EOK;
94}
95
[3711e7e]96void ext4_filesystem_fini(ext4_filesystem_t *fs)
97{
98 free(fs->superblock);
99 block_fini(fs->device);
100}
101
[6c501f8]102int ext4_filesystem_check_sanity(ext4_filesystem_t *fs)
103{
[01ab41b]104 int rc;
105
106 rc = ext4_superblock_check_sanity(fs->superblock);
107 if (rc != EOK) {
108 return rc;
109 }
110
[6c501f8]111 return EOK;
112}
113
[9c0c0e1]114int ext4_filesystem_check_features(ext4_filesystem_t *fs, bool *o_read_only)
[6c501f8]115{
[9c0c0e1]116 /* Feature flags are present in rev 1 and later */
117 if (ext4_superblock_get_rev_level(fs->superblock) == 0) {
118 *o_read_only = false;
119 return EOK;
120 }
121
122 uint32_t incompatible_features;
123 incompatible_features = ext4_superblock_get_features_incompatible(fs->superblock);
124 incompatible_features &= ~EXT4_FEATURE_INCOMPAT_SUPP;
125 if (incompatible_features > 0) {
126 *o_read_only = true;
127 return ENOTSUP;
128 }
129
130 uint32_t compatible_read_only;
131 compatible_read_only = ext4_superblock_get_features_read_only(fs->superblock);
132 compatible_read_only &= ~EXT4_FEATURE_RO_COMPAT_SUPP;
133 if (compatible_read_only > 0) {
134 *o_read_only = true;
135 }
136
[6c501f8]137 return EOK;
138}
139
[3711e7e]140int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *fs, uint32_t bgid,
141 ext4_block_group_ref_t **ref)
[6c501f8]142{
[3711e7e]143 int rc;
144 aoff64_t block_id;
145 uint32_t descriptors_per_block;
146 size_t offset;
147 ext4_block_group_ref_t *newref;
148
149 newref = malloc(sizeof(ext4_block_group_ref_t));
150 if (newref == NULL) {
151 return ENOMEM;
152 }
153
[c25e39b]154 //EXT4FS_DBG("desc size = \%u", (uint32_t)ext4_superblock_get_desc_size(fs->superblock));
155
[3711e7e]156 descriptors_per_block = ext4_superblock_get_block_size(fs->superblock)
[c25e39b]157 / ext4_superblock_get_desc_size(fs->superblock);
[3711e7e]158
159 /* Block group descriptor table starts at the next block after superblock */
[3712434]160 block_id = ext4_superblock_get_first_data_block(fs->superblock) + 1;
[3711e7e]161
162 /* Find the block containing the descriptor we are looking for */
163 block_id += bgid / descriptors_per_block;
[c25e39b]164 offset = (bgid % descriptors_per_block) * ext4_superblock_get_desc_size(fs->superblock);
[3711e7e]165
166 rc = block_get(&newref->block, fs->device, block_id, 0);
167 if (rc != EOK) {
168 free(newref);
169 return rc;
170 }
171
172 newref->block_group = newref->block->data + offset;
173
174 *ref = newref;
175
176 return EOK;
[6c501f8]177}
178
[829d238]179int ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *ref)
180{
181 int rc;
182
183 rc = block_put(ref->block);
184 free(ref);
185
186 return rc;
187}
188
[3711e7e]189int ext4_filesystem_get_inode_ref(ext4_filesystem_t *fs, uint32_t index,
190 ext4_inode_ref_t **ref)
191{
192 int rc;
193 aoff64_t block_id;
194 uint32_t block_group;
195 uint32_t offset_in_group;
196 uint32_t byte_offset_in_group;
197 size_t offset_in_block;
198 uint32_t inodes_per_group;
199 uint32_t inode_table_start;
200 uint16_t inode_size;
201 uint32_t block_size;
202 ext4_block_group_ref_t *bg_ref;
203 ext4_inode_ref_t *newref;
204
205 newref = malloc(sizeof(ext4_inode_ref_t));
206 if (newref == NULL) {
207 return ENOMEM;
208 }
209
210 inodes_per_group = ext4_superblock_get_inodes_per_group(fs->superblock);
211
212 /* inode numbers are 1-based, but it is simpler to work with 0-based
213 * when computing indices
214 */
215 index -= 1;
216 block_group = index / inodes_per_group;
217 offset_in_group = index % inodes_per_group;
218
219 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
220 if (rc != EOK) {
221 free(newref);
222 return rc;
223 }
224
225 inode_table_start = ext4_block_group_get_inode_table_first_block(
226 bg_ref->block_group);
227
[829d238]228 rc = ext4_filesystem_put_block_group_ref(bg_ref);
229 if (rc != EOK) {
230 free(newref);
231 return rc;
232 }
233
[3711e7e]234 inode_size = ext4_superblock_get_inode_size(fs->superblock);
235 block_size = ext4_superblock_get_block_size(fs->superblock);
236
237 byte_offset_in_group = offset_in_group * inode_size;
238
239 block_id = inode_table_start + (byte_offset_in_group / block_size);
240 offset_in_block = byte_offset_in_group % block_size;
241
242 rc = block_get(&newref->block, fs->device, block_id, 0);
243 if (rc != EOK) {
244 free(newref);
245 return rc;
246 }
247
248 newref->inode = newref->block->data + offset_in_block;
249 /* we decremented index above, but need to store the original value
250 * in the reference
251 */
252 newref->index = index+1;
253
254 *ref = newref;
255
[9b9d37bb]256 return EOK;
257}
258
[e68c834]259
[9b9d37bb]260int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref)
261{
262 int rc;
263
264 rc = block_put(ref->block);
265 free(ref);
266
267 return rc;
268}
269
270int ext4_filesystem_get_inode_data_block_index(ext4_filesystem_t *fs, ext4_inode_t* inode,
271 aoff64_t iblock, uint32_t* fblock)
272{
273 int rc;
274 uint32_t offset_in_block;
275 uint32_t current_block;
276 aoff64_t block_offset_in_level;
277 int i;
278 int level;
279 block_t *block;
280
[8958a26]281 /* Handle inode using extents */
[c25e39b]282 if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
283 ext4_inode_has_flag(inode, EXT4_INODE_FLAG_EXTENTS)) {
[1a7756a]284 current_block = ext4_inode_get_extent_block(inode, iblock, fs->device);
[acd869e]285 *fblock = current_block;
286 return EOK;
287
288 }
289
[9b9d37bb]290 /* Handle simple case when we are dealing with direct reference */
[e68c834]291 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
[9b9d37bb]292 current_block = ext4_inode_get_direct_block(inode, (uint32_t)iblock);
293 *fblock = current_block;
294 return EOK;
295 }
296
297 /* Determine the indirection level needed to get the desired block */
298 level = -1;
299 for (i = 1; i < 4; i++) {
[a9a0982]300 if (iblock < fs->inode_block_limits[i]) {
[9b9d37bb]301 level = i;
302 break;
303 }
304 }
305
306 if (level == -1) {
307 return EIO;
308 }
309
310 /* Compute offsets for the topmost level */
[a9a0982]311 block_offset_in_level = iblock - fs->inode_block_limits[level-1];
[9b9d37bb]312 current_block = ext4_inode_get_indirect_block(inode, level-1);
[a9a0982]313 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
[9b9d37bb]314
315 /* Navigate through other levels, until we find the block number
316 * or find null reference meaning we are dealing with sparse file
317 */
318 while (level > 0) {
319 rc = block_get(&block, fs->device, current_block, 0);
320 if (rc != EOK) {
321 return rc;
322 }
323
324 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
325
326 rc = block_put(block);
327 if (rc != EOK) {
328 return rc;
329 }
330
331 if (current_block == 0) {
332 /* This is a sparse file */
333 *fblock = 0;
334 return EOK;
335 }
336
337 level -= 1;
338
339 /* If we are on the last level, break here as
340 * there is no next level to visit
341 */
342 if (level == 0) {
343 break;
344 }
345
346 /* Visit the next level */
[a9a0982]347 block_offset_in_level %= fs->inode_blocks_per_level[level];
348 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
[9b9d37bb]349 }
350
351 *fblock = current_block;
352
[3711e7e]353 return EOK;
354}
[6c501f8]355
[d5a78e28]356
357int ext4_filesystem_release_inode_block(ext4_filesystem_t *fs, ext4_inode_t *inode, uint32_t iblock)
358{
359 int rc;
360 uint32_t fblock;
361
362 // TODO handle with extents
363
364 rc = ext4_filesystem_get_inode_data_block_index(fs, inode, iblock, &fblock);
365 if (rc != EOK) {
366 // TODO error
367 return rc;
368 }
369
370 // Sparse file
371 if (fblock == 0) {
372
373 //
374 return EOK;
375 }
376
377
378 // TODO vyhledat policko s ukazatelem a nastavit nulu
379
380
381 // TODO uvolnit blok v bitmape
382
383 // TODO return
384
385
386 return EOK;
387}
388
389
[6c501f8]390/**
391 * @}
392 */
Note: See TracBrowser for help on using the repository browser.