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

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

debugged initialization of block group structures

  • Property mode set to 100644
File size: 38.4 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_filesystem.c
35 * @brief More complex filesystem operations.
36 */
37
38#include <byteorder.h>
39#include <errno.h>
40#include <malloc.h>
41#include "libext4.h"
42
43/** Initialize filesystem and read all needed data.
44 *
45 * @param fs filesystem instance to be initialized
46 * @param service_id identifier if device with the filesystem
47 * @return error code
48 */
49int ext4_filesystem_init(ext4_filesystem_t *fs, service_id_t service_id)
50{
51 int rc;
52
53 fs->device = service_id;
54
55 /* Initialize block library (4096 is size of communication channel) */
56 rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);
57 if (rc != EOK) {
58 EXT4FS_DBG("block init error: \%d", rc);
59 return rc;
60 }
61
62 /* Read superblock from device to memory */
63 ext4_superblock_t *temp_superblock;
64 rc = ext4_superblock_read_direct(fs->device, &temp_superblock);
65 if (rc != EOK) {
66 block_fini(fs->device);
67 EXT4FS_DBG("superblock read error: \%d", rc);
68 return rc;
69 }
70
71 /* Read block size from superblock and check */
72 uint32_t block_size = ext4_superblock_get_block_size(temp_superblock);
73 if (block_size > EXT4_MAX_BLOCK_SIZE) {
74 block_fini(fs->device);
75 EXT4FS_DBG("get blocksize error: \%d", rc);
76 return ENOTSUP;
77 }
78
79 /* Initialize block caching by libblock */
80 rc = block_cache_init(service_id, block_size, 0, CACHE_MODE_WB);
81 if (rc != EOK) {
82 block_fini(fs->device);
83 EXT4FS_DBG("block cache init error: \%d", rc);
84 return rc;
85 }
86
87 /* Compute limits for indirect block levels */
88 uint32_t block_ids_per_block = block_size / sizeof(uint32_t);
89 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
90 fs->inode_blocks_per_level[0] = 1;
91 for (int i = 1; i < 4; i++) {
92 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i-1] *
93 block_ids_per_block;
94 fs->inode_block_limits[i] = fs->inode_block_limits[i-1] +
95 fs->inode_blocks_per_level[i];
96 }
97
98 /* Return loaded superblock */
99 fs->superblock = temp_superblock;
100
101 uint16_t state = ext4_superblock_get_state(fs->superblock);
102
103 if (state != EXT4_SUPERBLOCK_STATE_VALID_FS) {
104 block_cache_fini(fs->device);
105 block_fini(fs->device);
106 EXT4FS_DBG("Unable to mount: Invalid state error");
107 return ENOTSUP;
108 }
109
110 /* Mark system as mounted */
111 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS);
112 rc = ext4_superblock_write_direct(fs->device, fs->superblock);
113 if (rc != EOK) {
114 block_cache_fini(fs->device);
115 block_fini(fs->device);
116 EXT4FS_DBG("state write error: \%d", rc);
117 return rc;
118 }
119
120 uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock);
121 ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1);
122
123 return EOK;
124}
125
126/** Destroy filesystem instance (used by unmount operation).
127 *
128 * @param fs filesystem to be destroyed
129 * @param write_sb flag if superblock should be written to device
130 * @return error code
131 */
132int ext4_filesystem_fini(ext4_filesystem_t *fs)
133{
134 int rc = EOK;
135
136 /* Write the superblock to the device */
137 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_VALID_FS);
138 rc = ext4_superblock_write_direct(fs->device, fs->superblock);
139
140 /* Release memory space for superblock */
141 free(fs->superblock);
142
143 /* Finish work with block library */
144 block_fini(fs->device);
145
146 return rc;
147}
148
149/** Check sanity of the filesystem.
150 *
151 * Main is the check of the superblock structure.
152 *
153 * @param fs filesystem to be checked
154 * @return error code
155 */
156int ext4_filesystem_check_sanity(ext4_filesystem_t *fs)
157{
158 int rc;
159
160 /* Check superblock */
161 rc = ext4_superblock_check_sanity(fs->superblock);
162 if (rc != EOK) {
163 return rc;
164 }
165
166 return EOK;
167}
168
169/** Check filesystem's features, if supported by this driver
170 *
171 * Function can return EOK and set read_only flag. It mean's that
172 * there are some not-supported features, that can cause problems
173 * during some write operations.
174 *
175 * @param fs filesystem to be checked
176 * @param read_only flag if filesystem should be mounted only for reading
177 * @return error code
178 */
179int ext4_filesystem_check_features(ext4_filesystem_t *fs, bool *read_only)
180{
181 /* Feature flags are present only in higher revisions */
182 if (ext4_superblock_get_rev_level(fs->superblock) == 0) {
183 *read_only = false;
184 return EOK;
185 }
186
187 /* Check incompatible features - if filesystem has some,
188 * volume can't be mounted
189 */
190 uint32_t incompatible_features;
191 incompatible_features = ext4_superblock_get_features_incompatible(fs->superblock);
192 incompatible_features &= ~EXT4_FEATURE_INCOMPAT_SUPP;
193 if (incompatible_features > 0) {
194 EXT4FS_DBG("Not supported incompatible features");
195 return ENOTSUP;
196 }
197
198 /* Check read-only features, if filesystem has some,
199 * volume can be mount only in read-only mode
200 */
201 uint32_t compatible_read_only;
202 compatible_read_only = ext4_superblock_get_features_read_only(fs->superblock);
203 compatible_read_only &= ~EXT4_FEATURE_RO_COMPAT_SUPP;
204 if (compatible_read_only > 0) {
205 EXT4FS_DBG("Not supported readonly features - mounting READ-ONLY");
206 *read_only = true;
207 return EOK;
208 }
209
210 return EOK;
211}
212
213
214/** Convert block address to relative index in block group.
215 *
216 * @param sb superblock pointer
217 * @param block_addr block number to convert
218 * @return relative number of block
219 */
220uint32_t ext4_filesystem_blockaddr2_index_in_group(ext4_superblock_t *sb,
221 uint32_t block_addr)
222{
223 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
224 uint32_t first_block = ext4_superblock_get_first_data_block(sb);
225
226 /* First block == 0 or 1 */
227 if (first_block == 0) {
228 return block_addr % blocks_per_group;
229 } else {
230 return (block_addr - 1) % blocks_per_group;
231 }
232}
233
234
235/** Convert relative block address in group to absolute address.
236 *
237 * @param sb superblock pointer
238 * @param block_addr block number to convert
239 * @return absolute block address
240 */
241uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *sb,
242 uint32_t index, uint32_t bgid)
243{
244 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
245
246 if (ext4_superblock_get_first_data_block(sb) == 0) {
247 return bgid * blocks_per_group + index;
248 } else {
249 return bgid * blocks_per_group + index + 1;
250 }
251
252}
253
254/** Initialize block bitmap in block group.
255 *
256 * @param bg_ref reference to block group
257 * @return error code
258 */
259static int ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref)
260{
261 int rc;
262
263 /* Load bitmap */
264 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
265 bg_ref->block_group, bg_ref->fs->superblock);
266 block_t *bitmap_block;
267
268 rc = block_get(&bitmap_block, bg_ref->fs->device,
269 bitmap_block_addr, BLOCK_FLAGS_NOREAD);
270 if (rc != EOK) {
271 return rc;
272 }
273
274 uint8_t *bitmap = bitmap_block->data;
275
276 /* Initialize all bitmap bits to zero */
277 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock);
278 memset(bitmap, 0, block_size);
279
280 /* Determine first block and first data block in group */
281 uint32_t first_idx = 0;
282
283 uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
284 bg_ref->fs->superblock, bg_ref);
285 uint32_t first_data_idx = ext4_filesystem_blockaddr2_index_in_group(
286 bg_ref->fs->superblock, first_data);
287
288 /* Set bits from to first block to first data block - 1 to one (allocated) */
289 for (uint32_t block = first_idx; block < first_data_idx; ++block) {
290 ext4_bitmap_set_bit(bitmap, block);
291 }
292
293 bitmap_block->dirty = true;
294
295 /* Save bitmap */
296 rc = block_put(bitmap_block);
297 if (rc != EOK) {
298 return rc;
299 }
300
301 return EOK;
302}
303
304/** Initialize i-node bitmap in block group.
305 *
306 * @param bg_ref reference to block group
307 * @return error code
308 */
309static int ext4_filesystem_init_inode_bitmap(ext4_block_group_ref_t *bg_ref)
310{
311 int rc;
312
313 /* Load bitmap */
314 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
315 bg_ref->block_group, bg_ref->fs->superblock);
316 block_t *bitmap_block;
317
318 rc = block_get(&bitmap_block, bg_ref->fs->device,
319 bitmap_block_addr, BLOCK_FLAGS_NOREAD);
320 if (rc != EOK) {
321 return rc;
322 }
323
324 uint8_t *bitmap = bitmap_block->data;
325
326 /* Initialize all bitmap bits to zero */
327 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock);
328 uint32_t inodes_per_group =
329 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock);
330 memset(bitmap, 0, (inodes_per_group + 7) / 8);
331
332 uint32_t start_bit = inodes_per_group;
333 uint32_t end_bit = block_size * 8;
334
335 uint32_t i;
336 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) {
337 ext4_bitmap_set_bit(bitmap, i);
338 }
339
340 if (i < end_bit) {
341 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
342 }
343
344 bitmap_block->dirty = true;
345
346 /* Save bitmap */
347 rc = block_put(bitmap_block);
348 if (rc != EOK) {
349 return rc;
350 }
351
352 return EOK;
353}
354
355/** Initialize i-node table in block group.
356 *
357 * @param bg_ref reference to block group
358 * @return error code
359 */static int ext4_filesystem_init_inode_table(ext4_block_group_ref_t *bg_ref)
360{
361 int rc;
362
363 ext4_superblock_t *sb = bg_ref->fs->superblock;
364
365 uint32_t inode_size = ext4_superblock_get_inode_size(sb);
366 uint32_t block_size = ext4_superblock_get_block_size(sb);
367 uint32_t inodes_per_block = block_size / inode_size;
368
369 uint32_t inodes_in_group =
370 ext4_superblock_get_inodes_in_group(sb, bg_ref->index);
371
372 uint32_t table_blocks = inodes_in_group / inodes_per_block;
373
374 if (inodes_in_group % inodes_per_block) {
375 table_blocks++;
376 }
377
378 /* Compute initialization bounds */
379 uint32_t first_block = ext4_block_group_get_inode_table_first_block(
380 bg_ref->block_group, sb);
381
382 uint32_t last_block = first_block + table_blocks - 1;
383
384 /* Initialization of all itable blocks */
385 for (uint32_t fblock = first_block; fblock <= last_block; ++fblock) {
386 block_t *block;
387 rc = block_get(&block, bg_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD);
388 if (rc != EOK) {
389 return rc;
390 }
391
392 memset(block->data, 0, block_size);
393 block->dirty = true;
394
395 rc = block_put(block);
396 if (rc != EOK) {
397 return rc;
398 }
399 }
400
401 return EOK;
402}
403
404/** Get reference to block group specified by index.
405 *
406 * @param fs filesystem to find block group on
407 * @param bgid index of block group to load
408 * @param ref output pointer for reference
409 * @return error code
410 */
411int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *fs, uint32_t bgid,
412 ext4_block_group_ref_t **ref)
413{
414 int rc;
415
416 /* Allocate memory for new structure */
417 ext4_block_group_ref_t *newref = malloc(sizeof(ext4_block_group_ref_t));
418 if (newref == NULL) {
419 return ENOMEM;
420 }
421
422 /* Compute number of descriptors, that fits in one data block */
423 uint32_t descriptors_per_block = ext4_superblock_get_block_size(fs->superblock)
424 / ext4_superblock_get_desc_size(fs->superblock);
425
426 /* Block group descriptor table starts at the next block after superblock */
427 aoff64_t block_id = ext4_superblock_get_first_data_block(fs->superblock) + 1;
428
429 /* Find the block containing the descriptor we are looking for */
430 block_id += bgid / descriptors_per_block;
431 uint32_t offset = (bgid % descriptors_per_block) * ext4_superblock_get_desc_size(fs->superblock);
432
433 /* Load block with descriptors */
434 rc = block_get(&newref->block, fs->device, block_id, 0);
435 if (rc != EOK) {
436 free(newref);
437 return rc;
438 }
439
440 /* Inititialize in-memory representation */
441 newref->block_group = newref->block->data + offset;
442 newref->fs = fs;
443 newref->index = bgid;
444 newref->dirty = false;
445
446 *ref = newref;
447
448 if (ext4_block_group_has_flag(newref->block_group,
449 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
450
451 rc = ext4_filesystem_init_block_bitmap(newref);
452 if (rc != EOK) {
453 block_put(newref->block);
454 free(newref);
455 return rc;
456 }
457 ext4_block_group_clear_flag(newref->block_group,
458 EXT4_BLOCK_GROUP_BLOCK_UNINIT);
459
460 newref->dirty = true;
461 }
462
463 if (ext4_block_group_has_flag(newref->block_group,
464 EXT4_BLOCK_GROUP_INODE_UNINIT)) {
465
466 rc = ext4_filesystem_init_inode_bitmap(newref);
467 if (rc != EOK) {
468 block_put(newref->block);
469 free(newref);
470 return rc;
471 }
472
473 ext4_block_group_clear_flag(newref->block_group,
474 EXT4_BLOCK_GROUP_INODE_UNINIT);
475
476 ext4_block_group_set_itable_unused(newref->block_group,
477 newref->fs->superblock, 0);
478
479
480 if (! ext4_block_group_has_flag(newref->block_group,
481 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
482
483 rc = ext4_filesystem_init_inode_table(newref);
484 if (rc != EOK) {
485 return rc;
486 }
487
488 ext4_block_group_set_flag(newref->block_group,
489 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
490
491 }
492 newref->dirty = true;
493
494 }
495
496 return EOK;
497}
498
499/** Compute checksum of block group descriptor.
500 *
501 * It uses crc functions from Linux kernel implementation.
502 *
503 * @param sb superblock
504 * @param bgid index of block group in the filesystem
505 * @param bg block group to compute checksum for
506 * @return checksum value
507 */
508static uint16_t ext4_filesystem_bg_checksum(ext4_superblock_t *sb, uint32_t bgid,
509 ext4_block_group_t *bg)
510{
511 /* If checksum not supported, 0 will be returned */
512 uint16_t crc = 0;
513
514 /* Compute the checksum only if the filesystem supports it */
515 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
516
517 void *base = bg;
518 void *checksum = &bg->checksum;
519
520 uint32_t offset = (uint32_t)(checksum - base);
521
522 /* Convert block group index to little endian */
523 uint32_t le_group = host2uint32_t_le(bgid);
524
525 /* Initialization */
526 crc = crc16(~0, sb->uuid, sizeof(sb->uuid));
527
528 /* Include index of block group */
529 crc = crc16(crc, (uint8_t *)&le_group, sizeof(le_group));
530
531 /* Compute crc from the first part (stop before checksum field) */
532 crc = crc16(crc, (uint8_t *)bg, offset);
533
534 /* Skip checksum */
535 offset += sizeof(bg->checksum);
536
537 /* Checksum of the rest of block group descriptor */
538 if ((ext4_superblock_has_feature_incompatible(sb, EXT4_FEATURE_INCOMPAT_64BIT)) &&
539 offset < ext4_superblock_get_desc_size(sb)) {
540
541 crc = crc16(crc, ((uint8_t *)bg) + offset, ext4_superblock_get_desc_size(sb) - offset);
542 }
543 }
544
545 return crc;
546
547}
548
549/** Put reference to block group.
550 *
551 * @oaram ref pointer for reference to be put back
552 * @return error code
553 */
554int ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *ref)
555{
556 int rc;
557
558 /* Check if reference modified */
559 if (ref->dirty) {
560
561 /* Compute new checksum of block group */
562 uint16_t checksum = ext4_filesystem_bg_checksum(
563 ref->fs->superblock, ref->index, ref->block_group);
564 ext4_block_group_set_checksum(ref->block_group, checksum);
565
566 /* Mark block dirty for writing changes to physical device */
567 ref->block->dirty = true;
568 }
569
570 /* Put back block, that contains block group descriptor */
571 rc = block_put(ref->block);
572 free(ref);
573
574 return rc;
575}
576
577/** Get reference to i-node specified by index.
578 *
579 * @param fs filesystem to find i-node on
580 * @param index index of i-node to load
581 * @oaram ref output pointer for reference
582 * @return error code
583 */
584int ext4_filesystem_get_inode_ref(ext4_filesystem_t *fs, uint32_t index,
585 ext4_inode_ref_t **ref)
586{
587 int rc;
588
589 /* Allocate memory for new structure */
590 ext4_inode_ref_t *newref = malloc(sizeof(ext4_inode_ref_t));
591 if (newref == NULL) {
592 return ENOMEM;
593 }
594
595 /* Compute number of i-nodes, that fits in one data block */
596 uint32_t inodes_per_group =
597 ext4_superblock_get_inodes_per_group(fs->superblock);
598
599 /* Inode numbers are 1-based, but it is simpler to work with 0-based
600 * when computing indices
601 */
602 index -= 1;
603 uint32_t block_group = index / inodes_per_group;
604 uint32_t offset_in_group = index % inodes_per_group;
605
606 /* Load block group, where i-node is located */
607 ext4_block_group_ref_t *bg_ref;
608 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
609 if (rc != EOK) {
610 free(newref);
611 return rc;
612 }
613
614 /* Load block address, where i-node table is located */
615 uint32_t inode_table_start = ext4_block_group_get_inode_table_first_block(
616 bg_ref->block_group, fs->superblock);
617
618 /* Put back block group reference (not needed more) */
619 rc = ext4_filesystem_put_block_group_ref(bg_ref);
620 if (rc != EOK) {
621 free(newref);
622 return rc;
623 }
624
625 /* Compute position of i-node in the block group */
626 uint16_t inode_size = ext4_superblock_get_inode_size(fs->superblock);
627 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
628 uint32_t byte_offset_in_group = offset_in_group * inode_size;
629
630 /* Compute block address */
631 aoff64_t block_id = inode_table_start + (byte_offset_in_group / block_size);
632 rc = block_get(&newref->block, fs->device, block_id, 0);
633 if (rc != EOK) {
634 free(newref);
635 return rc;
636 }
637
638 /* Compute position of i-node in the data block */
639 uint32_t offset_in_block = byte_offset_in_group % block_size;
640 newref->inode = newref->block->data + offset_in_block;
641
642 /* We need to store the original value of index in the reference */
643 newref->index = index + 1;
644 newref->fs = fs;
645 newref->dirty = false;
646
647 *ref = newref;
648
649 return EOK;
650}
651
652/** Put reference to i-node.
653 *
654 * @param ref pointer for reference to be put back
655 * @return error code
656 */
657int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref)
658{
659 int rc;
660
661 /* Check if reference modified */
662 if (ref->dirty) {
663
664 /* Mark block dirty for writing changes to physical device */
665 ref->block->dirty = true;
666 }
667
668 /* Put back block, that contains i-node */
669 rc = block_put(ref->block);
670 free(ref);
671
672 return rc;
673}
674
675/** Allocate new i-node in the filesystem.
676 *
677 * @param fs filesystem to allocated i-node on
678 * @param inode_ref output pointer to return reference to allocated i-node
679 * @param flags flags to be set for newly created i-node
680 * @return error code
681 */
682int ext4_filesystem_alloc_inode(ext4_filesystem_t *fs,
683 ext4_inode_ref_t **inode_ref, int flags)
684{
685 int rc;
686
687 /* Check if newly allocated i-node will be a directory */
688 bool is_dir = false;
689 if (flags & L_DIRECTORY) {
690 is_dir = true;
691 }
692
693 /* Allocate inode by allocation algorithm */
694 uint32_t index;
695 rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
696 if (rc != EOK) {
697 return rc;
698 }
699
700 /* Load i-node from on-disk i-node table */
701 rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref);
702 if (rc != EOK) {
703 ext4_ialloc_free_inode(fs, index, is_dir);
704 return rc;
705 }
706
707 /* Initialize i-node */
708 ext4_inode_t *inode = (*inode_ref)->inode;
709
710 if (is_dir) {
711 ext4_inode_set_mode(fs->superblock, inode, EXT4_INODE_MODE_DIRECTORY);
712 ext4_inode_set_links_count(inode, 1); /* '.' entry */
713 } else {
714 ext4_inode_set_mode(fs->superblock, inode, EXT4_INODE_MODE_FILE);
715 ext4_inode_set_links_count(inode, 0);
716 }
717
718 ext4_inode_set_uid(inode, 0);
719 ext4_inode_set_gid(inode, 0);
720 ext4_inode_set_size(inode, 0);
721 ext4_inode_set_access_time(inode, 0);
722 ext4_inode_set_change_inode_time(inode, 0);
723 ext4_inode_set_modification_time(inode, 0);
724 ext4_inode_set_deletion_time(inode, 0);
725 ext4_inode_set_blocks_count(fs->superblock, inode, 0);
726 ext4_inode_set_flags(inode, 0);
727 ext4_inode_set_generation(inode, 0);
728
729 /* Reset blocks array */
730 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) {
731 inode->blocks[i] = 0;
732 }
733
734 /* Initialize extents if needed */
735 if (ext4_superblock_has_feature_incompatible(
736 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
737
738 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
739
740 /* Initialize extent root header */
741 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
742 ext4_extent_header_set_depth(header, 0);
743 ext4_extent_header_set_entries_count(header, 0);
744 ext4_extent_header_set_generation(header, 0);
745 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
746
747 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof (uint32_t) - sizeof(ext4_extent_header_t))
748 / sizeof(ext4_extent_t);
749
750 ext4_extent_header_set_max_entries_count(header, max_entries);
751 }
752
753 (*inode_ref)->dirty = true;
754
755 return EOK;
756}
757
758/** Release i-node and mark it as free.
759 *
760 * @param inode_ref i-node to be released
761 * @return error code
762 */
763int ext4_filesystem_free_inode(ext4_inode_ref_t *inode_ref)
764{
765 int rc;
766
767 ext4_filesystem_t *fs = inode_ref->fs;
768
769 /* For extents must be data block destroyed by other way */
770 if (ext4_superblock_has_feature_incompatible(
771 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
772 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
773
774 /* Data structures are released during truncate operation... */
775 goto finish;
776 }
777
778 /* Release all indirect (no data) blocks */
779
780 /* 1) Single indirect */
781 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
782 if (fblock != 0) {
783 rc = ext4_balloc_free_block(inode_ref, fblock);
784 if (rc != EOK) {
785 return rc;
786 }
787
788 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
789 }
790
791 block_t *block;
792 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
793 uint32_t count = block_size / sizeof(uint32_t);
794
795 /* 2) Double indirect */
796 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
797 if (fblock != 0) {
798 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
799 if (rc != EOK) {
800 return rc;
801 }
802
803 uint32_t ind_block;
804 for (uint32_t offset = 0; offset < count; ++offset) {
805 ind_block = uint32_t_le2host(((uint32_t*)block->data)[offset]);
806
807 if (ind_block != 0) {
808 rc = ext4_balloc_free_block(inode_ref, ind_block);
809 if (rc != EOK) {
810 block_put(block);
811 return rc;
812 }
813 }
814 }
815
816 block_put(block);
817 rc = ext4_balloc_free_block(inode_ref, fblock);
818 if (rc != EOK) {
819 return rc;
820 }
821
822 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
823 }
824
825
826 /* 3) Tripple indirect */
827 block_t *subblock;
828 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
829 if (fblock != 0) {
830 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
831 if (rc != EOK) {
832 return rc;
833 }
834
835 uint32_t ind_block;
836 for (uint32_t offset = 0; offset < count; ++offset) {
837 ind_block = uint32_t_le2host(((uint32_t*)block->data)[offset]);
838
839 if (ind_block != 0) {
840 rc = block_get(&subblock, fs->device, ind_block, BLOCK_FLAGS_NONE);
841 if (rc != EOK) {
842 block_put(block);
843 return rc;
844 }
845
846 uint32_t ind_subblock;
847 for (uint32_t suboffset = 0; suboffset < count; ++suboffset) {
848 ind_subblock = uint32_t_le2host(((uint32_t*)subblock->data)[suboffset]);
849
850 if (ind_subblock != 0) {
851 rc = ext4_balloc_free_block(inode_ref, ind_subblock);
852 if (rc != EOK) {
853 block_put(subblock);
854 block_put(block);
855 return rc;
856 }
857 }
858
859 }
860 block_put(subblock);
861
862 }
863
864 rc = ext4_balloc_free_block(inode_ref, ind_block);
865 if (rc != EOK) {
866 block_put(block);
867 return rc;
868 }
869
870
871 }
872
873 block_put(block);
874 rc = ext4_balloc_free_block(inode_ref, fblock);
875 if (rc != EOK) {
876 return rc;
877 }
878
879 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
880 }
881
882finish:
883
884 /* Mark inode dirty for writing to the physical device */
885 inode_ref->dirty = true;
886
887 /* Free inode by allocator */
888 if (ext4_inode_is_type(fs->superblock, inode_ref->inode,
889 EXT4_INODE_MODE_DIRECTORY)) {
890 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
891 } else {
892 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
893 }
894 if (rc != EOK) {
895 return rc;
896 }
897
898 return EOK;
899}
900
901/** Truncate i-node data blocks.
902 *
903 * @param inode_ref i-node to be truncated
904 * @param new_size new size of inode (must be < current size)
905 * @return error code
906 */
907int ext4_filesystem_truncate_inode(
908 ext4_inode_ref_t *inode_ref, aoff64_t new_size)
909{
910 int rc;
911
912 ext4_superblock_t *sb = inode_ref->fs->superblock;
913
914 /* Check flags, if i-node can be truncated */
915 if (! ext4_inode_can_truncate(sb, inode_ref->inode)) {
916 return EINVAL;
917 }
918
919 /* If sizes are equal, nothing has to be done. */
920 aoff64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
921 if (old_size == new_size) {
922 return EOK;
923 }
924
925 /* It's not suppported to make the larger file by truncate operation */
926 if (old_size < new_size) {
927 return EINVAL;
928 }
929
930 /* Compute how many blocks will be released */
931 aoff64_t size_diff = old_size - new_size;
932 uint32_t block_size = ext4_superblock_get_block_size(sb);
933 uint32_t diff_blocks_count = size_diff / block_size;
934 if (size_diff % block_size != 0) {
935 diff_blocks_count++;
936 }
937
938 uint32_t old_blocks_count = old_size / block_size;
939 if (old_size % block_size != 0) {
940 old_blocks_count++;
941 }
942
943 if (ext4_superblock_has_feature_incompatible(
944 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
945 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
946
947 /* Extents require special operation */
948
949 rc = ext4_extent_release_blocks_from(inode_ref,
950 old_blocks_count - diff_blocks_count);
951 if (rc != EOK) {
952 return rc;
953 }
954 } else {
955
956 /* Release data blocks from the end of file */
957
958 /* Starting from 1 because of logical blocks are numbered from 0 */
959 for (uint32_t i = 1; i <= diff_blocks_count; ++i) {
960 rc = ext4_filesystem_release_inode_block(inode_ref, old_blocks_count - i);
961 if (rc != EOK) {
962 return rc;
963 }
964 }
965 }
966
967 /* Update i-node */
968 ext4_inode_set_size(inode_ref->inode, new_size);
969 inode_ref->dirty = true;
970
971 return EOK;
972}
973
974/** Get physical block address by logical index of the block.
975 *
976 * @param inode_ref i-node to read block address from
977 * @param iblock logical index of block
978 * @param fblock output pointer for return physical block address
979 * @return error code
980 */
981int ext4_filesystem_get_inode_data_block_index(ext4_inode_ref_t *inode_ref,
982 aoff64_t iblock, uint32_t *fblock)
983{
984 int rc;
985
986 ext4_filesystem_t *fs = inode_ref->fs;
987
988 /* For empty file is situation simple */
989 if (ext4_inode_get_size(fs->superblock, inode_ref->inode) == 0) {
990 *fblock = 0;
991 return EOK;
992 }
993
994 uint32_t current_block;
995
996 /* Handle i-node using extents */
997 if (ext4_superblock_has_feature_incompatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
998 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
999
1000 rc = ext4_extent_find_block(inode_ref, iblock, &current_block);
1001
1002 if (rc != EOK) {
1003 return rc;
1004 }
1005
1006 *fblock = current_block;
1007 return EOK;
1008
1009 }
1010
1011 ext4_inode_t *inode = inode_ref->inode;
1012
1013 /* Direct block are read directly from array in i-node structure */
1014 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1015 current_block = ext4_inode_get_direct_block(inode, (uint32_t)iblock);
1016 *fblock = current_block;
1017 return EOK;
1018 }
1019
1020 /* Determine indirection level of the target block */
1021 int level = -1;
1022 for (int i = 1; i < 4; i++) {
1023 if (iblock < fs->inode_block_limits[i]) {
1024 level = i;
1025 break;
1026 }
1027 }
1028
1029 if (level == -1) {
1030 return EIO;
1031 }
1032
1033 /* Compute offsets for the topmost level */
1034 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1];
1035 current_block = ext4_inode_get_indirect_block(inode, level-1);
1036 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1037
1038 /* Sparse file */
1039 if (current_block == 0) {
1040 *fblock = 0;
1041 return EOK;
1042 }
1043
1044 block_t *block;
1045
1046 /* Navigate through other levels, until we find the block number
1047 * or find null reference meaning we are dealing with sparse file
1048 */
1049 while (level > 0) {
1050
1051 /* Load indirect block */
1052 rc = block_get(&block, fs->device, current_block, 0);
1053 if (rc != EOK) {
1054 return rc;
1055 }
1056
1057 /* Read block address from indirect block */
1058 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
1059
1060 /* Put back indirect block untouched */
1061 rc = block_put(block);
1062 if (rc != EOK) {
1063 return rc;
1064 }
1065
1066 /* Check for sparse file */
1067 if (current_block == 0) {
1068 *fblock = 0;
1069 return EOK;
1070 }
1071
1072 /* Jump to the next level */
1073 level -= 1;
1074
1075 /* Termination condition - we have address of data block loaded */
1076 if (level == 0) {
1077 break;
1078 }
1079
1080 /* Visit the next level */
1081 block_offset_in_level %= fs->inode_blocks_per_level[level];
1082 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1083 }
1084
1085 *fblock = current_block;
1086
1087 return EOK;
1088}
1089
1090/** Set physical block address for the block logical address into the i-node.
1091 *
1092 * @param inode_ref i-node to set block address to
1093 * @param iblock logical index of block
1094 * @param fblock physical block address
1095 * @return error code
1096 */
1097int ext4_filesystem_set_inode_data_block_index(ext4_inode_ref_t *inode_ref,
1098 aoff64_t iblock, uint32_t fblock)
1099{
1100 int rc;
1101
1102 ext4_filesystem_t *fs = inode_ref->fs;
1103
1104 /* Handle inode using extents */
1105 if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1106 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
1107 /* not reachable !!! */
1108 return ENOTSUP;
1109 }
1110
1111 /* Handle simple case when we are dealing with direct reference */
1112 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1113 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock, fblock);
1114 inode_ref->dirty = true;
1115 return EOK;
1116 }
1117
1118 /* Determine the indirection level needed to get the desired block */
1119 int level = -1;
1120 for (int i = 1; i < 4; i++) {
1121 if (iblock < fs->inode_block_limits[i]) {
1122 level = i;
1123 break;
1124 }
1125 }
1126
1127 if (level == -1) {
1128 return EIO;
1129 }
1130
1131 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
1132
1133 /* Compute offsets for the topmost level */
1134 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1];
1135 uint32_t current_block = ext4_inode_get_indirect_block(inode_ref->inode, level-1);
1136 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1137
1138 uint32_t new_block_addr;
1139 block_t *block, *new_block;
1140
1141 /* Is needed to allocate indirect block on the i-node level */
1142 if (current_block == 0) {
1143
1144 /* Allocate new indirect block */
1145 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
1146 if (rc != EOK) {
1147 return rc;
1148 }
1149
1150 /* Update i-node */
1151 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, new_block_addr);
1152 inode_ref->dirty = true;
1153
1154 /* Load newly allocated block */
1155 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
1156 if (rc != EOK) {
1157 ext4_balloc_free_block(inode_ref, new_block_addr);
1158 return rc;
1159 }
1160
1161 /* Initialize new block */
1162 memset(new_block->data, 0, block_size);
1163 new_block->dirty = true;
1164
1165 /* Put back the allocated block */
1166 rc = block_put(new_block);
1167 if (rc != EOK) {
1168 return rc;
1169 }
1170
1171 current_block = new_block_addr;
1172 }
1173
1174 /* Navigate through other levels, until we find the block number
1175 * or find null reference meaning we are dealing with sparse file
1176 */
1177 while (level > 0) {
1178
1179 rc = block_get(&block, fs->device, current_block, 0);
1180 if (rc != EOK) {
1181 return rc;
1182 }
1183
1184 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
1185
1186 if ((level > 1) && (current_block == 0)) {
1187
1188 /* Allocate new block */
1189 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
1190 if (rc != EOK) {
1191 block_put(block);
1192 return rc;
1193 }
1194
1195 /* Load newly allocated block */
1196 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
1197 if (rc != EOK) {
1198 block_put(block);
1199 return rc;
1200 }
1201
1202 /* Initialize allocated block */
1203 memset(new_block->data, 0, block_size);
1204 new_block->dirty = true;
1205
1206 rc = block_put(new_block);
1207 if (rc != EOK) {
1208 block_put(block);
1209 return rc;
1210 }
1211
1212 /* Write block address to the parent */
1213 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(new_block_addr);
1214 block->dirty = true;
1215 current_block = new_block_addr;
1216 }
1217
1218 /* Will be finished, write the fblock address */
1219 if (level == 1) {
1220 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(fblock);
1221 block->dirty = true;
1222 }
1223
1224 rc = block_put(block);
1225 if (rc != EOK) {
1226 return rc;
1227 }
1228
1229 level -= 1;
1230
1231 /* If we are on the last level, break here as
1232 * there is no next level to visit
1233 */
1234 if (level == 0) {
1235 break;
1236 }
1237
1238 /* Visit the next level */
1239 block_offset_in_level %= fs->inode_blocks_per_level[level];
1240 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1241 }
1242
1243 return EOK;
1244}
1245
1246/** Release data block from i-node
1247 *
1248 * @param inode_ref i-node to release block from
1249 * @param iblock logical block to be released
1250 * @return error code
1251 */
1252int ext4_filesystem_release_inode_block(
1253 ext4_inode_ref_t *inode_ref, uint32_t iblock)
1254{
1255 int rc;
1256
1257 uint32_t fblock;
1258
1259 ext4_filesystem_t *fs = inode_ref->fs;
1260
1261 /* EXTENTS are handled otherwise = there is not support in this function */
1262 assert(! (ext4_superblock_has_feature_incompatible(fs->superblock,
1263 EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1264 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)));
1265
1266 ext4_inode_t *inode = inode_ref->inode;
1267
1268 /* Handle simple case when we are dealing with direct reference */
1269 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1270 fblock = ext4_inode_get_direct_block(inode, iblock);
1271 /* Sparse file */
1272 if (fblock == 0) {
1273 return EOK;
1274 }
1275
1276 ext4_inode_set_direct_block(inode, iblock, 0);
1277 return ext4_balloc_free_block(inode_ref, fblock);
1278 }
1279
1280
1281 /* Determine the indirection level needed to get the desired block */
1282 int level = -1;
1283 for (int i = 1; i < 4; i++) {
1284 if (iblock < fs->inode_block_limits[i]) {
1285 level = i;
1286 break;
1287 }
1288 }
1289
1290 if (level == -1) {
1291 return EIO;
1292 }
1293
1294 /* Compute offsets for the topmost level */
1295 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1];
1296 uint32_t current_block = ext4_inode_get_indirect_block(inode, level-1);
1297 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1298
1299 /* Navigate through other levels, until we find the block number
1300 * or find null reference meaning we are dealing with sparse file
1301 */
1302 block_t *block;
1303 while (level > 0) {
1304 rc = block_get(&block, fs->device, current_block, 0);
1305 if (rc != EOK) {
1306 return rc;
1307 }
1308
1309 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
1310
1311 /* Set zero if physical data block address found */
1312 if (level == 1) {
1313 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(0);
1314 block->dirty = true;
1315 }
1316
1317 rc = block_put(block);
1318 if (rc != EOK) {
1319 return rc;
1320 }
1321
1322 level -= 1;
1323
1324 /* If we are on the last level, break here as
1325 * there is no next level to visit
1326 */
1327 if (level == 0) {
1328 break;
1329 }
1330
1331 /* Visit the next level */
1332 block_offset_in_level %= fs->inode_blocks_per_level[level];
1333 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
1334 }
1335
1336 fblock = current_block;
1337
1338 if (fblock == 0) {
1339 return EOK;
1340 }
1341
1342 /* Physical block is not referenced, it can be released */
1343
1344 return ext4_balloc_free_block(inode_ref, fblock);
1345
1346}
1347
1348/** Append following logical block to the i-node.
1349 *
1350 * @param inode_ref i-node to append block to
1351 * @param fblock output physical block address of newly allocated block
1352 * @param iblock output logical number of newly allocated block
1353 * @return error code
1354 */
1355int ext4_filesystem_append_inode_block(ext4_inode_ref_t *inode_ref,
1356 uint32_t *fblock, uint32_t *iblock)
1357{
1358 int rc;
1359
1360 /* Handle extents separately */
1361 if (ext4_superblock_has_feature_incompatible(
1362 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1363 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
1364
1365 return ext4_extent_append_block(inode_ref, iblock, fblock, true);
1366
1367 }
1368
1369 ext4_superblock_t *sb = inode_ref->fs->superblock;
1370
1371 /* Compute next block index and allocate data block */
1372 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1373 uint32_t block_size = ext4_superblock_get_block_size(sb);
1374
1375 /* Align size i-node size */
1376 if ((inode_size % block_size) != 0) {
1377 inode_size += block_size - (inode_size % block_size);
1378 }
1379
1380 /* Logical blocks are numbered from 0 */
1381 uint32_t new_block_idx = inode_size / block_size;
1382
1383 /* Allocate new physical block */
1384 uint32_t phys_block;
1385 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
1386 if (rc != EOK) {
1387 return rc;
1388 }
1389
1390 /* Add physical block address to the i-node */
1391 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, new_block_idx, phys_block);
1392 if (rc != EOK) {
1393 ext4_balloc_free_block(inode_ref, phys_block);
1394 return rc;
1395 }
1396
1397 /* Update i-node */
1398 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1399 inode_ref->dirty = true;
1400
1401 *fblock = phys_block;
1402 *iblock = new_block_idx;
1403
1404 return EOK;
1405}
1406
1407/** Add orphaned i-node to the orphans linked list.
1408 *
1409 * @param inode_ref i-node to be added to orphans list
1410 * @return error code
1411 */
1412int ext4_filesystem_add_orphan(ext4_inode_ref_t *inode_ref)
1413{
1414 uint32_t next_orphan = ext4_superblock_get_last_orphan(
1415 inode_ref->fs->superblock);
1416
1417 /* Deletion time is used for holding next item of the list */
1418 ext4_inode_set_deletion_time(inode_ref->inode, next_orphan);
1419
1420 /* Head of the list is in the superblock */
1421 ext4_superblock_set_last_orphan(
1422 inode_ref->fs->superblock, inode_ref->index);
1423 inode_ref->dirty = true;
1424
1425 return EOK;
1426}
1427
1428/** Delete orphaned i-node from the orphans linked list.
1429 *
1430 * @param inode_ref i-node to be deleted from the orphans list
1431 * @return error code
1432 */
1433int ext4_filesystem_delete_orphan(ext4_inode_ref_t *inode_ref)
1434{
1435 int rc;
1436
1437 /* Get head of the linked list */
1438 uint32_t last_orphan = ext4_superblock_get_last_orphan(
1439 inode_ref->fs->superblock);
1440
1441 assert (last_orphan != 0);
1442
1443 ext4_inode_ref_t *current;
1444 rc = ext4_filesystem_get_inode_ref(inode_ref->fs, last_orphan, &current);
1445 if (rc != EOK) {
1446 return rc;
1447 }
1448
1449 uint32_t next_orphan = ext4_inode_get_deletion_time(current->inode);
1450
1451 /* Check if the head is the target */
1452 if (last_orphan == inode_ref->index) {
1453 ext4_superblock_set_last_orphan(inode_ref->fs->superblock, next_orphan);
1454 return EOK;
1455 }
1456
1457 bool found = false;
1458
1459 /* Walk thourgh the linked list */
1460 while (next_orphan != 0) {
1461
1462 /* Found? */
1463 if (next_orphan == inode_ref->index) {
1464 next_orphan = ext4_inode_get_deletion_time(inode_ref->inode);
1465 ext4_inode_set_deletion_time(current->inode, next_orphan);
1466 current->dirty = true;
1467 found = true;
1468 break;
1469 }
1470
1471 ext4_filesystem_put_inode_ref(current);
1472
1473 rc = ext4_filesystem_get_inode_ref(inode_ref->fs, next_orphan, &current);
1474 if (rc != EOK) {
1475 return rc;
1476 }
1477 next_orphan = ext4_inode_get_deletion_time(current->inode);
1478
1479 }
1480
1481 rc = ext4_filesystem_put_inode_ref(current);
1482 if (rc != EOK) {
1483 return rc;
1484 }
1485
1486 if (!found) {
1487 return ENOENT;
1488 } else {
1489 return EOK;
1490 }
1491}
1492
1493/**
1494 * @}
1495 */
Note: See TracBrowser for help on using the repository browser.