10ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/*
20ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * create_inode.c --- create an inode
30ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey *
40ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * Copyright (C) 2014 Robert Yang <liezhi.yang@windriver.com>
50ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey *
60ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * %Begin-Header%
70ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * This file may be redistributed under the terms of the GNU library
80ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * General Public License, version 2.
90ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey * %End-Header%
100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey */
110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#define _FILE_OFFSET_BITS       64
130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#define _LARGEFILE64_SOURCE     1
140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#define _GNU_SOURCE		1
150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include "config.h"
170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <time.h>
180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <sys/types.h>
190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <unistd.h>
200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <limits.h> /* for PATH_MAX */
210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#ifdef HAVE_ATTR_XATTR_H
220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <attr/xattr.h>
230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <sys/ioctl.h>
250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <ext2fs/ext2fs.h>
260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <ext2fs/ext2_types.h>
270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include <ext2fs/fiemap.h>
280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include "create_inode.h"
300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#include "support/nls-enable.h"
310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* 64KiB is the minimium blksize to best minimize system call overhead. */
330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#define COPY_FILE_BUFLEN	65536
340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic int ext2_file_type(unsigned int mode)
360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISREG(mode))
380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_REG_FILE;
390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISDIR(mode))
410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_DIR;
420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISCHR(mode))
440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_CHRDEV;
450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISBLK(mode))
470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_BLKDEV;
480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISLNK(mode))
500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_SYMLINK;
510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISFIFO(mode))
530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_FIFO;
540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISSOCK(mode))
560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_FT_SOCK;
570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return 0;
590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Link an inode number to a directory */
620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			  ext2_ino_t ino, const char *name)
640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct ext2_inode	inode;
660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t		retval;
670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_read_inode(fs, ino, &inode);
690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey        if (retval) {
700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while reading inode %u"), ino);
710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_link(fs, parent_ino, name, ino,
750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			     ext2_file_type(inode.i_mode));
760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == EXT2_ET_DIR_NO_SPACE) {
770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_expand_dir(fs, parent_ino);
780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while expanding directory"));
810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_link(fs, parent_ino, name, ino,
840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				     ext2_file_type(inode.i_mode));
850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval) {
870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while linking \"%s\""), name);
880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_links_count++;
920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_write_inode(fs, ino, &inode);
940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while writing inode %u"), ino);
960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Set the uid, gid, mode and time for the inode */
1010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
1020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 struct stat *st)
1030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
1040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t		retval;
1050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct ext2_inode	inode;
1060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_read_inode(fs, ino, &inode);
1080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey        if (retval) {
1090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while reading inode %u"), ino);
1100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
1110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
1120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_uid = st->st_uid;
1140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_gid = st->st_gid;
1150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_mode |= st->st_mode;
1160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_atime = st->st_atime;
1170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_mtime = st->st_mtime;
1180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_ctime = st->st_ctime;
1190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_write_inode(fs, ino, &inode);
1210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
1220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while writing inode %u"), ino);
1230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
1240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
1250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#ifdef HAVE_LLISTXATTR
1270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino,
1280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 const char *filename)
1290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
1300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t			retval, close_retval;
1310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct ext2_xattr_handle	*handle;
1320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ssize_t				size, value_size;
1330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char				*list = NULL;
1340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int				i;
1350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	size = llistxattr(filename, NULL, 0);
1370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (size == -1) {
1380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
1390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while listing attributes of \"%s\""),
1400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			filename);
1410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
1420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	} else if (size == 0) {
1430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return 0;
1440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
1450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_xattrs_open(fs, ino, &handle);
1470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval) {
1480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval == EXT2_ET_MISSING_EA_FEATURE)
1490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return 0;
1500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while opening inode %u"), ino);
1510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
1520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
1530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_get_mem(size, &list);
1550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval) {
1560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while allocating memory"));
1570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
1580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
1590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	size = llistxattr(filename, list, size);
1610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (size == -1) {
1620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
1630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while listing attributes of \"%s\""),
1640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			filename);
1650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
1660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey        }
1670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	for (i = 0; i < size; i += strlen(&list[i]) + 1) {
1690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		const char *name = &list[i];
1700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		char *value;
1710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		value_size = lgetxattr(filename, name, NULL, 0);
1730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (value_size == -1) {
1740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = errno;
1750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
1760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while reading attribute \"%s\" of \"%s\""),
1770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				name, filename);
1780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
1790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
1800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_get_mem(value_size, &value);
1820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
1830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval, _("while allocating memory"));
1840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
1850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
1860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		value_size = lgetxattr(filename, name, value, value_size);
1880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (value_size == -1) {
1890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			ext2fs_free_mem(&value);
1900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = errno;
1910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
1920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while reading attribute \"%s\" of \"%s\""),
1930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				name, filename);
1940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
1950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
1960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
1970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_xattr_set(handle, name, value, value_size);
1980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		ext2fs_free_mem(&value);
1990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
2000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
2010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while writing attribute \"%s\" to inode %u"),
2020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				name, ino);
2030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
2040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
2050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey out:
2080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_free_mem(&list);
2090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	close_retval = ext2fs_xattrs_close(&handle);
2100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (close_retval) {
2110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while closing inode %u"), ino);
2120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = retval ? retval : close_retval;
2130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
2150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return 0;
2160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
2170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#else /* HAVE_LLISTXATTR */
2180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)),
2190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 ext2_ino_t ino EXT2FS_ATTR((unused)),
2200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 const char *filename EXT2FS_ATTR((unused)))
2210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
2220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return 0;
2230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
2240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif  /* HAVE_LLISTXATTR */
2250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Make a special files (block and character devices), fifo's, and sockets  */
2270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyerrcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
2280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			    struct stat *st)
2290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
2300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_ino_t		ino;
2310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t		retval;
2320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct ext2_inode	inode;
2330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	unsigned long		devmajor, devminor, mode;
2340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int			filetype;
2350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	switch(st->st_mode & S_IFMT) {
2370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	case S_IFCHR:
2380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		mode = LINUX_S_IFCHR;
2390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		filetype = EXT2_FT_CHRDEV;
2400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		break;
2410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	case S_IFBLK:
2420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		mode = LINUX_S_IFBLK;
2430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		filetype =  EXT2_FT_BLKDEV;
2440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		break;
2450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	case S_IFIFO:
2460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		mode = LINUX_S_IFIFO;
2470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		filetype = EXT2_FT_FIFO;
2480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		break;
2490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	case S_IFSOCK:
2500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		mode = LINUX_S_IFSOCK;
2510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		filetype = EXT2_FT_SOCK;
2520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		break;
2530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	default:
2540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EXT2_ET_INVALID_ARGUMENT;
2550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
2580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval) {
2590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while allocating inode \"%s\""),
2600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			name);
2610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
2620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#ifdef DEBUGFS
2650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	printf("Allocated inode: %u\n", ino);
2660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
2670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_link(fs, cwd, name, ino, filetype);
2680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == EXT2_ET_DIR_NO_SPACE) {
2690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_expand_dir(fs, cwd);
2700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
2710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
2720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while expanding directory"));
2730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
2740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
2750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_link(fs, cwd, name, ino, filetype);
2760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval) {
2780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(name, retval, _("while creating inode \"%s\""), name);
2790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
2800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
2810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
2820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, 0, "Warning: inode already set");
2830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
2840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	memset(&inode, 0, sizeof(inode));
2850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_mode = mode;
2860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_atime = inode.i_ctime = inode.i_mtime =
2870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		fs->now ? fs->now : time(0);
2880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (filetype != S_IFIFO) {
2900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		devmajor = major(st->st_rdev);
2910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		devminor = minor(st->st_rdev);
2920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
2930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if ((devmajor < 256) && (devminor < 256)) {
2940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			inode.i_block[0] = devmajor * 256 + devminor;
2950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			inode.i_block[1] = 0;
2960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		} else {
2970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			inode.i_block[0] = 0;
2980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
2990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					   ((devminor & ~0xff) << 12);
3000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
3010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
3020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_links_count = 1;
3030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_write_new_inode(fs, ino, &inode);
3050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
3060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while writing inode %u"), ino);
3070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
3090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
3100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Make a symlink name -> target */
3120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyerrcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
3130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			      char *target, ext2_ino_t root)
3140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
3150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char			*cp;
3160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_ino_t		parent_ino;
3170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t		retval;
3180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	cp = strrchr(name, '/');
3200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (cp) {
3210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		*cp = 0;
3220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
3230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
3240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(name, retval, 0);
3250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
3260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
3270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		name = cp+1;
3280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	} else
3290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		parent_ino = cwd;
3300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
3320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == EXT2_ET_DIR_NO_SPACE) {
3330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_expand_dir(fs, parent_ino);
3340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
3350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err("do_symlink_internal", retval,
3360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while expanding directory"));
3370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
3380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
3390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
3400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
3410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
3420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err("ext2fs_symlink", retval,
3430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			_("while creating symlink \"%s\""), name);
3440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
3450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
3460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Make a directory in the fs */
3480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyerrcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
3490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			    ext2_ino_t root)
3500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
3510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char			*cp;
3520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_ino_t		parent_ino;
3530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t		retval;
3540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	cp = strrchr(name, '/');
3570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (cp) {
3580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		*cp = 0;
3590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
3600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
3610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(name, retval, _("while looking up \"%s\""),
3620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				name);
3630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
3640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
3650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		name = cp+1;
3660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	} else
3670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		parent_ino = cwd;
3680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_mkdir(fs, parent_ino, 0, name);
3700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == EXT2_ET_DIR_NO_SPACE) {
3710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_expand_dir(fs, parent_ino);
3720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
3730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
3740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while expanding directory"));
3750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return retval;
3760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
3770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_mkdir(fs, parent_ino, 0, name);
3780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
3790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
3800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err("ext2fs_mkdir", retval,
3810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			_("while creating directory \"%s\""), name);
3820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
3830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
3840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#if !defined HAVE_PREAD64 && !defined HAVE_PREAD
3860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic ssize_t my_pread(int fd, void *buf, size_t count, off_t offset)
3870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
3880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (lseek(fd, offset, SEEK_SET) < 0)
3890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return 0;
3900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return read(fd, buf, count);
3920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
3930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */
3940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
3950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file,
3960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 off_t start, off_t end, char *buf,
3970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 char *zerobuf)
3980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
3990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	off_t off, bpos;
4000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ssize_t got, blen;
4010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	unsigned int written;
4020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char *ptr;
4030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t err = 0;
4040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	for (off = start; off < end; off += COPY_FILE_BUFLEN) {
4060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#ifdef HAVE_PREAD64
4070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		got = pread64(fd, buf, COPY_FILE_BUFLEN, off);
4080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#elif HAVE_PREAD
4090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		got = pread(fd, buf, COPY_FILE_BUFLEN, off);
4100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#else
4110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		got = my_pread(fd, buf, COPY_FILE_BUFLEN, off);
4120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
4130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (got < 0) {
4140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			err = errno;
4150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto fail;
4160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
4170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) {
4180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			blen = fs->blocksize;
4190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (blen > got - bpos)
4200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				blen = got - bpos;
4210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (memcmp(ptr, zerobuf, blen) == 0) {
4220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				ptr += blen;
4230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				continue;
4240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
4250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			err = ext2fs_file_lseek(e2_file, off + bpos,
4260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						EXT2_SEEK_SET, NULL);
4270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (err)
4280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto fail;
4290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			while (blen > 0) {
4300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				err = ext2fs_file_write(e2_file, ptr, blen,
4310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey							&written);
4320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				if (err)
4330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					goto fail;
4340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				if (written == 0) {
4350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					err = EIO;
4360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					goto fail;
4370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				}
4380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				blen -= written;
4390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				ptr += written;
4400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
4410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
4420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
4430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyfail:
4440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return err;
4450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
4460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#if defined(SEEK_DATA) && defined(SEEK_HOLE)
4480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf,
4490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				ext2_file_t e2_file, char *buf, char *zerobuf)
4500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
4510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	off_t data = 0, hole;
4520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	off_t data_blk, hole_blk;
4530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t err = 0;
4540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	/* Try to use SEEK_DATA and SEEK_HOLE */
4560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	while (data < statbuf->st_size) {
4570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		data = lseek(fd, data, SEEK_DATA);
4580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (data < 0) {
4590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (errno == ENXIO)
4600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				break;
4610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return EXT2_ET_UNIMPLEMENTED;
4620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
4630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		hole = lseek(fd, data, SEEK_HOLE);
4640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (hole < 0)
4650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return EXT2_ET_UNIMPLEMENTED;
4660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		data_blk = data & ~(fs->blocksize - 1);
4680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1);
4690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf,
4700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				      zerobuf);
4710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (err)
4720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return err;
4730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		data = hole;
4750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
4760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return err;
4780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
4790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif /* SEEK_DATA and SEEK_HOLE */
4800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#if defined(FS_IOC_FIEMAP)
4820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file,
4830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				 char *buf, char *zerobuf)
4840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
4850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#define EXTENT_MAX_COUNT 512
4860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct fiemap *fiemap_buf;
4870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct fiemap_extent *ext_buf, *ext;
4880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int ext_buf_size, fie_buf_size;
4890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	off_t pos = 0;
4900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	unsigned int i;
4910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t err;
4920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
4940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	fie_buf_size = sizeof(struct fiemap) + ext_buf_size;
4950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
4960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf);
4970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err)
4980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return err;
4990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext_buf = fiemap_buf->fm_extents;
5010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	memset(fiemap_buf, 0, fie_buf_size);
5020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	fiemap_buf->fm_length = FIEMAP_MAX_OFFSET;
5030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC;
5040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT;
5050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	do {
5070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		fiemap_buf->fm_start = pos;
5080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		memset(ext_buf, 0, ext_buf_size);
5090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
5100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) {
5110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			err = EXT2_ET_UNIMPLEMENTED;
5120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
5130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		} else if (err < 0 || fiemap_buf->fm_mapped_extents == 0) {
5140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			err = errno;
5150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
5160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
5170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents;
5180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		     i++, ext++) {
5190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			err = copy_file_range(fs, fd, e2_file, ext->fe_logical,
5200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					      ext->fe_logical + ext->fe_length,
5210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					      buf, zerobuf);
5220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (err)
5230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
5240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
5250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		ext--;
5270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		/* Record file's logical offset this time */
5280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		pos = ext->fe_logical + ext->fe_length;
5290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		/*
5300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		 * If fm_extents array has been filled and
5310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		 * there are extents left, continue to cycle.
5320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		 */
5330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	} while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT &&
5340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		 !(ext->fe_flags & FIEMAP_EXTENT_LAST));
5350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyout:
5360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_free_mem(&fiemap_buf);
5370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return err;
5380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
5390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif /* FS_IOC_FIEMAP */
5400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf,
5420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			   ext2_ino_t ino)
5430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
5440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_file_t e2_file;
5450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char *buf = NULL, *zerobuf = NULL;
5460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t err, close_err;
5470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
5490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err)
5500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return err;
5510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf);
5530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err)
5540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
5550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = ext2fs_get_memzero(fs->blocksize, &zerobuf);
5570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err)
5580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
5590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#if defined(SEEK_DATA) && defined(SEEK_HOLE)
5610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf);
5620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err != EXT2_ET_UNIMPLEMENTED)
5630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
5640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
5650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#if defined(FS_IOC_FIEMAP)
5670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf);
5680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err != EXT2_ET_UNIMPLEMENTED)
5690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
5700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
5710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf,
5730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			      zerobuf);
5740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyout:
5750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_free_mem(&zerobuf);
5760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_free_mem(&buf);
5770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	close_err = ext2fs_file_close(e2_file);
5780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (err == 0)
5790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		err = close_err;
5800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return err;
5810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
5820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
5840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
5850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int i;
5860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	for (i = 0; i < hdlinks->count; i++) {
5880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (hdlinks->hdl[i].src_dev == dev &&
5890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		    hdlinks->hdl[i].src_ino == ino)
5900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			return i;
5910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
5920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return -1;
5930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
5940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
5950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Copy the native file to the fs */
5960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyerrcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
5970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			    const char *dest, ext2_ino_t root)
5980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
5990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int		fd;
6000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct stat	statbuf;
6010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_ino_t	newfile;
6020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t	retval;
6030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct ext2_inode inode;
6040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
6050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	fd = ext2fs_open_file(src, O_RDONLY, 0);
6060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (fd < 0) {
6070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
6080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while opening \"%s\" to copy"),
6090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			src);
6100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
6110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (fstat(fd, &statbuf) < 0) {
6130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
6140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
6170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
6180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == 0) {
6190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = EXT2_ET_FILE_EXISTS;
6200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
6230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
6240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
6250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#ifdef DEBUGFS
6270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	printf("Allocated inode: %u\n", newfile);
6280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey#endif
6290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_link(fs, cwd, dest, newfile,
6300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				EXT2_FT_REG_FILE);
6310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval == EXT2_ET_DIR_NO_SPACE) {
6320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_expand_dir(fs, cwd);
6330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval)
6340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
6350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_link(fs, cwd, dest, newfile,
6360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					EXT2_FT_REG_FILE);
6370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
6390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
6410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, 0, "Warning: inode already set");
6420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
6430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	memset(&inode, 0, sizeof(inode));
6440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
6450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_atime = inode.i_ctime = inode.i_mtime =
6460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		fs->now ? fs->now : time(0);
6470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	inode.i_links_count = 1;
6480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
6490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
6500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (ext2fs_has_feature_inline_data(fs->super)) {
6520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		inode.i_flags |= EXT4_INLINE_DATA_FL;
6530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	} else if (ext2fs_has_feature_extents(fs->super)) {
6540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		ext2_extent_handle_t handle;
6550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
6560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		inode.i_flags &= ~EXT4_EXTENTS_FL;
6570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_extent_open2(fs, newfile, &inode, &handle);
6580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval)
6590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
6600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		ext2fs_extent_free(handle);
6610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
6630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	retval = ext2fs_write_new_inode(fs, newfile, &inode);
6640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (retval)
6650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		goto out;
6660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (inode.i_flags & EXT4_INLINE_DATA_FL) {
6670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = ext2fs_inline_data_init(fs, newfile);
6680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval)
6690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
6700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (LINUX_S_ISREG(inode.i_mode)) {
6720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = copy_file(fs, fd, &statbuf, newfile);
6730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval)
6740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
6750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
6760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyout:
6770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	close(fd);
6780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
6790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
6800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
681b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknechtstruct file_info {
682b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	char *path;
683b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	size_t path_len;
684b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	size_t path_max_len;
685b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht};
686b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
687b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknechtstatic errcode_t path_append(struct file_info *target, const char *file)
688b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht{
689b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	if (strlen(file) + target->path_len + 1 > target->path_max_len) {
690b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		target->path_max_len *= 2;
691b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		target->path = realloc(target->path, target->path_max_len);
692b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		if (!target->path)
693b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			return EXT2_ET_NO_MEMORY;
694b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	}
695b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	target->path_len += sprintf(target->path + target->path_len, "/%s",
696b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				    file);
697b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	return 0;
698b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht}
699b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
7000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey/* Copy files from source_dir to fs */
7010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeystatic errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
7020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			       const char *source_dir, ext2_ino_t root,
703b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			       struct hdlinks_s *hdlinks,
704b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			       struct file_info *target,
705b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			       struct fs_ops_callbacks *fs_callbacks)
7060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
7070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	const char	*name;
7080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	DIR		*dh;
7090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct dirent	*dent;
7100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct stat	st;
7110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	char		*ln_target = NULL;
7120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	unsigned int	save_inode;
7130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	ext2_ino_t	ino;
7140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t	retval = 0;
7150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int		read_cnt;
7160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	int		hdlink;
717b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	size_t		cur_dir_path_len;
7180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
7190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (chdir(source_dir) < 0) {
7200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
7210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval,
7220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			_("while changing working directory to \"%s\""),
7230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			source_dir);
7240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
7250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
7260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
7270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (!(dh = opendir("."))) {
7280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
7290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval,
7300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			_("while opening directory \"%s\""), source_dir);
7310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
7320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
7330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
7340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	while ((dent = readdir(dh))) {
7350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if ((!strcmp(dent->d_name, ".")) ||
7360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		    (!strcmp(dent->d_name, "..")))
7370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			continue;
7380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (lstat(dent->d_name, &st)) {
7390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = errno;
7400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval, _("while lstat \"%s\""),
7410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				dent->d_name);
7420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
7430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
7440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		name = dent->d_name;
7450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
7460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		/* Check for hardlinks */
7470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		save_inode = 0;
7480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
7490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		    st.st_nlink > 1) {
7500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
7510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (hdlink >= 0) {
7520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				retval = add_link(fs, parent_ino,
7530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						  hdlinks->hdl[hdlink].dst_ino,
7540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						  name);
7550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				if (retval) {
7560ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					com_err(__func__, retval,
7570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						"while linking %s", name);
7580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					goto out;
7590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				}
7600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				continue;
7610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			} else
7620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				save_inode = 1;
7630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
7640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
765b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		cur_dir_path_len = target->path_len;
766b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		retval = path_append(target, name);
767b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		if (retval)
768b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			return retval;
769b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
770b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		if (fs_callbacks && fs_callbacks->create_new_inode) {
771b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			retval = fs_callbacks->create_new_inode(fs,
772b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				target->path, name, parent_ino, root,
773b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				st.st_mode & S_IFMT);
774b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			if (retval)
775b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				goto out;
776b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		}
777b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
7780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		switch(st.st_mode & S_IFMT) {
7790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFCHR:
7800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFBLK:
7810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFIFO:
7820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFSOCK:
7830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = do_mknod_internal(fs, parent_ino, name, &st);
7840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval) {
7850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
7860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while creating special file "
7870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					  "\"%s\""), name);
7880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
7890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
7900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
7910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFLNK:
7920ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			ln_target = malloc(st.st_size + 1);
7930ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (ln_target == NULL) {
7940ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
7950ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("malloc failed"));
7960ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
7970ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
7980ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			read_cnt = readlink(name, ln_target,
7990ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					    st.st_size + 1);
8000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (read_cnt == -1) {
8010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				retval = errno;
8020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while trying to read link \"%s\""),
8040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					name);
8050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				free(ln_target);
8060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (read_cnt > st.st_size) {
8090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("symlink increased in size "
8110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					  "between lstat() and readlink()"));
8120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				free(ln_target);
8130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			ln_target[read_cnt] = '\0';
8160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = do_symlink_internal(fs, parent_ino, name,
8170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						     ln_target, root);
8180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			free(ln_target);
8190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval) {
8200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while writing symlink\"%s\""),
8220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					name);
8230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8250ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
8260ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFREG:
8270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = do_write_internal(fs, parent_ino, name, name,
8280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						   root);
8290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval) {
8300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while writing file \"%s\""), name);
8320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8340ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
8350ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		case S_IFDIR:
8360ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			/* Don't choke on /lost+found */
8370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (parent_ino == EXT2_ROOT_INO &&
8380ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			    strcmp(name, "lost+found") == 0)
8390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto find_lnf;
8400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = do_mkdir_internal(fs, parent_ino, name,
8410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						   root);
8420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval) {
8430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while making dir \"%s\""), name);
8450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyfind_lnf:
8480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			retval = ext2fs_namei(fs, root, parent_ino,
8490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					      name, &ino);
8500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval) {
8510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(name, retval, 0);
8520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					goto out;
8530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			/* Populate the dir recursively*/
855b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			retval = __populate_fs(fs, ino, name, root, hdlinks,
856b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht					       target, fs_callbacks);
8570ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (retval)
8580ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (chdir("..")) {
8600ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				retval = errno;
8610ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				com_err(__func__, retval,
8620ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					_("while changing directory"));
8630ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				goto out;
8640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
8650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			break;
8660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		default:
8670ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, 0,
8680ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("ignoring entry \"%s\""), name);
8690ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
8700ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
8710ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval =  ext2fs_namei(fs, root, parent_ino, name, &ino);
8720ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
8730ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(name, retval, _("while looking up \"%s\""),
8740ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				name);
8750ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
8760ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
8770ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
8780ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = set_inode_extra(fs, ino, &st);
8790ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
8800ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
8810ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while setting inode for \"%s\""), name);
8820ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
8830ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
8840ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
8850ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = set_inode_xattr(fs, ino, name);
8860ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (retval) {
8870ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			com_err(__func__, retval,
8880ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				_("while setting xattrs for \"%s\""), name);
8890ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			goto out;
8900ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
8910ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
892b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		if (fs_callbacks && fs_callbacks->end_create_new_inode) {
893b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			retval = fs_callbacks->end_create_new_inode(fs,
894b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				target->path, name, parent_ino, root,
895b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				st.st_mode & S_IFMT);
896b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			if (retval)
897b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht				goto out;
898b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		}
899b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
9000ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		/* Save the hardlink ino */
9010ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		if (save_inode) {
9020ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			/*
9030ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			 * Check whether need more memory, and we don't need
9040ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			 * free() since the lifespan will be over after the fs
9050ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			 * populated.
9060ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			 */
9070ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			if (hdlinks->count == hdlinks->size) {
9080ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				void *p = realloc(hdlinks->hdl,
9090ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						(hdlinks->size + HDLINK_CNT) *
9100ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						sizeof(struct hdlink_s));
9110ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				if (p == NULL) {
9120ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					retval = EXT2_ET_NO_MEMORY;
9130ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					com_err(name, retval,
9140ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey						_("while saving inode data"));
9150ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey					goto out;
9160ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				}
9170ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				hdlinks->hdl = p;
9180ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey				hdlinks->size += HDLINK_CNT;
9190ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			}
9200ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
9210ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
9220ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			hdlinks->hdl[hdlinks->count].dst_ino = ino;
9230ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey			hdlinks->count++;
9240ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		}
925b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		target->path_len = cur_dir_path_len;
926b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		target->path[target->path_len] = 0;
9270ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
9280ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
9290ce8844d681b935caad893db8ff740400262ec8bJeff Sharkeyout:
9300ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	closedir(dh);
9310ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
9320ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
9330ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
934b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknechterrcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
935b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		       const char *source_dir, ext2_ino_t root,
936b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		       struct fs_ops_callbacks *fs_callbacks)
9370ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey{
938b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	struct file_info file_info;
9390ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	struct hdlinks_s hdlinks;
9400ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	errcode_t retval;
9410ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
9420ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (!(fs->flags & EXT2_FLAG_RW)) {
9430ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, 0, "Filesystem opened readonly");
9440ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return EROFS;
9450ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
9460ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
9470ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	hdlinks.count = 0;
9480ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	hdlinks.size = HDLINK_CNT;
9490ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
9500ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	if (hdlinks.hdl == NULL) {
9510ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		retval = errno;
9520ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		com_err(__func__, retval, _("while allocating memory"));
9530ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey		return retval;
9540ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	}
9550ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
956b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	file_info.path_len = 0;
957b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	file_info.path_max_len = 255;
958b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	file_info.path = calloc(file_info.path_max_len, 1);
9590ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey
960b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
961b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht			       &file_info, fs_callbacks);
962b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
963b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	free(file_info.path);
9640ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	free(hdlinks.hdl);
9650ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey	return retval;
9660ce8844d681b935caad893db8ff740400262ec8bJeff Sharkey}
967b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht
968b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknechterrcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
969b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht		      const char *source_dir, ext2_ino_t root)
970b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht{
971b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht	return populate_fs2(fs, parent_ino, source_dir, root, NULL);
972b298f7e8a30775943ec21c2ad1c7fbe30bb8fd09Adrien Schildknecht}
973