>From dd3c5e3d4b44155807a6466385b98401aaca0f21 Mon Sep 17 00:00:00 2001
From: Pavel Raiskup
Date: Tue, 25 Nov 2014 13:21:55 +0100
Subject: [PATCH] copyin: buffer-alloc the link name
References:
http://lists.gnu.org/archive/html/bug-cpio/2014-11/msg00007.html
* gnulib.modules: Include 'obstack' module.
* src/copyin.c: Define obstack_chunk_alloc and obstack_chunk_free
to be used by include.
(read_link_name_from_file, get_link_name): New local functions
which use buffering for link name reading.
(list_file): Use get_link_name().
(copyin_link): Use get_link_name().
* tests/symlink-bad-length.at: New testcase.
* tests/symlink-long.at: Likewise.
* tests/Makefile.am: Mention new test-cases.
* tests/testsuite.at: Likewise.
---
gnulib.modules | 1 +
src/copyin.c | 104 +++++++++++++++++++++++++++-----------------
tests/Makefile.am | 2 +
tests/symlink-bad-length.at | 48 ++++++++++++++++++++
tests/symlink-long.at | 46 ++++++++++++++++++++
tests/testsuite.at | 2 +
6 files changed, 162 insertions(+), 41 deletions(-)
create mode 100644 tests/symlink-bad-length.at
create mode 100644 tests/symlink-long.at
diff --git a/gnulib.modules b/gnulib.modules
index f165870..4c99bc0 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -17,6 +17,7 @@ gitlog-to-changelog
hash
inttypes
lchown
+obstack
progname
safe-read
savedir
diff --git a/src/copyin.c b/src/copyin.c
index 38d809f..faa3dca 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -32,6 +32,10 @@
# include
#endif
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+#include
+
#ifndef HAVE_LCHOWN
# define lchown(f,u,g) 0
#endif
@@ -125,36 +129,66 @@ tape_skip_padding (int in_file_des, off_t offset)
tape_toss_input (in_file_des, pad);
}
+#ifdef CP_IFLNK
+static char *
+read_link_name_from_file (struct cpio_file_stat *file_hdr,
+ int in_file_des)
+{
+#define READBUFFSIZE 512
+ char buff[READBUFFSIZE];
+ off_t chunk, remains = file_hdr->c_filesize;
+ char *link_name = 0;
+ struct obstack stk;
+
+ obstack_init (&stk);
+
+ while (remains > 0)
+ {
+ chunk = remains < READBUFFSIZE ? remains : READBUFFSIZE;
+ tape_buffered_read (buff, in_file_des, chunk);
+ obstack_grow (&stk, buff, chunk);
+ remains -= chunk;
+ }
+
+ obstack_1grow (&stk, '\0');
+ link_name = xstrdup (obstack_finish (&stk));
+
+ obstack_free (&stk, NULL);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+
+ return link_name;
+#undef READBUFFSIZE
+}
+#endif /* CP_IFLNK */
+
+static char *
+get_link_name (struct cpio_file_stat* file_hdr, int in_file_des)
+{
+ char *link_name = NULL;
+
+#ifdef CP_IFLNK
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ link_name = read_link_name_from_file (file_hdr, in_file_des);
+ else
+ link_name = xstrdup (file_hdr->c_tar_linkname);
+ }
+#endif
+
+ return link_name;
+}
+
static void
list_file(struct cpio_file_stat* file_hdr, int in_file_des)
{
if (verbose_flag)
{
-#ifdef CP_IFLNK
- if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK)
- {
- if (archive_format != arf_tar && archive_format != arf_ustar)
- {
- char *link_name = NULL; /* Name of hard and symbolic links. */
-
- link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
- link_name[file_hdr->c_filesize] = '\0';
- tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
- long_format (file_hdr, link_name);
- free (link_name);
- tape_skip_padding (in_file_des, file_hdr->c_filesize);
- return;
- }
- else
- {
- long_format (file_hdr, file_hdr->c_tar_linkname);
- return;
- }
- }
- else
-#endif
- long_format (file_hdr, (char *) 0);
+ char *linkname = get_link_name (file_hdr, in_file_des);
+ long_format (file_hdr, linkname);
+ free (linkname);
+ return;
}
else
{
@@ -635,24 +669,12 @@ copyin_link(struct cpio_file_stat *file_hdr, int in_file_des)
char *link_name = NULL; /* Name of hard and symbolic links. */
int res; /* Result of various function calls. */
- if (archive_format != arf_tar && archive_format != arf_ustar)
+ /* make sure get_link_name to make sure the buffer is moved correctly */
+ link_name = get_link_name (file_hdr, in_file_des);
+ if (to_stdout_option)
{
- if (to_stdout_option)
- {
- tape_toss_input (in_file_des, file_hdr->c_filesize);
- tape_skip_padding (in_file_des, file_hdr->c_filesize);
- return;
- }
- link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
- link_name[file_hdr->c_filesize] = '\0';
- tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
- tape_skip_padding (in_file_des, file_hdr->c_filesize);
- }
- else
- {
- if (to_stdout_option)
- return;
- link_name = xstrdup (file_hdr->c_tar_linkname);
+ free (link_name);
+ return;
}
res = UMASKED_SYMLINK (link_name, file_hdr->c_name,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3f714d1..b4ca92d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -51,6 +51,8 @@ TESTSUITE_AT = \
setstat04.at\
setstat05.at\
symlink.at\
+ symlink-bad-length.at\
+ symlink-long.at\
symlink-to-stdout.at\
version.at
diff --git a/tests/symlink-bad-length.at b/tests/symlink-bad-length.at
new file mode 100644
index 0000000..88677a3
--- /dev/null
+++ b/tests/symlink-bad-length.at
@@ -0,0 +1,48 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA.
+
+# Cpio v2.11 did segfault with badly set symlink length.
+# References:
+# http://lists.gnu.org/archive/html/bug-cpio/2014-11/msg00007.html
+
+AT_SETUP([symlink-bad-length])
+AT_KEYWORDS([symlink-long copyout])
+
+AT_DATA([ARCHIVE_base64],
+[x3EjAIBAtIEtJy8nAQAAAHRUYW0FAAAADQBGSUxFAABzb21lIGNvbnRlbnQKAMdxIwBgQ/+hLScv
+JwEAAAB0VEhuBQD/////TElOSwAARklMRcdxAAAAAAAAAAAAAAEAAAAAAAAACwAAAAAAVFJBSUxF
+UiEhIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+])
+
+AT_CHECK([
+base64 -d ARCHIVE_base64 > ARCHIVE || AT_SKIP_TEST
+cpio -tv < ARCHIVE
+test $? -eq 2
+],
+[0],
+[-rw-rw-r-- 1 cpio_use cpio_use 13 Nov 25 12:52 FILE
+],[cpio: premature end of file
+])
+
+AT_CLEANUP
diff --git a/tests/symlink-long.at b/tests/symlink-long.at
new file mode 100644
index 0000000..d3def2d
--- /dev/null
+++ b/tests/symlink-long.at
@@ -0,0 +1,46 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA.
+
+# Cpio v2.11.90 changed the way symlink name is read from archive.
+# References:
+# http://lists.gnu.org/archive/html/bug-cpio/2014-11/msg00007.html
+
+AT_SETUP([symlink-long])
+AT_KEYWORDS([symlink-long copyout])
+
+AT_CHECK([
+
+# len(dirname) > READBUFSIZE
+dirname=
+for i in {1..52}; do
+ dirname="xxxxxxxxx/$dirname"
+ mkdir "$dirname"
+done
+ln -s "$dirname" x || AT_SKIP_TEST
+
+echo x | cpio -o > ar
+list=`cpio -tv < ar | sed 's|.*-> ||'`
+test "$list" = "$dirname" && echo success || echo fail
+],
+[0],
+[success
+],[2 blocks
+2 blocks
+])
+
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index e67689f..3b5377e 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -32,6 +32,8 @@ m4_include([version.at])
m4_include([inout.at])
m4_include([symlink.at])
+m4_include([symlink-bad-length.at])
+m4_include([symlink-long.at])
m4_include([symlink-to-stdout.at])
m4_include([interdir.at])
--
1.9.3