Use `errno_t` in all uspace and kernel code.
[helenos.git] / uspace / lib / ext4 / src / inode.c
blob313663bcd05d7581babc0ea429b8efdfa02b5c80
1 /*
2 * Copyright (c) 2011 Martin Sucha
3 * Copyright (c) 2012 Frantisek Princ
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 /** @addtogroup libext4
31 * @{
33 /**
34 * @file inode.c
35 * @brief Ext4 i-node structure operations.
38 #include <block.h>
39 #include <byteorder.h>
40 #include <errno.h>
41 #include "ext4/inode.h"
42 #include "ext4/superblock.h"
44 /** Compute number of bits for block count.
46 * @param block_size Filesystem block_size
48 * @return Number of bits
51 static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
53 uint32_t bits = 8;
54 uint32_t size = block_size;
56 do {
57 bits++;
58 size = size >> 1;
59 } while (size > 256);
61 return bits;
64 /** Get mode of the i-node.
66 * @param sb Superblock
67 * @param inode I-node to load mode from
69 * @return Mode of the i-node
72 uint32_t ext4_inode_get_mode(ext4_superblock_t *sb, ext4_inode_t *inode)
74 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {
75 return ((uint32_t) uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 |
76 ((uint32_t) uint16_t_le2host(inode->mode));
79 return uint16_t_le2host(inode->mode);
82 /** Set mode of the i-node.
84 * @param sb Superblock
85 * @param inode I-node to set mode to
86 * @param mode Mode to set to i-node
89 void ext4_inode_set_mode(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t mode)
91 inode->mode = host2uint16_t_le((mode << 16) >> 16);
93 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD)
94 inode->osd2.hurd2.mode_high = host2uint16_t_le(mode >> 16);
97 /** Get ID of the i-node owner (user id).
99 * @param inode I-node to load uid from
101 * @return User ID of the i-node owner
104 uint32_t ext4_inode_get_uid(ext4_inode_t *inode)
106 return uint32_t_le2host(inode->uid);
109 /** Set ID of the i-node owner.
111 * @param inode I-node to set uid to
112 * @param uid ID of the i-node owner
115 void ext4_inode_set_uid(ext4_inode_t *inode, uint32_t uid)
117 inode->uid = host2uint32_t_le(uid);
120 /** Get real i-node size.
122 * @param sb Superblock
123 * @param inode I-node to load size from
125 * @return Real size of i-node
128 uint64_t ext4_inode_get_size(ext4_superblock_t *sb, ext4_inode_t *inode)
130 uint32_t major_rev = ext4_superblock_get_rev_level(sb);
132 if ((major_rev > 0) &&
133 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)))
134 return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 |
135 ((uint64_t)uint32_t_le2host(inode->size_lo));
137 return uint32_t_le2host(inode->size_lo);
140 /** Set real i-node size.
142 * @param inode I-node to set size to
143 * @param size Size of the i-node
146 void ext4_inode_set_size(ext4_inode_t *inode, uint64_t size)
148 inode->size_lo = host2uint32_t_le((size << 32) >> 32);
149 inode->size_hi = host2uint32_t_le(size >> 32);
152 /** Get time, when i-node was last accessed.
154 * @param inode I-node
156 * @return Time of the last access (POSIX)
159 uint32_t ext4_inode_get_access_time(ext4_inode_t *inode)
161 return uint32_t_le2host(inode->access_time);
164 /** Set time, when i-node was last accessed.
166 * @param inode I-node
167 * @param time Time of the last access (POSIX)
170 void ext4_inode_set_access_time(ext4_inode_t *inode, uint32_t time)
172 inode->access_time = host2uint32_t_le(time);
175 /** Get time, when i-node was last changed.
177 * @param inode I-node
179 * @return Time of the last change (POSIX)
182 uint32_t ext4_inode_get_change_inode_time(ext4_inode_t *inode)
184 return uint32_t_le2host(inode->change_inode_time);
187 /** Set time, when i-node was last changed.
189 * @param inode I-node
190 * @param time Time of the last change (POSIX)
193 void ext4_inode_set_change_inode_time(ext4_inode_t *inode, uint32_t time)
195 inode->change_inode_time = host2uint32_t_le(time);
198 /** Get time, when i-node content was last modified.
200 * @param inode I-node
202 * @return Time of the last content modification (POSIX)
205 uint32_t ext4_inode_get_modification_time(ext4_inode_t *inode)
207 return uint32_t_le2host(inode->modification_time);
210 /** Set time, when i-node content was last modified.
212 * @param inode I-node
213 * @param time Time of the last content modification (POSIX)
216 void ext4_inode_set_modification_time(ext4_inode_t *inode, uint32_t time)
218 inode->modification_time = host2uint32_t_le(time);
221 /** Get time, when i-node was deleted.
223 * @param inode I-node
225 * @return Time of the delete action (POSIX)
228 uint32_t ext4_inode_get_deletion_time(ext4_inode_t *inode)
230 return uint32_t_le2host(inode->deletion_time);
233 /** Set time, when i-node was deleted.
235 * @param inode I-node
236 * @param time Time of the delete action (POSIX)
239 void ext4_inode_set_deletion_time(ext4_inode_t *inode, uint32_t time)
241 inode->deletion_time = host2uint32_t_le(time);
244 /** Get ID of the i-node owner's group.
246 * @param inode I-node to load gid from
248 * @return Group ID of the i-node owner
251 uint32_t ext4_inode_get_gid(ext4_inode_t *inode)
253 return uint32_t_le2host(inode->gid);
256 /** Set ID ot the i-node owner's group.
258 * @param inode I-node to set gid to
259 * @param gid Group ID of the i-node owner
262 void ext4_inode_set_gid(ext4_inode_t *inode, uint32_t gid)
264 inode->gid = host2uint32_t_le(gid);
267 /** Get number of links to i-node.
269 * @param inode I-node to load number of links from
271 * @return Number of links to i-node
274 uint16_t ext4_inode_get_links_count(ext4_inode_t *inode)
276 return uint16_t_le2host(inode->links_count);
279 /** Set number of links to i-node.
281 * @param inode I-node to set number of links to
282 * @param count Number of links to i-node
285 void ext4_inode_set_links_count(ext4_inode_t *inode, uint16_t count)
287 inode->links_count = host2uint16_t_le(count);
290 /** Get number of 512-bytes blocks used for i-node.
292 * @param sb Superblock
293 * @param inode I-node
295 * @return Number of 512-bytes blocks
298 uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode)
300 if (ext4_superblock_has_feature_read_only(sb,
301 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
302 /* 48-bit field */
303 uint64_t count = ((uint64_t)
304 uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 |
305 uint32_t_le2host(inode->blocks_count_lo);
307 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
308 uint32_t block_size = ext4_superblock_get_block_size(sb);
309 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
310 return count << (block_bits - 9);
311 } else
312 return count;
313 } else
314 return uint32_t_le2host(inode->blocks_count_lo);
317 /** Set number of 512-bytes blocks used for i-node.
319 * @param sb Superblock
320 * @param inode I-node
321 * @param count Number of 512-bytes blocks
323 * @return Error code
326 errno_t ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode,
327 uint64_t count)
329 /* 32-bit maximum */
330 uint64_t max = 0;
331 max = ~max >> 32;
333 if (count <= max) {
334 inode->blocks_count_lo = host2uint32_t_le(count);
335 inode->osd2.linux2.blocks_high = 0;
336 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
338 return EOK;
341 /* Check if there can be used huge files (many blocks) */
342 if (!ext4_superblock_has_feature_read_only(sb,
343 EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
344 return EINVAL;
346 /* 48-bit maximum */
347 max = 0;
348 max = ~max >> 16;
350 if (count <= max) {
351 inode->blocks_count_lo = host2uint32_t_le(count);
352 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
353 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
354 } else {
355 uint32_t block_size = ext4_superblock_get_block_size(sb);
356 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
357 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
358 count = count >> (block_bits - 9);
359 inode->blocks_count_lo = host2uint32_t_le(count);
360 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
363 return EOK;
366 /** Get flags (features) of i-node.
368 * @param inode I-node to get flags from
370 * @return Flags (bitmap)
373 uint32_t ext4_inode_get_flags(ext4_inode_t *inode)
375 return uint32_t_le2host(inode->flags);
378 /** Set flags (features) of i-node.
380 * @param inode I-node to set flags to
381 * @param flags Flags to set to i-node
384 void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags)
386 inode->flags = host2uint32_t_le(flags);
389 /** Get file generation (used by NFS).
391 * @param inode I-node
393 * @return File generation
396 uint32_t ext4_inode_get_generation(ext4_inode_t *inode)
398 return uint32_t_le2host(inode->generation);
401 /** Set file generation (used by NFS).
403 * @param inode I-node
404 * @param generation File generation
407 void ext4_inode_set_generation(ext4_inode_t *inode, uint32_t generation)
409 inode->generation = host2uint32_t_le(generation);
412 /** Get address of block, where are extended attributes located.
414 * @param inode I-node
415 * @param sb Superblock
417 * @return Block address
420 uint64_t ext4_inode_get_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb)
422 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX)
423 return ((uint32_t)
424 uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 |
425 (uint32_t_le2host(inode->file_acl_lo));
427 return uint32_t_le2host(inode->file_acl_lo);
430 /** Set address of block, where are extended attributes located.
432 * @param inode I-node
433 * @param sb Superblock
434 * @param file_acl Block address
437 void ext4_inode_set_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb,
438 uint64_t file_acl)
440 inode->file_acl_lo = host2uint32_t_le((file_acl << 32) >> 32);
442 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX)
443 inode->osd2.linux2.file_acl_high = host2uint16_t_le(file_acl >> 32);
446 /** Get block address of specified direct block.
448 * @param inode I-node to load block from
449 * @param idx Index of logical block
451 * @return Physical block address
454 uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx)
456 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
458 return uint32_t_le2host(inode->blocks[idx]);
461 /** Set block address of specified direct block.
463 * @param inode I-node to set block address to
464 * @param idx Index of logical block
465 * @param fblock Physical block address
468 void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
470 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
472 inode->blocks[idx] = host2uint32_t_le(fblock);
475 /** Get block address of specified indirect block.
477 * @param inode I-node to get block address from
478 * @param idx Index of indirect block
480 * @return Physical block address
483 uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx)
485 return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
488 /** Set block address of specified indirect block.
490 * @param inode I-node to set block address to
491 * @param idx Index of indirect block
492 * @param fblock Physical block address
495 void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx,
496 uint32_t fblock)
498 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] =
499 host2uint32_t_le(fblock);
502 /** Check if i-node has specified type.
504 * @param sb Superblock
505 * @param inode I-node to check type of
506 * @param type Type to check
508 * @return Result of check operation
511 bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode,
512 uint32_t type)
514 uint32_t mode = ext4_inode_get_mode(sb, inode);
515 return (mode & EXT4_INODE_MODE_TYPE_MASK) == type;
518 /** Get extent header from the root of the extent tree.
520 * @param inode I-node to get extent header from
522 * @return Pointer to extent header of the root node
525 ext4_extent_header_t * ext4_inode_get_extent_header(ext4_inode_t *inode)
527 return (ext4_extent_header_t *) inode->blocks;
530 /** Check if i-node has specified flag.
532 * @param inode I-node to check flags of
533 * @param flag Flag to check
535 * @return Result of check operation
538 bool ext4_inode_has_flag(ext4_inode_t *inode, uint32_t flag)
540 if (ext4_inode_get_flags(inode) & flag)
541 return true;
543 return false;
546 /** Remove specified flag from i-node.
548 * @param inode I-node to clear flag on
549 * @param clear_flag Flag to be cleared
552 void ext4_inode_clear_flag(ext4_inode_t *inode, uint32_t clear_flag)
554 uint32_t flags = ext4_inode_get_flags(inode);
555 flags = flags & (~clear_flag);
556 ext4_inode_set_flags(inode, flags);
559 /** Set specified flag to i-node.
561 * @param inode I-node to set flag on
562 * @param set_flag Flag to be set
565 void ext4_inode_set_flag(ext4_inode_t *inode, uint32_t set_flag)
567 uint32_t flags = ext4_inode_get_flags(inode);
568 flags = flags | set_flag;
569 ext4_inode_set_flags(inode, flags);
572 /** Check if i-node can be truncated.
574 * @param sb Superblock
575 * @param inode I-node to check
577 * @return Result of the check operation
580 bool ext4_inode_can_truncate(ext4_superblock_t *sb, ext4_inode_t *inode)
582 if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
583 (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
584 return false;
586 if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
587 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
588 return true;
590 return false;
594 * @}