source: mainline/uspace/lib/ext4/libext4_inode.c@ b3cf946

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b3cf946 was d1538a1, checked in by Martin Sucha <sucha14@…>, 13 years ago

Add missing copyright headers to ext4

Those files are based on ext2 filesystem driver code.

  • Property mode set to 100644
File size: 14.3 KB
RevLine 
[eb91db7]1/*
[d1538a1]2 * Copyright (c) 2011 Martin Sucha
[f22d5ef0]3 * Copyright (c) 2012 Frantisek Princ
[eb91db7]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
17 *
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.
28 */
29
30/** @addtogroup libext4
31 * @{
[38542dc]32 */
[eb91db7]33/**
[38542dc]34 * @file libext4_inode.c
35 * @brief Ext4 i-node structure operations.
[eb91db7]36 */
37
[9c0c0e1]38#include <byteorder.h>
[1a7756a]39#include <errno.h>
[f73b291]40#include <block.h>
[3711e7e]41#include "libext4.h"
[6c501f8]42
[296ef5d6]43/** Compute number of bits for block count.
44 *
[38542dc]45 * @param block_size Filesystem block_size
46 *
47 * @return Number of bits
48 *
[296ef5d6]49 */
[b3d7277]50static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
51{
52 uint32_t bits = 8;
53 uint32_t size = block_size;
[38542dc]54
[b3d7277]55 do {
56 bits++;
57 size = size >> 1;
58 } while (size > 256);
[38542dc]59
[b3d7277]60 return bits;
61}
62
[296ef5d6]63/** Get mode of the i-node.
64 *
[38542dc]65 * @param sb Superblock
66 * @param inode I-node to load mode from
67 *
68 * @return Mode of the i-node
69 *
[296ef5d6]70 */
[9b9d37bb]71uint32_t ext4_inode_get_mode(ext4_superblock_t *sb, ext4_inode_t *inode)
72{
73 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {
[38542dc]74 return ((uint32_t) uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 |
75 ((uint32_t) uint16_t_le2host(inode->mode));
[9b9d37bb]76 }
[38542dc]77
[9b9d37bb]78 return uint16_t_le2host(inode->mode);
79}
80
[296ef5d6]81/** Set mode of the i-node.
82 *
[38542dc]83 * @param sb Superblock
84 * @param inode I-node to set mode to
85 * @param mode Mode to set to i-node
86 *
[296ef5d6]87 */
[fe27eb4]88void ext4_inode_set_mode(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t mode)
[9b9d37bb]89{
[fe27eb4]90 inode->mode = host2uint16_t_le((mode << 16) >> 16);
[38542dc]91
92 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD)
[fe27eb4]93 inode->osd2.hurd2.mode_high = host2uint16_t_le(mode >> 16);
[9b9d37bb]94}
95
[296ef5d6]96/** Get ID of the i-node owner (user id).
97 *
[38542dc]98 * @param inode I-node to load uid from
99 *
100 * @return User ID of the i-node owner
101 *
[296ef5d6]102 */
[3712434]103uint32_t ext4_inode_get_uid(ext4_inode_t *inode)
[fe27eb4]104{
105 return uint32_t_le2host(inode->uid);
106}
107
[296ef5d6]108/** Set ID of the i-node owner.
109 *
[38542dc]110 * @param inode I-node to set uid to
111 * @param uid ID of the i-node owner
112 *
[296ef5d6]113 */
[fe27eb4]114void ext4_inode_set_uid(ext4_inode_t *inode, uint32_t uid)
115{
116 inode->uid = host2uint32_t_le(uid);
117}
[3712434]118
[296ef5d6]119/** Get real i-node size.
120 *
[38542dc]121 * @param sb Superblock
122 * @param inode I-node to load size from
123 *
124 * @return Real size of i-node
125 *
[296ef5d6]126 */
[9b9d37bb]127uint64_t ext4_inode_get_size(ext4_superblock_t *sb, ext4_inode_t *inode)
[3712434]128{
[9b9d37bb]129 uint32_t major_rev = ext4_superblock_get_rev_level(sb);
[38542dc]130
131 if ((major_rev > 0) &&
132 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)))
[9b9d37bb]133 return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 |
[38542dc]134 ((uint64_t)uint32_t_le2host(inode->size_lo));
135
[9b9d37bb]136 return uint32_t_le2host(inode->size_lo);
[3712434]137}
138
[296ef5d6]139/** Set real i-node size.
140 *
[38542dc]141 * @param inode I-node to set size to
142 * @param size Size of the i-node
143 *
[296ef5d6]144 */
[38542dc]145void ext4_inode_set_size(ext4_inode_t *inode, uint64_t size)
146{
[296ef5d6]147 inode->size_lo = host2uint32_t_le((size << 32) >> 32);
148 inode->size_hi = host2uint32_t_le(size >> 32);
[052e82d]149}
150
[2add9ec]151/** Get time, when i-node was last accessed.
152 *
[38542dc]153 * @param inode I-node
154 *
155 * @return Time of the last access (POSIX)
156 *
[2add9ec]157 */
[fe27eb4]158uint32_t ext4_inode_get_access_time(ext4_inode_t *inode)
159{
160 return uint32_t_le2host(inode->access_time);
161}
162
[2add9ec]163/** Set time, when i-node was last accessed.
[296ef5d6]164 *
[38542dc]165 * @param inode I-node
166 * @param time Time of the last access (POSIX)
167 *
[296ef5d6]168 */
[fe27eb4]169void ext4_inode_set_access_time(ext4_inode_t *inode, uint32_t time)
170{
171 inode->access_time = host2uint32_t_le(time);
172}
173
[da9f220d]174/** Get time, when i-node was last changed.
[296ef5d6]175 *
[38542dc]176 * @param inode I-node
177 *
178 * @return Time of the last change (POSIX)
179 *
[296ef5d6]180 */
[fe27eb4]181uint32_t ext4_inode_get_change_inode_time(ext4_inode_t *inode)
182{
183 return uint32_t_le2host(inode->change_inode_time);
184}
185
[da9f220d]186/** Set time, when i-node was last changed.
[296ef5d6]187 *
[38542dc]188 * @param inode I-node
189 * @param time Time of the last change (POSIX)
190 *
[296ef5d6]191 */
[fe27eb4]192void ext4_inode_set_change_inode_time(ext4_inode_t *inode, uint32_t time)
193{
194 inode->change_inode_time = host2uint32_t_le(time);
195}
196
[da9f220d]197/** Get time, when i-node content was last modified.
[296ef5d6]198 *
[38542dc]199 * @param inode I-node
200 *
201 * @return Time of the last content modification (POSIX)
202 *
[296ef5d6]203 */
[fe27eb4]204uint32_t ext4_inode_get_modification_time(ext4_inode_t *inode)
205{
206 return uint32_t_le2host(inode->modification_time);
207}
208
[da9f220d]209/** Set time, when i-node content was last modified.
[296ef5d6]210 *
[38542dc]211 * @param inode I-node
212 * @param time Time of the last content modification (POSIX)
213 *
[296ef5d6]214 */
[fe27eb4]215void ext4_inode_set_modification_time(ext4_inode_t *inode, uint32_t time)
216{
217 inode->modification_time = host2uint32_t_le(time);
218}
219
[5b26747]220/** Get time, when i-node was deleted.
[296ef5d6]221 *
[38542dc]222 * @param inode I-node
223 *
224 * @return Time of the delete action (POSIX)
225 *
[296ef5d6]226 */
[fe27eb4]227uint32_t ext4_inode_get_deletion_time(ext4_inode_t *inode)
228{
229 return uint32_t_le2host(inode->deletion_time);
230}
231
[5b26747]232/** Set time, when i-node was deleted.
[296ef5d6]233 *
[38542dc]234 * @param inode I-node
235 * @param time Time of the delete action (POSIX)
236 *
[296ef5d6]237 */
[fe27eb4]238void ext4_inode_set_deletion_time(ext4_inode_t *inode, uint32_t time)
239{
240 inode->deletion_time = host2uint32_t_le(time);
241}
242
[296ef5d6]243/** Get ID of the i-node owner's group.
244 *
[38542dc]245 * @param inode I-node to load gid from
246 *
247 * @return Group ID of the i-node owner
248 *
[296ef5d6]249 */
[fe27eb4]250uint32_t ext4_inode_get_gid(ext4_inode_t *inode)
251{
252 return uint32_t_le2host(inode->gid);
253}
254
[296ef5d6]255/** Set ID ot the i-node owner's group.
256 *
[38542dc]257 * @param inode I-node to set gid to
258 * @param gid Group ID of the i-node owner
259 *
[296ef5d6]260 */
[fe27eb4]261void ext4_inode_set_gid(ext4_inode_t *inode, uint32_t gid)
262{
263 inode->gid = host2uint32_t_le(gid);
264}
[3712434]265
[296ef5d6]266/** Get number of links to i-node.
267 *
[38542dc]268 * @param inode I-node to load number of links from
269 *
270 * @return Number of links to i-node
271 *
[296ef5d6]272 */
[3712434]273uint16_t ext4_inode_get_links_count(ext4_inode_t *inode)
[6c501f8]274{
[9c0c0e1]275 return uint16_t_le2host(inode->links_count);
[6c501f8]276}
277
[296ef5d6]278/** Set number of links to i-node.
279 *
[38542dc]280 * @param inode I-node to set number of links to
281 * @param count Number of links to i-node
282 *
[296ef5d6]283 */
[fe27eb4]284void ext4_inode_set_links_count(ext4_inode_t *inode, uint16_t count)
285{
286 inode->links_count = host2uint16_t_le(count);
287}
[b3d7277]288
[2add9ec]289/** Get number of 512-bytes blocks used for i-node.
[296ef5d6]290 *
[38542dc]291 * @param sb Superblock
292 * @param inode I-node
293 *
294 * @return Number of 512-bytes blocks
295 *
[296ef5d6]296 */
[b3d7277]297uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode)
298{
[38542dc]299 if (ext4_superblock_has_feature_read_only(sb,
300 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
[06d85e5]301 /* 48-bit field */
[38542dc]302 uint64_t count = ((uint64_t)
303 uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 |
304 uint32_t_le2host(inode->blocks_count_lo);
305
[b3d7277]306 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
[38542dc]307 uint32_t block_size = ext4_superblock_get_block_size(sb);
308 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
309 return count << (block_bits - 9);
310 } else
[b3d7277]311 return count;
[38542dc]312 } else
[b3d7277]313 return uint32_t_le2host(inode->blocks_count_lo);
314}
315
[2add9ec]316/** Set number of 512-bytes blocks used for i-node.
[296ef5d6]317 *
[38542dc]318 * @param sb Superblock
319 * @param inode I-node
320 * @param count Number of 512-bytes blocks
321 *
322 * @return Error code
323 *
[296ef5d6]324 */
[b3d7277]325int ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode,
[38542dc]326 uint64_t count)
327{
328 /* 32-bit maximum */
329 uint64_t max = 0;
330 max = ~max >> 32;
331
332 if (count <= max) {
333 inode->blocks_count_lo = host2uint32_t_le(count);
334 inode->osd2.linux2.blocks_high = 0;
335 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
336
337 return EOK;
338 }
339
340 /* Check if there can be used huge files (many blocks) */
341 if (!ext4_superblock_has_feature_read_only(sb,
342 EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
343 return EINVAL;
344
345 /* 48-bit maximum */
346 max = 0;
347 max = ~max >> 16;
348
349 if (count <= max) {
350 inode->blocks_count_lo = host2uint32_t_le(count);
351 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
352 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
353 } else {
354 uint32_t block_size = ext4_superblock_get_block_size(sb);
355 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
356 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
357 count = count >> (block_bits - 9);
358 inode->blocks_count_lo = host2uint32_t_le(count);
359 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
360 }
361
362 return EOK;
[b3d7277]363}
[eb91db7]364
[296ef5d6]365/** Get flags (features) of i-node.
[38542dc]366 *
367 * @param inode I-node to get flags from
368 *
369 * @return Flags (bitmap)
370 *
[296ef5d6]371 */
[38542dc]372uint32_t ext4_inode_get_flags(ext4_inode_t *inode)
373{
[7b9381b]374 return uint32_t_le2host(inode->flags);
375}
376
[296ef5d6]377/** Set flags (features) of i-node.
378 *
[38542dc]379 * @param inode I-node to set flags to
380 * @param flags Flags to set to i-node
381 *
[296ef5d6]382 */
[38542dc]383void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags)
384{
[b3d7277]385 inode->flags = host2uint32_t_le(flags);
386}
387
[2add9ec]388/** Get file generation (used by NFS).
[296ef5d6]389 *
[38542dc]390 * @param inode I-node
391 *
392 * @return File generation
393 *
[296ef5d6]394 */
[fe27eb4]395uint32_t ext4_inode_get_generation(ext4_inode_t *inode)
396{
397 return uint32_t_le2host(inode->generation);
398}
399
[2add9ec]400/** Set file generation (used by NFS).
[296ef5d6]401 *
[38542dc]402 * @param inode I-node
403 * @param generation File generation
404 *
[296ef5d6]405 */
[fe27eb4]406void ext4_inode_set_generation(ext4_inode_t *inode, uint32_t generation)
407{
408 inode->generation = host2uint32_t_le(generation);
409}
410
[2add9ec]411/** Get address of block, where are extended attributes located.
[296ef5d6]412 *
[38542dc]413 * @param inode I-node
414 * @param sb Superblock
415 *
416 * @return Block address
417 *
[296ef5d6]418 */
[b191acae]419uint64_t ext4_inode_get_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb)
[343ccfd]420{
[38542dc]421 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX)
422 return ((uint32_t)
423 uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 |
[343ccfd]424 (uint32_t_le2host(inode->file_acl_lo));
[38542dc]425
[343ccfd]426 return uint32_t_le2host(inode->file_acl_lo);
427}
428
[2add9ec]429/** Set address of block, where are extended attributes located.
[296ef5d6]430 *
[38542dc]431 * @param inode I-node
432 * @param sb Superblock
433 * @param file_acl Block address
434 *
[296ef5d6]435 */
[b191acae]436void ext4_inode_set_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb,
[38542dc]437 uint64_t file_acl)
[343ccfd]438{
439 inode->file_acl_lo = host2uint32_t_le((file_acl << 32) >> 32);
[38542dc]440
441 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX)
[343ccfd]442 inode->osd2.linux2.file_acl_high = host2uint16_t_le(file_acl >> 32);
443}
444
[296ef5d6]445/** Get block address of specified direct block.
446 *
[38542dc]447 * @param inode I-node to load block from
448 * @param idx Index of logical block
449 *
450 * @return Physical block address
451 *
[296ef5d6]452 */
[1e65444]453uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx)
[9b9d37bb]454{
455 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
[38542dc]456
[9b9d37bb]457 return uint32_t_le2host(inode->blocks[idx]);
458}
459
[296ef5d6]460/** Set block address of specified direct block.
461 *
[38542dc]462 * @param inode I-node to set block address to
463 * @param idx Index of logical block
464 * @param fblock Physical block address
465 *
[296ef5d6]466 */
[1e65444]467void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
[d5a78e28]468{
469 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
[38542dc]470
[d5a78e28]471 inode->blocks[idx] = host2uint32_t_le(fblock);
472}
473
[296ef5d6]474/** Get block address of specified indirect block.
475 *
[38542dc]476 * @param inode I-node to get block address from
477 * @param idx Index of indirect block
478 *
479 * @return Physical block address
480 *
[296ef5d6]481 */
[1e65444]482uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx)
[9b9d37bb]483{
484 return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
485}
486
[296ef5d6]487/** Set block address of specified indirect block.
488 *
[38542dc]489 * @param inode I-node to set block address to
490 * @param idx Index of indirect block
491 * @param fblock Physical block address
492 *
[296ef5d6]493 */
[38542dc]494void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx,
495 uint32_t fblock)
[1e65444]496{
[38542dc]497 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] =
498 host2uint32_t_le(fblock);
[1e65444]499}
500
[296ef5d6]501/** Check if i-node has specified type.
502 *
[38542dc]503 * @param sb Superblock
504 * @param inode I-node to check type of
505 * @param type Type to check
506 *
507 * @return Result of check operation
508 *
[296ef5d6]509 */
[38542dc]510bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode,
511 uint32_t type)
[fe27eb4]512{
513 uint32_t mode = ext4_inode_get_mode(sb, inode);
514 return (mode & EXT4_INODE_MODE_TYPE_MASK) == type;
515}
516
[296ef5d6]517/** Get extent header from the root of the extent tree.
518 *
[38542dc]519 * @param inode I-node to get extent header from
520 *
521 * @return Pointer to extent header of the root node
522 *
[296ef5d6]523 */
[acd869e]524ext4_extent_header_t * ext4_inode_get_extent_header(ext4_inode_t *inode)
525{
[38542dc]526 return (ext4_extent_header_t *) inode->blocks;
[acd869e]527}
[7b9381b]528
[296ef5d6]529/** Check if i-node has specified flag.
530 *
[38542dc]531 * @param inode I-node to check flags of
532 * @param flag Flag to check
533 *
534 * @return Result of check operation
535 *
[296ef5d6]536 */
[7bc4508]537bool ext4_inode_has_flag(ext4_inode_t *inode, uint32_t flag)
538{
[38542dc]539 if (ext4_inode_get_flags(inode) & flag)
[7b9381b]540 return true;
[38542dc]541
[7b9381b]542 return false;
543}
544
[296ef5d6]545/** Remove specified flag from i-node.
546 *
[38542dc]547 * @param inode I-node to clear flag on
548 * @param clear_flag Flag to be cleared
549 *
[296ef5d6]550 */
[b3d7277]551void ext4_inode_clear_flag(ext4_inode_t *inode, uint32_t clear_flag)
552{
553 uint32_t flags = ext4_inode_get_flags(inode);
554 flags = flags & (~clear_flag);
555 ext4_inode_set_flags(inode, flags);
556}
557
[296ef5d6]558/** Set specified flag to i-node.
559 *
[38542dc]560 * @param inode I-node to set flag on
561 * @param set_flag Flag to be set
562 *
[296ef5d6]563 */
[b3d7277]564void ext4_inode_set_flag(ext4_inode_t *inode, uint32_t set_flag)
565{
566 uint32_t flags = ext4_inode_get_flags(inode);
567 flags = flags | set_flag;
568 ext4_inode_set_flags(inode, flags);
569}
570
[296ef5d6]571/** Check if i-node can be truncated.
572 *
[38542dc]573 * @param sb Superblock
574 * @param inode I-node to check
575 *
576 * @return Result of the check operation
577 *
[296ef5d6]578 */
[43a9968]579bool ext4_inode_can_truncate(ext4_superblock_t *sb, ext4_inode_t *inode)
[12b4a7f]580{
[38542dc]581 if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
582 (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
583 return false;
584
585 if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
586 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
587 return true;
588
589 return false;
[12b4a7f]590}
591
[eb91db7]592/**
593 * @}
[38542dc]594 */
Note: See TracBrowser for help on using the repository browser.