Home | History | Annotate | Download | only in misc
      1 /*
      2  * create_inode.c --- create an inode
      3  *
      4  * Copyright (C) 2014 Robert Yang <liezhi.yang (at) windriver.com>
      5  *
      6  * %Begin-Header%
      7  * This file may be redistributed under the terms of the GNU library
      8  * General Public License, version 2.
      9  * %End-Header%
     10  */
     11 
     12 #define _FILE_OFFSET_BITS       64
     13 #define _LARGEFILE64_SOURCE     1
     14 #define _GNU_SOURCE		1
     15 
     16 #include "config.h"
     17 #include <time.h>
     18 #include <sys/stat.h>
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 #include <limits.h> /* for PATH_MAX */
     22 #ifdef HAVE_ATTR_XATTR_H
     23 #include <attr/xattr.h>
     24 #endif
     25 #ifdef HAVE_SYS_IOCTL_H
     26 #include <sys/ioctl.h>
     27 #endif
     28 #ifdef HAVE_SYS_SYSMACROS_H
     29 #include <sys/sysmacros.h>
     30 #endif
     31 
     32 #include <ext2fs/ext2fs.h>
     33 #include <ext2fs/ext2_types.h>
     34 #include <ext2fs/fiemap.h>
     35 
     36 #include "create_inode.h"
     37 #include "support/nls-enable.h"
     38 
     39 /* 64KiB is the minimium blksize to best minimize system call overhead. */
     40 #define COPY_FILE_BUFLEN	65536
     41 
     42 static int ext2_file_type(unsigned int mode)
     43 {
     44 	if (LINUX_S_ISREG(mode))
     45 		return EXT2_FT_REG_FILE;
     46 
     47 	if (LINUX_S_ISDIR(mode))
     48 		return EXT2_FT_DIR;
     49 
     50 	if (LINUX_S_ISCHR(mode))
     51 		return EXT2_FT_CHRDEV;
     52 
     53 	if (LINUX_S_ISBLK(mode))
     54 		return EXT2_FT_BLKDEV;
     55 
     56 	if (LINUX_S_ISLNK(mode))
     57 		return EXT2_FT_SYMLINK;
     58 
     59 	if (LINUX_S_ISFIFO(mode))
     60 		return EXT2_FT_FIFO;
     61 
     62 	if (LINUX_S_ISSOCK(mode))
     63 		return EXT2_FT_SOCK;
     64 
     65 	return 0;
     66 }
     67 
     68 /* Link an inode number to a directory */
     69 static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
     70 			  ext2_ino_t ino, const char *name)
     71 {
     72 	struct ext2_inode	inode;
     73 	errcode_t		retval;
     74 
     75 	retval = ext2fs_read_inode(fs, ino, &inode);
     76         if (retval) {
     77 		com_err(__func__, retval, _("while reading inode %u"), ino);
     78 		return retval;
     79 	}
     80 
     81 	retval = ext2fs_link(fs, parent_ino, name, ino,
     82 			     ext2_file_type(inode.i_mode));
     83 	if (retval == EXT2_ET_DIR_NO_SPACE) {
     84 		retval = ext2fs_expand_dir(fs, parent_ino);
     85 		if (retval) {
     86 			com_err(__func__, retval,
     87 				_("while expanding directory"));
     88 			return retval;
     89 		}
     90 		retval = ext2fs_link(fs, parent_ino, name, ino,
     91 				     ext2_file_type(inode.i_mode));
     92 	}
     93 	if (retval) {
     94 		com_err(__func__, retval, _("while linking \"%s\""), name);
     95 		return retval;
     96 	}
     97 
     98 	inode.i_links_count++;
     99 
    100 	retval = ext2fs_write_inode(fs, ino, &inode);
    101 	if (retval)
    102 		com_err(__func__, retval, _("while writing inode %u"), ino);
    103 
    104 	return retval;
    105 }
    106 
    107 /* Set the uid, gid, mode and time for the inode */
    108 static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
    109 				 struct stat *st)
    110 {
    111 	errcode_t		retval;
    112 	struct ext2_inode	inode;
    113 
    114 	retval = ext2fs_read_inode(fs, ino, &inode);
    115         if (retval) {
    116 		com_err(__func__, retval, _("while reading inode %u"), ino);
    117 		return retval;
    118 	}
    119 
    120 	inode.i_uid = st->st_uid;
    121 	inode.i_gid = st->st_gid;
    122 	inode.i_mode |= st->st_mode;
    123 	inode.i_atime = st->st_atime;
    124 	inode.i_mtime = st->st_mtime;
    125 	inode.i_ctime = st->st_ctime;
    126 
    127 	retval = ext2fs_write_inode(fs, ino, &inode);
    128 	if (retval)
    129 		com_err(__func__, retval, _("while writing inode %u"), ino);
    130 	return retval;
    131 }
    132 
    133 #ifdef HAVE_LLISTXATTR
    134 static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino,
    135 				 const char *filename)
    136 {
    137 	errcode_t			retval, close_retval;
    138 	struct ext2_xattr_handle	*handle;
    139 	ssize_t				size, value_size;
    140 	char				*list = NULL;
    141 	int				i;
    142 
    143 	size = llistxattr(filename, NULL, 0);
    144 	if (size == -1) {
    145 		retval = errno;
    146 		com_err(__func__, retval, _("while listing attributes of \"%s\""),
    147 			filename);
    148 		return retval;
    149 	} else if (size == 0) {
    150 		return 0;
    151 	}
    152 
    153 	retval = ext2fs_xattrs_open(fs, ino, &handle);
    154 	if (retval) {
    155 		if (retval == EXT2_ET_MISSING_EA_FEATURE)
    156 			return 0;
    157 		com_err(__func__, retval, _("while opening inode %u"), ino);
    158 		return retval;
    159 	}
    160 
    161 	retval = ext2fs_get_mem(size, &list);
    162 	if (retval) {
    163 		com_err(__func__, retval, _("while allocating memory"));
    164 		goto out;
    165 	}
    166 
    167 	size = llistxattr(filename, list, size);
    168 	if (size == -1) {
    169 		retval = errno;
    170 		com_err(__func__, retval, _("while listing attributes of \"%s\""),
    171 			filename);
    172 		goto out;
    173         }
    174 
    175 	for (i = 0; i < size; i += strlen(&list[i]) + 1) {
    176 		const char *name = &list[i];
    177 		char *value;
    178 
    179 		value_size = lgetxattr(filename, name, NULL, 0);
    180 		if (value_size == -1) {
    181 			retval = errno;
    182 			com_err(__func__, retval,
    183 				_("while reading attribute \"%s\" of \"%s\""),
    184 				name, filename);
    185 			break;
    186 		}
    187 
    188 		retval = ext2fs_get_mem(value_size, &value);
    189 		if (retval) {
    190 			com_err(__func__, retval, _("while allocating memory"));
    191 			break;
    192 		}
    193 
    194 		value_size = lgetxattr(filename, name, value, value_size);
    195 		if (value_size == -1) {
    196 			ext2fs_free_mem(&value);
    197 			retval = errno;
    198 			com_err(__func__, retval,
    199 				_("while reading attribute \"%s\" of \"%s\""),
    200 				name, filename);
    201 			break;
    202 		}
    203 
    204 		retval = ext2fs_xattr_set(handle, name, value, value_size);
    205 		ext2fs_free_mem(&value);
    206 		if (retval) {
    207 			com_err(__func__, retval,
    208 				_("while writing attribute \"%s\" to inode %u"),
    209 				name, ino);
    210 			break;
    211 		}
    212 
    213 	}
    214  out:
    215 	ext2fs_free_mem(&list);
    216 	close_retval = ext2fs_xattrs_close(&handle);
    217 	if (close_retval) {
    218 		com_err(__func__, retval, _("while closing inode %u"), ino);
    219 		retval = retval ? retval : close_retval;
    220 	}
    221 	return retval;
    222 	return 0;
    223 }
    224 #else /* HAVE_LLISTXATTR */
    225 static errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)),
    226 				 ext2_ino_t ino EXT2FS_ATTR((unused)),
    227 				 const char *filename EXT2FS_ATTR((unused)))
    228 {
    229 	return 0;
    230 }
    231 #endif  /* HAVE_LLISTXATTR */
    232 
    233 #ifndef _WIN32
    234 /* Make a special files (block and character devices), fifo's, and sockets  */
    235 errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
    236 			    struct stat *st)
    237 {
    238 	ext2_ino_t		ino;
    239 	errcode_t		retval;
    240 	struct ext2_inode	inode;
    241 	unsigned long		devmajor, devminor, mode;
    242 	int			filetype;
    243 
    244 	switch(st->st_mode & S_IFMT) {
    245 	case S_IFCHR:
    246 		mode = LINUX_S_IFCHR;
    247 		filetype = EXT2_FT_CHRDEV;
    248 		break;
    249 	case S_IFBLK:
    250 		mode = LINUX_S_IFBLK;
    251 		filetype =  EXT2_FT_BLKDEV;
    252 		break;
    253 	case S_IFIFO:
    254 		mode = LINUX_S_IFIFO;
    255 		filetype = EXT2_FT_FIFO;
    256 		break;
    257 #ifndef _WIN32
    258 	case S_IFSOCK:
    259 		mode = LINUX_S_IFSOCK;
    260 		filetype = EXT2_FT_SOCK;
    261 		break;
    262 #endif
    263 	default:
    264 		return EXT2_ET_INVALID_ARGUMENT;
    265 	}
    266 
    267 	retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
    268 	if (retval) {
    269 		com_err(__func__, retval, _("while allocating inode \"%s\""),
    270 			name);
    271 		return retval;
    272 	}
    273 
    274 #ifdef DEBUGFS
    275 	printf("Allocated inode: %u\n", ino);
    276 #endif
    277 	retval = ext2fs_link(fs, cwd, name, ino, filetype);
    278 	if (retval == EXT2_ET_DIR_NO_SPACE) {
    279 		retval = ext2fs_expand_dir(fs, cwd);
    280 		if (retval) {
    281 			com_err(__func__, retval,
    282 				_("while expanding directory"));
    283 			return retval;
    284 		}
    285 		retval = ext2fs_link(fs, cwd, name, ino, filetype);
    286 	}
    287 	if (retval) {
    288 		com_err(name, retval, _("while creating inode \"%s\""), name);
    289 		return retval;
    290 	}
    291 	if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
    292 		com_err(__func__, 0, "Warning: inode already set");
    293 	ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
    294 	memset(&inode, 0, sizeof(inode));
    295 	inode.i_mode = mode;
    296 	inode.i_atime = inode.i_ctime = inode.i_mtime =
    297 		fs->now ? fs->now : time(0);
    298 
    299 	if (filetype != S_IFIFO) {
    300 		devmajor = major(st->st_rdev);
    301 		devminor = minor(st->st_rdev);
    302 
    303 		if ((devmajor < 256) && (devminor < 256)) {
    304 			inode.i_block[0] = devmajor * 256 + devminor;
    305 			inode.i_block[1] = 0;
    306 		} else {
    307 			inode.i_block[0] = 0;
    308 			inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
    309 					   ((devminor & ~0xff) << 12);
    310 		}
    311 	}
    312 	inode.i_links_count = 1;
    313 
    314 	retval = ext2fs_write_new_inode(fs, ino, &inode);
    315 	if (retval)
    316 		com_err(__func__, retval, _("while writing inode %u"), ino);
    317 
    318 	return retval;
    319 }
    320 #endif
    321 
    322 /* Make a symlink name -> target */
    323 errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
    324 			      char *target, ext2_ino_t root)
    325 {
    326 	char			*cp;
    327 	ext2_ino_t		parent_ino;
    328 	errcode_t		retval;
    329 
    330 	cp = strrchr(name, '/');
    331 	if (cp) {
    332 		*cp = 0;
    333 		retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
    334 		if (retval) {
    335 			com_err(name, retval, 0);
    336 			return retval;
    337 		}
    338 		name = cp+1;
    339 	} else
    340 		parent_ino = cwd;
    341 
    342 	retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
    343 	if (retval == EXT2_ET_DIR_NO_SPACE) {
    344 		retval = ext2fs_expand_dir(fs, parent_ino);
    345 		if (retval) {
    346 			com_err("do_symlink_internal", retval,
    347 				_("while expanding directory"));
    348 			return retval;
    349 		}
    350 		retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
    351 	}
    352 	if (retval)
    353 		com_err("ext2fs_symlink", retval,
    354 			_("while creating symlink \"%s\""), name);
    355 	return retval;
    356 }
    357 
    358 /* Make a directory in the fs */
    359 errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
    360 			    ext2_ino_t root)
    361 {
    362 	char			*cp;
    363 	ext2_ino_t		parent_ino;
    364 	errcode_t		retval;
    365 
    366 
    367 	cp = strrchr(name, '/');
    368 	if (cp) {
    369 		*cp = 0;
    370 		retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
    371 		if (retval) {
    372 			com_err(name, retval, _("while looking up \"%s\""),
    373 				name);
    374 			return retval;
    375 		}
    376 		name = cp+1;
    377 	} else
    378 		parent_ino = cwd;
    379 
    380 	retval = ext2fs_mkdir(fs, parent_ino, 0, name);
    381 	if (retval == EXT2_ET_DIR_NO_SPACE) {
    382 		retval = ext2fs_expand_dir(fs, parent_ino);
    383 		if (retval) {
    384 			com_err(__func__, retval,
    385 				_("while expanding directory"));
    386 			return retval;
    387 		}
    388 		retval = ext2fs_mkdir(fs, parent_ino, 0, name);
    389 	}
    390 	if (retval)
    391 		com_err("ext2fs_mkdir", retval,
    392 			_("while creating directory \"%s\""), name);
    393 	return retval;
    394 }
    395 
    396 #if !defined HAVE_PREAD64 && !defined HAVE_PREAD
    397 static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset)
    398 {
    399 	if (lseek(fd, offset, SEEK_SET) < 0)
    400 		return 0;
    401 
    402 	return read(fd, buf, count);
    403 }
    404 #endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */
    405 
    406 static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file,
    407 				 off_t start, off_t end, char *buf,
    408 				 char *zerobuf)
    409 {
    410 	off_t off, bpos;
    411 	ssize_t got, blen;
    412 	unsigned int written;
    413 	char *ptr;
    414 	errcode_t err = 0;
    415 
    416 	for (off = start; off < end; off += COPY_FILE_BUFLEN) {
    417 #ifdef HAVE_PREAD64
    418 		got = pread64(fd, buf, COPY_FILE_BUFLEN, off);
    419 #elif HAVE_PREAD
    420 		got = pread(fd, buf, COPY_FILE_BUFLEN, off);
    421 #else
    422 		got = my_pread(fd, buf, COPY_FILE_BUFLEN, off);
    423 #endif
    424 		if (got < 0) {
    425 			err = errno;
    426 			goto fail;
    427 		}
    428 		for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) {
    429 			blen = fs->blocksize;
    430 			if (blen > got - bpos)
    431 				blen = got - bpos;
    432 			if (memcmp(ptr, zerobuf, blen) == 0) {
    433 				ptr += blen;
    434 				continue;
    435 			}
    436 			err = ext2fs_file_lseek(e2_file, off + bpos,
    437 						EXT2_SEEK_SET, NULL);
    438 			if (err)
    439 				goto fail;
    440 			while (blen > 0) {
    441 				err = ext2fs_file_write(e2_file, ptr, blen,
    442 							&written);
    443 				if (err)
    444 					goto fail;
    445 				if (written == 0) {
    446 					err = EIO;
    447 					goto fail;
    448 				}
    449 				blen -= written;
    450 				ptr += written;
    451 			}
    452 		}
    453 	}
    454 fail:
    455 	return err;
    456 }
    457 
    458 #if defined(SEEK_DATA) && defined(SEEK_HOLE)
    459 static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf,
    460 				ext2_file_t e2_file, char *buf, char *zerobuf)
    461 {
    462 	off_t data = 0, hole;
    463 	off_t data_blk, hole_blk;
    464 	errcode_t err = 0;
    465 
    466 	/* Try to use SEEK_DATA and SEEK_HOLE */
    467 	while (data < statbuf->st_size) {
    468 		data = lseek(fd, data, SEEK_DATA);
    469 		if (data < 0) {
    470 			if (errno == ENXIO)
    471 				break;
    472 			return EXT2_ET_UNIMPLEMENTED;
    473 		}
    474 		hole = lseek(fd, data, SEEK_HOLE);
    475 		if (hole < 0)
    476 			return EXT2_ET_UNIMPLEMENTED;
    477 
    478 		data_blk = data & ~(fs->blocksize - 1);
    479 		hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1);
    480 		err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf,
    481 				      zerobuf);
    482 		if (err)
    483 			return err;
    484 
    485 		data = hole;
    486 	}
    487 
    488 	return err;
    489 }
    490 #endif /* SEEK_DATA and SEEK_HOLE */
    491 
    492 #if defined(FS_IOC_FIEMAP)
    493 static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file,
    494 				 char *buf, char *zerobuf)
    495 {
    496 #define EXTENT_MAX_COUNT 512
    497 	struct fiemap *fiemap_buf;
    498 	struct fiemap_extent *ext_buf, *ext;
    499 	int ext_buf_size, fie_buf_size;
    500 	off_t pos = 0;
    501 	unsigned int i;
    502 	errcode_t err;
    503 
    504 	ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
    505 	fie_buf_size = sizeof(struct fiemap) + ext_buf_size;
    506 
    507 	err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf);
    508 	if (err)
    509 		return err;
    510 
    511 	ext_buf = fiemap_buf->fm_extents;
    512 	memset(fiemap_buf, 0, fie_buf_size);
    513 	fiemap_buf->fm_length = FIEMAP_MAX_OFFSET;
    514 	fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC;
    515 	fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT;
    516 
    517 	do {
    518 		fiemap_buf->fm_start = pos;
    519 		memset(ext_buf, 0, ext_buf_size);
    520 		err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
    521 		if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) {
    522 			err = EXT2_ET_UNIMPLEMENTED;
    523 			goto out;
    524 		} else if (err < 0 || fiemap_buf->fm_mapped_extents == 0) {
    525 			err = errno;
    526 			goto out;
    527 		}
    528 		for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents;
    529 		     i++, ext++) {
    530 			err = copy_file_range(fs, fd, e2_file, ext->fe_logical,
    531 					      ext->fe_logical + ext->fe_length,
    532 					      buf, zerobuf);
    533 			if (err)
    534 				goto out;
    535 		}
    536 
    537 		ext--;
    538 		/* Record file's logical offset this time */
    539 		pos = ext->fe_logical + ext->fe_length;
    540 		/*
    541 		 * If fm_extents array has been filled and
    542 		 * there are extents left, continue to cycle.
    543 		 */
    544 	} while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT &&
    545 		 !(ext->fe_flags & FIEMAP_EXTENT_LAST));
    546 out:
    547 	ext2fs_free_mem(&fiemap_buf);
    548 	return err;
    549 }
    550 #endif /* FS_IOC_FIEMAP */
    551 
    552 static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf,
    553 			   ext2_ino_t ino)
    554 {
    555 	ext2_file_t e2_file;
    556 	char *buf = NULL, *zerobuf = NULL;
    557 	errcode_t err, close_err;
    558 
    559 	err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
    560 	if (err)
    561 		return err;
    562 
    563 	err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf);
    564 	if (err)
    565 		goto out;
    566 
    567 	err = ext2fs_get_memzero(fs->blocksize, &zerobuf);
    568 	if (err)
    569 		goto out;
    570 
    571 #if defined(SEEK_DATA) && defined(SEEK_HOLE)
    572 	err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf);
    573 	if (err != EXT2_ET_UNIMPLEMENTED)
    574 		goto out;
    575 #endif
    576 
    577 #if defined(FS_IOC_FIEMAP)
    578 	err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf);
    579 	if (err != EXT2_ET_UNIMPLEMENTED)
    580 		goto out;
    581 #endif
    582 
    583 	err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf,
    584 			      zerobuf);
    585 out:
    586 	ext2fs_free_mem(&zerobuf);
    587 	ext2fs_free_mem(&buf);
    588 	close_err = ext2fs_file_close(e2_file);
    589 	if (err == 0)
    590 		err = close_err;
    591 	return err;
    592 }
    593 
    594 static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
    595 {
    596 	int i;
    597 
    598 	for (i = 0; i < hdlinks->count; i++) {
    599 		if (hdlinks->hdl[i].src_dev == dev &&
    600 		    hdlinks->hdl[i].src_ino == ino)
    601 			return i;
    602 	}
    603 	return -1;
    604 }
    605 
    606 /* Copy the native file to the fs */
    607 errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
    608 			    const char *dest, ext2_ino_t root)
    609 {
    610 	int		fd;
    611 	struct stat	statbuf;
    612 	ext2_ino_t	newfile;
    613 	errcode_t	retval;
    614 	struct ext2_inode inode;
    615 
    616 	fd = ext2fs_open_file(src, O_RDONLY, 0);
    617 	if (fd < 0) {
    618 		retval = errno;
    619 		com_err(__func__, retval, _("while opening \"%s\" to copy"),
    620 			src);
    621 		return retval;
    622 	}
    623 	if (fstat(fd, &statbuf) < 0) {
    624 		retval = errno;
    625 		goto out;
    626 	}
    627 
    628 	retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
    629 	if (retval == 0) {
    630 		retval = EXT2_ET_FILE_EXISTS;
    631 		goto out;
    632 	}
    633 
    634 	retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
    635 	if (retval)
    636 		goto out;
    637 #ifdef DEBUGFS
    638 	printf("Allocated inode: %u\n", newfile);
    639 #endif
    640 	retval = ext2fs_link(fs, cwd, dest, newfile,
    641 				EXT2_FT_REG_FILE);
    642 	if (retval == EXT2_ET_DIR_NO_SPACE) {
    643 		retval = ext2fs_expand_dir(fs, cwd);
    644 		if (retval)
    645 			goto out;
    646 		retval = ext2fs_link(fs, cwd, dest, newfile,
    647 					EXT2_FT_REG_FILE);
    648 	}
    649 	if (retval)
    650 		goto out;
    651 	if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
    652 		com_err(__func__, 0, "Warning: inode already set");
    653 	ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
    654 	memset(&inode, 0, sizeof(inode));
    655 	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
    656 	inode.i_atime = inode.i_ctime = inode.i_mtime =
    657 		fs->now ? fs->now : time(0);
    658 	inode.i_links_count = 1;
    659 	retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
    660 	if (retval)
    661 		goto out;
    662 	if (ext2fs_has_feature_inline_data(fs->super)) {
    663 		inode.i_flags |= EXT4_INLINE_DATA_FL;
    664 	} else if (ext2fs_has_feature_extents(fs->super)) {
    665 		ext2_extent_handle_t handle;
    666 
    667 		inode.i_flags &= ~EXT4_EXTENTS_FL;
    668 		retval = ext2fs_extent_open2(fs, newfile, &inode, &handle);
    669 		if (retval)
    670 			goto out;
    671 		ext2fs_extent_free(handle);
    672 	}
    673 
    674 	retval = ext2fs_write_new_inode(fs, newfile, &inode);
    675 	if (retval)
    676 		goto out;
    677 	if (inode.i_flags & EXT4_INLINE_DATA_FL) {
    678 		retval = ext2fs_inline_data_init(fs, newfile);
    679 		if (retval)
    680 			goto out;
    681 	}
    682 	if (LINUX_S_ISREG(inode.i_mode)) {
    683 		retval = copy_file(fs, fd, &statbuf, newfile);
    684 		if (retval)
    685 			goto out;
    686 	}
    687 out:
    688 	close(fd);
    689 	return retval;
    690 }
    691 
    692 struct file_info {
    693 	char *path;
    694 	size_t path_len;
    695 	size_t path_max_len;
    696 };
    697 
    698 static errcode_t path_append(struct file_info *target, const char *file)
    699 {
    700 	if (strlen(file) + target->path_len + 1 > target->path_max_len) {
    701 		target->path_max_len *= 2;
    702 		target->path = realloc(target->path, target->path_max_len);
    703 		if (!target->path)
    704 			return EXT2_ET_NO_MEMORY;
    705 	}
    706 	target->path_len += sprintf(target->path + target->path_len, "/%s",
    707 				    file);
    708 	return 0;
    709 }
    710 
    711 /* Copy files from source_dir to fs */
    712 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
    713 			       const char *source_dir, ext2_ino_t root,
    714 			       struct hdlinks_s *hdlinks,
    715 			       struct file_info *target,
    716 			       struct fs_ops_callbacks *fs_callbacks)
    717 {
    718 	const char	*name;
    719 	DIR		*dh;
    720 	struct dirent	*dent;
    721 	struct stat	st;
    722 	char		*ln_target = NULL;
    723 	unsigned int	save_inode;
    724 	ext2_ino_t	ino;
    725 	errcode_t	retval = 0;
    726 	int		read_cnt;
    727 	int		hdlink;
    728 	size_t		cur_dir_path_len;
    729 
    730 	if (chdir(source_dir) < 0) {
    731 		retval = errno;
    732 		com_err(__func__, retval,
    733 			_("while changing working directory to \"%s\""),
    734 			source_dir);
    735 		return retval;
    736 	}
    737 
    738 	if (!(dh = opendir("."))) {
    739 		retval = errno;
    740 		com_err(__func__, retval,
    741 			_("while opening directory \"%s\""), source_dir);
    742 		return retval;
    743 	}
    744 
    745 	while ((dent = readdir(dh))) {
    746 		if ((!strcmp(dent->d_name, ".")) ||
    747 		    (!strcmp(dent->d_name, "..")))
    748 			continue;
    749 		if (lstat(dent->d_name, &st)) {
    750 			retval = errno;
    751 			com_err(__func__, retval, _("while lstat \"%s\""),
    752 				dent->d_name);
    753 			goto out;
    754 		}
    755 		name = dent->d_name;
    756 
    757 		/* Check for hardlinks */
    758 		save_inode = 0;
    759 		if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
    760 		    st.st_nlink > 1) {
    761 			hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
    762 			if (hdlink >= 0) {
    763 				retval = add_link(fs, parent_ino,
    764 						  hdlinks->hdl[hdlink].dst_ino,
    765 						  name);
    766 				if (retval) {
    767 					com_err(__func__, retval,
    768 						"while linking %s", name);
    769 					goto out;
    770 				}
    771 				continue;
    772 			} else
    773 				save_inode = 1;
    774 		}
    775 
    776 		cur_dir_path_len = target->path_len;
    777 		retval = path_append(target, name);
    778 		if (retval) {
    779 			com_err(__func__, retval,
    780 				"while appending %s", name);
    781 			goto out;
    782 		}
    783 
    784 		if (fs_callbacks && fs_callbacks->create_new_inode) {
    785 			retval = fs_callbacks->create_new_inode(fs,
    786 				target->path, name, parent_ino, root,
    787 				st.st_mode & S_IFMT);
    788 			if (retval)
    789 				goto out;
    790 		}
    791 
    792 		switch(st.st_mode & S_IFMT) {
    793 		case S_IFCHR:
    794 		case S_IFBLK:
    795 		case S_IFIFO:
    796 #ifndef _WIN32
    797 		case S_IFSOCK:
    798 			retval = do_mknod_internal(fs, parent_ino, name, &st);
    799 			if (retval) {
    800 				com_err(__func__, retval,
    801 					_("while creating special file "
    802 					  "\"%s\""), name);
    803 				goto out;
    804 			}
    805 			break;
    806 		case S_IFLNK:
    807 			ln_target = malloc(st.st_size + 1);
    808 			if (ln_target == NULL) {
    809 				com_err(__func__, retval,
    810 					_("malloc failed"));
    811 				goto out;
    812 			}
    813 			read_cnt = readlink(name, ln_target,
    814 					    st.st_size + 1);
    815 			if (read_cnt == -1) {
    816 				retval = errno;
    817 				com_err(__func__, retval,
    818 					_("while trying to read link \"%s\""),
    819 					name);
    820 				free(ln_target);
    821 				goto out;
    822 			}
    823 			if (read_cnt > st.st_size) {
    824 				com_err(__func__, retval,
    825 					_("symlink increased in size "
    826 					  "between lstat() and readlink()"));
    827 				free(ln_target);
    828 				goto out;
    829 			}
    830 			ln_target[read_cnt] = '\0';
    831 			retval = do_symlink_internal(fs, parent_ino, name,
    832 						     ln_target, root);
    833 			free(ln_target);
    834 			if (retval) {
    835 				com_err(__func__, retval,
    836 					_("while writing symlink\"%s\""),
    837 					name);
    838 				goto out;
    839 			}
    840 			break;
    841 #endif
    842 		case S_IFREG:
    843 			retval = do_write_internal(fs, parent_ino, name, name,
    844 						   root);
    845 			if (retval) {
    846 				com_err(__func__, retval,
    847 					_("while writing file \"%s\""), name);
    848 				goto out;
    849 			}
    850 			break;
    851 		case S_IFDIR:
    852 			/* Don't choke on /lost+found */
    853 			if (parent_ino == EXT2_ROOT_INO &&
    854 			    strcmp(name, "lost+found") == 0)
    855 				goto find_lnf;
    856 			retval = do_mkdir_internal(fs, parent_ino, name,
    857 						   root);
    858 			if (retval) {
    859 				com_err(__func__, retval,
    860 					_("while making dir \"%s\""), name);
    861 				goto out;
    862 			}
    863 find_lnf:
    864 			retval = ext2fs_namei(fs, root, parent_ino,
    865 					      name, &ino);
    866 			if (retval) {
    867 				com_err(name, retval, 0);
    868 					goto out;
    869 			}
    870 			/* Populate the dir recursively*/
    871 			retval = __populate_fs(fs, ino, name, root, hdlinks,
    872 					       target, fs_callbacks);
    873 			if (retval)
    874 				goto out;
    875 			if (chdir("..")) {
    876 				retval = errno;
    877 				com_err(__func__, retval,
    878 					_("while changing directory"));
    879 				goto out;
    880 			}
    881 			break;
    882 		default:
    883 			com_err(__func__, 0,
    884 				_("ignoring entry \"%s\""), name);
    885 		}
    886 
    887 		retval =  ext2fs_namei(fs, root, parent_ino, name, &ino);
    888 		if (retval) {
    889 			com_err(name, retval, _("while looking up \"%s\""),
    890 				name);
    891 			goto out;
    892 		}
    893 
    894 		retval = set_inode_extra(fs, ino, &st);
    895 		if (retval) {
    896 			com_err(__func__, retval,
    897 				_("while setting inode for \"%s\""), name);
    898 			goto out;
    899 		}
    900 
    901 		retval = set_inode_xattr(fs, ino, name);
    902 		if (retval) {
    903 			com_err(__func__, retval,
    904 				_("while setting xattrs for \"%s\""), name);
    905 			goto out;
    906 		}
    907 
    908 		if (fs_callbacks && fs_callbacks->end_create_new_inode) {
    909 			retval = fs_callbacks->end_create_new_inode(fs,
    910 				target->path, name, parent_ino, root,
    911 				st.st_mode & S_IFMT);
    912 			if (retval)
    913 				goto out;
    914 		}
    915 
    916 		/* Save the hardlink ino */
    917 		if (save_inode) {
    918 			/*
    919 			 * Check whether need more memory, and we don't need
    920 			 * free() since the lifespan will be over after the fs
    921 			 * populated.
    922 			 */
    923 			if (hdlinks->count == hdlinks->size) {
    924 				void *p = realloc(hdlinks->hdl,
    925 						(hdlinks->size + HDLINK_CNT) *
    926 						sizeof(struct hdlink_s));
    927 				if (p == NULL) {
    928 					retval = EXT2_ET_NO_MEMORY;
    929 					com_err(name, retval,
    930 						_("while saving inode data"));
    931 					goto out;
    932 				}
    933 				hdlinks->hdl = p;
    934 				hdlinks->size += HDLINK_CNT;
    935 			}
    936 			hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
    937 			hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
    938 			hdlinks->hdl[hdlinks->count].dst_ino = ino;
    939 			hdlinks->count++;
    940 		}
    941 		target->path_len = cur_dir_path_len;
    942 		target->path[target->path_len] = 0;
    943 	}
    944 
    945 out:
    946 	closedir(dh);
    947 	return retval;
    948 }
    949 
    950 errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
    951 		       const char *source_dir, ext2_ino_t root,
    952 		       struct fs_ops_callbacks *fs_callbacks)
    953 {
    954 	struct file_info file_info;
    955 	struct hdlinks_s hdlinks;
    956 	errcode_t retval;
    957 
    958 	if (!(fs->flags & EXT2_FLAG_RW)) {
    959 		com_err(__func__, 0, "Filesystem opened readonly");
    960 		return EROFS;
    961 	}
    962 
    963 	hdlinks.count = 0;
    964 	hdlinks.size = HDLINK_CNT;
    965 	hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
    966 	if (hdlinks.hdl == NULL) {
    967 		retval = errno;
    968 		com_err(__func__, retval, _("while allocating memory"));
    969 		return retval;
    970 	}
    971 
    972 	file_info.path_len = 0;
    973 	file_info.path_max_len = 255;
    974 	file_info.path = calloc(file_info.path_max_len, 1);
    975 
    976 	retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
    977 			       &file_info, fs_callbacks);
    978 
    979 	free(file_info.path);
    980 	free(hdlinks.hdl);
    981 	return retval;
    982 }
    983 
    984 errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
    985 		      const char *source_dir, ext2_ino_t root)
    986 {
    987 	return populate_fs2(fs, parent_ino, source_dir, root, NULL);
    988 }
    989