source: mainline/uspace/lib/ext4/src/directory.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was b7fd2a0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

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