Add extra config options
[lwext4.git] / lwext4 / ext4_inode.c
1 /*\r
2  * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)\r
3  *\r
4  *\r
5  * HelenOS:\r
6  * Copyright (c) 2012 Martin Sucha\r
7  * Copyright (c) 2012 Frantisek Princ\r
8  * All rights reserved.\r
9  *\r
10  * Redistribution and use in source and binary forms, with or without\r
11  * modification, are permitted provided that the following conditions\r
12  * are met:\r
13  *\r
14  * - Redistributions of source code must retain the above copyright\r
15  *   notice, this list of conditions and the following disclaimer.\r
16  * - Redistributions in binary form must reproduce the above copyright\r
17  *   notice, this list of conditions and the following disclaimer in the\r
18  *   documentation and/or other materials provided with the distribution.\r
19  * - The name of the author may not be used to endorse or promote products\r
20  *   derived from this software without specific prior written permission.\r
21  *\r
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
32  */\r
33 \r
34 /** @addtogroup lwext4\r
35  * @{\r
36  */\r
37 /**\r
38  * @file  ext4_inode.c\r
39  * @brief Inode handle functions\r
40  */\r
41 \r
42 #include <ext4_config.h>\r
43 #include <ext4_types.h>\r
44 #include <ext4_inode.h>\r
45 #include <ext4_super.h>\r
46 \r
47 /**@brief  Compute number of bits for block count.\r
48  * @param block_size Filesystem block_size\r
49  * @return Number of bits\r
50  */\r
51 static uint32_t ext4_inode_block_bits_count(uint32_t block_size)\r
52 {\r
53     uint32_t bits = 8;\r
54     uint32_t size = block_size;\r
55 \r
56     do {\r
57         bits++;\r
58         size = size >> 1;\r
59     } while (size > 256);\r
60 \r
61     return bits;\r
62 }\r
63 \r
64 uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)\r
65 {\r
66     uint32_t v = to_le16(inode->mode);\r
67 \r
68     if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD){\r
69         v |= ((uint32_t) to_le16(inode->osd2.hurd2.mode_high)) << 16;\r
70     }\r
71 \r
72     return v;\r
73 }\r
74 \r
75 void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,\r
76     uint32_t mode)\r
77 {\r
78     inode->mode = to_le16((mode << 16) >> 16);\r
79 \r
80     if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)\r
81         inode->osd2.hurd2.mode_high = to_le16(mode >> 16);\r
82 }\r
83 \r
84 uint32_t ext4_inode_get_uid(struct ext4_inode *inode)\r
85 {\r
86     return to_le32(inode->uid);\r
87 }\r
88 \r
89 void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)\r
90 {\r
91     inode->uid = to_le32(uid);\r
92 }\r
93 \r
94 uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode)\r
95 {\r
96     uint64_t v = to_le32(inode->size_lo);\r
97 \r
98     if ((ext4_get32(sb, rev_level) > 0) && (ext4_inode_is_type(sb, inode,\r
99             EXT4_INODE_MODE_FILE)))\r
100         v |= ((uint64_t)to_le32(inode->size_hi)) << 32;\r
101 \r
102     return v;\r
103 }\r
104 \r
105 void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size)\r
106 {\r
107     inode->size_lo = to_le32((size << 32) >> 32);\r
108     inode->size_hi = to_le32(size >> 32);\r
109 }\r
110 \r
111 uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)\r
112 {\r
113     return to_le32(inode->access_time);\r
114 }\r
115 void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)\r
116 {\r
117     inode->access_time = to_le32(time);\r
118 }\r
119 \r
120 \r
121 uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)\r
122 {\r
123     return to_le32(inode->change_inode_time);\r
124 }\r
125 void ext4_inode_set_change_inode_time(struct ext4_inode *inode,\r
126     uint32_t time)\r
127 {\r
128     inode->change_inode_time = to_le32(time);\r
129 }\r
130 \r
131 \r
132 uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)\r
133 {\r
134     return to_le32(inode->modification_time);\r
135 }\r
136 \r
137 void ext4_inode_set_modification_time(struct ext4_inode *inode,\r
138     uint32_t time)\r
139 {\r
140     inode->modification_time = to_le32(time);\r
141 }\r
142 \r
143 \r
144 uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)\r
145 {\r
146     return to_le32(inode->deletion_time);\r
147 }\r
148 \r
149 void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)\r
150 {\r
151     inode->deletion_time = to_le32(time);\r
152 }\r
153 \r
154 uint32_t ext4_inode_get_gid(struct ext4_inode *inode)\r
155 {\r
156     return to_le32(inode->gid);\r
157 }\r
158 void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)\r
159 {\r
160     inode->gid = to_le32(gid);\r
161 }\r
162 \r
163 uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)\r
164 {\r
165     return to_le16(inode->links_count);\r
166 }\r
167 void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)\r
168 {\r
169     inode->links_count = to_le16(cnt);\r
170 }\r
171 \r
172 uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,\r
173     struct ext4_inode *inode)\r
174 {\r
175     uint64_t count = to_le32(inode->blocks_count_lo);\r
176 \r
177     if (ext4_sb_has_feature_read_only(sb,\r
178             EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {\r
179 \r
180         /* 48-bit field */\r
181         count |= ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;\r
182 \r
183         if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {\r
184 \r
185             uint32_t block_bits =\r
186                     ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
187             return count << (block_bits - 9);\r
188         }\r
189     }\r
190 \r
191     return count;\r
192 }\r
193 \r
194 int ext4_inode_set_blocks_count(struct ext4_sblock *sb,\r
195     struct ext4_inode *inode, uint64_t count)\r
196 {\r
197     /* 32-bit maximum */\r
198     uint64_t max = 0;\r
199     max = ~max >> 32;\r
200 \r
201     if (count <= max) {\r
202         inode->blocks_count_lo = to_le32(count);\r
203         inode->osd2.linux2.blocks_high = 0;\r
204         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
205 \r
206         return EOK;\r
207     }\r
208 \r
209     /* Check if there can be used huge files (many blocks) */\r
210     if (!ext4_sb_has_feature_read_only(sb,\r
211             EXT4_FEATURE_RO_COMPAT_HUGE_FILE))\r
212         return EINVAL;\r
213 \r
214     /* 48-bit maximum */\r
215     max = 0;\r
216     max = ~max >> 16;\r
217 \r
218     if (count <= max) {\r
219         inode->blocks_count_lo = to_le32(count);\r
220         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
221         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
222     } else {\r
223         uint32_t block_bits = ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
224 \r
225         ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
226         count = count >> (block_bits - 9);\r
227         inode->blocks_count_lo = to_le32(count);\r
228         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
229     }\r
230 \r
231     return EOK;\r
232 }\r
233 \r
234 uint32_t ext4_inode_get_flags(struct ext4_inode *inode)\r
235 {\r
236     return to_le32(inode->flags);\r
237 }\r
238 void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)\r
239 {\r
240     inode->flags = to_le32(flags);\r
241 }\r
242 \r
243 uint32_t ext4_inode_get_generation(struct ext4_inode *inode)\r
244 {\r
245     return to_le32(inode->generation);\r
246 }\r
247 void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)\r
248 {\r
249     inode->generation = to_le32(gen);\r
250 }\r
251 \r
252 uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,\r
253     struct ext4_sblock *sb)\r
254 {\r
255     /*TODO: Verify it*/\r
256     uint64_t v = to_le32(inode->file_acl_lo);\r
257 \r
258     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
259         v |= ((uint32_t) to_le16(inode->osd2.linux2.file_acl_high)) << 16;\r
260 \r
261 \r
262     return v;\r
263 }\r
264 \r
265 void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,\r
266     uint64_t acl)\r
267 {\r
268     /*TODO: Verify it*/\r
269     inode->file_acl_lo = to_le32((acl << 32) >> 32);\r
270 \r
271     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
272         inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);\r
273 }\r
274 \r
275 uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)\r
276 {\r
277     return to_le32(inode->blocks[idx]);\r
278 }\r
279 void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,\r
280     uint32_t block)\r
281 {\r
282     inode->blocks[idx] = to_le32(block);\r
283 }\r
284 \r
285 uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)\r
286 {\r
287     return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);\r
288 }\r
289 \r
290 void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,\r
291     uint32_t block)\r
292 {\r
293     inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);\r
294 }\r
295 \r
296 bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,\r
297     uint32_t type)\r
298 {\r
299     return (ext4_inode_get_mode(sb, inode) &\r
300             EXT4_INODE_MODE_TYPE_MASK) == type;\r
301 }\r
302 \r
303 bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)\r
304 {\r
305     return ext4_inode_get_flags(inode) & f;\r
306 }\r
307 \r
308 void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)\r
309 {\r
310     uint32_t flags = ext4_inode_get_flags(inode);\r
311     flags = flags & (~f);\r
312     ext4_inode_set_flags(inode, flags);\r
313 }\r
314 \r
315 void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)\r
316 {\r
317     uint32_t flags = ext4_inode_get_flags(inode);\r
318     flags = flags | f;\r
319     ext4_inode_set_flags(inode, flags);\r
320 }\r
321 \r
322 bool ext4_inode_can_truncate(struct ext4_sblock *sb,\r
323     struct ext4_inode *inode)\r
324 {\r
325     if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||\r
326             (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))\r
327         return false;\r
328 \r
329     if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||\r
330             (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))\r
331         return true;\r
332 \r
333     return false;\r
334 }\r
335 \r
336 struct ext4_extent_header * ext4_inode_get_extent_header(\r
337     struct ext4_inode *inode)\r
338 {\r
339     return (struct ext4_extent_header *) inode->blocks;\r
340 }\r
341 \r
342 /**\r
343  * @}\r
344  */\r