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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e25d78c was 06d85e5, checked in by Frantisek Princ <frantisek.princ@…>, 13 years ago

Most of comments modified by current coding style

  • Property mode set to 100644
File size: 14.3 KB
Line 
1/*
2 * Copyright (c) 2012 Frantisek Princ
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libext4
30 * @{
31 */
32
33/**
34 * @file libext4_inode.c
35 * @brief Ext4 inode structure operations.
36 */
37
38#include <byteorder.h>
39#include <errno.h>
40#include <libblock.h>
41#include "libext4.h"
42
43/** Compute number of bits for block count.
44 *
45 * @param block_size filesystem block_size
46 * @return number of bits
47 */
48static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
49{
50 uint32_t bits = 8;
51 uint32_t size = block_size;
52
53 do {
54 bits++;
55 size = size >> 1;
56 } while (size > 256);
57
58 return bits;
59}
60
61/** Get mode of the i-node.
62 *
63 * @param sb superblock
64 * @param inode i-node to load mode from
65 * @return mode of the i-node
66 */
67uint32_t ext4_inode_get_mode(ext4_superblock_t *sb, ext4_inode_t *inode)
68{
69 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {
70 return ((uint32_t)uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 |
71 ((uint32_t)uint16_t_le2host(inode->mode));
72 }
73 return uint16_t_le2host(inode->mode);
74}
75
76/** Set mode of the i-node.
77 *
78 * @param sb superblock
79 * @param inode i-node to set mode to
80 * @param mode mode to set to i-node
81 */
82void ext4_inode_set_mode(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t mode)
83{
84 inode->mode = host2uint16_t_le((mode << 16) >> 16);
85
86 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {
87 inode->osd2.hurd2.mode_high = host2uint16_t_le(mode >> 16);
88 }
89}
90
91/** Get ID of the i-node owner (user id).
92 *
93 * @param inode i-node to load uid from
94 * @return user ID of the i-node owner
95 */
96uint32_t ext4_inode_get_uid(ext4_inode_t *inode)
97{
98 return uint32_t_le2host(inode->uid);
99}
100
101/** Set ID of the i-node owner.
102 *
103 * @param inode i-node to set uid to
104 * @param uid ID of the i-node owner
105 */
106void ext4_inode_set_uid(ext4_inode_t *inode, uint32_t uid)
107{
108 inode->uid = host2uint32_t_le(uid);
109}
110
111/** Get real i-node size.
112 *
113 * @param sb superblock
114 * @param inode i-node to load size from
115 * @return real size of i-node
116 */
117uint64_t ext4_inode_get_size(ext4_superblock_t *sb, ext4_inode_t *inode)
118{
119 uint32_t major_rev = ext4_superblock_get_rev_level(sb);
120
121 if ((major_rev > 0) && ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) {
122 return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 |
123 ((uint64_t)uint32_t_le2host(inode->size_lo));
124 }
125 return uint32_t_le2host(inode->size_lo);
126}
127
128/** Set real i-node size.
129 *
130 * @param inode inode to set size to
131 * @param size size of the i-node
132 */
133void ext4_inode_set_size(ext4_inode_t *inode, uint64_t size) {
134 inode->size_lo = host2uint32_t_le((size << 32) >> 32);
135 inode->size_hi = host2uint32_t_le(size >> 32);
136}
137
138/** Get time, when i-node was last accessed.
139 *
140 * @param inode i-node
141 * @return time of the last access (POSIX)
142 */
143uint32_t ext4_inode_get_access_time(ext4_inode_t *inode)
144{
145 return uint32_t_le2host(inode->access_time);
146}
147
148/** Set time, when i-node was last accessed.
149 *
150 * @param inode i-node
151 * @param time time of the last access (POSIX)
152 */
153void ext4_inode_set_access_time(ext4_inode_t *inode, uint32_t time)
154{
155 inode->access_time = host2uint32_t_le(time);
156}
157
158/** Get time, when i-node was last changed.
159 *
160 * @param inode i-node
161 * @return time of the last change (POSIX)
162 */
163uint32_t ext4_inode_get_change_inode_time(ext4_inode_t *inode)
164{
165 return uint32_t_le2host(inode->change_inode_time);
166}
167
168/** Set time, when i-node was last changed.
169 *
170 * @param inode i-node
171 * @param time time of the last change (POSIX)
172 */
173void ext4_inode_set_change_inode_time(ext4_inode_t *inode, uint32_t time)
174{
175 inode->change_inode_time = host2uint32_t_le(time);
176}
177
178/** Get time, when i-node content was last modified.
179 *
180 * @param inode i-node
181 * @return time of the last content modification (POSIX)
182 */
183uint32_t ext4_inode_get_modification_time(ext4_inode_t *inode)
184{
185 return uint32_t_le2host(inode->modification_time);
186}
187
188/** Set time, when i-node content was last modified.
189 *
190 * @param inode i-node
191 * @param time time of the last content modification (POSIX)
192 */
193void ext4_inode_set_modification_time(ext4_inode_t *inode, uint32_t time)
194{
195 inode->modification_time = host2uint32_t_le(time);
196}
197
198/** Get time, when i-node was deleted.
199 *
200 * @param inode i-node
201 * @return time of the delete action (POSIX)
202 */
203uint32_t ext4_inode_get_deletion_time(ext4_inode_t *inode)
204{
205 return uint32_t_le2host(inode->deletion_time);
206}
207
208/** Set time, when i-node was deleted.
209 *
210 * @param inode i-node
211 * @param time time of the delete action (POSIX)
212 */
213void ext4_inode_set_deletion_time(ext4_inode_t *inode, uint32_t time)
214{
215 inode->deletion_time = host2uint32_t_le(time);
216}
217
218/** Get ID of the i-node owner's group.
219 *
220 * @param inode i-node to load gid from
221 * @return group ID of the i-node owner
222 */
223uint32_t ext4_inode_get_gid(ext4_inode_t *inode)
224{
225 return uint32_t_le2host(inode->gid);
226}
227
228/** Set ID ot the i-node owner's group.
229 *
230 * @param inode i-node to set gid to
231 * @param gid group ID of the i-node owner
232 */
233void ext4_inode_set_gid(ext4_inode_t *inode, uint32_t gid)
234{
235 inode->gid = host2uint32_t_le(gid);
236}
237
238/** Get number of links to i-node.
239 *
240 * @param inode i-node to load number of links from
241 * @return number of links to i-node
242 */
243uint16_t ext4_inode_get_links_count(ext4_inode_t *inode)
244{
245 return uint16_t_le2host(inode->links_count);
246}
247
248/** Set number of links to i-node.
249 *
250 * @param inode i-node to set number of links to
251 * @param count number of links to i-node
252 */
253void ext4_inode_set_links_count(ext4_inode_t *inode, uint16_t count)
254{
255 inode->links_count = host2uint16_t_le(count);
256}
257
258/** Get number of 512-bytes blocks used for i-node.
259 *
260 * @param sb superblock
261 * @param inode i-node
262 * @return number of 512-bytes blocks
263 */
264uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode)
265{
266 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
267
268 /* 48-bit field */
269 uint64_t count = ((uint64_t)uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 |
270 uint32_t_le2host(inode->blocks_count_lo);
271
272 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
273 uint32_t block_size = ext4_superblock_get_block_size(sb);
274 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
275 return count << (block_bits - 9);
276 } else {
277 return count;
278 }
279 } else {
280 return uint32_t_le2host(inode->blocks_count_lo);
281 }
282}
283
284/** Set number of 512-bytes blocks used for i-node.
285 *
286 * @param sb superblock
287 * @param inode i-node
288 * @param count number of 512-bytes blocks
289 * @return error code
290 */
291int ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode,
292 uint64_t count)
293{
294 /* 32-bit maximum */
295 uint64_t max = 0;
296 max = ~max >> 32;
297
298 if (count <= max) {
299 inode->blocks_count_lo = host2uint32_t_le(count);
300 inode->osd2.linux2.blocks_high = 0;
301 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
302 return EOK;
303 }
304
305 /* Check if there can be used huge files (many blocks) */
306 if (!ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
307 return EINVAL;
308 }
309
310 /* 48-bit maximum */
311 max = 0;
312 max = ~max >> 16;
313
314 if (count <= max) {
315 inode->blocks_count_lo = host2uint32_t_le(count);
316 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
317 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
318 } else {
319 uint32_t block_size = ext4_superblock_get_block_size(sb);
320 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
321 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
322 count = count >> (block_bits - 9);
323 inode->blocks_count_lo = host2uint32_t_le(count);
324 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
325 }
326 return EOK;
327}
328
329/** Get flags (features) of i-node.
330 *
331 * @param inode i-node to get flags from
332 * @return flags (bitmap)
333 */
334uint32_t ext4_inode_get_flags(ext4_inode_t *inode) {
335 return uint32_t_le2host(inode->flags);
336}
337
338/** Set flags (features) of i-node.
339 *
340 * @param inode i-node to set flags to
341 * @param flags flags to set to i-node
342 */
343void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags) {
344 inode->flags = host2uint32_t_le(flags);
345}
346
347/** Get file generation (used by NFS).
348 *
349 * @param inode i-node
350 * @return file generation
351 */
352uint32_t ext4_inode_get_generation(ext4_inode_t *inode)
353{
354 return uint32_t_le2host(inode->generation);
355}
356
357/** Set file generation (used by NFS).
358 *
359 * @param inode i-node
360 * @param generation file generation
361 */
362void ext4_inode_set_generation(ext4_inode_t *inode, uint32_t generation)
363{
364 inode->generation = host2uint32_t_le(generation);
365}
366
367/** Get address of block, where are extended attributes located.
368 *
369 * @param inode i-node
370 * @param sb superblock
371 * @return block address
372 */
373uint64_t ext4_inode_get_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb)
374{
375 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) {
376 return ((uint32_t)uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 |
377 (uint32_t_le2host(inode->file_acl_lo));
378 }
379
380 return uint32_t_le2host(inode->file_acl_lo);
381}
382
383/** Set address of block, where are extended attributes located.
384 *
385 * @param inode i-node
386 * @param sb superblock
387 * @param file_acl block address
388 */
389void ext4_inode_set_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb,
390 uint64_t file_acl)
391{
392 inode->file_acl_lo = host2uint32_t_le((file_acl << 32) >> 32);
393
394 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) {
395 inode->osd2.linux2.file_acl_high = host2uint16_t_le(file_acl >> 32);
396 }
397}
398
399/***********************************************************************/
400
401/** Get block address of specified direct block.
402 *
403 * @param inode i-node to load block from
404 * @param idx index of logical block
405 * @return physical block address
406 */
407uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx)
408{
409 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
410 return uint32_t_le2host(inode->blocks[idx]);
411}
412
413/** Set block address of specified direct block.
414 *
415 * @param inode i-node to set block address to
416 * @param idx index of logical block
417 * @param fblock physical block address
418 */
419void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
420{
421 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
422 inode->blocks[idx] = host2uint32_t_le(fblock);
423}
424
425/** Get block address of specified indirect block.
426 *
427 * @param inode i-node to get block address from
428 * @param idx index of indirect block
429 * @return physical block address
430 */
431uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx)
432{
433 return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
434}
435
436/** Set block address of specified indirect block.
437 *
438 * @param inode i-node to set block address to
439 * @param idx index of indirect block
440 * @param fblock physical block address
441 */
442void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
443{
444 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = host2uint32_t_le(fblock);
445}
446
447/** Check if i-node has specified type.
448 *
449 * @param sb superblock
450 * @param inode i-node to check type of
451 * @param type type to check
452 * @return result of check operation
453 */
454bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t type)
455{
456 uint32_t mode = ext4_inode_get_mode(sb, inode);
457 return (mode & EXT4_INODE_MODE_TYPE_MASK) == type;
458}
459
460/** Get extent header from the root of the extent tree.
461 *
462 * @param inode i-node to get extent header from
463 * @return pointer to extent header of the root node
464 */
465ext4_extent_header_t * ext4_inode_get_extent_header(ext4_inode_t *inode)
466{
467 return (ext4_extent_header_t *)inode->blocks;
468}
469
470/** Check if i-node has specified flag.
471 *
472 * @param inode i-node to check flags of
473 * @param flag flag to check
474 * @return result of check operation
475 */
476bool ext4_inode_has_flag(ext4_inode_t *inode, uint32_t flag)
477{
478 if (ext4_inode_get_flags(inode) & flag) {
479 return true;
480 }
481 return false;
482}
483
484/** Remove specified flag from i-node.
485 *
486 * @param inode i-node to clear flag on
487 * @param clear_flag flag to be cleared
488 */
489void ext4_inode_clear_flag(ext4_inode_t *inode, uint32_t clear_flag)
490{
491 uint32_t flags = ext4_inode_get_flags(inode);
492 flags = flags & (~clear_flag);
493 ext4_inode_set_flags(inode, flags);
494}
495
496/** Set specified flag to i-node.
497 *
498 * @param inode i-node to set flag on
499 * @param set_flag falt to be set
500 */
501void ext4_inode_set_flag(ext4_inode_t *inode, uint32_t set_flag)
502{
503 uint32_t flags = ext4_inode_get_flags(inode);
504 flags = flags | set_flag;
505 ext4_inode_set_flags(inode, flags);
506}
507
508/** Check if i-node can be truncated.
509 *
510 * @param sb superblock
511 * @param inode i-node to check
512 * @return result of the check operation
513 */
514bool ext4_inode_can_truncate(ext4_superblock_t *sb, ext4_inode_t *inode)
515{
516 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)
517 || ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)) {
518 return false;
519 }
520
521 if (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)
522 || ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)) {
523 return true;
524 }
525
526 return false;
527}
528
529/**
530 * @}
531 */
Note: See TracBrowser for help on using the repository browser.