source: mainline/uspace/lib/ext4/src/inode.c

Last change on this file was 1433ecda, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

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