source: mainline/uspace/lib/ext4/libext4_inode.c@ 69146b93

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