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

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

Debug messages removed

  • Property mode set to 100644
File size: 19.8 KB
Line 
1/*
2 * Copyright (c) 2012 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_directory.c
35 * @brief Ext4 directory structure operations.
36 */
37
38#include <byteorder.h>
39#include <errno.h>
40#include <malloc.h>
41#include <string.h>
42#include "libext4.h"
43
44
45/** Get i-node number from directory entry.
46 *
47 * @param de directory entry
48 * @return i-node number
49 */
50uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *de)
51{
52 return uint32_t_le2host(de->inode);
53}
54
55/** Set i-node number to directory entry.
56 *
57 * @param de directory entry
58 * @param inode i-node number
59 */
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
66/** Get directory entry length.
67 *
68 * @param de directory entry
69 * @return entry length
70 */
71uint16_t ext4_directory_entry_ll_get_entry_length(
72 ext4_directory_entry_ll_t *de)
73{
74 return uint16_t_le2host(de->entry_length);
75}
76
77/** Set directory entry length.
78 *
79 * @param de directory entry
80 * @param length entry length
81 */
82
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
89/** Get directory entry name length.
90 *
91 * @param sb superblock
92 * @param de directory entry
93 * @return entry name length
94 */
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) {
100
101 return ((uint16_t)de->name_length_high) << 8 |
102 ((uint16_t)de->name_length);
103
104 }
105 return de->name_length;
106
107}
108
109/** Set directory entry name length.
110 *
111 * @param sb superblock
112 * @param de directory entry
113 * @param length entry name length
114 */
115void ext4_directory_entry_ll_set_name_length(ext4_superblock_t *sb,
116 ext4_directory_entry_ll_t *de, uint16_t length)
117{
118 de->name_length = (length << 8) >> 8;
119
120 if (ext4_superblock_get_rev_level(sb) == 0 &&
121 ext4_superblock_get_minor_rev_level(sb) < 5) {
122
123 de->name_length_high = length >> 8;
124 }
125}
126
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 */
133uint8_t ext4_directory_entry_ll_get_inode_type(
134 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de)
135{
136 if (ext4_superblock_get_rev_level(sb) > 0 ||
137 ext4_superblock_get_minor_rev_level(sb) >= 5) {
138
139 return de->inode_type;
140 }
141
142 return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
143
144}
145
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 */
152void ext4_directory_entry_ll_set_inode_type(
153 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de, uint8_t type)
154{
155 if (ext4_superblock_get_rev_level(sb) > 0 ||
156 ext4_superblock_get_minor_rev_level(sb) >= 5) {
157
158 de->inode_type = type;
159 }
160
161 /* else do nothing */
162
163}
164
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 */
180int ext4_directory_iterator_init(ext4_directory_iterator_t *it,
181 ext4_inode_ref_t *inode_ref, aoff64_t pos)
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
191/** Jump to the next valid entry
192 *
193 * @param it initialized iterator
194 * @return error code
195 */
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
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 */
215int ext4_directory_iterator_seek(ext4_directory_iterator_t *it, aoff64_t pos)
216{
217 int rc;
218
219 uint64_t size = ext4_inode_get_size(
220 it->inode_ref->fs->superblock, it->inode_ref->inode);
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
239 /* Compute next block address */
240 uint32_t block_size = ext4_superblock_get_block_size(
241 it->inode_ref->fs->superblock);
242 aoff64_t current_block_idx = it->current_offset / block_size;
243 aoff64_t next_block_idx = pos / block_size;
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
257 uint32_t next_block_phys_idx;
258 rc = ext4_filesystem_get_inode_data_block_index(it->inode_ref,
259 next_block_idx, &next_block_phys_idx);
260 if (rc != EOK) {
261 return rc;
262 }
263
264 rc = block_get(&it->current_block, it->inode_ref->fs->device,
265 next_block_phys_idx, BLOCK_FLAGS_NONE);
266 if (rc != EOK) {
267 it->current_block = NULL;
268 return rc;
269 }
270 }
271
272 it->current_offset = pos;
273
274 return ext4_directory_iterator_set(it, block_size);
275}
276
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 */
283static int ext4_directory_iterator_set(ext4_directory_iterator_t *it,
284 uint32_t block_size)
285{
286
287 it->current = NULL;
288
289 uint32_t offset_in_block = it->current_offset % block_size;
290
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 */
310 if (ext4_directory_entry_ll_get_name_length(it->inode_ref->fs->superblock,
311 entry) > length-8) {
312 return EIO;
313 }
314
315 /* Everything OK - "publish" the entry */
316 it->current = entry;
317 return EOK;
318}
319
320
321/** Uninitialize directory iterator.
322 *
323 * Release all allocated structures.
324 *
325 * @param it iterator to be finished
326 * @return error code
327 */
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
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 */
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
359 /* Check maximum entry length */
360 uint32_t block_size = ext4_superblock_get_block_size(sb);
361 assert(entry_len <= block_size);
362
363 /* Set basic attributes */
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
368 /* Write name */
369 memcpy(entry->name, name, name_len);
370
371 /* Set type of entry */
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 }
379
380}
381
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 */
389int ext4_directory_add_entry(ext4_inode_ref_t * parent,
390 const char *name, ext4_inode_ref_t *child)
391{
392 int rc;
393
394 ext4_filesystem_t *fs = parent->fs;
395
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
400 rc = ext4_directory_dx_add_entry(parent, child, name);
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
412 /* Needed to clear dir index flag if corrupted */
413 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
414 parent->dirty = true;
415 }
416
417 /* Linear algorithm */
418
419 uint32_t iblock = 0, fblock = 0;
420 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
421 uint32_t inode_size = ext4_inode_get_size(fs->superblock, parent->inode);
422 uint32_t total_blocks = inode_size / block_size;
423
424 uint32_t name_len = strlen(name);
425
426 /* Find block, where is space for new entry and try to add */
427 bool success = false;
428 for (iblock = 0; iblock < total_blocks; ++iblock) {
429
430 rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, &fblock);
431 if (rc != EOK) {
432 return rc;
433 }
434
435 block_t *block;
436 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
437 if (rc != EOK) {
438 return rc;
439 }
440
441 /* If adding is successful, function can finish */
442 rc = ext4_directory_try_insert_entry(fs->superblock, block, child, name, name_len);
443 if (rc == EOK) {
444 success = true;
445 }
446
447 rc = block_put(block);
448 if (rc != EOK) {
449 return rc;
450 }
451
452 if (success) {
453 return EOK;
454 }
455 }
456
457 /* No free block found - needed to allocate next data block */
458
459 iblock = 0;
460 fblock = 0;
461 rc = ext4_filesystem_append_inode_block(parent, &fblock, &iblock);
462 if (rc != EOK) {
463 return rc;
464 }
465
466 /* Load new block */
467 block_t *new_block;
468 rc = block_get(&new_block, fs->device, fblock, BLOCK_FLAGS_NOREAD);
469 if (rc != EOK) {
470 return rc;
471 }
472
473 /* Fill block with zeroes */
474 memset(new_block->data, 0, block_size);
475 ext4_directory_entry_ll_t *block_entry = new_block->data;
476 ext4_directory_write_entry(fs->superblock, block_entry, block_size, child, name, name_len);
477
478 /* Save new block */
479 new_block->dirty = true;
480 rc = block_put(new_block);
481 if (rc != EOK) {
482 return rc;
483 }
484
485 return EOK;
486}
487
488/** Find directory entry with passed name.
489 *
490 * @param result result structure to be returned if entry found
491 * @param parent directory i-node
492 * @param name name of entry to be found
493 * @return error code
494 */
495int ext4_directory_find_entry(ext4_directory_search_result_t *result,
496 ext4_inode_ref_t *parent, const char *name)
497{
498 int rc;
499 uint32_t name_len = strlen(name);
500
501 ext4_superblock_t *sb = parent->fs->superblock;
502
503 /* Index search */
504 if (ext4_superblock_has_feature_compatible(sb, EXT4_FEATURE_COMPAT_DIR_INDEX) &&
505 ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX)) {
506
507 rc = ext4_directory_dx_find_entry(result, parent, name_len, name);
508
509 /* Check if index is not corrupted */
510 if (rc != EXT4_ERR_BAD_DX_DIR) {
511
512 if (rc != EOK) {
513 return rc;
514 }
515 return EOK;
516 }
517
518 /* Needed to clear dir index flag if corrupted */
519 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
520 parent->dirty = true;
521
522 }
523
524 /* Linear algorithm */
525
526 uint32_t iblock, fblock;
527 uint32_t block_size = ext4_superblock_get_block_size(sb);
528 uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
529 uint32_t total_blocks = inode_size / block_size;
530
531 /* Walk through all data blocks */
532 for (iblock = 0; iblock < total_blocks; ++iblock) {
533
534 /* Load block address */
535 rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, &fblock);
536 if (rc != EOK) {
537 return rc;
538 }
539
540 /* Load data block */
541 block_t *block;
542 rc = block_get(&block, parent->fs->device, fblock, BLOCK_FLAGS_NONE);
543 if (rc != EOK) {
544 return rc;
545 }
546
547 /* Try to find entry in block */
548 ext4_directory_entry_ll_t *res_entry;
549 rc = ext4_directory_find_in_block(block, sb, name_len, name, &res_entry);
550 if (rc == EOK) {
551 result->block = block;
552 result->dentry = res_entry;
553 return EOK;
554 }
555
556 /* Entry not found - put block and continue to the next block */
557
558 rc = block_put(block);
559 if (rc != EOK) {
560 return rc;
561 }
562 }
563
564 /* Entry was not found */
565
566 result->block = NULL;
567 result->dentry = NULL;
568
569 return ENOENT;
570}
571
572
573/** Remove directory entry.
574 *
575 * @param parent directory i-node
576 * @param name name of the entry to be removed
577 * @return error code
578 */
579int ext4_directory_remove_entry(ext4_inode_ref_t *parent, const char *name)
580{
581 int rc;
582
583 /* Check if removing from directory */
584 if (!ext4_inode_is_type(parent->fs->superblock, parent->inode,
585 EXT4_INODE_MODE_DIRECTORY)) {
586 return ENOTDIR;
587 }
588
589 /* Try to find entry */
590 ext4_directory_search_result_t result;
591 rc = ext4_directory_find_entry(&result, parent, name);
592 if (rc != EOK) {
593 return rc;
594 }
595
596 /* Invalidate entry */
597 ext4_directory_entry_ll_set_inode(result.dentry, 0);
598
599 /* Store entry position in block */
600 uint32_t pos = (void *)result.dentry - result.block->data;
601
602 /* If entry is not the first in block, it must be merged
603 * with previous entry
604 */
605 if (pos != 0) {
606
607 uint32_t offset = 0;
608
609 /* Start from the first entry in block */
610 ext4_directory_entry_ll_t *tmp_dentry = result.block->data;
611 uint16_t tmp_dentry_length =
612 ext4_directory_entry_ll_get_entry_length(tmp_dentry);
613
614 /* Find direct predecessor of removed entry */
615 while ((offset + tmp_dentry_length) < pos) {
616 offset += ext4_directory_entry_ll_get_entry_length(tmp_dentry);
617 tmp_dentry = result.block->data + offset;
618 tmp_dentry_length =
619 ext4_directory_entry_ll_get_entry_length(tmp_dentry);
620 }
621
622 assert(tmp_dentry_length + offset == pos);
623
624 /* Add to removed entry length to predecessor's length */
625 uint16_t del_entry_length =
626 ext4_directory_entry_ll_get_entry_length(result.dentry);
627 ext4_directory_entry_ll_set_entry_length(tmp_dentry,
628 tmp_dentry_length + del_entry_length);
629
630 }
631
632 result.block->dirty = true;
633
634 return ext4_directory_destroy_result(&result);
635}
636
637/** Try to insert entry to concrete data block.
638 *
639 * @param sb superblock
640 * @param target_block block to try to insert entry to
641 * @param child child i-node to be inserted by new entry
642 * @param name name of the new entry
643 * @param name_len length of the new entry name
644 * @return error code
645 */
646int ext4_directory_try_insert_entry(ext4_superblock_t *sb,
647 block_t *target_block, ext4_inode_ref_t *child,
648 const char *name, uint32_t name_len)
649{
650 /* Compute required length entry and align it to 4 bytes */
651 uint32_t block_size = ext4_superblock_get_block_size(sb);
652 uint16_t required_len = sizeof(ext4_fake_directory_entry_t) + name_len;
653 if ((required_len % 4) != 0) {
654 required_len += 4 - (required_len % 4);
655 }
656
657 /* Initialize pointers, stop means to upper bound */
658 ext4_directory_entry_ll_t *dentry = target_block->data;
659 ext4_directory_entry_ll_t *stop = target_block->data + block_size;
660
661 /* Walk through the block and check for invalid entries
662 * or entries with free space for new entry
663 */
664 while (dentry < stop) {
665
666 uint32_t inode = ext4_directory_entry_ll_get_inode(dentry);
667 uint16_t rec_len = ext4_directory_entry_ll_get_entry_length(dentry);
668
669 /* If invalid and large enough entry, use it */
670 if ((inode == 0) && (rec_len >= required_len)) {
671 ext4_directory_write_entry(sb, dentry, rec_len, child, name, name_len);
672 target_block->dirty = true;
673 return EOK;
674 }
675
676 /* Valid entry, try to split it */
677 if (inode != 0) {
678 uint16_t used_name_len =
679 ext4_directory_entry_ll_get_name_length(sb, dentry);
680
681 uint16_t used_space =
682 sizeof(ext4_fake_directory_entry_t) + used_name_len;
683 if ((used_name_len % 4) != 0) {
684 used_space += 4 - (used_name_len % 4);
685 }
686 uint16_t free_space = rec_len - used_space;
687
688 /* There is free space for new entry */
689 if (free_space >= required_len) {
690
691 /* Cut tail of current entry */
692 ext4_directory_entry_ll_set_entry_length(dentry, used_space);
693 ext4_directory_entry_ll_t *new_entry =
694 (void *)dentry + used_space;
695 ext4_directory_write_entry(sb, new_entry,
696 free_space, child, name, name_len);
697
698 target_block->dirty = true;
699 return EOK;
700 }
701 }
702
703 /* Jump to the next entry */
704 dentry = (void *)dentry + rec_len;
705 }
706
707 /* No free space found for new entry */
708
709 return ENOSPC;
710}
711
712/** Try to find entry in block by name.
713 *
714 * @param block block containing entries
715 * @param sb superblock
716 * @param name_len length of entry name
717 * @param name name of entry to be found
718 * @param res_entry output pointer to found entry, NULL if not found
719 * @return error code
720 */
721int ext4_directory_find_in_block(block_t *block,
722 ext4_superblock_t *sb, size_t name_len, const char *name,
723 ext4_directory_entry_ll_t **res_entry)
724{
725 /* Start from the first entry in block */
726 ext4_directory_entry_ll_t *dentry = (ext4_directory_entry_ll_t *)block->data;
727 /*Set upper bound for cycling */
728 uint8_t *addr_limit = block->data + ext4_superblock_get_block_size(sb);
729
730 /* Walk through the block and check entries */
731 while ((uint8_t *)dentry < addr_limit) {
732
733 /* Termination condition */
734 if ((uint8_t*) dentry + name_len > addr_limit) {
735 break;
736 }
737
738 /* Valid entry - check it */
739 if (dentry->inode != 0) {
740
741 /* For more effectivity compare firstly only lengths */
742 if (name_len == ext4_directory_entry_ll_get_name_length(sb, dentry)) {
743 /* Compare names */
744 if (bcmp((uint8_t *)name, dentry->name, name_len) == 0) {
745 *res_entry = dentry;
746 return EOK;
747 }
748 }
749 }
750
751 uint16_t dentry_len = ext4_directory_entry_ll_get_entry_length(dentry);
752
753 /* Corrupted entry */
754 if (dentry_len == 0) {
755 return EINVAL;
756 }
757
758 /* Jump to next entry */
759 dentry = (ext4_directory_entry_ll_t *)((uint8_t *)dentry + dentry_len);
760 }
761
762 /* Entry not found */
763 return ENOENT;
764}
765
766/** Simple function to release allocated data from result.
767 *
768 * @param result search result to destroy
769 * @return error code
770 */
771int ext4_directory_destroy_result(ext4_directory_search_result_t *result)
772{
773 if (result->block) {
774 return block_put(result->block);
775 }
776
777 return EOK;
778}
779
780/**
781 * @}
782 */
Note: See TracBrowser for help on using the repository browser.