diff mbox

[V4,05/11] misc/create_inode.c: copy regular file

Message ID 1393661175-459-6-git-send-email-liezhi.yang@windriver.com
State Accepted, archived
Headers show

Commit Message

Robert Yang March 1, 2014, 8:06 a.m. UTC
The do_write_internal() is used for copying file from native fs to
target, most of the code are from debugfs/debugfs.c, the
debugfs/debugfs.c will be modified to use this function.

Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Reviewed-by: Darren Hart <dvhart@linux.intel.com>
---
 misc/create_inode.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

Comments

Darrick Wong March 6, 2014, 7:06 p.m. UTC | #1
I noticed a few things while merging -next into my dev tree...

On Sat, Mar 01, 2014 at 03:06:09AM -0500, Robert Yang wrote:
> The do_write_internal() is used for copying file from native fs to
> target, most of the code are from debugfs/debugfs.c, the
> debugfs/debugfs.c will be modified to use this function.
> 
> Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
> Reviewed-by: Darren Hart <dvhart@linux.intel.com>
> ---
>  misc/create_inode.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 183 insertions(+)
> 
> diff --git a/misc/create_inode.c b/misc/create_inode.c
> index f845103..98f4a93 100644
> --- a/misc/create_inode.c
> +++ b/misc/create_inode.c
> @@ -8,6 +8,16 @@
>  # endif
>  #endif
>  
> +/* 64KiB is the minimium blksize to best minimize system call overhead. */
> +#ifndef IO_BUFSIZE
> +#define IO_BUFSIZE 64*1024
> +#endif
> +
> +/* Block size for `st_blocks' */
> +#ifndef S_BLKSIZE
> +#define S_BLKSIZE 512
> +#endif
> +
>  /* Make a special file which is block, character and fifo */
>  errcode_t do_mknod_internal(ext2_ino_t cwd, const char *name, struct stat *st)
>  {
> @@ -127,9 +137,182 @@ errcode_t do_mkdir_internal(ext2_ino_t cwd, const char *name, struct stat *st)
>  {
>  }
>  
> +static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
> +{
> +	ext2_file_t	e2_file;
> +	errcode_t	retval;
> +	int		got;
> +	unsigned int	written;
> +	char		*buf;
> +	char		*ptr;
> +	char		*zero_buf;
> +	int		cmp;
> +
> +	retval = ext2fs_file_open(current_fs, newfile,
> +				  EXT2_FILE_WRITE, &e2_file);
> +	if (retval)
> +		return retval;
> +
> +	retval = ext2fs_get_mem(bufsize, &buf);
> +	if (retval) {
> +		com_err("copy_file", retval, "can't allocate buffer\n");
> +		return retval;
> +	}
> +
> +	/* This is used for checking whether the whole block is zero */
> +	retval = ext2fs_get_memzero(bufsize, &zero_buf);
> +	if (retval) {
> +		com_err("copy_file", retval, "can't allocate buffer\n");
> +		ext2fs_free_mem(&buf);
> +		return retval;
> +	}
> +
> +	while (1) {
> +		got = read(fd, buf, bufsize);
> +		if (got == 0)
> +			break;
> +		if (got < 0) {
> +			retval = errno;
> +			goto fail;
> +		}
> +		ptr = buf;
> +
> +		/* Sparse copy */
> +		if (make_holes) {
> +			/* Check whether all is zero */
> +			cmp = memcmp(ptr, zero_buf, got);
> +			if (cmp == 0) {
> +				 /* The whole block is zero, make a hole */
> +				retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
> +				if (retval)
> +					goto fail;
> +				got = 0;
> +			}
> +		}
> +
> +		/* Normal copy */
> +		while (got > 0) {
> +			retval = ext2fs_file_write(e2_file, ptr,
> +						   got, &written);
> +			if (retval)
> +				goto fail;
> +
> +			got -= written;
> +			ptr += written;
> +		}
> +	}
> +	ext2fs_free_mem(&buf);
> +	ext2fs_free_mem(&zero_buf);
> +	retval = ext2fs_file_close(e2_file);
> +	return retval;
> +
> +fail:
> +	ext2fs_free_mem(&buf);
> +	ext2fs_free_mem(&zero_buf);
> +	(void) ext2fs_file_close(e2_file);
> +	return retval;
> +}
> +
>  /* Copy the native file to the fs */
>  errcode_t do_write_internal(ext2_ino_t cwd, const char *src, const char *dest)
>  {
> +	int		fd;
> +	struct stat	statbuf;
> +	ext2_ino_t	newfile;
> +	errcode_t	retval;
> +	struct ext2_inode inode;
> +	int		bufsize = IO_BUFSIZE;
> +	int		make_holes = 0;
> +
> +	fd = open(src, O_RDONLY);
> +	if (fd < 0) {
> +		com_err(src, errno, 0);
> +		return errno;
> +	}
> +	if (fstat(fd, &statbuf) < 0) {
> +		com_err(src, errno, 0);
> +		close(fd);
> +		return errno;
> +	}
> +
> +	retval = ext2fs_namei(current_fs, root, cwd, dest, &newfile);
> +	if (retval == 0) {
> +		com_err(__func__, 0, "The file '%s' already exists\n", dest);
> +		close(fd);
> +		return errno;
> +	}
> +
> +	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
> +	if (retval) {
> +		com_err(__func__, retval, 0);
> +		close(fd);
> +		return errno;

Why return errno here, instead of retval?

> +	}
> +#ifdef DEBUGFS
> +	printf("Allocated inode: %u\n", newfile);
> +#endif
> +	retval = ext2fs_link(current_fs, cwd, dest, newfile,
> +				EXT2_FT_REG_FILE);
> +	if (retval == EXT2_ET_DIR_NO_SPACE) {
> +		retval = ext2fs_expand_dir(current_fs, cwd);
> +		if (retval) {
> +			com_err(__func__, retval, "while expanding directory");
> +			close(fd);
> +			return errno;

Or here...

> +		}
> +		retval = ext2fs_link(current_fs, cwd, dest, newfile,
> +					EXT2_FT_REG_FILE);
> +	}
> +	if (retval) {
> +		com_err(dest, retval, 0);
> +		close(fd);
> +		return errno;

Or here...

--D
> +	}
> +        if (ext2fs_test_inode_bitmap2(current_fs->inode_map, newfile))
> +		com_err(__func__, 0, "Warning: inode already set");
> +	ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
> +	memset(&inode, 0, sizeof(inode));
> +	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
> +	inode.i_atime = inode.i_ctime = inode.i_mtime =
> +		current_fs->now ? current_fs->now : time(0);
> +	inode.i_links_count = 1;
> +	inode.i_size = statbuf.st_size;
> +	if (current_fs->super->s_feature_incompat &
> +	    EXT3_FEATURE_INCOMPAT_EXTENTS) {
> +		int i;
> +		struct ext3_extent_header *eh;
> +
> +		eh = (struct ext3_extent_header *) &inode.i_block[0];
> +		eh->eh_depth = 0;
> +		eh->eh_entries = 0;
> +		eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
> +		i = (sizeof(inode.i_block) - sizeof(*eh)) /
> +			sizeof(struct ext3_extent);
> +		eh->eh_max = ext2fs_cpu_to_le16(i);
> +		inode.i_flags |= EXT4_EXTENTS_FL;
> +	}
> +
> +	if ((retval = ext2fs_write_new_inode(current_fs, newfile, &inode))) {
> +		com_err(__func__, retval, "while creating inode %u", newfile);
> +		close(fd);
> +		return errno;
> +	}
> +	if (LINUX_S_ISREG(inode.i_mode)) {
> +		if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
> +			make_holes = 1;
> +			/*
> +			 * Use I/O blocksize as buffer size when
> +			 * copying sparse files.
> +			 */
> +			bufsize = statbuf.st_blksize;
> +		}
> +		retval = copy_file(fd, newfile, bufsize, make_holes);
> +		if (retval)
> +			com_err("copy_file", retval, 0);
> +	}
> +	close(fd);
> +
> +	return 0;
>  }
>  
>  /* Copy files from source_dir to fs */
> -- 
> 1.7.10.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Theodore Ts'o March 6, 2014, 7:47 p.m. UTC | #2
On Thu, Mar 06, 2014 at 11:06:22AM -0800, Darrick J. Wong wrote:
> I noticed a few things while merging -next into my dev tree...

Darrick, good catch!

> > +	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
> > +	if (retval) {
> > +		com_err(__func__, retval, 0);
> > +		close(fd);
> > +		return errno;
> 
> Why return errno here, instead of retval?

Yep, we should do s/errno/retval/ at the places that you noted.

Robert, since these are in next already, could you submit a patch to
fixt this up?

Thanks!!

					- Ted

P.S.  Fortunately, this isn't crypto code ala gnutls.  :-)

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong March 6, 2014, 8:14 p.m. UTC | #3
On Thu, Mar 06, 2014 at 02:47:15PM -0500, Theodore Ts'o wrote:
> On Thu, Mar 06, 2014 at 11:06:22AM -0800, Darrick J. Wong wrote:
> > I noticed a few things while merging -next into my dev tree...
> 
> Darrick, good catch!
> 
> > > +	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
> > > +	if (retval) {
> > > +		com_err(__func__, retval, 0);
> > > +		close(fd);
> > > +		return errno;
> > 
> > Why return errno here, instead of retval?
> 
> Yep, we should do s/errno/retval/ at the places that you noted.
> 
> Robert, since these are in next already, could you submit a patch to
> fixt this up?

I'm already queuing up a bunch of (more) fixes... there's more weird things I
didn't notice.  Such as, why is current_fs now defined in current_inode.h?
That really ought to have stayed in debugfs.c, and current_inode.h should have
'extern ext2_filsys current_fs;', no?

Also there's a no-return-value 'return;' if the inline data write fails later
down in that function, and I think it's time to pull in cppcheck on a make
C=1 build.

...I'll also respin the patchset I sent out a few days ago.

--D
> 
> Thanks!!
> 
> 					- Ted
> 
> P.S.  Fortunately, this isn't crypto code ala gnutls.  :-)
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Theodore Ts'o March 6, 2014, 10:57 p.m. UTC | #4
On Thu, Mar 06, 2014 at 12:14:39PM -0800, Darrick J. Wong wrote:
> 
> I'm already queuing up a bunch of (more) fixes... there's more weird things I
> didn't notice.  Such as, why is current_fs now defined in current_inode.h?
> That really ought to have stayed in debugfs.c, and current_inode.h should have
> 'extern ext2_filsys current_fs;', no?

Yes, that would be better --- although in the long term we should
probably try to get rid of the global variable and pass in an "fs"
parameter into functions in misc/create_inode.c.

Since these aren't in a shared library, I wasn't worried that much
about the details of the abstraction interface, but I'm sure there are
some ways that we can improve things.

BTW, one of my plans for 1.43 is to rename libquota.a to libe2int.a,
and to move things like profile.c, and other files shared between misc
and e2fsck, etc., into an "internal support" library.  I suspect
create_inoode.c would be a candidate for moving into this internal
support library.

Cheers,

> ...I'll also respin the patchset I sent out a few days ago.

Sorry for having you respin the patchset yet again --- although
hopefully it should be easier this time around.  I'm trying to be fair
in catching up with th e2fsprogs backlog, and Robert and Zheng's
patches have been outstanding for a long time.  Don't worry, yours are
next on the list.  :-)

Cheers,

						- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robert Yang March 7, 2014, 1:24 a.m. UTC | #5
On 03/07/2014 06:57 AM, Theodore Ts'o wrote:
> On Thu, Mar 06, 2014 at 12:14:39PM -0800, Darrick J. Wong wrote:
>>
>> I'm already queuing up a bunch of (more) fixes... there's more weird things I
>> didn't notice.  Such as, why is current_fs now defined in current_inode.h?
>> That really ought to have stayed in debugfs.c, and current_inode.h should have
>> 'extern ext2_filsys current_fs;', no?
>
> Yes, that would be better --- although in the long term we should
> probably try to get rid of the global variable and pass in an "fs"
> parameter into functions in misc/create_inode.c.
>
> Since these aren't in a shared library, I wasn't worried that much
> about the details of the abstraction interface, but I'm sure there are
> some ways that we can improve things.
>
> BTW, one of my plans for 1.43 is to rename libquota.a to libe2int.a,
> and to move things like profile.c, and other files shared between misc
> and e2fsck, etc., into an "internal support" library.  I suspect
> create_inoode.c would be a candidate for moving into this internal
> support library.
>

Hi Ted and Darrick,

Thank you very much for the great help, I think that I don't have to
submit a fix patch again since Darrick has helped me to fix the
problem, please feel free to let me know if there is anything I
can do.

// Robert

> Cheers,
>
>> ...I'll also respin the patchset I sent out a few days ago.
>
> Sorry for having you respin the patchset yet again --- although
> hopefully it should be easier this time around.  I'm trying to be fair
> in catching up with th e2fsprogs backlog, and Robert and Zheng's
> patches have been outstanding for a long time.  Don't worry, yours are
> next on the list.  :-)
>
> Cheers,
>
> 						- Ted
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong March 7, 2014, 2:38 a.m. UTC | #6
On Thu, Mar 06, 2014 at 05:57:14PM -0500, Theodore Ts'o wrote:
> On Thu, Mar 06, 2014 at 12:14:39PM -0800, Darrick J. Wong wrote:
> > 
> > I'm already queuing up a bunch of (more) fixes... there's more weird things I
> > didn't notice.  Such as, why is current_fs now defined in current_inode.h?
> > That really ought to have stayed in debugfs.c, and current_inode.h should have
> > 'extern ext2_filsys current_fs;', no?
> 
> Yes, that would be better --- although in the long term we should
> probably try to get rid of the global variable and pass in an "fs"
> parameter into functions in misc/create_inode.c.

Agreed (and fixed).

> Since these aren't in a shared library, I wasn't worried that much
> about the details of the abstraction interface, but I'm sure there are
> some ways that we can improve things.
> 
> BTW, one of my plans for 1.43 is to rename libquota.a to libe2int.a,
> and to move things like profile.c, and other files shared between misc
> and e2fsck, etc., into an "internal support" library.  I suspect
> create_inoode.c would be a candidate for moving into this internal
> support library.

Higher level functionality?  I'd been musing that such a thing might be
beneficial to userland tools.

> 
> Cheers,
> 
> > ...I'll also respin the patchset I sent out a few days ago.
> 
> Sorry for having you respin the patchset yet again --- although
> hopefully it should be easier this time around.  I'm trying to be fair
> in catching up with th e2fsprogs backlog, and Robert and Zheng's
> patches have been outstanding for a long time.  Don't worry, yours are
> next on the list.  :-)

It's fine, (st)git merging isn't usually that painful.  I was more worried
about the impact of spamming linux-ext4 with giant patchsets, but respinning is
better than nothing happening at all. :)

That said, combing through all the "new arrivals" when I run the static
checkers ... was intense this time.

Though, it is a little time consuming to run checkpatch, then sparse/cppcheck,
then make check, then the metadata checksum test, and then xfstests.  But,
skipping tests isn't acceptable either, given the things I've fubar'd in the
past from /not/ doing that. :)

--D

> 
> Cheers,
> 
> 						- Ted
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong March 7, 2014, 2:56 a.m. UTC | #7
On Fri, Mar 07, 2014 at 09:24:12AM +0800, Robert Yang wrote:
> 
> 
> On 03/07/2014 06:57 AM, Theodore Ts'o wrote:
> >On Thu, Mar 06, 2014 at 12:14:39PM -0800, Darrick J. Wong wrote:
> >>
> >>I'm already queuing up a bunch of (more) fixes... there's more weird things I
> >>didn't notice.  Such as, why is current_fs now defined in current_inode.h?
> >>That really ought to have stayed in debugfs.c, and current_inode.h should have
> >>'extern ext2_filsys current_fs;', no?
> >
> >Yes, that would be better --- although in the long term we should
> >probably try to get rid of the global variable and pass in an "fs"
> >parameter into functions in misc/create_inode.c.
> >
> >Since these aren't in a shared library, I wasn't worried that much
> >about the details of the abstraction interface, but I'm sure there are
> >some ways that we can improve things.
> >
> >BTW, one of my plans for 1.43 is to rename libquota.a to libe2int.a,
> >and to move things like profile.c, and other files shared between misc
> >and e2fsck, etc., into an "internal support" library.  I suspect
> >create_inoode.c would be a candidate for moving into this internal
> >support library.
> >
> 
> Hi Ted and Darrick,
> 
> Thank you very much for the great help, I think that I don't have to
> submit a fix patch again since Darrick has helped me to fix the
> problem, please feel free to let me know if there is anything I
> can do.

I'll have 6 patches for you to review soon.  I also fixed a number of style and
whitespace errors. :)

I had another thought about populate_fs -- it should be in charge of setting up
and tearing down the hdlinks_s hardlink map, not the caller, and it shouldn't
really be a global variable.  I noticed that populate_fs recursively calls
itself, so I moved the functionality to a static function and wrote a wrapper
that takes care of hdlinks and calls the static function.

By the way, one of the things I /didn't/ fix was the root inode parameter that
you pass to ext2fs_namei.  I couldn't tell if supporting debugfs' chroot
command is part of your requirements set (though it doesn't seem likely to me),
but I also think that a better interface would be to have callers of the
create_inode functions pass in the destination dir inode instead of a pathname,
similar to the do_mknod_internal interface.  debugfs is the only tool that
knows about the notion of a 'chroot'; the rest would seem to do all namei
operations starting at EXT2_ROOT_INO.

Also I recommend running sparse/cppcheck on any source files that a patch of
yours touches.

--D
> 
> // Robert
> 
> >Cheers,
> >
> >>...I'll also respin the patchset I sent out a few days ago.
> >
> >Sorry for having you respin the patchset yet again --- although
> >hopefully it should be easier this time around.  I'm trying to be fair
> >in catching up with th e2fsprogs backlog, and Robert and Zheng's
> >patches have been outstanding for a long time.  Don't worry, yours are
> >next on the list.  :-)
> >
> >Cheers,
> >
> >						- Ted
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Robert Yang March 7, 2014, 3:22 a.m. UTC | #8
On 03/07/2014 10:56 AM, Darrick J. Wong wrote:
> On Fri, Mar 07, 2014 at 09:24:12AM +0800, Robert Yang wrote:
>>
>>
>> On 03/07/2014 06:57 AM, Theodore Ts'o wrote:
>>> On Thu, Mar 06, 2014 at 12:14:39PM -0800, Darrick J. Wong wrote:
>>>>
>>>> I'm already queuing up a bunch of (more) fixes... there's more weird things I
>>>> didn't notice.  Such as, why is current_fs now defined in current_inode.h?
>>>> That really ought to have stayed in debugfs.c, and current_inode.h should have
>>>> 'extern ext2_filsys current_fs;', no?
>>>
>>> Yes, that would be better --- although in the long term we should
>>> probably try to get rid of the global variable and pass in an "fs"
>>> parameter into functions in misc/create_inode.c.
>>>
>>> Since these aren't in a shared library, I wasn't worried that much
>>> about the details of the abstraction interface, but I'm sure there are
>>> some ways that we can improve things.
>>>
>>> BTW, one of my plans for 1.43 is to rename libquota.a to libe2int.a,
>>> and to move things like profile.c, and other files shared between misc
>>> and e2fsck, etc., into an "internal support" library.  I suspect
>>> create_inoode.c would be a candidate for moving into this internal
>>> support library.
>>>
>>
>> Hi Ted and Darrick,
>>
>> Thank you very much for the great help, I think that I don't have to
>> submit a fix patch again since Darrick has helped me to fix the
>> problem, please feel free to let me know if there is anything I
>> can do.
>
> I'll have 6 patches for you to review soon.  I also fixed a number of style and
> whitespace errors. :)
>

Thank you very much:-)

> I had another thought about populate_fs -- it should be in charge of setting up
> and tearing down the hdlinks_s hardlink map, not the caller, and it shouldn't
> really be a global variable.  I noticed that populate_fs recursively calls
> itself, so I moved the functionality to a static function and wrote a wrapper
> that takes care of hdlinks and calls the static function.
>
> By the way, one of the things I /didn't/ fix was the root inode parameter that
> you pass to ext2fs_namei.  I couldn't tell if supporting debugfs' chroot
> command is part of your requirements set (though it doesn't seem likely to me),
> but I also think that a better interface would be to have callers of the
> create_inode functions pass in the destination dir inode instead of a pathname,
> similar to the do_mknod_internal interface.  debugfs is the only tool that
> knows about the notion of a 'chroot'; the rest would seem to do all namei
> operations starting at EXT2_ROOT_INO.
>

Thank you very much, I will try later.

> Also I recommend running sparse/cppcheck on any source files that a patch of
> yours touches.
>

Thanks, got it.

// Robert

> --D
>>
>> // Robert
>>
>>> Cheers,
>>>
>>>> ...I'll also respin the patchset I sent out a few days ago.
>>>
>>> Sorry for having you respin the patchset yet again --- although
>>> hopefully it should be easier this time around.  I'm trying to be fair
>>> in catching up with th e2fsprogs backlog, and Robert and Zheng's
>>> patches have been outstanding for a long time.  Don't worry, yours are
>>> next on the list.  :-)
>>>
>>> Cheers,
>>>
>>> 						- Ted
>>>
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/misc/create_inode.c b/misc/create_inode.c
index f845103..98f4a93 100644
--- a/misc/create_inode.c
+++ b/misc/create_inode.c
@@ -8,6 +8,16 @@ 
 # endif
 #endif
 
+/* 64KiB is the minimium blksize to best minimize system call overhead. */
+#ifndef IO_BUFSIZE
+#define IO_BUFSIZE 64*1024
+#endif
+
+/* Block size for `st_blocks' */
+#ifndef S_BLKSIZE
+#define S_BLKSIZE 512
+#endif
+
 /* Make a special file which is block, character and fifo */
 errcode_t do_mknod_internal(ext2_ino_t cwd, const char *name, struct stat *st)
 {
@@ -127,9 +137,182 @@  errcode_t do_mkdir_internal(ext2_ino_t cwd, const char *name, struct stat *st)
 {
 }
 
+static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
+{
+	ext2_file_t	e2_file;
+	errcode_t	retval;
+	int		got;
+	unsigned int	written;
+	char		*buf;
+	char		*ptr;
+	char		*zero_buf;
+	int		cmp;
+
+	retval = ext2fs_file_open(current_fs, newfile,
+				  EXT2_FILE_WRITE, &e2_file);
+	if (retval)
+		return retval;
+
+	retval = ext2fs_get_mem(bufsize, &buf);
+	if (retval) {
+		com_err("copy_file", retval, "can't allocate buffer\n");
+		return retval;
+	}
+
+	/* This is used for checking whether the whole block is zero */
+	retval = ext2fs_get_memzero(bufsize, &zero_buf);
+	if (retval) {
+		com_err("copy_file", retval, "can't allocate buffer\n");
+		ext2fs_free_mem(&buf);
+		return retval;
+	}
+
+	while (1) {
+		got = read(fd, buf, bufsize);
+		if (got == 0)
+			break;
+		if (got < 0) {
+			retval = errno;
+			goto fail;
+		}
+		ptr = buf;
+
+		/* Sparse copy */
+		if (make_holes) {
+			/* Check whether all is zero */
+			cmp = memcmp(ptr, zero_buf, got);
+			if (cmp == 0) {
+				 /* The whole block is zero, make a hole */
+				retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
+				if (retval)
+					goto fail;
+				got = 0;
+			}
+		}
+
+		/* Normal copy */
+		while (got > 0) {
+			retval = ext2fs_file_write(e2_file, ptr,
+						   got, &written);
+			if (retval)
+				goto fail;
+
+			got -= written;
+			ptr += written;
+		}
+	}
+	ext2fs_free_mem(&buf);
+	ext2fs_free_mem(&zero_buf);
+	retval = ext2fs_file_close(e2_file);
+	return retval;
+
+fail:
+	ext2fs_free_mem(&buf);
+	ext2fs_free_mem(&zero_buf);
+	(void) ext2fs_file_close(e2_file);
+	return retval;
+}
+
 /* Copy the native file to the fs */
 errcode_t do_write_internal(ext2_ino_t cwd, const char *src, const char *dest)
 {
+	int		fd;
+	struct stat	statbuf;
+	ext2_ino_t	newfile;
+	errcode_t	retval;
+	struct ext2_inode inode;
+	int		bufsize = IO_BUFSIZE;
+	int		make_holes = 0;
+
+	fd = open(src, O_RDONLY);
+	if (fd < 0) {
+		com_err(src, errno, 0);
+		return errno;
+	}
+	if (fstat(fd, &statbuf) < 0) {
+		com_err(src, errno, 0);
+		close(fd);
+		return errno;
+	}
+
+	retval = ext2fs_namei(current_fs, root, cwd, dest, &newfile);
+	if (retval == 0) {
+		com_err(__func__, 0, "The file '%s' already exists\n", dest);
+		close(fd);
+		return errno;
+	}
+
+	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
+	if (retval) {
+		com_err(__func__, retval, 0);
+		close(fd);
+		return errno;
+	}
+#ifdef DEBUGFS
+	printf("Allocated inode: %u\n", newfile);
+#endif
+	retval = ext2fs_link(current_fs, cwd, dest, newfile,
+				EXT2_FT_REG_FILE);
+	if (retval == EXT2_ET_DIR_NO_SPACE) {
+		retval = ext2fs_expand_dir(current_fs, cwd);
+		if (retval) {
+			com_err(__func__, retval, "while expanding directory");
+			close(fd);
+			return errno;
+		}
+		retval = ext2fs_link(current_fs, cwd, dest, newfile,
+					EXT2_FT_REG_FILE);
+	}
+	if (retval) {
+		com_err(dest, retval, 0);
+		close(fd);
+		return errno;
+	}
+        if (ext2fs_test_inode_bitmap2(current_fs->inode_map, newfile))
+		com_err(__func__, 0, "Warning: inode already set");
+	ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
+	memset(&inode, 0, sizeof(inode));
+	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
+	inode.i_atime = inode.i_ctime = inode.i_mtime =
+		current_fs->now ? current_fs->now : time(0);
+	inode.i_links_count = 1;
+	inode.i_size = statbuf.st_size;
+	if (current_fs->super->s_feature_incompat &
+	    EXT3_FEATURE_INCOMPAT_EXTENTS) {
+		int i;
+		struct ext3_extent_header *eh;
+
+		eh = (struct ext3_extent_header *) &inode.i_block[0];
+		eh->eh_depth = 0;
+		eh->eh_entries = 0;
+		eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
+		i = (sizeof(inode.i_block) - sizeof(*eh)) /
+			sizeof(struct ext3_extent);
+		eh->eh_max = ext2fs_cpu_to_le16(i);
+		inode.i_flags |= EXT4_EXTENTS_FL;
+	}
+
+	if ((retval = ext2fs_write_new_inode(current_fs, newfile, &inode))) {
+		com_err(__func__, retval, "while creating inode %u", newfile);
+		close(fd);
+		return errno;
+	}
+	if (LINUX_S_ISREG(inode.i_mode)) {
+		if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
+			make_holes = 1;
+			/*
+			 * Use I/O blocksize as buffer size when
+			 * copying sparse files.
+			 */
+			bufsize = statbuf.st_blksize;
+		}
+		retval = copy_file(fd, newfile, bufsize, make_holes);
+		if (retval)
+			com_err("copy_file", retval, 0);
+	}
+	close(fd);
+
+	return 0;
 }
 
 /* Copy files from source_dir to fs */