FEATURES:
[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 static uint32_t ext4_inode_block_bits_count(uint32_t block_size)\r
48 {\r
49     uint32_t bits = 8;\r
50     uint32_t size = block_size;\r
51 \r
52     do {\r
53         bits++;\r
54         size = size >> 1;\r
55     } while (size > 256);\r
56 \r
57     return bits;\r
58 }\r
59 \r
60 \r
61 uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)\r
62 {\r
63     uint32_t v = to_le16(inode->mode);\r
64 \r
65     if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD){\r
66         v |= ((uint32_t) to_le16(inode->osd2.hurd2.mode_high)) << 16;\r
67     }\r
68 \r
69     return v;\r
70 }\r
71 \r
72 void     ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,\r
73     uint32_t mode)\r
74 {\r
75     inode->mode = to_le16((mode << 16) >> 16);\r
76 \r
77     if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)\r
78         inode->osd2.hurd2.mode_high = to_le16(mode >> 16);\r
79 }\r
80 \r
81 \r
82 \r
83 uint32_t ext4_inode_get_uid(struct ext4_inode *inode)\r
84 {\r
85     return to_le32(inode->uid);\r
86 }\r
87 \r
88 void     ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)\r
89 {\r
90     inode->uid = to_le32(uid);\r
91 }\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 \r
112 uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)\r
113 {\r
114     return to_le32(inode->access_time);\r
115 }\r
116 void     ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)\r
117 {\r
118     inode->access_time = to_le32(time);\r
119 }\r
120 \r
121 \r
122 uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)\r
123 {\r
124     return to_le32(inode->change_inode_time);\r
125 }\r
126 void     ext4_inode_set_change_inode_time(struct ext4_inode *inode,\r
127     uint32_t time)\r
128 {\r
129     inode->change_inode_time = to_le32(time);\r
130 }\r
131 \r
132 \r
133 uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)\r
134 {\r
135     return to_le32(inode->modification_time);\r
136 }\r
137 \r
138 void     ext4_inode_set_modification_time(struct ext4_inode *inode,\r
139     uint32_t time)\r
140 {\r
141     inode->modification_time = to_le32(time);\r
142 }\r
143 \r
144 \r
145 uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)\r
146 {\r
147     return to_le32(inode->deletion_time);\r
148 }\r
149 \r
150 void     ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)\r
151 {\r
152     inode->deletion_time = to_le32(time);\r
153 }\r
154 \r
155 uint32_t ext4_inode_get_gid(struct ext4_inode *inode)\r
156 {\r
157     return to_le32(inode->gid);\r
158 }\r
159 void     ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)\r
160 {\r
161     inode->gid  = to_le32(gid);\r
162 }\r
163 \r
164 uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)\r
165 {\r
166     return to_le16(inode->links_count);\r
167 }\r
168 void     ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)\r
169 {\r
170     inode->links_count = to_le16(cnt);\r
171 }\r
172 \r
173 \r
174 uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,\r
175     struct ext4_inode *inode)\r
176 {\r
177     uint64_t count = to_le32(inode->blocks_count_lo);\r
178 \r
179     if (ext4_sb_check_read_only(sb,\r
180             EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {\r
181 \r
182         /* 48-bit field */\r
183         count |= ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;\r
184 \r
185         if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {\r
186 \r
187             uint32_t block_bits =\r
188                     ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
189             return count << (block_bits - 9);\r
190         } else\r
191             return count;\r
192     }\r
193 \r
194     return count;\r
195 }\r
196 \r
197 \r
198 int ext4_inode_set_blocks_count(struct ext4_sblock *sb,\r
199     struct ext4_inode *inode, uint64_t count)\r
200 {\r
201     /* 32-bit maximum */\r
202     uint64_t max = 0;\r
203     max = ~max >> 32;\r
204 \r
205     if (count <= max) {\r
206         inode->blocks_count_lo = to_le32(count);\r
207         inode->osd2.linux2.blocks_high = 0;\r
208         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
209 \r
210         return EOK;\r
211     }\r
212 \r
213     /* Check if there can be used huge files (many blocks) */\r
214     if (!ext4_sb_check_read_only(sb,\r
215             EXT4_FEATURE_RO_COMPAT_HUGE_FILE))\r
216         return EINVAL;\r
217 \r
218     /* 48-bit maximum */\r
219     max = 0;\r
220     max = ~max >> 16;\r
221 \r
222     if (count <= max) {\r
223         inode->blocks_count_lo = to_le32(count);\r
224         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
225         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
226     } else {\r
227         uint32_t block_bits = ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
228 \r
229         ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
230         count = count >> (block_bits - 9);\r
231         inode->blocks_count_lo = to_le32(count);\r
232         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
233     }\r
234 \r
235     return EOK;\r
236 }\r
237 \r
238 \r
239 uint32_t ext4_inode_get_flags(struct ext4_inode *inode)\r
240 {\r
241     return to_le32(inode->flags);\r
242 }\r
243 void     ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)\r
244 {\r
245     inode->flags =      to_le32(flags);\r
246 }\r
247 \r
248 uint32_t ext4_inode_get_generation(struct ext4_inode *inode)\r
249 {\r
250     return to_le32(inode->generation);\r
251 }\r
252 void     ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)\r
253 {\r
254     inode->generation = to_le32(gen);\r
255 }\r
256 \r
257 uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,\r
258     struct ext4_sblock *sb)\r
259 {\r
260     /*TODO: Verify it*/\r
261     uint64_t v = to_le32(inode->file_acl_lo);\r
262 \r
263     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
264         v |= ((uint32_t) to_le16(inode->osd2.linux2.file_acl_high)) << 16;\r
265 \r
266 \r
267     return v;\r
268 }\r
269 \r
270 void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,\r
271     uint64_t acl)\r
272 {\r
273     /*TODO: Verify it*/\r
274     inode->file_acl_lo = to_le32((acl << 32) >> 32);\r
275 \r
276     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
277         inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);\r
278 }\r
279 \r
280 \r
281 \r
282 uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)\r
283 {\r
284     return to_le32(inode->blocks[idx]);\r
285 }\r
286 void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,\r
287     uint32_t block)\r
288 {\r
289     inode->blocks[idx] = to_le32(block);\r
290 }\r
291 \r
292 \r
293 uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)\r
294 {\r
295     return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);\r
296 }\r
297 \r
298 void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,\r
299     uint32_t block)\r
300 {\r
301     inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);\r
302 }\r
303 \r
304 bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,\r
305     uint32_t type)\r
306 {\r
307     return (ext4_inode_get_mode(sb, inode) &\r
308             EXT4_INODE_MODE_TYPE_MASK) == type;\r
309 }\r
310 \r
311 bool     ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)\r
312 {\r
313     return ext4_inode_get_flags(inode) & f;\r
314 }\r
315 \r
316 void     ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)\r
317 {\r
318     uint32_t flags = ext4_inode_get_flags(inode);\r
319     flags = flags & (~f);\r
320     ext4_inode_set_flags(inode, flags);\r
321 }\r
322 \r
323 void     ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)\r
324 {\r
325     uint32_t flags = ext4_inode_get_flags(inode);\r
326     flags = flags | f;\r
327     ext4_inode_set_flags(inode, flags);\r
328 }\r
329 \r
330 bool     ext4_inode_can_truncate(struct ext4_sblock *sb,\r
331     struct ext4_inode *inode)\r
332 {\r
333     if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||\r
334             (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))\r
335         return false;\r
336 \r
337     if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||\r
338             (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))\r
339         return true;\r
340 \r
341     return false;\r
342 }\r
343 \r
344 \r
345 struct ext4_extent_header * ext4_inode_get_extent_header(\r
346     struct ext4_inode *inode)\r
347 {\r
348     return (struct ext4_extent_header *) inode->blocks;\r
349 }\r
350 \r
351 /**\r
352  * @}\r
353  */\r