source: mainline/uspace/lib/ext4/libext4_inode.c@ 5b26747

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

More comments - mostly by filesystem operations

  • Property mode set to 100644
File size: 13.8 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/** TODO comment
159 *
160 */
161uint32_t ext4_inode_get_change_inode_time(ext4_inode_t *inode)
162{
163 return uint32_t_le2host(inode->change_inode_time);
164}
165
166/** TODO comment
167 *
168 */
169void ext4_inode_set_change_inode_time(ext4_inode_t *inode, uint32_t time)
170{
171 inode->change_inode_time = host2uint32_t_le(time);
172}
173
174/** TODO comment
175 *
176 */
177uint32_t ext4_inode_get_modification_time(ext4_inode_t *inode)
178{
179 return uint32_t_le2host(inode->modification_time);
180}
181
182/** TODO comment
183 *
184 */
185void ext4_inode_set_modification_time(ext4_inode_t *inode, uint32_t time)
186{
187 inode->modification_time = host2uint32_t_le(time);
188}
189
190/** Get time, when i-node was deleted.
191 *
192 * @param inode i-node
193 * @return time of the delete action (POSIX)
194 */
195uint32_t ext4_inode_get_deletion_time(ext4_inode_t *inode)
196{
197 return uint32_t_le2host(inode->deletion_time);
198}
199
200/** Set time, when i-node was deleted.
201 *
202 * @param inode i-node
203 * @param time time of the delete action (POSIX)
204 */
205void ext4_inode_set_deletion_time(ext4_inode_t *inode, uint32_t time)
206{
207 inode->deletion_time = host2uint32_t_le(time);
208}
209
210/** Get ID of the i-node owner's group.
211 *
212 * @param inode i-node to load gid from
213 * @return group ID of the i-node owner
214 */
215uint32_t ext4_inode_get_gid(ext4_inode_t *inode)
216{
217 return uint32_t_le2host(inode->gid);
218}
219
220/** Set ID ot the i-node owner's group.
221 *
222 * @param inode i-node to set gid to
223 * @param gid group ID of the i-node owner
224 */
225void ext4_inode_set_gid(ext4_inode_t *inode, uint32_t gid)
226{
227 inode->gid = host2uint32_t_le(gid);
228}
229
230/** Get number of links to i-node.
231 *
232 * @param inode i-node to load number of links from
233 * @return number of links to i-node
234 */
235uint16_t ext4_inode_get_links_count(ext4_inode_t *inode)
236{
237 return uint16_t_le2host(inode->links_count);
238}
239
240/** Set number of links to i-node.
241 *
242 * @param inode i-node to set number of links to
243 * @param count number of links to i-node
244 */
245void ext4_inode_set_links_count(ext4_inode_t *inode, uint16_t count)
246{
247 inode->links_count = host2uint16_t_le(count);
248}
249
250/** Get number of 512-bytes blocks used for i-node.
251 *
252 * @param sb superblock
253 * @param inode i-node
254 * @return number of 512-bytes blocks
255 */
256uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode)
257{
258 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
259
260 // 48-bit field
261 uint64_t count = ((uint64_t)uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 |
262 uint32_t_le2host(inode->blocks_count_lo);
263
264 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
265 uint32_t block_size = ext4_superblock_get_block_size(sb);
266 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
267 return count << (block_bits - 9);
268 } else {
269 return count;
270 }
271 } else {
272 return uint32_t_le2host(inode->blocks_count_lo);
273 }
274}
275
276/** Set number of 512-bytes blocks used for i-node.
277 *
278 * @param sb superblock
279 * @param inode i-node
280 * @param count number of 512-bytes blocks
281 * @return error code
282 */
283int ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode,
284 uint64_t count)
285{
286 // 32-bit maximum
287 uint64_t max = 0;
288 max = ~max >> 32;
289
290 if (count <= max) {
291 inode->blocks_count_lo = host2uint32_t_le(count);
292 inode->osd2.linux2.blocks_high = 0;
293 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
294 return EOK;
295 }
296
297 // Check if there can be used huge files (many blocks)
298 if (!ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
299 return EINVAL;
300 }
301
302 // 48-bit maximum
303 max = 0;
304 max = ~max >> 16;
305
306 if (count <= max) {
307 inode->blocks_count_lo = host2uint32_t_le(count);
308 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
309 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
310 } else {
311 uint32_t block_size = ext4_superblock_get_block_size(sb);
312 uint32_t block_bits = ext4_inode_block_bits_count(block_size);
313 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
314 count = count >> (block_bits - 9);
315 inode->blocks_count_lo = host2uint32_t_le(count);
316 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32);
317 }
318 return EOK;
319}
320
321/** Get flags (features) of i-node.
322 *
323 * @param inode i-node to get flags from
324 * @return flags (bitmap)
325 */
326uint32_t ext4_inode_get_flags(ext4_inode_t *inode) {
327 return uint32_t_le2host(inode->flags);
328}
329
330/** Set flags (features) of i-node.
331 *
332 * @param inode i-node to set flags to
333 * @param flags flags to set to i-node
334 */
335void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags) {
336 inode->flags = host2uint32_t_le(flags);
337}
338
339/** Get file generation (used by NFS).
340 *
341 * @param inode i-node
342 * @return file generation
343 */
344uint32_t ext4_inode_get_generation(ext4_inode_t *inode)
345{
346 return uint32_t_le2host(inode->generation);
347}
348
349/** Set file generation (used by NFS).
350 *
351 * @param inode i-node
352 * @param generation file generation
353 */
354void ext4_inode_set_generation(ext4_inode_t *inode, uint32_t generation)
355{
356 inode->generation = host2uint32_t_le(generation);
357}
358
359/** Get address of block, where are extended attributes located.
360 *
361 * @param inode i-node
362 * @param sb superblock
363 * @return block address
364 */
365uint64_t ext4_inode_get_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb)
366{
367 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) {
368 return ((uint32_t)uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 |
369 (uint32_t_le2host(inode->file_acl_lo));
370 }
371
372 return uint32_t_le2host(inode->file_acl_lo);
373}
374
375/** Set address of block, where are extended attributes located.
376 *
377 * @param inode i-node
378 * @param sb superblock
379 * @param file_acl block address
380 */
381void ext4_inode_set_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb,
382 uint64_t file_acl)
383{
384 inode->file_acl_lo = host2uint32_t_le((file_acl << 32) >> 32);
385
386 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) {
387 inode->osd2.linux2.file_acl_high = host2uint16_t_le(file_acl >> 32);
388 }
389}
390
391/***********************************************************************/
392
393/** Get block address of specified direct block.
394 *
395 * @param inode i-node to load block from
396 * @param idx index of logical block
397 * @return physical block address
398 */
399uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx)
400{
401 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
402 return uint32_t_le2host(inode->blocks[idx]);
403}
404
405/** Set block address of specified direct block.
406 *
407 * @param inode i-node to set block address to
408 * @param idx index of logical block
409 * @param fblock physical block address
410 */
411void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
412{
413 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
414 inode->blocks[idx] = host2uint32_t_le(fblock);
415}
416
417/** Get block address of specified indirect block.
418 *
419 * @param inode i-node to get block address from
420 * @param idx index of indirect block
421 * @return physical block address
422 */
423uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx)
424{
425 return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
426}
427
428/** Set block address of specified indirect block.
429 *
430 * @param inode i-node to set block address to
431 * @param idx index of indirect block
432 * @param fblock physical block address
433 */
434void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
435{
436 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = host2uint32_t_le(fblock);
437}
438
439/** Check if i-node has specified type.
440 *
441 * @param sb superblock
442 * @param inode i-node to check type of
443 * @param type type to check
444 * @return result of check operation
445 */
446bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t type)
447{
448 uint32_t mode = ext4_inode_get_mode(sb, inode);
449 return (mode & EXT4_INODE_MODE_TYPE_MASK) == type;
450}
451
452/** Get extent header from the root of the extent tree.
453 *
454 * @param inode i-node to get extent header from
455 * @return pointer to extent header of the root node
456 */
457ext4_extent_header_t * ext4_inode_get_extent_header(ext4_inode_t *inode)
458{
459 return (ext4_extent_header_t *)inode->blocks;
460}
461
462/** Check if i-node has specified flag.
463 *
464 * @param inode i-node to check flags of
465 * @param flag flag to check
466 * @return result of check operation
467 */
468bool ext4_inode_has_flag(ext4_inode_t *inode, uint32_t flag)
469{
470 if (ext4_inode_get_flags(inode) & flag) {
471 return true;
472 }
473 return false;
474}
475
476/** Remove specified flag from i-node.
477 *
478 * @param inode i-node to clear flag on
479 * @param clear_flag flag to be cleared
480 */
481void ext4_inode_clear_flag(ext4_inode_t *inode, uint32_t clear_flag)
482{
483 uint32_t flags = ext4_inode_get_flags(inode);
484 flags = flags & (~clear_flag);
485 ext4_inode_set_flags(inode, flags);
486}
487
488/** Set specified flag to i-node.
489 *
490 * @param inode i-node to set flag on
491 * @param set_flag falt to be set
492 */
493void ext4_inode_set_flag(ext4_inode_t *inode, uint32_t set_flag)
494{
495 uint32_t flags = ext4_inode_get_flags(inode);
496 flags = flags | set_flag;
497 ext4_inode_set_flags(inode, flags);
498}
499
500/** Check if i-node can be truncated.
501 *
502 * @param sb superblock
503 * @param inode i-node to check
504 * @return result of the check operation
505 */
506bool ext4_inode_can_truncate(ext4_superblock_t *sb, ext4_inode_t *inode)
507{
508 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)
509 || ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)) {
510 return false;
511 }
512
513 if (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)
514 || ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)) {
515 return true;
516 }
517
518 return false;
519}
520
521/**
522 * @}
523 */
Note: See TracBrowser for help on using the repository browser.