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

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

filesystem code comments

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