2 * Copyright (c) 2011 Martin Sucha
3 * Copyright (c) 2012 Frantisek Princ
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
35 * @brief Ext4 i-node structure operations.
39 #include <byteorder.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
)
54 uint32_t size
= block_size
;
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
)) {
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);
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
326 errno_t
ext4_inode_set_blocks_count(ext4_superblock_t
*sb
, ext4_inode_t
*inode
,
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
);
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
))
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
);
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);
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
)
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
,
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
,
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
,
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
)
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
)))
586 if ((ext4_inode_is_type(sb
, inode
, EXT4_INODE_MODE_FILE
)) ||
587 (ext4_inode_is_type(sb
, inode
, EXT4_INODE_MODE_DIRECTORY
)))