source: mainline/uspace/lib/ext4/libext4_directory.c@ ca47f656

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

Comments and some simple modifications of code for work with directory entry

  • Property mode set to 100644
File size: 19.8 KB
RevLine 
[eb91db7]1/*
[f22d5ef0]2 * Copyright (c) 2012 Frantisek Princ
[eb91db7]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_directory.c
[c25e39b]35 * @brief Ext4 directory structure operations.
[eb91db7]36 */
37
[9b9d37bb]38#include <byteorder.h>
39#include <errno.h>
[f49638e]40#include <malloc.h>
41#include <string.h>
[3711e7e]42#include "libext4.h"
[eb91db7]43
[9b9d37bb]44
[bae2a79e]45/** Get i-node number from directory entry.
46 *
47 * @param de directory entry
48 * @return i-node number
49 */
[9b9d37bb]50uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *de)
51{
52 return uint32_t_le2host(de->inode);
53}
54
[bae2a79e]55/** Set i-node number to directory entry.
56 *
57 * @param de directory entry
58 * @param inode i-node number
59 */
[343ccfd]60void ext4_directory_entry_ll_set_inode(ext4_directory_entry_ll_t *de,
61 uint32_t inode)
62{
63 de->inode = host2uint32_t_le(inode);
64}
65
[bae2a79e]66/** Get directory entry length.
67 *
68 * @param de directory entry
69 * @return entry length
70 */
[9b9d37bb]71uint16_t ext4_directory_entry_ll_get_entry_length(
[343ccfd]72 ext4_directory_entry_ll_t *de)
[9b9d37bb]73{
74 return uint16_t_le2host(de->entry_length);
75}
76
[bae2a79e]77/** Set directory entry length.
78 *
79 * @param de directory entry
80 * @param length entry length
81 */
82
[343ccfd]83void ext4_directory_entry_ll_set_entry_length(ext4_directory_entry_ll_t *de,
84 uint16_t length)
85{
86 de->entry_length = host2uint16_t_le(length);
87}
88
[bae2a79e]89/** Get directory entry name length.
90 *
91 * @param sb superblock
92 * @param de directory entry
93 * @return entry name length
94 */
[9b9d37bb]95uint16_t ext4_directory_entry_ll_get_name_length(
96 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de)
97{
98 if (ext4_superblock_get_rev_level(sb) == 0 &&
99 ext4_superblock_get_minor_rev_level(sb) < 5) {
[343ccfd]100
[8be96a0]101 return ((uint16_t)de->name_length_high) << 8 |
102 ((uint16_t)de->name_length);
[7bc4508]103
[8be96a0]104 }
105 return de->name_length;
[7bc4508]106
107}
108
[bae2a79e]109/** Set directory entry name length.
110 *
111 * @param sb superblock
112 * @param de directory entry
113 * @param length entry name length
114 */
[343ccfd]115void ext4_directory_entry_ll_set_name_length(ext4_superblock_t *sb,
116 ext4_directory_entry_ll_t *de, uint16_t length)
[7bc4508]117{
[343ccfd]118 de->name_length = (length << 8) >> 8;
[7bc4508]119
[8be96a0]120 if (ext4_superblock_get_rev_level(sb) == 0 &&
121 ext4_superblock_get_minor_rev_level(sb) < 5) {
[7bc4508]122
[343ccfd]123 de->name_length_high = length >> 8;
124 }
125}
[7bc4508]126
[bae2a79e]127/** Get i-node type of directory entry.
128 *
129 * @param sb superblock
130 * @param de directory entry
131 * @return i-node type (file, dir, etc.)
132 */
[cd1cc4e6]133uint8_t ext4_directory_entry_ll_get_inode_type(
134 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de)
135{
[1d69c69]136 if (ext4_superblock_get_rev_level(sb) > 0 ||
137 ext4_superblock_get_minor_rev_level(sb) >= 5) {
[cd1cc4e6]138
139 return de->inode_type;
140 }
141
142 return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
143
144}
145
[bae2a79e]146/** Set i-node type of directory entry.
147 *
148 * @param sb superblock
149 * @param de directory entry
150 * @param type i-node type (file, dir, etc.)
151 */
[cd1cc4e6]152void ext4_directory_entry_ll_set_inode_type(
153 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de, uint8_t type)
154{
[1d69c69]155 if (ext4_superblock_get_rev_level(sb) > 0 ||
156 ext4_superblock_get_minor_rev_level(sb) >= 5) {
[cd1cc4e6]157
158 de->inode_type = type;
159 }
160
161 // else do nothing
162
163}
[7bc4508]164
[bae2a79e]165static int ext4_directory_iterator_seek(
166 ext4_directory_iterator_t *, aoff64_t);
167static int ext4_directory_iterator_set(
168 ext4_directory_iterator_t *, uint32_t);
169
170
171/** Initialize directory iterator.
172 *
173 * Set position to the first valid entry from the required position.
174 *
175 * @param it pointer to iterator to be initialized
176 * @param inode_ref directory i-node
177 * @param pos position to start reading entries from
178 * @return error code
179 */
[9b9d37bb]180int ext4_directory_iterator_init(ext4_directory_iterator_t *it,
[bae2a79e]181 ext4_inode_ref_t *inode_ref, aoff64_t pos)
[9b9d37bb]182{
183 it->inode_ref = inode_ref;
184 it->current = NULL;
185 it->current_offset = 0;
186 it->current_block = NULL;
187
188 return ext4_directory_iterator_seek(it, pos);
189}
190
[bae2a79e]191/** Jump to the next valid entry
192 *
193 * @param it initialized iterator
194 * @return error code
195 */
[9b9d37bb]196int ext4_directory_iterator_next(ext4_directory_iterator_t *it)
197{
198 uint16_t skip;
199
200 assert(it->current != NULL);
201
202 skip = ext4_directory_entry_ll_get_entry_length(it->current);
203
204 return ext4_directory_iterator_seek(it, it->current_offset + skip);
205}
206
[bae2a79e]207/** Seek to next valid directory entry.
208 *
209 * Here can be jumped to the next data block.
210 *
211 * @param it initialized iterator
212 * @param pos position of the next entry
213 * @return error code
214 */
[9b9d37bb]215int ext4_directory_iterator_seek(ext4_directory_iterator_t *it, aoff64_t pos)
216{
217 int rc;
218
[bae2a79e]219 uint64_t size = ext4_inode_get_size(
220 it->inode_ref->fs->superblock, it->inode_ref->inode);
[9b9d37bb]221
222 /* The iterator is not valid until we seek to the desired position */
223 it->current = NULL;
224
225 /* Are we at the end? */
226 if (pos >= size) {
227 if (it->current_block) {
228 rc = block_put(it->current_block);
229 it->current_block = NULL;
230 if (rc != EOK) {
231 return rc;
232 }
233 }
234
235 it->current_offset = pos;
236 return EOK;
237 }
238
[bae2a79e]239 // Compute next block address
240 uint32_t block_size = ext4_superblock_get_block_size(
241 it->inode_ref->fs->superblock);
[d9bbe45]242 aoff64_t current_block_idx = it->current_offset / block_size;
243 aoff64_t next_block_idx = pos / block_size;
[9b9d37bb]244
245 /* If we don't have a block or are moving accross block boundary,
246 * we need to get another block
247 */
248 if (it->current_block == NULL || current_block_idx != next_block_idx) {
249 if (it->current_block) {
250 rc = block_put(it->current_block);
251 it->current_block = NULL;
252 if (rc != EOK) {
253 return rc;
254 }
255 }
256
[d9bbe45]257 uint32_t next_block_phys_idx;
[1ac1ab4]258 rc = ext4_filesystem_get_inode_data_block_index(it->inode_ref,
259 next_block_idx, &next_block_phys_idx);
[9b9d37bb]260 if (rc != EOK) {
261 return rc;
262 }
263
[bae2a79e]264 rc = block_get(&it->current_block, it->inode_ref->fs->device,
265 next_block_phys_idx, BLOCK_FLAGS_NONE);
[9b9d37bb]266 if (rc != EOK) {
267 it->current_block = NULL;
268 return rc;
269 }
270 }
271
272 it->current_offset = pos;
[e68c834]273
[9b9d37bb]274 return ext4_directory_iterator_set(it, block_size);
275}
276
[bae2a79e]277/** Do some checks before returning iterator.
278 *
279 * @param it iterator to be checked
280 * @param block_size size of data block
281 * @return error code
282 */
[9b9d37bb]283static int ext4_directory_iterator_set(ext4_directory_iterator_t *it,
284 uint32_t block_size)
285{
286
287 it->current = NULL;
288
[d9bbe45]289 uint32_t offset_in_block = it->current_offset % block_size;
290
[9b9d37bb]291 /* Ensure proper alignment */
292 if ((offset_in_block % 4) != 0) {
293 return EIO;
294 }
295
296 /* Ensure that the core of the entry does not overflow the block */
297 if (offset_in_block > block_size - 8) {
298 return EIO;
299 }
300
301 ext4_directory_entry_ll_t *entry = it->current_block->data + offset_in_block;
302
303 /* Ensure that the whole entry does not overflow the block */
304 uint16_t length = ext4_directory_entry_ll_get_entry_length(entry);
305 if (offset_in_block + length > block_size) {
306 return EIO;
307 }
308
309 /* Ensure the name length is not too large */
[bae2a79e]310 if (ext4_directory_entry_ll_get_name_length(it->inode_ref->fs->superblock,
[9b9d37bb]311 entry) > length-8) {
312 return EIO;
313 }
314
[bae2a79e]315 // Everything OK - "publish" the entry
[9b9d37bb]316 it->current = entry;
317 return EOK;
318}
319
320
[bae2a79e]321/** Uninitialize directory iterator.
322 *
323 * Release all allocated structures.
324 *
325 * @param it iterator to be finished
326 * @return error code
327 */
[9b9d37bb]328int ext4_directory_iterator_fini(ext4_directory_iterator_t *it)
329{
330 int rc;
331
332 it->inode_ref = NULL;
333 it->current = NULL;
334
335 if (it->current_block) {
336 rc = block_put(it->current_block);
337 if (rc != EOK) {
338 return rc;
339 }
340 }
341
342 return EOK;
343}
344
[bae2a79e]345/** Write directory entry to concrete data block.
346 *
347 * @param sb superblock
348 * @param entry pointer to entry to be written
349 * @param entry_len lenght of new entry
350 * @param child child i-node to be written to new entry
351 * @param name name of the new entry
352 * @param name_len length of entry name
353 */
[5c83612b]354void ext4_directory_write_entry(ext4_superblock_t *sb,
[1d69c69]355 ext4_directory_entry_ll_t *entry, uint16_t entry_len,
356 ext4_inode_ref_t *child, const char *name, size_t name_len)
357{
[7eb033ce]358
[bae2a79e]359 // Check maximum entry length
360 uint32_t block_size = ext4_superblock_get_block_size(sb);
361 assert(entry_len <= block_size);
[7eb033ce]362
[bae2a79e]363 // Set basic attributes
[1d69c69]364 ext4_directory_entry_ll_set_inode(entry, child->index);
365 ext4_directory_entry_ll_set_entry_length(entry, entry_len);
366 ext4_directory_entry_ll_set_name_length(sb, entry, name_len);
367
[bae2a79e]368 // Write name
369 memcpy(entry->name, name, name_len);
370
371 // Set type of entry
[1d69c69]372 if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY)) {
373 ext4_directory_entry_ll_set_inode_type(
374 sb, entry, EXT4_DIRECTORY_FILETYPE_DIR);
375 } else {
376 ext4_directory_entry_ll_set_inode_type(
377 sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE);
378 }
[bae2a79e]379
[1d69c69]380}
381
[bae2a79e]382/** Add new entry to the directory.
383 *
384 * @param parent directory i-node
385 * @param name name of new entry
386 * @param child i-node to be referenced from new entry
387 * @return error code
388 */
[1ac1ab4]389int ext4_directory_add_entry(ext4_inode_ref_t * parent,
[d0d7afb]390 const char *name, ext4_inode_ref_t *child)
[73196d2]391{
392 int rc;
393
[1ac1ab4]394 ext4_filesystem_t *fs = parent->fs;
395
[565b6ff]396 // Index adding (if allowed)
397 if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_COMPAT_DIR_INDEX) &&
398 ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX)) {
399
[1ac1ab4]400 rc = ext4_directory_dx_add_entry(parent, child, name);
[565b6ff]401
402 // Check if index is not corrupted
403 if (rc != EXT4_ERR_BAD_DX_DIR) {
404
405 if (rc != EOK) {
406 return rc;
407 }
408
409 return EOK;
410 }
411
[bae2a79e]412 // Needed to clear dir index flag if corrupted
[565b6ff]413 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
414 parent->dirty = true;
415
416 EXT4FS_DBG("index is corrupted - doing linear algorithm, index flag cleared");
417 }
418
419 // Linear algorithm
[73196d2]420
[7eb033ce]421 uint32_t iblock = 0, fblock = 0;
[565b6ff]422 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
[d0d7afb]423 uint32_t inode_size = ext4_inode_get_size(fs->superblock, parent->inode);
424 uint32_t total_blocks = inode_size / block_size;
[565b6ff]425
[d0d7afb]426 uint32_t name_len = strlen(name);
[73196d2]427
[bae2a79e]428 // Find block, where is space for new entry and try to add
[d0d7afb]429 bool success = false;
430 for (iblock = 0; iblock < total_blocks; ++iblock) {
[73196d2]431
[1ac1ab4]432 rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, &fblock);
[d0d7afb]433 if (rc != EOK) {
434 return rc;
[73196d2]435 }
436
[d0d7afb]437 block_t *block;
438 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
439 if (rc != EOK) {
440 return rc;
441 }
[73196d2]442
[bae2a79e]443 // If adding is successful, function can finish
[d0d7afb]444 rc = ext4_directory_try_insert_entry(fs->superblock, block, child, name, name_len);
445 if (rc == EOK) {
446 success = true;
[73196d2]447 }
448
[d0d7afb]449 rc = block_put(block);
[73196d2]450 if (rc != EOK) {
451 return rc;
452 }
[d0d7afb]453
454 if (success) {
455 return EOK;
456 }
[73196d2]457 }
458
[bae2a79e]459 // No free block found - needed to allocate next data block
[b7e0260]460
[7eb033ce]461 iblock = 0;
462 fblock = 0;
[5b16912]463 rc = ext4_filesystem_append_inode_block(parent, &fblock, &iblock);
[b7e0260]464 if (rc != EOK) {
465 return rc;
466 }
467
[7689590]468 // Load new block
[ed6fdc7]469 block_t *new_block;
470 rc = block_get(&new_block, fs->device, fblock, BLOCK_FLAGS_NOREAD);
[b7e0260]471 if (rc != EOK) {
472 return rc;
473 }
474
[ca3d77a]475 // Fill block with zeroes
476 memset(new_block->data, 0, block_size);
[ed6fdc7]477 ext4_directory_entry_ll_t *block_entry = new_block->data;
[d0d7afb]478 ext4_directory_write_entry(fs->superblock, block_entry, block_size, child, name, name_len);
[b7e0260]479
[7689590]480 // Save new block
[ed6fdc7]481 new_block->dirty = true;
482 rc = block_put(new_block);
483 if (rc != EOK) {
484 return rc;
485 }
[b7e0260]486
[ed6fdc7]487 return EOK;
[73196d2]488}
[246a5af]489
[bae2a79e]490/** Find directory entry with passed name.
491 *
492 * @param result result structure to be returned if entry found
493 * @param parent directory i-node
494 * @param name name of entry to be found
495 * @return error code
496 */
[1ac1ab4]497int ext4_directory_find_entry(ext4_directory_search_result_t *result,
498 ext4_inode_ref_t *parent, const char *name)
[f49638e]499{
500 int rc;
[7689590]501 uint32_t name_len = strlen(name);
[f49638e]502
[1ac1ab4]503 ext4_superblock_t *sb = parent->fs->superblock;
504
[8be96a0]505 // Index search
[1ac1ab4]506 if (ext4_superblock_has_feature_compatible(sb, EXT4_FEATURE_COMPAT_DIR_INDEX) &&
[8be96a0]507 ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX)) {
[f49638e]508
[1ac1ab4]509 rc = ext4_directory_dx_find_entry(result, parent, name_len, name);
[f49638e]510
[8be96a0]511 // Check if index is not corrupted
512 if (rc != EXT4_ERR_BAD_DX_DIR) {
[f49638e]513
[8be96a0]514 if (rc != EOK) {
515 return rc;
516 }
517 return EOK;
[f49638e]518 }
519
[bae2a79e]520 // Needed to clear dir index flag if corrupted
521 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
522 parent->dirty = true;
523
[8be96a0]524 EXT4FS_DBG("index is corrupted - doing linear search");
525 }
[f49638e]526
[bae2a79e]527 // Linear algorithm
528
[7689590]529 uint32_t iblock, fblock;
[1ac1ab4]530 uint32_t block_size = ext4_superblock_get_block_size(sb);
531 uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
[7689590]532 uint32_t total_blocks = inode_size / block_size;
[8be96a0]533
[bae2a79e]534 // Walk through all data blocks
[7689590]535 for (iblock = 0; iblock < total_blocks; ++iblock) {
[8be96a0]536
[bae2a79e]537 // Load block address
[1ac1ab4]538 rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, &fblock);
[7689590]539 if (rc != EOK) {
540 return rc;
[f49638e]541 }
542
[bae2a79e]543 // Load data block
[7689590]544 block_t *block;
[1ac1ab4]545 rc = block_get(&block, parent->fs->device, fblock, BLOCK_FLAGS_NONE);
[f49638e]546 if (rc != EOK) {
547 return rc;
548 }
549
[bae2a79e]550 // Try to find entry in block
[7689590]551 ext4_directory_entry_ll_t *res_entry;
[1ac1ab4]552 rc = ext4_directory_find_in_block(block, sb, name_len, name, &res_entry);
[7689590]553 if (rc == EOK) {
554 result->block = block;
555 result->dentry = res_entry;
556 return EOK;
557 }
558
[bae2a79e]559 // Entry not found - put block and continue to the next block
560
[7689590]561 rc = block_put(block);
562 if (rc != EOK) {
563 return rc;
564 }
[f49638e]565 }
566
[bae2a79e]567 // Entry was not found
568
[7689590]569 result->block = NULL;
570 result->dentry = NULL;
571
572 return ENOENT;
[8be96a0]573}
574
575
[bae2a79e]576/** Remove directory entry.
577 *
578 * @param parent directory i-node
579 * @param name name of the entry to be removed
580 * @return error code
581 */
[1ac1ab4]582int ext4_directory_remove_entry(ext4_inode_ref_t *parent, const char *name)
[8be96a0]583{
584 int rc;
585
[bae2a79e]586 // Check if removing from directory
[1ac1ab4]587 if (!ext4_inode_is_type(parent->fs->superblock, parent->inode,
[8be96a0]588 EXT4_INODE_MODE_DIRECTORY)) {
589 return ENOTDIR;
590 }
591
[bae2a79e]592 // Try to find entry
[7689590]593 ext4_directory_search_result_t result;
[1ac1ab4]594 rc = ext4_directory_find_entry(&result, parent, name);
[8be96a0]595 if (rc != EOK) {
596 return rc;
597 }
598
[bae2a79e]599 // Invalidate entry
[7689590]600 ext4_directory_entry_ll_set_inode(result.dentry, 0);
[f49638e]601
[bae2a79e]602 // Store entry position in block
[7689590]603 uint32_t pos = (void *)result.dentry - result.block->data;
[f49638e]604
[bae2a79e]605 // If entry is not the first in block, it must be merged
606 // with previous entry
[f49638e]607 if (pos != 0) {
608
[bae2a79e]609 uint32_t offset = 0;
610
611 // Start from the first entry in block
[7689590]612 ext4_directory_entry_ll_t *tmp_dentry = result.block->data;
[f49638e]613 uint16_t tmp_dentry_length =
614 ext4_directory_entry_ll_get_entry_length(tmp_dentry);
615
[bae2a79e]616 // Find direct predecessor of removed entry
[f49638e]617 while ((offset + tmp_dentry_length) < pos) {
618 offset += ext4_directory_entry_ll_get_entry_length(tmp_dentry);
[7689590]619 tmp_dentry = result.block->data + offset;
[f49638e]620 tmp_dentry_length =
621 ext4_directory_entry_ll_get_entry_length(tmp_dentry);
622 }
623
624 assert(tmp_dentry_length + offset == pos);
625
[bae2a79e]626 // Add to removed entry length to predecessor's length
[f49638e]627 uint16_t del_entry_length =
[7689590]628 ext4_directory_entry_ll_get_entry_length(result.dentry);
[f49638e]629 ext4_directory_entry_ll_set_entry_length(tmp_dentry,
630 tmp_dentry_length + del_entry_length);
631
632 }
633
[7689590]634 result.block->dirty = true;
[f49638e]635
[7689590]636 return ext4_directory_destroy_result(&result);
[f49638e]637}
[7bc4508]638
[bae2a79e]639/** Try to insert entry to concrete data block.
640 *
641 * @param sb superblock
642 * @param target_block block to try to insert entry to
643 * @param child child i-node to be inserted by new entry
644 * @param name name of the new entry
645 * @param name_len length of the new entry name
646 * @return error code
647 */
[d0d7afb]648int ext4_directory_try_insert_entry(ext4_superblock_t *sb,
649 block_t *target_block, ext4_inode_ref_t *child,
650 const char *name, uint32_t name_len)
651{
[bae2a79e]652 // Compute required length entry and align it to 4 bytes
[d0d7afb]653 uint32_t block_size = ext4_superblock_get_block_size(sb);
654 uint16_t required_len = sizeof(ext4_fake_directory_entry_t) + name_len;
655 if ((required_len % 4) != 0) {
656 required_len += 4 - (required_len % 4);
657 }
658
[bae2a79e]659 // Initialize pointers, stop means to upper bound
[d0d7afb]660 ext4_directory_entry_ll_t *dentry = target_block->data;
661 ext4_directory_entry_ll_t *stop = target_block->data + block_size;
662
[bae2a79e]663 // Walk through the block and check for invalid entries
664 // or entries with free space for new entry
[d0d7afb]665 while (dentry < stop) {
666
667 uint32_t inode = ext4_directory_entry_ll_get_inode(dentry);
668 uint16_t rec_len = ext4_directory_entry_ll_get_entry_length(dentry);
669
[bae2a79e]670 // If invalid and large enough entry, use it
[d0d7afb]671 if ((inode == 0) && (rec_len >= required_len)) {
672 ext4_directory_write_entry(sb, dentry, rec_len, child, name, name_len);
673 target_block->dirty = true;
674 return EOK;
675 }
676
[bae2a79e]677 // Valid entry, try to split it
[d0d7afb]678 if (inode != 0) {
679 uint16_t used_name_len =
680 ext4_directory_entry_ll_get_name_length(sb, dentry);
681
682 uint16_t used_space =
683 sizeof(ext4_fake_directory_entry_t) + used_name_len;
684 if ((used_name_len % 4) != 0) {
685 used_space += 4 - (used_name_len % 4);
686 }
687 uint16_t free_space = rec_len - used_space;
688
[bae2a79e]689 // There is free space for new entry
[d0d7afb]690 if (free_space >= required_len) {
691
692 // Cut tail of current entry
693 ext4_directory_entry_ll_set_entry_length(dentry, used_space);
694 ext4_directory_entry_ll_t *new_entry =
695 (void *)dentry + used_space;
696 ext4_directory_write_entry(sb, new_entry,
697 free_space, child, name, name_len);
698
699 target_block->dirty = true;
700 return EOK;
701 }
702 }
703
[bae2a79e]704 // Jump to the next entry
[d0d7afb]705 dentry = (void *)dentry + rec_len;
706 }
707
[bae2a79e]708 // No free space found for new entry
709
[d0d7afb]710 return ENOSPC;
711}
712
[bae2a79e]713/** Try to find entry in block by name.
714 *
715 * @param block block containing entries
716 * @param sb superblock
717 * @param name_len length of entry name
718 * @param name name of entry to be found
719 * @param res_entry output pointer to found entry, NULL if not found
720 * @return error code
721 */
[7689590]722int ext4_directory_find_in_block(block_t *block,
723 ext4_superblock_t *sb, size_t name_len, const char *name,
724 ext4_directory_entry_ll_t **res_entry)
725{
[bae2a79e]726 // Start from the first entry in block
[7689590]727 ext4_directory_entry_ll_t *dentry = (ext4_directory_entry_ll_t *)block->data;
[bae2a79e]728 //Set upper bound for cycling
[7689590]729 uint8_t *addr_limit = block->data + ext4_superblock_get_block_size(sb);
730
[bae2a79e]731 // Walk through the block and check entries
[7689590]732 while ((uint8_t *)dentry < addr_limit) {
733
[bae2a79e]734 // Termination condition
[7689590]735 if ((uint8_t*) dentry + name_len > addr_limit) {
736 break;
737 }
738
[bae2a79e]739 // Valid entry - check it
[7689590]740 if (dentry->inode != 0) {
[bae2a79e]741
742 // For more effectivity compare firstly only lengths
[7689590]743 if (name_len == ext4_directory_entry_ll_get_name_length(sb, dentry)) {
744 // Compare names
745 if (bcmp((uint8_t *)name, dentry->name, name_len) == 0) {
746 *res_entry = dentry;
747 return EOK;
748 }
749 }
750 }
751
752 uint16_t dentry_len = ext4_directory_entry_ll_get_entry_length(dentry);
753
[bae2a79e]754 // Corrupted entry
[7689590]755 if (dentry_len == 0) {
756 return EINVAL;
757 }
758
[bae2a79e]759 // Jump to next entry
[7689590]760 dentry = (ext4_directory_entry_ll_t *)((uint8_t *)dentry + dentry_len);
761 }
762
[bae2a79e]763 // Entry not found
[7689590]764 return ENOENT;
765}
766
[bae2a79e]767/** Simple function to release allocated data from result.
768 *
769 * @param result search result to destroy
770 * @return error code
771 */
[7689590]772int ext4_directory_destroy_result(ext4_directory_search_result_t *result)
773{
774 if (result->block) {
775 return block_put(result->block);
776 }
777
778 return EOK;
779}
[eb91db7]780
781/**
782 * @}
[7689590]783 */
Note: See TracBrowser for help on using the repository browser.