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.
14 #include <limits.h> /* for PATH_MAX */
15 #ifdef HAVE_ATTR_XATTR_H
16 #include <attr/xattr.h>
19 #include "create_inode.h"
21 #if __STDC_VERSION__ < 199901L
23 # define __func__ __FUNCTION__
25 # define __func__ "<unknown>"
29 /* 64KiB is the minimium blksize to best minimize system call overhead. */
31 #define IO_BUFSIZE 64*1024
34 /* Block size for `st_blocks' */
39 /* Link an inode number to a directory */
40 static errcode_t
add_link(ext2_filsys fs
, ext2_ino_t parent_ino
,
41 ext2_ino_t ino
, const char *name
)
43 struct ext2_inode inode
;
46 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
48 com_err(__func__
, retval
, "while reading inode %u", ino
);
52 retval
= ext2fs_link(fs
, parent_ino
, name
, ino
, inode
.i_flags
);
53 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
54 retval
= ext2fs_expand_dir(fs
, parent_ino
);
56 com_err(__func__
, retval
, "while expanding directory");
59 retval
= ext2fs_link(fs
, parent_ino
, name
, ino
, inode
.i_flags
);
62 com_err(__func__
, retval
, "while linking %s", name
);
66 inode
.i_links_count
++;
68 retval
= ext2fs_write_inode(fs
, ino
, &inode
);
70 com_err(__func__
, retval
, "while writing inode %u", ino
);
75 /* Fill the uid, gid, mode and time for the inode */
76 static void fill_inode(struct ext2_inode
*inode
, struct stat
*st
)
79 inode
->i_uid
= st
->st_uid
;
80 inode
->i_gid
= st
->st_gid
;
81 inode
->i_mode
|= st
->st_mode
;
82 inode
->i_atime
= st
->st_atime
;
83 inode
->i_mtime
= st
->st_mtime
;
84 inode
->i_ctime
= st
->st_ctime
;
88 /* Set the uid, gid, mode and time for the inode */
89 static errcode_t
set_inode_extra(ext2_filsys fs
, ext2_ino_t cwd
,
90 ext2_ino_t ino
, struct stat
*st
)
93 struct ext2_inode inode
;
95 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
97 com_err(__func__
, retval
, "while reading inode %u", ino
);
101 fill_inode(&inode
, st
);
103 retval
= ext2fs_write_inode(fs
, ino
, &inode
);
105 com_err(__func__
, retval
, "while writing inode %u", ino
);
109 static errcode_t
set_inode_xattr(ext2_filsys fs
, ext2_ino_t ino
, const char *filename
)
111 #ifdef HAVE_LLISTXATTR
112 errcode_t retval
, close_retval
;
113 struct ext2_inode inode
;
114 struct ext2_xattr_handle
*handle
;
115 ssize_t size
, value_size
;
119 size
= llistxattr(filename
, NULL
, 0);
121 com_err(__func__
, errno
, "llistxattr failed on %s", filename
);
123 } else if (size
== 0) {
127 retval
= ext2fs_xattrs_open(fs
, ino
, &handle
);
129 if (retval
== EXT2_ET_MISSING_EA_FEATURE
)
131 com_err(__func__
, retval
, "while opening inode %u", ino
);
135 retval
= ext2fs_get_mem(size
, &list
);
137 com_err(__func__
, retval
, "whilst allocating memory");
141 size
= llistxattr(filename
, list
, size
);
143 com_err(__func__
, errno
, "llistxattr failed on %s", filename
);
148 for (i
= 0; i
< size
; i
+= strlen(&list
[i
]) + 1) {
149 const char *name
= &list
[i
];
152 value_size
= getxattr(filename
, name
, NULL
, 0);
153 if (value_size
== -1) {
154 com_err(__func__
, errno
, "getxattr failed on %s",
160 retval
= ext2fs_get_mem(value_size
, &value
);
162 com_err(__func__
, retval
, "whilst allocating memory");
166 value_size
= getxattr(filename
, name
, value
, value_size
);
167 if (value_size
== -1) {
168 ext2fs_free_mem(&value
);
169 com_err(__func__
, errno
, "getxattr failed on %s",
175 retval
= ext2fs_xattr_set(handle
, name
, value
, value_size
);
176 ext2fs_free_mem(&value
);
178 com_err(__func__
, retval
,
179 "while writing xattr %u", ino
);
185 ext2fs_free_mem(&list
);
186 close_retval
= ext2fs_xattrs_close(&handle
);
188 com_err(__func__
, retval
, "while closing inode %u", ino
);
189 retval
= retval
? retval
: close_retval
;
192 #else /* HAVE_LLISTXATTR */
194 #endif /* HAVE_LLISTXATTR */
197 /* Make a special files (block and character devices), fifo's, and sockets */
198 errcode_t
do_mknod_internal(ext2_filsys fs
, ext2_ino_t cwd
, const char *name
,
203 struct ext2_inode inode
;
204 unsigned long devmajor
, devminor
, mode
;
207 switch(st
->st_mode
& S_IFMT
) {
209 mode
= LINUX_S_IFCHR
;
210 filetype
= EXT2_FT_CHRDEV
;
213 mode
= LINUX_S_IFBLK
;
214 filetype
= EXT2_FT_BLKDEV
;
217 mode
= LINUX_S_IFIFO
;
218 filetype
= EXT2_FT_FIFO
;
221 mode
= LINUX_S_IFSOCK
;
222 filetype
= EXT2_FT_SOCK
;
225 return EXT2_ET_INVALID_ARGUMENT
;
228 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
229 com_err(__func__
, 0, "Filesystem opened read/only");
232 retval
= ext2fs_new_inode(fs
, cwd
, 010755, 0, &ino
);
234 com_err(__func__
, retval
, 0);
239 printf("Allocated inode: %u\n", ino
);
241 retval
= ext2fs_link(fs
, cwd
, name
, ino
, filetype
);
242 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
243 retval
= ext2fs_expand_dir(fs
, cwd
);
245 com_err(__func__
, retval
, "while expanding directory");
248 retval
= ext2fs_link(fs
, cwd
, name
, ino
, filetype
);
251 com_err(name
, retval
, 0);
254 if (ext2fs_test_inode_bitmap2(fs
->inode_map
, ino
))
255 com_err(__func__
, 0, "Warning: inode already set");
256 ext2fs_inode_alloc_stats2(fs
, ino
, +1, 0);
257 memset(&inode
, 0, sizeof(inode
));
259 inode
.i_atime
= inode
.i_ctime
= inode
.i_mtime
=
260 fs
->now
? fs
->now
: time(0);
262 if (filetype
!= S_IFIFO
) {
263 devmajor
= major(st
->st_rdev
);
264 devminor
= minor(st
->st_rdev
);
266 if ((devmajor
< 256) && (devminor
< 256)) {
267 inode
.i_block
[0] = devmajor
* 256 + devminor
;
268 inode
.i_block
[1] = 0;
270 inode
.i_block
[0] = 0;
271 inode
.i_block
[1] = (devminor
& 0xff) | (devmajor
<< 8) |
272 ((devminor
& ~0xff) << 12);
275 inode
.i_links_count
= 1;
277 retval
= ext2fs_write_new_inode(fs
, ino
, &inode
);
279 com_err(__func__
, retval
, "while creating inode %u", ino
);
284 /* Make a symlink name -> target */
285 errcode_t
do_symlink_internal(ext2_filsys fs
, ext2_ino_t cwd
, const char *name
,
286 char *target
, ext2_ino_t root
)
289 ext2_ino_t parent_ino
;
291 struct ext2_inode inode
;
294 cp
= strrchr(name
, '/');
297 retval
= ext2fs_namei(fs
, root
, cwd
, name
, &parent_ino
);
299 com_err(name
, retval
, 0);
307 retval
= ext2fs_symlink(fs
, parent_ino
, 0, name
, target
);
308 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
309 retval
= ext2fs_expand_dir(fs
, parent_ino
);
311 com_err("do_symlink_internal", retval
,
312 "while expanding directory");
318 com_err("ext2fs_symlink", retval
, 0);
322 /* Make a directory in the fs */
323 errcode_t
do_mkdir_internal(ext2_filsys fs
, ext2_ino_t cwd
, const char *name
,
324 struct stat
*st
, ext2_ino_t root
)
327 ext2_ino_t parent_ino
, ino
;
329 struct ext2_inode inode
;
332 cp
= strrchr(name
, '/');
335 retval
= ext2fs_namei(fs
, root
, cwd
, name
, &parent_ino
);
337 com_err(name
, retval
, 0);
345 retval
= ext2fs_mkdir(fs
, parent_ino
, 0, name
);
346 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
347 retval
= ext2fs_expand_dir(fs
, parent_ino
);
349 com_err(__func__
, retval
, "while expanding directory");
355 com_err("ext2fs_mkdir", retval
, 0);
359 static errcode_t
copy_file(ext2_filsys fs
, int fd
, ext2_ino_t newfile
,
360 int bufsize
, int make_holes
)
363 errcode_t retval
, close_ret
;
365 unsigned int written
;
371 retval
= ext2fs_file_open(fs
, newfile
,
372 EXT2_FILE_WRITE
, &e2_file
);
376 retval
= ext2fs_get_mem(bufsize
, &buf
);
378 com_err("copy_file", retval
, "can't allocate buffer\n");
382 /* This is used for checking whether the whole block is zero */
383 retval
= ext2fs_get_memzero(bufsize
, &zero_buf
);
385 com_err("copy_file", retval
, "can't allocate zero buffer\n");
390 got
= read(fd
, buf
, bufsize
);
401 /* Check whether all is zero */
402 cmp
= memcmp(ptr
, zero_buf
, got
);
404 /* The whole block is zero, make a hole */
405 retval
= ext2fs_file_lseek(e2_file
, got
,
416 retval
= ext2fs_file_write(e2_file
, ptr
,
427 ext2fs_free_mem(&zero_buf
);
429 ext2fs_free_mem(&buf
);
431 close_ret
= ext2fs_file_close(e2_file
);
437 static int is_hardlink(struct hdlinks_s
*hdlinks
, dev_t dev
, ino_t ino
)
441 for (i
= 0; i
< hdlinks
->count
; i
++) {
442 if (hdlinks
->hdl
[i
].src_dev
== dev
&&
443 hdlinks
->hdl
[i
].src_ino
== ino
)
449 /* Copy the native file to the fs */
450 errcode_t
do_write_internal(ext2_filsys fs
, ext2_ino_t cwd
, const char *src
,
451 const char *dest
, ext2_ino_t root
)
457 struct ext2_inode inode
;
458 int bufsize
= IO_BUFSIZE
;
461 fd
= ext2fs_open_file(src
, O_RDONLY
, 0);
463 com_err(src
, errno
, 0);
466 if (fstat(fd
, &statbuf
) < 0) {
467 com_err(src
, errno
, 0);
472 retval
= ext2fs_namei(fs
, root
, cwd
, dest
, &newfile
);
475 return EXT2_ET_FILE_EXISTS
;
478 retval
= ext2fs_new_inode(fs
, cwd
, 010755, 0, &newfile
);
480 com_err(__func__
, retval
, 0);
485 printf("Allocated inode: %u\n", newfile
);
487 retval
= ext2fs_link(fs
, cwd
, dest
, newfile
,
489 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
490 retval
= ext2fs_expand_dir(fs
, cwd
);
492 com_err(__func__
, retval
, "while expanding directory");
496 retval
= ext2fs_link(fs
, cwd
, dest
, newfile
,
500 com_err(dest
, retval
, 0);
504 if (ext2fs_test_inode_bitmap2(fs
->inode_map
, newfile
))
505 com_err(__func__
, 0, "Warning: inode already set");
506 ext2fs_inode_alloc_stats2(fs
, newfile
, +1, 0);
507 memset(&inode
, 0, sizeof(inode
));
508 inode
.i_mode
= (statbuf
.st_mode
& ~LINUX_S_IFMT
) | LINUX_S_IFREG
;
509 inode
.i_atime
= inode
.i_ctime
= inode
.i_mtime
=
510 fs
->now
? fs
->now
: time(0);
511 inode
.i_links_count
= 1;
512 retval
= ext2fs_inode_size_set(fs
, &inode
, statbuf
.st_size
);
514 com_err(dest
, retval
, 0);
518 if (EXT2_HAS_INCOMPAT_FEATURE(fs
->super
,
519 EXT4_FEATURE_INCOMPAT_INLINE_DATA
)) {
520 inode
.i_flags
|= EXT4_INLINE_DATA_FL
;
521 } else if (fs
->super
->s_feature_incompat
&
522 EXT3_FEATURE_INCOMPAT_EXTENTS
) {
524 struct ext3_extent_header
*eh
;
526 eh
= (struct ext3_extent_header
*) &inode
.i_block
[0];
529 eh
->eh_magic
= ext2fs_cpu_to_le16(EXT3_EXT_MAGIC
);
530 i
= (sizeof(inode
.i_block
) - sizeof(*eh
)) /
531 sizeof(struct ext3_extent
);
532 eh
->eh_max
= ext2fs_cpu_to_le16(i
);
533 inode
.i_flags
|= EXT4_EXTENTS_FL
;
536 retval
= ext2fs_write_new_inode(fs
, newfile
, &inode
);
538 com_err(__func__
, retval
, "while creating inode %u", newfile
);
542 if (inode
.i_flags
& EXT4_INLINE_DATA_FL
) {
543 retval
= ext2fs_inline_data_init(fs
, newfile
);
545 com_err("copy_file", retval
, 0);
550 if (LINUX_S_ISREG(inode
.i_mode
)) {
551 if (statbuf
.st_blocks
< statbuf
.st_size
/ S_BLKSIZE
) {
554 * Use I/O blocksize as buffer size when
555 * copying sparse files.
557 bufsize
= statbuf
.st_blksize
;
559 retval
= copy_file(fs
, fd
, newfile
, bufsize
, make_holes
);
561 com_err("copy_file", retval
, 0);
568 /* Copy files from source_dir to fs */
569 static errcode_t
__populate_fs(ext2_filsys fs
, ext2_ino_t parent_ino
,
570 const char *source_dir
, ext2_ino_t root
,
571 struct hdlinks_s
*hdlinks
)
577 char ln_target
[PATH_MAX
];
578 unsigned int save_inode
;
580 errcode_t retval
= 0;
584 if (chdir(source_dir
) < 0) {
585 com_err(__func__
, errno
,
586 _("while changing working directory to \"%s\""),
591 if (!(dh
= opendir("."))) {
592 com_err(__func__
, errno
,
593 _("while opening directory \"%s\""), source_dir
);
597 while ((dent
= readdir(dh
))) {
598 if ((!strcmp(dent
->d_name
, ".")) ||
599 (!strcmp(dent
->d_name
, "..")))
601 if (lstat(dent
->d_name
, &st
)) {
602 com_err(__func__
, errno
, _("while lstat \"%s\""),
608 /* Check for hardlinks */
610 if (!S_ISDIR(st
.st_mode
) && !S_ISLNK(st
.st_mode
) &&
612 hdlink
= is_hardlink(hdlinks
, st
.st_dev
, st
.st_ino
);
614 retval
= add_link(fs
, parent_ino
,
615 hdlinks
->hdl
[hdlink
].dst_ino
,
618 com_err(__func__
, retval
,
619 "while linking %s", name
);
627 switch(st
.st_mode
& S_IFMT
) {
632 retval
= do_mknod_internal(fs
, parent_ino
, name
, &st
);
634 com_err(__func__
, retval
,
635 _("while creating special file "
641 read_cnt
= readlink(name
, ln_target
,
642 sizeof(ln_target
) - 1);
643 if (read_cnt
== -1) {
644 com_err(__func__
, errno
,
645 _("while trying to readlink \"%s\""),
650 ln_target
[read_cnt
] = '\0';
651 retval
= do_symlink_internal(fs
, parent_ino
, name
,
654 com_err(__func__
, retval
,
655 _("while writing symlink\"%s\""),
661 retval
= do_write_internal(fs
, parent_ino
, name
, name
,
664 com_err(__func__
, retval
,
665 _("while writing file \"%s\""), name
);
670 retval
= do_mkdir_internal(fs
, parent_ino
, name
, &st
,
673 com_err(__func__
, retval
,
674 _("while making dir \"%s\""), name
);
677 retval
= ext2fs_namei(fs
, root
, parent_ino
,
680 com_err(name
, retval
, 0);
683 /* Populate the dir recursively*/
684 retval
= __populate_fs(fs
, ino
, name
, root
, hdlinks
);
686 com_err(__func__
, retval
,
687 _("while adding dir \"%s\""), name
);
691 com_err(__func__
, errno
, _("during cd .."));
698 _("ignoring entry \"%s\""), name
);
701 retval
= ext2fs_namei(fs
, root
, parent_ino
, name
, &ino
);
703 com_err(name
, retval
, 0);
707 retval
= set_inode_extra(fs
, parent_ino
, ino
, &st
);
709 com_err(__func__
, retval
,
710 _("while setting inode for \"%s\""), name
);
714 retval
= set_inode_xattr(fs
, ino
, name
);
716 com_err(__func__
, retval
,
717 _("while setting xattrs for \"%s\""), name
);
721 /* Save the hardlink ino */
724 * Check whether need more memory, and we don't need
725 * free() since the lifespan will be over after the fs
728 if (hdlinks
->count
== hdlinks
->size
) {
729 void *p
= realloc(hdlinks
->hdl
,
730 (hdlinks
->size
+ HDLINK_CNT
) *
731 sizeof(struct hdlink_s
));
734 _("Not enough memory"));
735 retval
= EXT2_ET_NO_MEMORY
;
739 hdlinks
->size
+= HDLINK_CNT
;
741 hdlinks
->hdl
[hdlinks
->count
].src_dev
= st
.st_dev
;
742 hdlinks
->hdl
[hdlinks
->count
].src_ino
= st
.st_ino
;
743 hdlinks
->hdl
[hdlinks
->count
].dst_ino
= ino
;
753 errcode_t
populate_fs(ext2_filsys fs
, ext2_ino_t parent_ino
,
754 const char *source_dir
, ext2_ino_t root
)
756 struct hdlinks_s hdlinks
;
760 hdlinks
.size
= HDLINK_CNT
;
761 hdlinks
.hdl
= realloc(NULL
, hdlinks
.size
* sizeof(struct hdlink_s
));
762 if (hdlinks
.hdl
== NULL
) {
763 com_err(__func__
, errno
, "Not enough memory");
767 retval
= __populate_fs(fs
, parent_ino
, source_dir
, root
, &hdlinks
);