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