ffe4596078557f7d6ffd1a5ffe1972c9430e210d
[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) &&\r
99         (ext4_inode_is_type(sb, inode, 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 uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)\r
121 {\r
122     return to_le32(inode->change_inode_time);\r
123 }\r
124 void ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time)\r
125 {\r
126     inode->change_inode_time = to_le32(time);\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, uint32_t time)\r
135 {\r
136     inode->modification_time = to_le32(time);\r
137 }\r
138 \r
139 uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)\r
140 {\r
141     return to_le32(inode->deletion_time);\r
142 }\r
143 \r
144 void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)\r
145 {\r
146     inode->deletion_time = to_le32(time);\r
147 }\r
148 \r
149 uint32_t ext4_inode_get_gid(struct ext4_inode *inode)\r
150 {\r
151     return to_le32(inode->gid);\r
152 }\r
153 void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)\r
154 {\r
155     inode->gid = to_le32(gid);\r
156 }\r
157 \r
158 uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)\r
159 {\r
160     return to_le16(inode->links_count);\r
161 }\r
162 void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)\r
163 {\r
164     inode->links_count = to_le16(cnt);\r
165 }\r
166 \r
167 uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,\r
168                                      struct ext4_inode *inode)\r
169 {\r
170     uint64_t count = to_le32(inode->blocks_count_lo);\r
171 \r
172     if (ext4_sb_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {\r
173 \r
174         /* 48-bit field */\r
175         count |= ((uint64_t)to_le16(inode->osd2.linux2.blocks_high)) << 32;\r
176 \r
177         if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {\r
178 \r
179             uint32_t block_bits =\r
180                 ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
181             return count << (block_bits - 9);\r
182         }\r
183     }\r
184 \r
185     return count;\r
186 }\r
187 \r
188 int ext4_inode_set_blocks_count(struct ext4_sblock *sb,\r
189                                 struct ext4_inode *inode, uint64_t count)\r
190 {\r
191     /* 32-bit maximum */\r
192     uint64_t max = 0;\r
193     max = ~max >> 32;\r
194 \r
195     if (count <= max) {\r
196         inode->blocks_count_lo = to_le32(count);\r
197         inode->osd2.linux2.blocks_high = 0;\r
198         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
199 \r
200         return EOK;\r
201     }\r
202 \r
203     /* Check if there can be used huge files (many blocks) */\r
204     if (!ext4_sb_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE))\r
205         return EINVAL;\r
206 \r
207     /* 48-bit maximum */\r
208     max = 0;\r
209     max = ~max >> 16;\r
210 \r
211     if (count <= max) {\r
212         inode->blocks_count_lo = to_le32(count);\r
213         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
214         ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
215     } else {\r
216         uint32_t block_bits =\r
217             ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));\r
218 \r
219         ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);\r
220         count = count >> (block_bits - 9);\r
221         inode->blocks_count_lo = to_le32(count);\r
222         inode->osd2.linux2.blocks_high = to_le16(count >> 32);\r
223     }\r
224 \r
225     return EOK;\r
226 }\r
227 \r
228 uint32_t ext4_inode_get_flags(struct ext4_inode *inode)\r
229 {\r
230     return to_le32(inode->flags);\r
231 }\r
232 void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)\r
233 {\r
234     inode->flags = to_le32(flags);\r
235 }\r
236 \r
237 uint32_t ext4_inode_get_generation(struct ext4_inode *inode)\r
238 {\r
239     return to_le32(inode->generation);\r
240 }\r
241 void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)\r
242 {\r
243     inode->generation = to_le32(gen);\r
244 }\r
245 \r
246 uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,\r
247                                  struct ext4_sblock *sb)\r
248 {\r
249     /*TODO: Verify it*/\r
250     uint64_t v = to_le32(inode->file_acl_lo);\r
251 \r
252     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
253         v |= ((uint32_t)to_le16(inode->osd2.linux2.file_acl_high)) << 16;\r
254 \r
255     return v;\r
256 }\r
257 \r
258 void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,\r
259                              uint64_t acl)\r
260 {\r
261     /*TODO: Verify it*/\r
262     inode->file_acl_lo = to_le32((acl << 32) >> 32);\r
263 \r
264     if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)\r
265         inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);\r
266 }\r
267 \r
268 uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)\r
269 {\r
270     return to_le32(inode->blocks[idx]);\r
271 }\r
272 void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,\r
273                                  uint32_t block)\r
274 {\r
275     inode->blocks[idx] = to_le32(block);\r
276 }\r
277 \r
278 uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)\r
279 {\r
280     return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);\r
281 }\r
282 \r
283 void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,\r
284                                    uint32_t block)\r
285 {\r
286     inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);\r
287 }\r
288 \r
289 bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,\r
290                         uint32_t type)\r
291 {\r
292     return (ext4_inode_get_mode(sb, inode) & EXT4_INODE_MODE_TYPE_MASK) == type;\r
293 }\r
294 \r
295 bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)\r
296 {\r
297     return ext4_inode_get_flags(inode) & f;\r
298 }\r
299 \r
300 void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)\r
301 {\r
302     uint32_t flags = ext4_inode_get_flags(inode);\r
303     flags = flags & (~f);\r
304     ext4_inode_set_flags(inode, flags);\r
305 }\r
306 \r
307 void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)\r
308 {\r
309     uint32_t flags = ext4_inode_get_flags(inode);\r
310     flags = flags | f;\r
311     ext4_inode_set_flags(inode, flags);\r
312 }\r
313 \r
314 bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode)\r
315 {\r
316     if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||\r
317         (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))\r
318         return false;\r
319 \r
320     if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||\r
321         (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))\r
322         return true;\r
323 \r
324     return false;\r
325 }\r
326 \r
327 struct ext4_extent_header *\r
328 ext4_inode_get_extent_header(struct ext4_inode *inode)\r
329 {\r
330     return (struct ext4_extent_header *)inode->blocks;\r
331 }\r
332 \r
333 /**\r
334  * @}\r
335  */\r