2 * create_inode.c --- create an inode
4 * Copyright (C) 2014 Robert Yang <liezhi.yang@windriver.com>
7 * This file may be redistributed under the terms of the GNU library
8 * General Public License, version 2.
12 #define _FILE_OFFSET_BITS 64
13 #define _LARGEFILE64_SOURCE 1
18 #include <sys/types.h>
20 #include <limits.h> /* for PATH_MAX */
21 #ifdef HAVE_ATTR_XATTR_H
22 #include <attr/xattr.h>
24 #include <sys/ioctl.h>
25 #ifdef HAVE_SYS_SYSMACROS_H
26 #include <sys/sysmacros.h>
29 #include <ext2fs/ext2fs.h>
30 #include <ext2fs/ext2_types.h>
31 #include <ext2fs/fiemap.h>
33 #include "create_inode.h"
34 #include "support/nls-enable.h"
36 /* 64KiB is the minimum blksize to best minimize system call overhead. */
37 #define COPY_FILE_BUFLEN 65536
39 static int ext2_file_type(unsigned int mode)
41 if (LINUX_S_ISREG(mode))
42 return EXT2_FT_REG_FILE;
44 if (LINUX_S_ISDIR(mode))
47 if (LINUX_S_ISCHR(mode))
48 return EXT2_FT_CHRDEV;
50 if (LINUX_S_ISBLK(mode))
51 return EXT2_FT_BLKDEV;
53 if (LINUX_S_ISLNK(mode))
54 return EXT2_FT_SYMLINK;
56 if (LINUX_S_ISFIFO(mode))
59 if (LINUX_S_ISSOCK(mode))
65 /* Link an inode number to a directory */
66 static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
67 ext2_ino_t ino, const char *name)
69 struct ext2_inode inode;
72 retval = ext2fs_read_inode(fs, ino, &inode);
74 com_err(__func__, retval, _("while reading inode %u"), ino);
78 retval = ext2fs_link(fs, parent_ino, name, ino,
79 ext2_file_type(inode.i_mode));
80 if (retval == EXT2_ET_DIR_NO_SPACE) {
81 retval = ext2fs_expand_dir(fs, parent_ino);
83 com_err(__func__, retval,
84 _("while expanding directory"));
87 retval = ext2fs_link(fs, parent_ino, name, ino,
88 ext2_file_type(inode.i_mode));
91 com_err(__func__, retval, _("while linking \"%s\""), name);
95 inode.i_links_count++;
97 retval = ext2fs_write_inode(fs, ino, &inode);
99 com_err(__func__, retval, _("while writing inode %u"), ino);
104 /* Set the uid, gid, mode and time for the inode */
105 static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
109 struct ext2_inode inode;
111 retval = ext2fs_read_inode(fs, ino, &inode);
113 com_err(__func__, retval, _("while reading inode %u"), ino);
117 inode.i_uid = st->st_uid;
118 inode.i_gid = st->st_gid;
119 inode.i_mode |= st->st_mode;
120 inode.i_atime = st->st_atime;
121 inode.i_mtime = st->st_mtime;
122 inode.i_ctime = st->st_ctime;
124 retval = ext2fs_write_inode(fs, ino, &inode);
126 com_err(__func__, retval, _("while writing inode %u"), ino);
130 #ifdef HAVE_LLISTXATTR
131 static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino,
132 const char *filename)
134 errcode_t retval, close_retval;
135 struct ext2_xattr_handle *handle;
136 ssize_t size, value_size;
140 size = llistxattr(filename, NULL, 0);
143 com_err(__func__, retval, _("while listing attributes of \"%s\""),
146 } else if (size == 0) {
150 retval = ext2fs_xattrs_open(fs, ino, &handle);
152 if (retval == EXT2_ET_MISSING_EA_FEATURE)
154 com_err(__func__, retval, _("while opening inode %u"), ino);
158 retval = ext2fs_get_mem(size, &list);
160 com_err(__func__, retval, _("while allocating memory"));
164 size = llistxattr(filename, list, size);
167 com_err(__func__, retval, _("while listing attributes of \"%s\""),
172 for (i = 0; i < size; i += strlen(&list[i]) + 1) {
173 const char *name = &list[i];
176 value_size = lgetxattr(filename, name, NULL, 0);
177 if (value_size == -1) {
179 com_err(__func__, retval,
180 _("while reading attribute \"%s\" of \"%s\""),
185 retval = ext2fs_get_mem(value_size, &value);
187 com_err(__func__, retval, _("while allocating memory"));
191 value_size = lgetxattr(filename, name, value, value_size);
192 if (value_size == -1) {
193 ext2fs_free_mem(&value);
195 com_err(__func__, retval,
196 _("while reading attribute \"%s\" of \"%s\""),
201 retval = ext2fs_xattr_set(handle, name, value, value_size);
202 ext2fs_free_mem(&value);
204 com_err(__func__, retval,
205 _("while writing attribute \"%s\" to inode %u"),
212 ext2fs_free_mem(&list);
213 close_retval = ext2fs_xattrs_close(&handle);
215 com_err(__func__, retval, _("while closing inode %u"), ino);
216 retval = retval ? retval : close_retval;
221 #else /* HAVE_LLISTXATTR */
222 static errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)),
223 ext2_ino_t ino EXT2FS_ATTR((unused)),
224 const char *filename EXT2FS_ATTR((unused)))
228 #endif /* HAVE_LLISTXATTR */
230 /* Make a special files (block and character devices), fifo's, and sockets */
231 errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
236 struct ext2_inode inode;
237 unsigned long devmajor, devminor, mode;
240 switch(st->st_mode & S_IFMT) {
242 mode = LINUX_S_IFCHR;
243 filetype = EXT2_FT_CHRDEV;
246 mode = LINUX_S_IFBLK;
247 filetype = EXT2_FT_BLKDEV;
250 mode = LINUX_S_IFIFO;
251 filetype = EXT2_FT_FIFO;
254 mode = LINUX_S_IFSOCK;
255 filetype = EXT2_FT_SOCK;
258 return EXT2_ET_INVALID_ARGUMENT;
261 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
263 com_err(__func__, retval, _("while allocating inode \"%s\""),
269 printf("Allocated inode: %u\n", ino);
271 retval = ext2fs_link(fs, cwd, name, ino, filetype);
272 if (retval == EXT2_ET_DIR_NO_SPACE) {
273 retval = ext2fs_expand_dir(fs, cwd);
275 com_err(__func__, retval,
276 _("while expanding directory"));
279 retval = ext2fs_link(fs, cwd, name, ino, filetype);
282 com_err(name, retval, _("while creating inode \"%s\""), name);
285 if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
286 com_err(__func__, 0, "Warning: inode already set");
287 ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
288 memset(&inode, 0, sizeof(inode));
290 inode.i_atime = inode.i_ctime = inode.i_mtime =
291 fs->now ? fs->now : time(0);
293 if (filetype != S_IFIFO) {
294 devmajor = major(st->st_rdev);
295 devminor = minor(st->st_rdev);
297 if ((devmajor < 256) && (devminor < 256)) {
298 inode.i_block[0] = devmajor * 256 + devminor;
299 inode.i_block[1] = 0;
301 inode.i_block[0] = 0;
302 inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
303 ((devminor & ~0xff) << 12);
306 inode.i_links_count = 1;
308 retval = ext2fs_write_new_inode(fs, ino, &inode);
310 com_err(__func__, retval, _("while writing inode %u"), ino);
315 /* Make a symlink name -> target */
316 errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
317 char *target, ext2_ino_t root)
320 ext2_ino_t parent_ino;
323 cp = strrchr(name, '/');
326 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
328 com_err(name, retval, 0);
335 retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
336 if (retval == EXT2_ET_DIR_NO_SPACE) {
337 retval = ext2fs_expand_dir(fs, parent_ino);
339 com_err("do_symlink_internal", retval,
340 _("while expanding directory"));
343 retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
346 com_err("ext2fs_symlink", retval,
347 _("while creating symlink \"%s\""), name);
351 /* Make a directory in the fs */
352 errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
356 ext2_ino_t parent_ino;
360 cp = strrchr(name, '/');
363 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
365 com_err(name, retval, _("while looking up \"%s\""),
373 retval = ext2fs_mkdir(fs, parent_ino, 0, name);
374 if (retval == EXT2_ET_DIR_NO_SPACE) {
375 retval = ext2fs_expand_dir(fs, parent_ino);
377 com_err(__func__, retval,
378 _("while expanding directory"));
381 retval = ext2fs_mkdir(fs, parent_ino, 0, name);
384 com_err("ext2fs_mkdir", retval,
385 _("while creating directory \"%s\""), name);
389 #if !defined HAVE_PREAD64 && !defined HAVE_PREAD
390 static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset)
392 if (lseek(fd, offset, SEEK_SET) < 0)
395 return read(fd, buf, count);
397 #endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */
399 static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file,
400 off_t start, off_t end, char *buf,
405 unsigned int written;
409 for (off = start; off < end; off += COPY_FILE_BUFLEN) {
411 got = pread64(fd, buf, COPY_FILE_BUFLEN, off);
413 got = pread(fd, buf, COPY_FILE_BUFLEN, off);
415 got = my_pread(fd, buf, COPY_FILE_BUFLEN, off);
421 for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) {
422 blen = fs->blocksize;
423 if (blen > got - bpos)
425 if (memcmp(ptr, zerobuf, blen) == 0) {
429 err = ext2fs_file_lseek(e2_file, off + bpos,
430 EXT2_SEEK_SET, NULL);
434 err = ext2fs_file_write(e2_file, ptr, blen,
451 #if defined(SEEK_DATA) && defined(SEEK_HOLE)
452 static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf,
453 ext2_file_t e2_file, char *buf, char *zerobuf)
455 off_t data = 0, hole;
456 off_t data_blk, hole_blk;
459 /* Try to use SEEK_DATA and SEEK_HOLE */
460 while (data < statbuf->st_size) {
461 data = lseek(fd, data, SEEK_DATA);
465 return EXT2_ET_UNIMPLEMENTED;
467 hole = lseek(fd, data, SEEK_HOLE);
469 return EXT2_ET_UNIMPLEMENTED;
471 data_blk = data & ~(fs->blocksize - 1);
472 hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1);
473 err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf,
483 #endif /* SEEK_DATA and SEEK_HOLE */
485 #if defined(FS_IOC_FIEMAP)
486 static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file,
487 char *buf, char *zerobuf)
489 #define EXTENT_MAX_COUNT 512
490 struct fiemap *fiemap_buf;
491 struct fiemap_extent *ext_buf, *ext;
492 int ext_buf_size, fie_buf_size;
497 ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
498 fie_buf_size = sizeof(struct fiemap) + ext_buf_size;
500 err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf);
504 ext_buf = fiemap_buf->fm_extents;
505 memset(fiemap_buf, 0, fie_buf_size);
506 fiemap_buf->fm_length = FIEMAP_MAX_OFFSET;
507 fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC;
508 fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT;
511 fiemap_buf->fm_start = pos;
512 memset(ext_buf, 0, ext_buf_size);
513 err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
514 if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) {
515 err = EXT2_ET_UNIMPLEMENTED;
517 } else if (err < 0) {
520 } else if (fiemap_buf->fm_mapped_extents == 0)
522 for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents;
524 err = copy_file_range(fs, fd, e2_file, ext->fe_logical,
525 ext->fe_logical + ext->fe_length,
532 /* Record file's logical offset this time */
533 pos = ext->fe_logical + ext->fe_length;
535 * If fm_extents array has been filled and
536 * there are extents left, continue to cycle.
538 } while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT &&
539 !(ext->fe_flags & FIEMAP_EXTENT_LAST));
541 ext2fs_free_mem(&fiemap_buf);
544 #endif /* FS_IOC_FIEMAP */
546 static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf,
550 char *buf = NULL, *zerobuf = NULL;
551 errcode_t err, close_err;
553 err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
557 err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf);
561 err = ext2fs_get_memzero(fs->blocksize, &zerobuf);
565 #if defined(SEEK_DATA) && defined(SEEK_HOLE)
566 err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf);
567 if (err != EXT2_ET_UNIMPLEMENTED)
571 #if defined(FS_IOC_FIEMAP)
572 err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf);
573 if (err != EXT2_ET_UNIMPLEMENTED)
577 err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf,
580 ext2fs_free_mem(&zerobuf);
581 ext2fs_free_mem(&buf);
582 close_err = ext2fs_file_close(e2_file);
588 static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
592 for (i = 0; i < hdlinks->count; i++) {
593 if (hdlinks->hdl[i].src_dev == dev &&
594 hdlinks->hdl[i].src_ino == ino)
600 /* Copy the native file to the fs */
601 errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
602 const char *dest, ext2_ino_t root)
608 struct ext2_inode inode;
610 fd = ext2fs_open_file(src, O_RDONLY, 0);
613 com_err(__func__, retval, _("while opening \"%s\" to copy"),
617 if (fstat(fd, &statbuf) < 0) {
622 retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
624 retval = EXT2_ET_FILE_EXISTS;
628 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
632 printf("Allocated inode: %u\n", newfile);
634 retval = ext2fs_link(fs, cwd, dest, newfile,
636 if (retval == EXT2_ET_DIR_NO_SPACE) {
637 retval = ext2fs_expand_dir(fs, cwd);
640 retval = ext2fs_link(fs, cwd, dest, newfile,
645 if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
646 com_err(__func__, 0, "Warning: inode already set");
647 ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
648 memset(&inode, 0, sizeof(inode));
649 inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
650 inode.i_atime = inode.i_ctime = inode.i_mtime =
651 fs->now ? fs->now : time(0);
652 inode.i_links_count = 1;
653 retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
656 if (ext2fs_has_feature_inline_data(fs->super)) {
657 inode.i_flags |= EXT4_INLINE_DATA_FL;
658 } else if (ext2fs_has_feature_extents(fs->super)) {
659 ext2_extent_handle_t handle;
661 inode.i_flags &= ~EXT4_EXTENTS_FL;
662 retval = ext2fs_extent_open2(fs, newfile, &inode, &handle);
665 ext2fs_extent_free(handle);
668 retval = ext2fs_write_new_inode(fs, newfile, &inode);
671 if (inode.i_flags & EXT4_INLINE_DATA_FL) {
672 retval = ext2fs_inline_data_init(fs, newfile);
676 if (LINUX_S_ISREG(inode.i_mode)) {
677 retval = copy_file(fs, fd, &statbuf, newfile);
692 static errcode_t path_append(struct file_info *target, const char *file)
694 if (strlen(file) + target->path_len + 1 > target->path_max_len) {
695 target->path_max_len *= 2;
696 target->path = realloc(target->path, target->path_max_len);
698 return EXT2_ET_NO_MEMORY;
700 target->path_len += sprintf(target->path + target->path_len, "/%s",
705 /* Copy files from source_dir to fs */
706 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
707 const char *source_dir, ext2_ino_t root,
708 struct hdlinks_s *hdlinks,
709 struct file_info *target,
710 struct fs_ops_callbacks *fs_callbacks)
716 char *ln_target = NULL;
717 unsigned int save_inode;
719 errcode_t retval = 0;
722 size_t cur_dir_path_len;
724 if (chdir(source_dir) < 0) {
726 com_err(__func__, retval,
727 _("while changing working directory to \"%s\""),
732 if (!(dh = opendir("."))) {
734 com_err(__func__, retval,
735 _("while opening directory \"%s\""), source_dir);
739 while ((dent = readdir(dh))) {
740 if ((!strcmp(dent->d_name, ".")) ||
741 (!strcmp(dent->d_name, "..")))
743 if (lstat(dent->d_name, &st)) {
745 com_err(__func__, retval, _("while lstat \"%s\""),
751 /* Check for hardlinks */
753 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
755 hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
757 retval = add_link(fs, parent_ino,
758 hdlinks->hdl[hdlink].dst_ino,
761 com_err(__func__, retval,
762 "while linking %s", name);
770 cur_dir_path_len = target->path_len;
771 retval = path_append(target, name);
775 if (fs_callbacks && fs_callbacks->create_new_inode) {
776 retval = fs_callbacks->create_new_inode(fs,
777 target->path, name, parent_ino, root,
778 st.st_mode & S_IFMT);
783 switch(st.st_mode & S_IFMT) {
788 retval = do_mknod_internal(fs, parent_ino, name, &st);
790 com_err(__func__, retval,
791 _("while creating special file "
797 ln_target = malloc(st.st_size + 1);
798 if (ln_target == NULL) {
799 com_err(__func__, retval,
803 read_cnt = readlink(name, ln_target,
805 if (read_cnt == -1) {
807 com_err(__func__, retval,
808 _("while trying to read link \"%s\""),
813 if (read_cnt > st.st_size) {
814 com_err(__func__, retval,
815 _("symlink increased in size "
816 "between lstat() and readlink()"));
820 ln_target[read_cnt] = '\0';
821 retval = do_symlink_internal(fs, parent_ino, name,
825 com_err(__func__, retval,
826 _("while writing symlink\"%s\""),
832 retval = do_write_internal(fs, parent_ino, name, name,
835 com_err(__func__, retval,
836 _("while writing file \"%s\""), name);
841 /* Don't choke on /lost+found */
842 if (parent_ino == EXT2_ROOT_INO &&
843 strcmp(name, "lost+found") == 0)
845 retval = do_mkdir_internal(fs, parent_ino, name,
848 com_err(__func__, retval,
849 _("while making dir \"%s\""), name);
853 retval = ext2fs_namei(fs, root, parent_ino,
856 com_err(name, retval, 0);
859 /* Populate the dir recursively*/
860 retval = __populate_fs(fs, ino, name, root, hdlinks,
861 target, fs_callbacks);
866 com_err(__func__, retval,
867 _("while changing directory"));
873 _("ignoring entry \"%s\""), name);
876 retval = ext2fs_namei(fs, root, parent_ino, name, &ino);
878 com_err(name, retval, _("while looking up \"%s\""),
883 retval = set_inode_extra(fs, ino, &st);
885 com_err(__func__, retval,
886 _("while setting inode for \"%s\""), name);
890 retval = set_inode_xattr(fs, ino, name);
892 com_err(__func__, retval,
893 _("while setting xattrs for \"%s\""), name);
897 if (fs_callbacks && fs_callbacks->end_create_new_inode) {
898 retval = fs_callbacks->end_create_new_inode(fs,
899 target->path, name, parent_ino, root,
900 st.st_mode & S_IFMT);
905 /* Save the hardlink ino */
908 * Check whether need more memory, and we don't need
909 * free() since the lifespan will be over after the fs
912 if (hdlinks->count == hdlinks->size) {
913 void *p = realloc(hdlinks->hdl,
914 (hdlinks->size + HDLINK_CNT) *
915 sizeof(struct hdlink_s));
917 retval = EXT2_ET_NO_MEMORY;
918 com_err(name, retval,
919 _("while saving inode data"));
923 hdlinks->size += HDLINK_CNT;
925 hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
926 hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
927 hdlinks->hdl[hdlinks->count].dst_ino = ino;
930 target->path_len = cur_dir_path_len;
931 target->path[target->path_len] = 0;
939 errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
940 const char *source_dir, ext2_ino_t root,
941 struct fs_ops_callbacks *fs_callbacks)
943 struct file_info file_info;
944 struct hdlinks_s hdlinks;
947 if (!(fs->flags & EXT2_FLAG_RW)) {
948 com_err(__func__, 0, "Filesystem opened readonly");
953 hdlinks.size = HDLINK_CNT;
954 hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
955 if (hdlinks.hdl == NULL) {
957 com_err(__func__, retval, _("while allocating memory"));
961 file_info.path_len = 0;
962 file_info.path_max_len = 255;
963 file_info.path = calloc(file_info.path_max_len, 1);
965 retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
966 &file_info, fs_callbacks);
968 free(file_info.path);
973 errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
974 const char *source_dir, ext2_ino_t root)
976 return populate_fs2(fs, parent_ino, source_dir, root, NULL);