• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/make_ext4fs/contents.c

  1 /*
  2  * Copyright (C) 2010 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 #include <sys/stat.h>
 18 #include <string.h>
 19 #include <stdio.h>
 20 
 21 #include <private/android_filesystem_capability.h>
 22 
 23 #define XATTR_SELINUX_SUFFIX "selinux"
 24 #define XATTR_CAPS_SUFFIX "capability"
 25 
 26 #include "ext4_utils.h"
 27 #include "allocate.h"
 28 #include "contents.h"
 29 #include "extent.h"
 30 #include "indirect.h"
 31 
 32 static struct block_allocation* saved_allocation_head = NULL;
 33 
 34 struct block_allocation* get_saved_allocation_chain() {
 35         return saved_allocation_head;
 36 }
 37 
 38 static u32 dentry_size(u32 entries, struct dentry *dentries)
 39 {
 40         u32 len = 24;
 41         unsigned int i;
 42         unsigned int dentry_len;
 43 
 44         for (i = 0; i < entries; i++) {
 45                 dentry_len = 8 + EXT4_ALIGN(strlen(dentries[i].filename), 4);
 46                 if (len % info.block_size + dentry_len > info.block_size)
 47                         len += info.block_size - (len % info.block_size);
 48                 len += dentry_len;
 49         }
 50 
 51         return len;
 52 }
 53 
 54 static struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset,
 55                 struct ext4_dir_entry_2 *prev, u32 inode, const char *name,
 56                 u8 file_type)
 57 {
 58         u8 name_len = strlen(name);
 59         u16 rec_len = 8 + EXT4_ALIGN(name_len, 4);
 60         struct ext4_dir_entry_2 *dentry;
 61 
 62         u32 start_block = *offset / info.block_size;
 63         u32 end_block = (*offset + rec_len - 1) / info.block_size;
 64         if (start_block != end_block) {
 65                 /* Adding this dentry will cross a block boundary, so pad the previous
 66                    dentry to the block boundary */
 67                 if (!prev)
 68                         critical_error("no prev");
 69                 prev->rec_len += end_block * info.block_size - *offset;
 70                 *offset = end_block * info.block_size;
 71         }
 72 
 73         dentry = (struct ext4_dir_entry_2 *)(data + *offset);
 74         dentry->inode = inode;
 75         dentry->rec_len = rec_len;
 76         dentry->name_len = name_len;
 77         dentry->file_type = file_type;
 78         memcpy(dentry->name, name, name_len);
 79 
 80         *offset += rec_len;
 81         return dentry;
 82 }
 83 
 84 /* Creates a directory structure for an array of directory entries, dentries,
 85    and stores the location of the structure in an inode.  The new inode's
 86    .. link is set to dir_inode_num.  Stores the location of the inode number
 87    of each directory entry into dentries[i].inode, to be filled in later
 88    when the inode for the entry is allocated.  Returns the inode number of the
 89    new directory */
 90 u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
 91         u32 dirs)
 92 {
 93         struct ext4_inode *inode;
 94         u32 blocks;
 95         u32 len;
 96         u32 offset = 0;
 97         u32 inode_num;
 98         u8 *data;
 99         unsigned int i;
100         struct ext4_dir_entry_2 *dentry;
101 
102         blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size);
103         len = blocks * info.block_size;
104 
105         if (dir_inode_num) {
106                 inode_num = allocate_inode();
107         } else {
108                 dir_inode_num = EXT4_ROOT_INO;
109                 inode_num = EXT4_ROOT_INO;
110         }
111 
112         if (inode_num == EXT4_ALLOCATE_FAILED) {
113                 error("failed to allocate inode\n");
114                 return EXT4_ALLOCATE_FAILED;
115         }
116 
117         add_directory(inode_num);
118 
119         inode = get_inode(inode_num);
120         if (inode == NULL) {
121                 error("failed to get inode %u", inode_num);
122                 return EXT4_ALLOCATE_FAILED;
123         }
124 
125         data = inode_allocate_data_extents(inode, len, len);
126         if (data == NULL) {
127                 error("failed to allocate %u extents", len);
128                 return EXT4_ALLOCATE_FAILED;
129         }
130 
131         inode->i_mode = S_IFDIR;
132         inode->i_links_count = dirs + 2;
133         inode->i_flags |= aux_info.default_i_flags;
134 
135         dentry = NULL;
136 
137         dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR);
138         if (!dentry) {
139                 error("failed to add . directory");
140                 return EXT4_ALLOCATE_FAILED;
141         }
142 
143         dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR);
144         if (!dentry) {
145                 error("failed to add .. directory");
146                 return EXT4_ALLOCATE_FAILED;
147         }
148 
149         for (i = 0; i < entries; i++) {
150                 dentry = add_dentry(data, &offset, dentry, 0,
151                                 dentries[i].filename, dentries[i].file_type);
152                 if (offset > len || (offset == len && i != entries - 1))
153                         critical_error("internal error: dentry for %s ends at %d, past %d\n",
154                                 dentries[i].filename, offset, len);
155                 dentries[i].inode = &dentry->inode;
156                 if (!dentry) {
157                         error("failed to add directory");
158                         return EXT4_ALLOCATE_FAILED;
159                 }
160         }
161 
162         /* pad the last dentry out to the end of the block */
163         dentry->rec_len += len - offset;
164 
165         return inode_num;
166 }
167 
168 /* Creates a file on disk.  Returns the inode number of the new file */
169 u32 make_file(const char *filename, u64 len)
170 {
171         struct ext4_inode *inode;
172         u32 inode_num;
173 
174         inode_num = allocate_inode();
175         if (inode_num == EXT4_ALLOCATE_FAILED) {
176                 error("failed to allocate inode\n");
177                 return EXT4_ALLOCATE_FAILED;
178         }
179 
180         inode = get_inode(inode_num);
181         if (inode == NULL) {
182                 error("failed to get inode %u", inode_num);
183                 return EXT4_ALLOCATE_FAILED;
184         }
185 
186         if (len > 0) {
187                 struct block_allocation* alloc = inode_allocate_file_extents(inode, len, filename);
188                 if (alloc) {
189                         alloc->filename = strdup(filename);
190                         alloc->next = saved_allocation_head;
191                         saved_allocation_head = alloc;
192                 }
193         }
194 
195         inode->i_mode = S_IFREG;
196         inode->i_links_count = 1;
197         inode->i_flags |= aux_info.default_i_flags;
198 
199         return inode_num;
200 }
201 
202 /* Creates a file on disk.  Returns the inode number of the new file */
203 u32 make_link(const char *link)
204 {
205         struct ext4_inode *inode;
206         u32 inode_num;
207         u32 len = strlen(link);
208 
209         inode_num = allocate_inode();
210         if (inode_num == EXT4_ALLOCATE_FAILED) {
211                 error("failed to allocate inode\n");
212                 return EXT4_ALLOCATE_FAILED;
213         }
214 
215         inode = get_inode(inode_num);
216         if (inode == NULL) {
217                 error("failed to get inode %u", inode_num);
218                 return EXT4_ALLOCATE_FAILED;
219         }
220 
221         inode->i_mode = S_IFLNK;
222         inode->i_links_count = 1;
223         inode->i_flags |= aux_info.default_i_flags;
224         inode->i_size_lo = len;
225 
226         if (len + 1 <= sizeof(inode->i_block)) {
227                 /* Fast symlink */
228                 memcpy((char*)inode->i_block, link, len);
229         } else {
230                 u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size);
231                 memcpy(data, link, len);
232                 inode->i_blocks_lo = info.block_size / 512;
233         }
234 
235         return inode_num;
236 }
237 
238 /* Creates a special file on disk.  Returns the inode number of the new file */
239 u32 make_special(const char *path)
240 {
241         struct ext4_inode *inode;
242         struct stat s;
243         u32 inode_num;
244 
245         if (stat(path, &s)) {
246                 error("failed to stat file\n");
247                 return EXT4_ALLOCATE_FAILED;
248         }
249 
250         inode_num = allocate_inode();
251         if (inode_num == EXT4_ALLOCATE_FAILED) {
252                 error("failed to allocate inode\n");
253                 return EXT4_ALLOCATE_FAILED;
254         }
255 
256         inode = get_inode(inode_num);
257         if (inode == NULL) {
258                 error("failed to get inode %u", inode_num);
259                 return EXT4_ALLOCATE_FAILED;
260         }
261 
262         inode->i_mode = s.st_mode & S_IFMT;
263         inode->i_links_count = 1;
264         inode->i_flags |= aux_info.default_i_flags;
265 
266         ((u8 *)inode->i_block)[0] = major(s.st_rdev);
267         ((u8 *)inode->i_block)[1] = minor(s.st_rdev);
268 
269         return inode_num;
270 }
271 
272 int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime)
273 {
274         struct ext4_inode *inode = get_inode(inode_num);
275 
276         if (!inode)
277                 return -1;
278 
279         inode->i_mode |= mode;
280         inode->i_uid = uid;
281         inode->i_gid = gid;
282         inode->i_mtime = mtime;
283         inode->i_atime = mtime;
284         inode->i_ctime = mtime;
285 
286         return 0;
287 }
288 
289 /*
290  * Returns the amount of free space available in the specified
291  * xattr region
292  */
293 static size_t xattr_free_space(struct ext4_xattr_entry *entry, char *end)
294 {
295         while(!IS_LAST_ENTRY(entry) && (((char *) entry) < end)) {
296                 end   -= EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
297                 entry  = EXT4_XATTR_NEXT(entry);
298         }
299 
300         if (((char *) entry) > end) {
301                 error("unexpected read beyond end of xattr space");
302                 return 0;
303         }
304 
305         return end - ((char *) entry);
306 }
307 
308 /*
309  * Returns a pointer to the free space immediately after the
310  * last xattr element
311  */
312 static struct ext4_xattr_entry* xattr_get_last(struct ext4_xattr_entry *entry)
313 {
314         for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
315                 // skip entry
316         }
317         return entry;
318 }
319 
320 /*
321  * assert that the elements in the ext4 xattr section are in sorted order
322  *
323  * The ext4 filesystem requires extended attributes to be sorted when
324  * they're not stored in the inode. The kernel ext4 code uses the following
325  * sorting algorithm:
326  *
327  * 1) First sort extended attributes by their name_index. For example,
328  *    EXT4_XATTR_INDEX_USER (1) comes before EXT4_XATTR_INDEX_SECURITY (6).
329  * 2) If the name_indexes are equal, then sorting is based on the length
330  *    of the name. For example, XATTR_SELINUX_SUFFIX ("selinux") comes before
331  *    XATTR_CAPS_SUFFIX ("capability") because "selinux" is shorter than "capability"
332  * 3) If the name_index and name_length are equal, then memcmp() is used to determine
333  *    which name comes first. For example, "selinux" would come before "yelinux".
334  *
335  * This method is intended to implement the sorting function defined in
336  * the Linux kernel file fs/ext4/xattr.c function ext4_xattr_find_entry().
337  */
338 static void xattr_assert_sane(struct ext4_xattr_entry *entry)
339 {
340         for( ; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
341                 struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
342                 if (IS_LAST_ENTRY(next)) {
343                         return;
344                 }
345 
346                 int cmp = next->e_name_index - entry->e_name_index;
347                 if (cmp == 0)
348                         cmp = next->e_name_len - entry->e_name_len;
349                 if (cmp == 0)
350                         cmp = memcmp(next->e_name, entry->e_name, next->e_name_len);
351                 if (cmp < 0) {
352                         error("BUG: extended attributes are not sorted\n");
353                         return;
354                 }
355                 if (cmp == 0) {
356                         error("BUG: duplicate extended attributes detected\n");
357                         return;
358                 }
359         }
360 }
361 
362 #define NAME_HASH_SHIFT 5
363 #define VALUE_HASH_SHIFT 16
364 
365 static void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
366                 struct ext4_xattr_entry *entry)
367 {
368         u32 hash = 0;
369         char *name = entry->e_name;
370         int n;
371 
372         for (n = 0; n < entry->e_name_len; n++) {
373                 hash = (hash << NAME_HASH_SHIFT) ^
374                         (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
375                         *name++;
376         }
377 
378         if (entry->e_value_block == 0 && entry->e_value_size != 0) {
379                 u32 *value = (u32 *)((char *)header +
380                         le16_to_cpu(entry->e_value_offs));
381                 for (n = (le32_to_cpu(entry->e_value_size) +
382                         EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
383                         hash = (hash << VALUE_HASH_SHIFT) ^
384                                 (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
385                                 le32_to_cpu(*value++);
386                 }
387         }
388         entry->e_hash = cpu_to_le32(hash);
389 }
390 
391 #undef NAME_HASH_SHIFT
392 #undef VALUE_HASH_SHIFT
393 
394 static struct ext4_xattr_entry* xattr_addto_range(
395                 void *block_start,
396                 void *block_end,
397                 struct ext4_xattr_entry *first,
398                 int name_index,
399                 const char *name,
400                 const void *value,
401                 size_t value_len)
402 {
403         size_t name_len = strlen(name);
404         if (name_len > 255)
405                 return NULL;
406 
407         size_t available_size = xattr_free_space(first, block_end);
408         size_t needed_size = EXT4_XATTR_LEN(name_len) + EXT4_XATTR_SIZE(value_len);
409 
410         if (needed_size > available_size)
411                 return NULL;
412 
413         struct ext4_xattr_entry *new_entry = xattr_get_last(first);
414         memset(new_entry, 0, EXT4_XATTR_LEN(name_len));
415 
416         new_entry->e_name_len = name_len;
417         new_entry->e_name_index = name_index;
418         memcpy(new_entry->e_name, name, name_len);
419         new_entry->e_value_block = 0;
420         new_entry->e_value_size = cpu_to_le32(value_len);
421 
422         char *val = (char *) new_entry + available_size - EXT4_XATTR_SIZE(value_len);
423         size_t e_value_offs = val - (char *) block_start;
424 
425         new_entry->e_value_offs = cpu_to_le16(e_value_offs);
426         memset(val, 0, EXT4_XATTR_SIZE(value_len));
427         memcpy(val, value, value_len);
428 
429         xattr_assert_sane(first);
430         return new_entry;
431 }
432 
433 static int xattr_addto_inode(struct ext4_inode *inode, int name_index,
434                 const char *name, const void *value, size_t value_len)
435 {
436         struct ext4_xattr_ibody_header *hdr = (struct ext4_xattr_ibody_header *) (inode + 1);
437         struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (hdr + 1);
438         char *block_end = ((char *) inode) + info.inode_size;
439 
440         struct ext4_xattr_entry *result =
441                 xattr_addto_range(first, block_end, first, name_index, name, value, value_len);
442 
443         if (result == NULL)
444                 return -1;
445 
446         hdr->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
447         inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
448 
449         return 0;
450 }
451 
452 static int xattr_addto_block(struct ext4_inode *inode, int name_index,
453                 const char *name, const void *value, size_t value_len)
454 {
455         struct ext4_xattr_header *header = get_xattr_block_for_inode(inode);
456         if (!header)
457                 return -1;
458 
459         struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (header + 1);
460         char *block_end = ((char *) header) + info.block_size;
461 
462         struct ext4_xattr_entry *result =
463                 xattr_addto_range(header, block_end, first, name_index, name, value, value_len);
464 
465         if (result == NULL)
466                 return -1;
467 
468         ext4_xattr_hash_entry(header, result);
469         return 0;
470 }
471 
472 
473 static int xattr_add(u32 inode_num, int name_index, const char *name,
474                 const void *value, size_t value_len)
475 {
476         if (!value)
477                 return 0;
478 
479         struct ext4_inode *inode = get_inode(inode_num);
480 
481         if (!inode)
482                 return -1;
483 
484         int result = xattr_addto_inode(inode, name_index, name, value, value_len);
485         if (result != 0) {
486                 result = xattr_addto_block(inode, name_index, name, value, value_len);
487         }
488         return result;
489 }
490 
491 int inode_set_capabilities(u32 inode_num, uint64_t capabilities) {
492         if (capabilities == 0)
493                 return 0;
494 
495         struct vfs_cap_data cap_data;
496         memset(&cap_data, 0, sizeof(cap_data));
497 
498         cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
499         cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
500         cap_data.data[0].inheritable = 0;
501         cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
502         cap_data.data[1].inheritable = 0;
503 
504         return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
505                 XATTR_CAPS_SUFFIX, &cap_data, sizeof(cap_data));
506 }
507 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt