]> code.ossystems Code Review - openembedded-core.git/blob
215106edb8b6a0bdd404535f7ad52e9397089b21
[openembedded-core.git] /
1 Upstream-Status: Inappropriate [Backport]
2 From e3736c698e8b490bea1375576b718a2de6e89603 Mon Sep 17 00:00:00 2001
3 From: Donggeun Kim <dg77.kim@samsung.com>
4 Date: Thu, 8 Jul 2010 09:17:59 +0000
5 Subject: [PATCH 13/15] btrfs-progs: Add new feature to mkfs.btrfs to make file system image file from source directory
6
7 Changes from V1 to V2:
8 - support extended attributes
9 - move btrfs_alloc_data_chunk function to volumes.c
10 - fix an execution error when additional useless parameters are specified
11 - fix traverse_directory function so that the insertion functions for the common items are invoked in a single point
12
13 The extended attributes is implemented through llistxattr and getxattr function calls.
14
15 Thanks
16
17 Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
18 Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
19 Signed-off-by: Chris Mason <chris.mason@oracle.com>
20 ---
21  mkfs.c    |  864 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
22  volumes.c |  104 ++++++++
23  volumes.h |    3 +
24  3 files changed, 947 insertions(+), 24 deletions(-)
25
26 diff --git a/mkfs.c b/mkfs.c
27 index 04de93a..57c88f9 100644
28 --- a/mkfs.c
29 +++ b/mkfs.c
30 @@ -29,12 +29,14 @@
31  #include <stdlib.h>
32  #include <sys/types.h>
33  #include <sys/stat.h>
34 +#include <sys/dir.h>
35  #include <fcntl.h>
36  #include <unistd.h>
37  #include <getopt.h>
38  #include <uuid/uuid.h>
39  #include <linux/fs.h>
40  #include <ctype.h>
41 +#include <attr/xattr.h>
42  #include "kerncompat.h"
43  #include "ctree.h"
44  #include "disk-io.h"
45 @@ -43,6 +45,15 @@
46  #include "utils.h"
47  #include "version.h"
48  
49 +static u64 index_cnt = 2;
50 +
51 +struct directory_name_entry {
52 +       char *dir_name;
53 +       char *path;
54 +       ino_t inum;
55 +       struct list_head list;
56 +};
57 +
58  static u64 parse_size(char *s)
59  {
60         int len = strlen(s);
61 @@ -298,6 +309,7 @@ static void print_usage(void)
62         fprintf(stderr, "\t -M --mixed mix metadata and data together\n");
63         fprintf(stderr, "\t -n --nodesize size of btree nodes\n");
64         fprintf(stderr, "\t -s --sectorsize min block allocation\n");
65 +       fprintf(stderr, "\t -r --rootdir the source directory\n");
66         fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
67         exit(1);
68  }
69 @@ -355,9 +367,768 @@ static struct option long_options[] = {
70         { "sectorsize", 1, NULL, 's' },
71         { "data", 1, NULL, 'd' },
72         { "version", 0, NULL, 'V' },
73 +       { "rootdir", 1, NULL, 'r' },
74         { 0, 0, 0, 0}
75  };
76  
77 +static int add_directory_items(struct btrfs_trans_handle *trans,
78 +                              struct btrfs_root *root, u64 objectid,
79 +                              ino_t parent_inum, const char *name,
80 +                              struct stat *st, int *dir_index_cnt)
81 +{
82 +       int ret;
83 +       int name_len;
84 +       struct btrfs_key location;
85 +       u8 filetype = 0;
86 +
87 +       name_len = strlen(name);
88 +
89 +       location.objectid = objectid;
90 +       location.offset = 0;
91 +       btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY);
92 +
93 +       if (S_ISDIR(st->st_mode))
94 +               filetype = BTRFS_FT_DIR;
95 +       if (S_ISREG(st->st_mode))
96 +               filetype = BTRFS_FT_REG_FILE;
97 +       if (S_ISLNK(st->st_mode))
98 +               filetype = BTRFS_FT_SYMLINK;
99 +
100 +       ret = btrfs_insert_dir_item(trans, root, name, name_len,
101 +                                   parent_inum, &location,
102 +                                   filetype, index_cnt);
103 +
104 +       *dir_index_cnt = index_cnt;
105 +       index_cnt++;
106 +
107 +       return ret;
108 +}
109 +
110 +static int fill_inode_item(struct btrfs_trans_handle *trans,
111 +                          struct btrfs_root *root,
112 +                          struct btrfs_inode_item *dst, struct stat *src)
113 +{
114 +       u64 blocks = 0;
115 +       u64 sectorsize = root->sectorsize;
116 +
117 +       btrfs_set_stack_inode_generation(dst, trans->transid);
118 +       btrfs_set_stack_inode_size(dst, src->st_size);
119 +       btrfs_set_stack_inode_nbytes(dst, 0);
120 +       btrfs_set_stack_inode_block_group(dst, 0);
121 +       btrfs_set_stack_inode_nlink(dst, src->st_nlink);
122 +       btrfs_set_stack_inode_uid(dst, src->st_uid);
123 +       btrfs_set_stack_inode_gid(dst, src->st_gid);
124 +       btrfs_set_stack_inode_mode(dst, src->st_mode);
125 +       btrfs_set_stack_inode_rdev(dst, 0);
126 +       btrfs_set_stack_inode_flags(dst, 0);
127 +       btrfs_set_stack_timespec_sec(&dst->atime, src->st_atime);
128 +       btrfs_set_stack_timespec_nsec(&dst->atime, 0);
129 +       btrfs_set_stack_timespec_sec(&dst->ctime, src->st_ctime);
130 +       btrfs_set_stack_timespec_nsec(&dst->ctime, 0);
131 +       btrfs_set_stack_timespec_sec(&dst->mtime, src->st_mtime);
132 +       btrfs_set_stack_timespec_nsec(&dst->mtime, 0);
133 +       btrfs_set_stack_timespec_sec(&dst->otime, 0);
134 +       btrfs_set_stack_timespec_nsec(&dst->otime, 0);
135 +
136 +       if (S_ISDIR(src->st_mode)) {
137 +               btrfs_set_stack_inode_size(dst, 0);
138 +               btrfs_set_stack_inode_nlink(dst, 1);
139 +       }
140 +       if (S_ISREG(src->st_mode)) {
141 +               btrfs_set_stack_inode_size(dst, (u64)src->st_size);
142 +               if (src->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root))
143 +                       btrfs_set_stack_inode_nbytes(dst, src->st_size);
144 +               else {
145 +                       blocks = src->st_size / sectorsize;
146 +                       if (src->st_size % sectorsize)
147 +                               blocks += 1;
148 +                       blocks *= sectorsize;
149 +                       btrfs_set_stack_inode_nbytes(dst, blocks);
150 +               }
151 +       }
152 +       if (S_ISLNK(src->st_mode))
153 +               btrfs_set_stack_inode_nbytes(dst, src->st_size + 1);
154 +
155 +       return 0;
156 +}
157 +
158 +static int directory_select(const struct direct *entry)
159 +{
160 +       if ((strncmp(entry->d_name, ".", entry->d_reclen) == 0) ||
161 +               (strncmp(entry->d_name, "..", entry->d_reclen) == 0))
162 +               return 0;
163 +       else
164 +               return 1;
165 +}
166 +
167 +static u64 calculate_dir_inode_size(char *dirname)
168 +{
169 +       int count, i;
170 +       struct direct **files, *cur_file;
171 +       u64 dir_inode_size = 0;
172 +
173 +       count = scandir(dirname, &files, directory_select, NULL);
174 +
175 +       for (i = 0; i < count; i++) {
176 +               cur_file = files[i];
177 +               dir_inode_size += strlen(cur_file->d_name);
178 +       }
179 +
180 +       dir_inode_size *= 2;
181 +       return dir_inode_size;
182 +}
183 +
184 +static int add_inode_items(struct btrfs_trans_handle *trans,
185 +                          struct btrfs_root *root,
186 +                          struct stat *st, char *name,
187 +                          u64 self_objectid, ino_t parent_inum,
188 +                          int dir_index_cnt, struct btrfs_inode_item *inode_ret)
189 +{
190 +       int ret;
191 +       struct btrfs_key inode_key;
192 +       struct btrfs_inode_item btrfs_inode;
193 +       u64 objectid;
194 +       u64 inode_size = 0;
195 +       int name_len;
196 +
197 +       name_len = strlen(name);
198 +       fill_inode_item(trans, root, &btrfs_inode, st);
199 +       objectid = self_objectid;
200 +
201 +       if (S_ISDIR(st->st_mode)) {
202 +               inode_size = calculate_dir_inode_size(name);
203 +               btrfs_set_stack_inode_size(&btrfs_inode, inode_size);
204 +       }
205 +
206 +       inode_key.objectid = objectid;
207 +       inode_key.offset = 0;
208 +       btrfs_set_key_type(&inode_key, BTRFS_INODE_ITEM_KEY);
209 +
210 +       ret = btrfs_insert_inode(trans, root, objectid, &btrfs_inode);
211 +       if (ret)
212 +               goto fail;
213 +
214 +       ret = btrfs_insert_inode_ref(trans, root, name, name_len,
215 +                                    objectid, parent_inum, dir_index_cnt);
216 +       if (ret)
217 +               goto fail;
218 +
219 +       *inode_ret = btrfs_inode;
220 +fail:
221 +       return ret;
222 +}
223 +
224 +static int add_xattr_item(struct btrfs_trans_handle *trans,
225 +                         struct btrfs_root *root, u64 objectid,
226 +                         const char *file_name)
227 +{
228 +       int ret;
229 +       int cur_name_len;
230 +       char xattr_list[XATTR_LIST_MAX];
231 +       char *cur_name;
232 +       char cur_value[XATTR_SIZE_MAX];
233 +       char delimiter = '\0';
234 +       char *next_location = xattr_list;
235 +
236 +       ret = llistxattr(file_name, xattr_list, XATTR_LIST_MAX);
237 +       if (ret < 0) {
238 +               fprintf(stderr, "get a list of xattr failed for %s\n",
239 +                       file_name);
240 +               return ret;
241 +       }
242 +       if (ret == 0)
243 +               return ret;
244 +
245 +       cur_name = strtok(xattr_list, &delimiter);
246 +       while (cur_name != NULL) {
247 +               cur_name_len = strlen(cur_name);
248 +               next_location += cur_name_len + 1;
249 +
250 +               ret = getxattr(file_name, cur_name, cur_value, XATTR_SIZE_MAX);
251 +               if (ret < 0) {
252 +                       fprintf(stderr, "get a xattr value failed for %s\n",
253 +                               cur_name);
254 +               }
255 +
256 +               ret = btrfs_insert_xattr_item(trans, root, cur_name,
257 +                                             cur_name_len, cur_value,
258 +                                             ret, objectid);
259 +               if (ret) {
260 +                       fprintf(stderr, "insert a xattr item failed for %s\n",
261 +                               file_name);
262 +               }
263 +
264 +               cur_name = strtok(next_location, &delimiter);
265 +       }
266 +
267 +       return ret;
268 +}
269 +
270 +static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes,
271 +                              u64 hint_byte, struct btrfs_key *ins)
272 +{
273 +       u64 start;
274 +       u64 end;
275 +       u64 last = hint_byte;
276 +       int ret;
277 +       int wrapped = 0;
278 +       struct btrfs_block_group_cache *cache;
279 +
280 +       while (1) {
281 +               ret = find_first_extent_bit(&root->fs_info->free_space_cache,
282 +                                           last, &start, &end, EXTENT_DIRTY);
283 +               if (ret) {
284 +                       if (wrapped++ == 0) {
285 +                               last = 0;
286 +                               continue;
287 +                       } else {
288 +                               goto fail;
289 +                       }
290 +               }
291 +
292 +               start = max(last, start);
293 +               last = end + 1;
294 +               if (last - start < num_bytes)
295 +                       continue;
296 +
297 +               last = start + num_bytes;
298 +               if (test_range_bit(&root->fs_info->pinned_extents,
299 +                                  start, last - 1, EXTENT_DIRTY, 0))
300 +                       continue;
301 +
302 +               cache = btrfs_lookup_block_group(root->fs_info, start);
303 +               BUG_ON(!cache);
304 +               if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM ||
305 +                   last > cache->key.objectid + cache->key.offset) {
306 +                       last = cache->key.objectid + cache->key.offset;
307 +                       continue;
308 +               }
309 +
310 +               if (cache->flags & (BTRFS_BLOCK_GROUP_SYSTEM |
311 +                           BTRFS_BLOCK_GROUP_METADATA)) {
312 +                       last = cache->key.objectid + cache->key.offset;
313 +                       continue;
314 +               }
315 +
316 +               clear_extent_dirty(&root->fs_info->free_space_cache,
317 +                                  start, start + num_bytes - 1, 0);
318 +
319 +               ins->objectid = start;
320 +               ins->offset = num_bytes;
321 +               ins->type = BTRFS_EXTENT_ITEM_KEY;
322 +               return 0;
323 +       }
324 +fail:
325 +       fprintf(stderr, "not enough free space\n");
326 +       return -ENOSPC;
327 +}
328 +
329 +static int record_file_extent(struct btrfs_trans_handle *trans,
330 +                             struct btrfs_root *root, u64 objectid,
331 +                             struct btrfs_inode_item *inode,
332 +                             u64 file_pos, u64 disk_bytenr,
333 +                             u64 num_bytes)
334 +{
335 +       int ret;
336 +       struct btrfs_fs_info *info = root->fs_info;
337 +       struct btrfs_root *extent_root = info->extent_root;
338 +       struct extent_buffer *leaf;
339 +       struct btrfs_file_extent_item *fi;
340 +       struct btrfs_key ins_key;
341 +       struct btrfs_path path;
342 +       struct btrfs_extent_item *ei;
343 +
344 +       btrfs_init_path(&path);
345 +
346 +       ins_key.objectid = objectid;
347 +       ins_key.offset = 0;
348 +       btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY);
349 +       ret = btrfs_insert_empty_item(trans, root, &path, &ins_key,
350 +                                     sizeof(*fi));
351 +       if (ret)
352 +               goto fail;
353 +       leaf = path.nodes[0];
354 +       fi = btrfs_item_ptr(leaf, path.slots[0],
355 +                           struct btrfs_file_extent_item);
356 +       btrfs_set_file_extent_generation(leaf, fi, trans->transid);
357 +       btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
358 +       btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
359 +       btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
360 +       btrfs_set_file_extent_offset(leaf, fi, 0);
361 +       btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
362 +       btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
363 +       btrfs_set_file_extent_compression(leaf, fi, 0);
364 +       btrfs_set_file_extent_encryption(leaf, fi, 0);
365 +       btrfs_set_file_extent_other_encoding(leaf, fi, 0);
366 +       btrfs_mark_buffer_dirty(leaf);
367 +
368 +       btrfs_release_path(root, &path);
369 +
370 +       ins_key.objectid = disk_bytenr;
371 +       ins_key.offset = num_bytes;
372 +       ins_key.type = BTRFS_EXTENT_ITEM_KEY;
373 +
374 +       ret = btrfs_insert_empty_item(trans, extent_root, &path,
375 +                               &ins_key, sizeof(*ei));
376 +       if (ret == 0) {
377 +               leaf = path.nodes[0];
378 +               ei = btrfs_item_ptr(leaf, path.slots[0],
379 +                                   struct btrfs_extent_item);
380 +
381 +               btrfs_set_extent_refs(leaf, ei, 0);
382 +               btrfs_set_extent_generation(leaf, ei, trans->transid);
383 +               btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA);
384 +
385 +               btrfs_mark_buffer_dirty(leaf);
386 +               ret = btrfs_update_block_group(trans, root, disk_bytenr,
387 +                                              num_bytes, 1, 0);
388 +               if (ret)
389 +                       goto fail;
390 +       } else if (ret != -EEXIST) {
391 +               goto fail;
392 +       }
393 +
394 +       ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0,
395 +                                  root->root_key.objectid,
396 +                                  objectid, 0);
397 +fail:
398 +       btrfs_release_path(root, &path);
399 +       return ret;
400 +}
401 +
402 +static int add_symbolic_link(struct btrfs_trans_handle *trans,
403 +                            struct btrfs_root *root,
404 +                            u64 objectid, const char *path_name)
405 +{
406 +       int ret;
407 +       u64 sectorsize = root->sectorsize;
408 +       char *buf = malloc(sectorsize);
409 +
410 +       ret = readlink(path_name, buf, sectorsize);
411 +       if (ret <= 0) {
412 +               fprintf(stderr, "readlink failed for %s\n", path_name);
413 +               goto fail;
414 +       }
415 +       if (ret > sectorsize) {
416 +               fprintf(stderr, "symlink too long for %s", path_name);
417 +               ret = -1;
418 +               goto fail;
419 +       }
420 +       ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
421 +                                        buf, ret + 1);
422 +fail:
423 +       free(buf);
424 +       return ret;
425 +}
426 +
427 +static int add_file_items(struct btrfs_trans_handle *trans,
428 +                         struct btrfs_root *root,
429 +                         struct btrfs_inode_item *btrfs_inode, u64 objectid,
430 +                         ino_t parent_inum, struct stat *st,
431 +                         const char *path_name, int out_fd)
432 +{
433 +       int ret;
434 +       ssize_t ret_read;
435 +       u64 bytes_read = 0;
436 +       char *buffer = NULL;
437 +       struct btrfs_key key;
438 +       int blocks;
439 +       u32 sectorsize = root->sectorsize;
440 +       u64 first_block = 0;
441 +       u64 num_blocks = 0;
442 +       int fd;
443 +
444 +       fd = open(path_name, O_RDONLY);
445 +       if (fd == -1) {
446 +               fprintf(stderr, "%s open failed\n", path_name);
447 +               goto end;
448 +       }
449 +
450 +       blocks = st->st_size / sectorsize;
451 +       if (st->st_size % sectorsize)
452 +               blocks += 1;
453 +
454 +       if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
455 +               buffer = malloc(st->st_size);
456 +               ret_read = pread64(fd, buffer, st->st_size, bytes_read);
457 +               if (ret_read == -1) {
458 +                       fprintf(stderr, "%s read failed\n", path_name);
459 +                       goto end;
460 +               }
461 +
462 +               ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
463 +                                                buffer, st->st_size);
464 +               goto end;
465 +       }
466 +
467 +       ret = custom_alloc_extent(root, blocks * sectorsize, 0, &key);
468 +       if (ret)
469 +               goto end;
470 +
471 +       first_block = key.objectid;
472 +       bytes_read = 0;
473 +       buffer = malloc(sectorsize);
474 +
475 +       do {
476 +               memset(buffer, 0, sectorsize);
477 +               ret_read = pread64(fd, buffer, sectorsize, bytes_read);
478 +               if (ret_read == -1) {
479 +                       fprintf(stderr, "%s read failed\n", path_name);
480 +                       goto end;
481 +               }
482 +
483 +               ret = pwrite64(out_fd, buffer, sectorsize,
484 +                              first_block + bytes_read);
485 +               if (ret != sectorsize) {
486 +                       fprintf(stderr, "output file write failed\n");
487 +                       goto end;
488 +               }
489 +
490 +               /* checksum for file data */
491 +               ret = btrfs_csum_file_block(trans, root->fs_info->csum_root,
492 +                               first_block + (blocks * sectorsize),
493 +                               first_block + bytes_read,
494 +                               buffer, sectorsize);
495 +               if (ret) {
496 +                       fprintf(stderr, "%s checksum failed\n", path_name);
497 +                       goto end;
498 +               }
499 +
500 +               bytes_read += ret_read;
501 +               num_blocks++;
502 +       } while (ret_read == sectorsize);
503 +
504 +       if (num_blocks > 0) {
505 +               ret = record_file_extent(trans, root, objectid, btrfs_inode,
506 +                                        first_block, first_block,
507 +                                        blocks * sectorsize);
508 +               if (ret)
509 +                       goto end;
510 +       }
511 +
512 +end:
513 +       if (buffer)
514 +               free(buffer);
515 +       close(fd);
516 +       return ret;
517 +}
518 +
519 +static char *make_path(char *dir, char *name)
520 +{
521 +       char *path;
522 +
523 +       path = malloc(strlen(dir) + strlen(name) + 2);
524 +       if (!path)
525 +               return NULL;
526 +       strcpy(path, dir);
527 +       if (dir[strlen(dir) - 1] != '/')
528 +               strcat(path, "/");
529 +       strcat(path, name);
530 +       return path;
531 +}
532 +
533 +static int traverse_directory(struct btrfs_trans_handle *trans,
534 +                             struct btrfs_root *root, char *dir_name,
535 +                             struct directory_name_entry *dir_head, int out_fd)
536 +{
537 +       int ret = 0;
538 +
539 +       struct btrfs_inode_item cur_inode;
540 +       struct btrfs_inode_item *inode_item;
541 +       int count, i, dir_index_cnt;
542 +       struct direct **files;
543 +       struct stat st;
544 +       struct directory_name_entry *dir_entry, *parent_dir_entry;
545 +       struct direct *cur_file;
546 +       ino_t parent_inum, cur_inum;
547 +       ino_t highest_inum = 0;
548 +       char *parent_dir_name;
549 +       struct btrfs_path path;
550 +       struct extent_buffer *leaf;
551 +       struct btrfs_key root_dir_key;
552 +       u64 root_dir_inode_size = 0;
553 +
554 +       /* Add list for source directory */
555 +       dir_entry = malloc(sizeof(struct directory_name_entry));
556 +       dir_entry->dir_name = dir_name;
557 +       dir_entry->path = malloc(strlen(dir_name) + 1);
558 +       strcpy(dir_entry->path, dir_name);
559 +
560 +       parent_inum = highest_inum + BTRFS_FIRST_FREE_OBJECTID;
561 +       dir_entry->inum = parent_inum;
562 +       list_add_tail(&dir_entry->list, &dir_head->list);
563 +
564 +       btrfs_init_path(&path);
565 +
566 +       root_dir_key.objectid = btrfs_root_dirid(&root->root_item);
567 +       root_dir_key.offset = 0;
568 +       btrfs_set_key_type(&root_dir_key, BTRFS_INODE_ITEM_KEY);
569 +       ret = btrfs_lookup_inode(trans, root, &path, &root_dir_key, 1);
570 +       if (ret) {
571 +               fprintf(stderr, "root dir lookup error\n");
572 +               goto fail;
573 +       }
574 +
575 +       leaf = path.nodes[0];
576 +       inode_item = btrfs_item_ptr(leaf, path.slots[0],
577 +                                   struct btrfs_inode_item);
578 +
579 +       root_dir_inode_size = calculate_dir_inode_size(dir_name);
580 +       btrfs_set_inode_size(leaf, inode_item, root_dir_inode_size);
581 +       btrfs_mark_buffer_dirty(leaf);
582 +
583 +       btrfs_release_path(root, &path);
584 +
585 +       do {
586 +               parent_dir_entry = list_entry(dir_head->list.next,
587 +                                             struct directory_name_entry,
588 +                                             list);
589 +               list_del(&parent_dir_entry->list);
590 +
591 +               parent_inum = parent_dir_entry->inum;
592 +               parent_dir_name = parent_dir_entry->dir_name;
593 +               if (chdir(parent_dir_entry->path)) {
594 +                       fprintf(stderr, "chdir error for %s\n",
595 +                               parent_dir_name);
596 +                       goto fail;
597 +               }
598 +
599 +               count = scandir(parent_dir_entry->path, &files,
600 +                               directory_select, NULL);
601 +
602 +               for (i = 0; i < count; i++) {
603 +                       cur_file = files[i];
604 +
605 +                       if (lstat(cur_file->d_name, &st) == -1) {
606 +                               fprintf(stderr, "lstat failed for file %s\n",
607 +                                       cur_file->d_name);
608 +                               goto fail;
609 +                       }
610 +
611 +                       cur_inum = ++highest_inum + BTRFS_FIRST_FREE_OBJECTID;
612 +                       ret = add_directory_items(trans, root,
613 +                                                 cur_inum, parent_inum,
614 +                                                 cur_file->d_name,
615 +                                                 &st, &dir_index_cnt);
616 +                       if (ret) {
617 +                               fprintf(stderr, "add_directory_items failed\n");
618 +                               goto fail;
619 +                       }
620 +
621 +                       ret = add_inode_items(trans, root, &st,
622 +                                             cur_file->d_name, cur_inum,
623 +                                             parent_inum, dir_index_cnt,
624 +                                             &cur_inode);
625 +                       if (ret) {
626 +                               fprintf(stderr, "add_inode_items failed\n");
627 +                               goto fail;
628 +                       }
629 +
630 +                       ret = add_xattr_item(trans, root,
631 +                                            cur_inum, cur_file->d_name);
632 +                       if (ret) {
633 +                               fprintf(stderr, "add_xattr_item failed\n");
634 +                               goto fail;
635 +                       }
636 +
637 +                       if (S_ISDIR(st.st_mode)) {
638 +                               dir_entry = malloc(sizeof(struct directory_name_entry));
639 +                               dir_entry->dir_name = cur_file->d_name;
640 +                               dir_entry->path = make_path(parent_dir_entry->path,
641 +                                                           cur_file->d_name);
642 +                               dir_entry->inum = cur_inum;
643 +                               list_add_tail(&dir_entry->list, &dir_head->list);
644 +                       } else if (S_ISREG(st.st_mode)) {
645 +                               ret = add_file_items(trans, root, &cur_inode,
646 +                                                    cur_inum, parent_inum, &st,
647 +                                                    cur_file->d_name, out_fd);
648 +                               if (ret) {
649 +                                       fprintf(stderr, "add_file_items failed\n");
650 +                                       goto fail;
651 +                               }
652 +                       } else if (S_ISLNK(st.st_mode)) {
653 +                               ret = add_symbolic_link(trans, root,
654 +                                                       cur_inum, cur_file->d_name);
655 +                               if (ret) {
656 +                                       fprintf(stderr, "add_symbolic_link failed\n");
657 +                                       goto fail;
658 +                               }
659 +                       }
660 +               }
661 +
662 +               free(parent_dir_entry->path);
663 +               free(parent_dir_entry);
664 +
665 +               index_cnt = 2;
666 +
667 +       } while (!list_empty(&dir_head->list));
668 +
669 +       return 0;
670 +fail:
671 +       free(parent_dir_entry->path);
672 +       free(parent_dir_entry);
673 +       return -1;
674 +}
675 +
676 +static int open_target(char *output_name)
677 +{
678 +       int output_fd;
679 +       output_fd = open(output_name, O_CREAT | O_RDWR | O_TRUNC,
680 +                        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
681 +
682 +       return output_fd;
683 +}
684 +
685 +static int create_chunks(struct btrfs_trans_handle *trans,
686 +                        struct btrfs_root *root, u64 num_of_meta_chunks,
687 +                        u64 size_of_data)
688 +{
689 +       u64 chunk_start;
690 +       u64 chunk_size;
691 +       u64 meta_type = BTRFS_BLOCK_GROUP_METADATA;
692 +       u64 data_type = BTRFS_BLOCK_GROUP_DATA;
693 +       u64 minimum_data_chunk_size = 64 * 1024 * 1024;
694 +       u64 i;
695 +       int ret;
696 +
697 +       for (i = 0; i < num_of_meta_chunks; i++) {
698 +               ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
699 +                                       &chunk_start, &chunk_size, meta_type);
700 +               BUG_ON(ret);
701 +               ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
702 +                                            meta_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
703 +                                            chunk_start, chunk_size);
704 +               BUG_ON(ret);
705 +               set_extent_dirty(&root->fs_info->free_space_cache,
706 +                                chunk_start, chunk_start + chunk_size - 1, 0);
707 +       }
708 +
709 +       if (size_of_data < minimum_data_chunk_size)
710 +               size_of_data = minimum_data_chunk_size;
711 +       ret = btrfs_alloc_data_chunk(trans, root->fs_info->extent_root,
712 +                                    &chunk_start, size_of_data, data_type);
713 +       BUG_ON(ret);
714 +       ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
715 +                                    data_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
716 +                                    chunk_start, size_of_data);
717 +       BUG_ON(ret);
718 +       set_extent_dirty(&root->fs_info->free_space_cache,
719 +                        chunk_start, chunk_start + size_of_data - 1, 0);
720 +       return ret;
721 +}
722 +
723 +static int make_image(char *source_dir, struct btrfs_root *root, int out_fd)
724 +{
725 +       int ret;
726 +       struct btrfs_trans_handle *trans;
727 +
728 +       struct stat root_st;
729 +       int root_len;
730 +
731 +       struct directory_name_entry dir_head;
732 +
733 +       ret = lstat(source_dir, &root_st);
734 +       if (ret) {
735 +               fprintf(stderr, "unable to lstat the %s\n", source_dir);
736 +               goto fail;
737 +       }
738 +
739 +       root_len = strlen(source_dir);
740 +
741 +       INIT_LIST_HEAD(&dir_head.list);
742 +
743 +       trans = btrfs_start_transaction(root, 1);
744 +       ret = traverse_directory(trans, root, source_dir, &dir_head, out_fd);
745 +       if (ret) {
746 +               fprintf(stderr, "unable to traverse_directory\n");
747 +               goto fail;
748 +       }
749 +       btrfs_commit_transaction(trans, root);
750 +
751 +       printf("Making image is completed.\n");
752 +       return 0;
753 +fail:
754 +       fprintf(stderr, "Making image is aborted.\n");
755 +       return -1;
756 +}
757 +
758 +static u64 size_sourcedir(char *dir_name, u64 sectorsize,
759 +                         u64 *num_of_meta_chunks_ret, u64 *size_of_data_ret)
760 +{
761 +       u64 dir_size = 0;
762 +       u64 total_size = 0;
763 +       int ret;
764 +       char command[1024];
765 +       char path[512];
766 +       char *file_name = "temp_file";
767 +       FILE *file;
768 +       u64 minimum_data_size = 256 * 1024 * 1024;      /* 256MB */
769 +       u64 default_chunk_size = 8 * 1024 * 1024;       /* 8MB */
770 +       u64 allocated_meta_size = 8 * 1024 * 1024;      /* 8MB */
771 +       u64 allocated_total_size = 20 * 1024 * 1024;    /* 20MB */
772 +       u64 num_of_meta_chunks = 0;
773 +       u64 num_of_allocated_meta_chunks =
774 +                       allocated_meta_size / default_chunk_size;
775 +
776 +       ret = sprintf(command, "du -B 4096 -s ");
777 +       if (ret < 0) {
778 +               fprintf(stderr, "error executing sprintf for du command\n");
779 +               return -1;
780 +       }
781 +       strcat(command, dir_name);
782 +       strcat(command, " > ");
783 +       strcat(command, file_name);
784 +       ret = system(command);
785 +
786 +       file = fopen(file_name, "r");
787 +       ret = fscanf(file, "%lld %s\n", &dir_size, path);
788 +       fclose(file);
789 +       remove(file_name);
790 +
791 +       dir_size *= sectorsize;
792 +       *size_of_data_ret = dir_size;
793 +
794 +       num_of_meta_chunks = (dir_size / 2) / default_chunk_size;
795 +       if (((dir_size / 2) % default_chunk_size) != 0)
796 +               num_of_meta_chunks++;
797 +       if (num_of_meta_chunks <= num_of_allocated_meta_chunks)
798 +               num_of_meta_chunks = 0;
799 +       else
800 +               num_of_meta_chunks -= num_of_allocated_meta_chunks;
801 +
802 +       total_size = allocated_total_size + dir_size +
803 +                    (num_of_meta_chunks * default_chunk_size);
804 +
805 +       *num_of_meta_chunks_ret = num_of_meta_chunks;
806 +
807 +       if (total_size < minimum_data_size)
808 +               total_size = minimum_data_size;
809 +
810 +       return total_size;
811 +}
812 +
813 +static int zero_output_file(int out_fd, u64 size, u32 sectorsize)
814 +{
815 +       int len = sectorsize;
816 +       int loop_num = size / sectorsize;
817 +       u64 location = 0;
818 +       char *buf = malloc(len);
819 +       int ret = 0, i;
820 +       ssize_t written;
821 +
822 +       if (!buf)
823 +               return -ENOMEM;
824 +       memset(buf, 0, len);
825 +       for (i = 0; i < loop_num; i++) {
826 +               written = pwrite64(out_fd, buf, len, location);
827 +               if (written != len)
828 +                       ret = -EIO;
829 +               location += sectorsize;
830 +       }
831 +       free(buf);
832 +       return ret;
833 +}
834 +
835  int main(int ac, char **av)
836  {
837         char *file;
838 @@ -385,9 +1156,15 @@ int main(int ac, char **av)
839         int data_profile_opt = 0;
840         int metadata_profile_opt = 0;
841  
842 +       char *source_dir = NULL;
843 +       int source_dir_set = 0;
844 +       char *output = "output.img";
845 +       u64 num_of_meta_chunks = 0;
846 +       u64 size_of_data = 0;
847 +
848         while(1) {
849                 int c;
850 -               c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options,
851 +               c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:r:VM", long_options,
852                                 &option_index);
853                 if (c < 0)
854                         break;
855 @@ -430,6 +1207,10 @@ int main(int ac, char **av)
856                         case 'V':
857                                 print_version();
858                                 break;
859 +                       case 'r':
860 +                               source_dir = optarg;
861 +                               source_dir_set = 1;
862 +                               break;
863                         default:
864                                 print_usage();
865                 }
866 @@ -443,6 +1224,8 @@ int main(int ac, char **av)
867                 fprintf(stderr, "Illegal nodesize %u\n", nodesize);
868                 exit(1);
869         }
870 +       if (source_dir_set)
871 +               ac++;
872         ac = ac - optind;
873         if (ac == 0)
874                 print_usage();
875 @@ -450,28 +1233,47 @@ int main(int ac, char **av)
876         printf("\nWARNING! - %s IS EXPERIMENTAL\n", BTRFS_BUILD_VERSION);
877         printf("WARNING! - see http://btrfs.wiki.kernel.org before using\n\n");
878  
879 -       file = av[optind++];
880 -       ret = check_mounted(file);
881 -       if (ret < 0) {
882 -               fprintf(stderr, "error checking %s mount status\n", file);
883 -               exit(1);
884 -       }
885 -       if (ret == 1) {
886 -               fprintf(stderr, "%s is mounted\n", file);
887 -               exit(1);
888 -       }
889 -       ac--;
890 -       fd = open(file, O_RDWR);
891 -       if (fd < 0) {
892 -               fprintf(stderr, "unable to open %s\n", file);
893 -               exit(1);
894 +       if (source_dir == 0) {
895 +               file = av[optind++];
896 +               ret = check_mounted(file);
897 +               if (ret < 0) {
898 +                       fprintf(stderr, "error checking %s mount status\n", file);
899 +                       exit(1);
900 +               }
901 +               if (ret == 1) {
902 +                       fprintf(stderr, "%s is mounted\n", file);
903 +                       exit(1);
904 +               }
905 +               ac--;
906 +               fd = open(file, O_RDWR);
907 +               if (fd < 0) {
908 +                       fprintf(stderr, "unable to open %s\n", file);
909 +                       exit(1);
910 +               }
911 +               first_fd = fd;
912 +               first_file = file;
913 +               ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, &mixed);
914 +               if (block_count == 0)
915 +                       block_count = dev_block_count;
916 +       } else {
917 +               ac = 0;
918 +               fd = open_target(output);
919 +               if (fd < 0) {
920 +                       fprintf(stderr, "unable to open the %s\n", file);
921 +                       exit(1);
922 +               }
923 +
924 +               file = output;
925 +               first_fd = fd;
926 +               first_file = file;
927 +               block_count = size_sourcedir(source_dir, sectorsize,
928 +                                            &num_of_meta_chunks, &size_of_data);
929 +               ret = zero_output_file(fd, block_count, sectorsize);
930 +               if (ret) {
931 +                       fprintf(stderr, "unable to zero the output file\n");
932 +                       exit(1);
933 +               }
934         }
935 -       first_fd = fd;
936 -       first_file = file;
937 -       ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count,
938 -                                  &mixed);
939 -       if (block_count == 0)
940 -               block_count = dev_block_count;
941         if (mixed) {
942                 if (!metadata_profile_opt)
943                         metadata_profile = 0;
944 @@ -558,9 +1360,11 @@ int main(int ac, char **av)
945         }
946  
947  raid_groups:
948 -       ret = create_raid_groups(trans, root, data_profile,
949 +       if (!source_dir_set) {
950 +               ret = create_raid_groups(trans, root, data_profile,
951                                  metadata_profile, mixed);
952 -       BUG_ON(ret);
953 +               BUG_ON(ret);
954 +       }
955  
956         ret = create_data_reloc_tree(trans, root);
957         BUG_ON(ret);
958 @@ -580,6 +1384,18 @@ raid_groups:
959  
960         printf("%s\n", BTRFS_BUILD_VERSION);
961         btrfs_commit_transaction(trans, root);
962 +
963 +       if (source_dir_set) {
964 +               trans = btrfs_start_transaction(root, 1);
965 +               ret = create_chunks(trans, root,
966 +                                   num_of_meta_chunks, size_of_data);
967 +               BUG_ON(ret);
968 +               btrfs_commit_transaction(trans, root);
969 +
970 +               ret = make_image(source_dir, root, fd);
971 +               BUG_ON(ret);
972 +       }
973 +
974         ret = close_ctree(root);
975         BUG_ON(ret);
976  
977 diff --git a/volumes.c b/volumes.c
978 index 7671855..4bb77e2 100644
979 --- a/volumes.c
980 +++ b/volumes.c
981 @@ -857,6 +857,110 @@ again:
982         return ret;
983  }
984  
985 +int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
986 +                          struct btrfs_root *extent_root, u64 *start,
987 +                          u64 num_bytes, u64 type)
988 +{
989 +       u64 dev_offset;
990 +       struct btrfs_fs_info *info = extent_root->fs_info;
991 +       struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root;
992 +       struct btrfs_stripe *stripes;
993 +       struct btrfs_device *device = NULL;
994 +       struct btrfs_chunk *chunk;
995 +       struct list_head *dev_list = &extent_root->fs_info->fs_devices->devices;
996 +       struct list_head *cur;
997 +       struct map_lookup *map;
998 +       u64 physical;
999 +       u64 calc_size = 8 * 1024 * 1024;
1000 +       int num_stripes = 1;
1001 +       int sub_stripes = 0;
1002 +       int ret;
1003 +       int index;
1004 +       int stripe_len = 64 * 1024;
1005 +       struct btrfs_key key;
1006 +
1007 +       key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
1008 +       key.type = BTRFS_CHUNK_ITEM_KEY;
1009 +       ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
1010 +                             &key.offset);
1011 +       if (ret)
1012 +               return ret;
1013 +
1014 +       chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS);
1015 +       if (!chunk)
1016 +               return -ENOMEM;
1017 +
1018 +       map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
1019 +       if (!map) {
1020 +               kfree(chunk);
1021 +               return -ENOMEM;
1022 +       }
1023 +
1024 +       stripes = &chunk->stripe;
1025 +       calc_size = num_bytes;
1026 +
1027 +       index = 0;
1028 +       cur = dev_list->next;
1029 +       device = list_entry(cur, struct btrfs_device, dev_list);
1030 +
1031 +       while (index < num_stripes) {
1032 +               struct btrfs_stripe *stripe;
1033 +
1034 +               ret = btrfs_alloc_dev_extent(trans, device,
1035 +                            info->chunk_root->root_key.objectid,
1036 +                            BTRFS_FIRST_CHUNK_TREE_OBJECTID, key.offset,
1037 +                            calc_size, &dev_offset);
1038 +               BUG_ON(ret);
1039 +
1040 +               device->bytes_used += calc_size;
1041 +               ret = btrfs_update_device(trans, device);
1042 +               BUG_ON(ret);
1043 +
1044 +               map->stripes[index].dev = device;
1045 +               map->stripes[index].physical = dev_offset;
1046 +               stripe = stripes + index;
1047 +               btrfs_set_stack_stripe_devid(stripe, device->devid);
1048 +               btrfs_set_stack_stripe_offset(stripe, dev_offset);
1049 +               memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE);
1050 +               physical = dev_offset;
1051 +               index++;
1052 +       }
1053 +
1054 +       /* key was set above */
1055 +       btrfs_set_stack_chunk_length(chunk, num_bytes);
1056 +       btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid);
1057 +       btrfs_set_stack_chunk_stripe_len(chunk, stripe_len);
1058 +       btrfs_set_stack_chunk_type(chunk, type);
1059 +       btrfs_set_stack_chunk_num_stripes(chunk, num_stripes);
1060 +       btrfs_set_stack_chunk_io_align(chunk, stripe_len);
1061 +       btrfs_set_stack_chunk_io_width(chunk, stripe_len);
1062 +       btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize);
1063 +       btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes);
1064 +       map->sector_size = extent_root->sectorsize;
1065 +       map->stripe_len = stripe_len;
1066 +       map->io_align = stripe_len;
1067 +       map->io_width = stripe_len;
1068 +       map->type = type;
1069 +       map->num_stripes = num_stripes;
1070 +       map->sub_stripes = sub_stripes;
1071 +
1072 +       ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
1073 +                               btrfs_chunk_item_size(num_stripes));
1074 +       BUG_ON(ret);
1075 +       *start = key.offset;
1076 +
1077 +       map->ce.start = key.offset;
1078 +       map->ce.size = num_bytes;
1079 +
1080 +       ret = insert_existing_cache_extent(
1081 +                          &extent_root->fs_info->mapping_tree.cache_tree,
1082 +                          &map->ce);
1083 +       BUG_ON(ret);
1084 +
1085 +       kfree(chunk);
1086 +       return ret;
1087 +}
1088 +
1089  void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
1090  {
1091         cache_tree_init(&tree->cache_tree);
1092 diff --git a/volumes.h b/volumes.h
1093 index bb78751..93b0e48 100644
1094 --- a/volumes.h
1095 +++ b/volumes.h
1096 @@ -107,6 +107,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root);
1097  int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
1098                       struct btrfs_root *extent_root, u64 *start,
1099                       u64 *num_bytes, u64 type);
1100 +int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
1101 +                          struct btrfs_root *extent_root, u64 *start,
1102 +                          u64 num_bytes, u64 type);
1103  int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
1104  int btrfs_add_device(struct btrfs_trans_handle *trans,
1105                      struct btrfs_root *root,
1106 -- 
1107 1.7.2.3
1108