summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2010-02-12 21:07:25 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2010-02-12 21:07:25 (GMT)
commit5864f3267f4c1c002a5f405477c113a093f3b5bd (patch) (side-by-side diff)
tree4cd7bd51f188825116ff0316e22fd779e9c722f9
parent7c5fda3fbada772e53e0c347621921a8111738c0 (diff)
downloadcpio-5864f3267f4c1c002a5f405477c113a093f3b5bd.tar.gz
cpio-5864f3267f4c1c002a5f405477c113a093f3b5bd.tar.bz2
Use same code when creating directories in copy-in and copy-pass modes.
* src/copyin.c (copyin_mkdir): Remove. (copyin_directory): Remove. (copyin_file): Use cpio_create_dir instead of copyin_directory. * src/copypass.c (process_copy_pass): Use cpio_create_dir to create directories. * src/extern.h (delay_cpio_set_stat): New proto. * src/util.c (delay_cpio_set_stat): New function. (delay_set_stat): Rewrite as a wrapper to the above. (cpio_create_dir): New function. * tests/setstat01.at: Fix testcase. * tests/setstat02.at: Likewise. * tests/setstat03.at: New testcase. * tests/setstat04.at: New testcase. * tests/setstat05.at: New testcase. * tests/Makefile.am: Add new testcases. * tests/testsuite.at: Likewise.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/copyin.c112
-rw-r--r--src/copypass.c49
-rw-r--r--src/extern.h5
-rw-r--r--src/util.c129
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/setstat01.at2
-rw-r--r--tests/setstat02.at13
-rw-r--r--tests/setstat03.at46
-rw-r--r--tests/setstat04.at50
-rw-r--r--tests/setstat05.at47
-rw-r--r--tests/testsuite.at3
11 files changed, 292 insertions, 167 deletions
diff --git a/src/copyin.c b/src/copyin.c
index 2db6bb3..ac921e1 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -566,114 +566,6 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
}
}
-static int
-copyin_mkdir (struct cpio_file_stat *file_hdr, int *setstat_delayed)
-{
- int rc;
- mode_t mode = file_hdr->c_mode;
- if (!(file_hdr->c_mode & S_IWUSR))
- {
- rc = mkdir (file_hdr->c_name, mode | S_IWUSR);
- if (rc == 0)
- {
- struct stat st;
- cpio_to_stat (&st, file_hdr);
- delay_set_stat (file_hdr->c_name, &st, false);
- *setstat_delayed = 1;
- }
- }
- else
- {
- rc = mkdir (file_hdr->c_name, mode);
- *setstat_delayed = 0;
- }
- return rc;
-}
-
-static void
-copyin_directory (struct cpio_file_stat *file_hdr, int existing_dir)
-{
- int res; /* Result of various function calls. */
-#ifdef HPUX_CDF
- int cdf_flag; /* True if file is a CDF. */
- int cdf_char; /* Index of `+' char indicating a CDF. */
-#endif
- int setstat_delayed = 0;
-
- if (to_stdout_option)
- return;
-
- /* Strip any trailing `/'s off the filename; tar puts
- them on. We might as well do it here in case anybody
- else does too, since they cause strange things to happen. */
- strip_trailing_slashes (file_hdr->c_name);
-
- /* Ignore the current directory. It must already exist,
- and we don't want to change its permission, ownership
- or time. */
- if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0')
- {
- return;
- }
-
-#ifdef HPUX_CDF
- cdf_flag = 0;
-#endif
- if (!existing_dir)
-
- {
-#ifdef HPUX_CDF
- /* If the directory name ends in a + and is SUID,
- then it is a CDF. Strip the trailing + from
- the name before creating it. */
- cdf_char = strlen (file_hdr->c_name) - 1;
- if ( (cdf_char > 0) &&
- (file_hdr->c_mode & 04000) &&
- (file_hdr->c_name [cdf_char] == '+') )
- {
- file_hdr->c_name [cdf_char] = '\0';
- cdf_flag = 1;
- }
-#endif
- res = copyin_mkdir (file_hdr, &setstat_delayed);
- }
- else
- res = 0;
- if (res < 0 && create_dir_flag)
- {
- create_all_directories (file_hdr->c_name);
- res = copyin_mkdir (file_hdr, &setstat_delayed);
- }
- if (res < 0)
- {
- /* In some odd cases where the file_hdr->c_name includes `.',
- the directory may have actually been created by
- create_all_directories(), so the mkdir will fail
- because the directory exists. If that's the case,
- don't complain about it. */
- struct stat file_stat;
- if (errno != EEXIST)
- {
- mkdir_error (file_hdr->c_name);
- return;
- }
- if (lstat (file_hdr->c_name, &file_stat))
- {
- stat_error (file_hdr->c_name);
- return;
- }
- if (!(S_ISDIR (file_stat.st_mode)))
- {
- error (0, 0, _("%s is not a directory"),
- quotearg_colon (file_hdr->c_name));
- return;
- }
- }
-
- if (!setstat_delayed && repair_delayed_set_stat (file_hdr) == 0)
- set_perms (-1, file_hdr);
-}
-
static void
copyin_device (struct cpio_file_stat* file_hdr)
{
@@ -795,7 +687,7 @@ copyin_link(struct cpio_file_stat *file_hdr, int in_file_des)
}
static void
-copyin_file (struct cpio_file_stat* file_hdr, int in_file_des)
+copyin_file (struct cpio_file_stat *file_hdr, int in_file_des)
{
int existing_dir;
@@ -811,7 +703,7 @@ copyin_file (struct cpio_file_stat* file_hdr, int in_file_des)
break;
case CP_IFDIR:
- copyin_directory (file_hdr, existing_dir);
+ cpio_create_dir (file_hdr, existing_dir);
break;
case CP_IFCHR:
diff --git a/src/copypass.c b/src/copypass.c
index ab44c20..d249a31 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -221,50 +221,11 @@ process_copy_pass ()
}
else if (S_ISDIR (in_file_stat.st_mode))
{
-#ifdef HPUX_CDF
- cdf_flag = 0;
-#endif
- if (!existing_dir)
- {
-#ifdef HPUX_CDF
- /* If the directory name ends in a + and is SUID,
- then it is a CDF. Strip the trailing + from the name
- before creating it. */
- cdf_char = strlen (output_name.ds_string) - 1;
- if ( (cdf_char > 0) &&
- (in_file_stat.st_mode & 04000) &&
- (output_name.ds_string [cdf_char] == '+') )
- {
- output_name.ds_string [cdf_char] = '\0';
- cdf_flag = 1;
- }
-#endif
- res = mkdir (output_name.ds_string, in_file_stat.st_mode);
-
- }
- else
- res = 0;
- if (res < 0 && create_dir_flag)
- {
- create_all_directories (output_name.ds_string);
- res = mkdir (output_name.ds_string, in_file_stat.st_mode);
- }
- if (res < 0)
- {
- /* In some odd cases where the output_name includes `.',
- the directory may have actually been created by
- create_all_directories(), so the mkdir will fail
- because the directory exists. If that's the case,
- don't complain about it. */
- if ( (errno != EEXIST) ||
- (lstat (output_name.ds_string, &out_file_stat) != 0) ||
- !(S_ISDIR (out_file_stat.st_mode) ) )
- {
- stat_error (output_name.ds_string);
- continue;
- }
- }
- set_copypass_perms (-1, output_name.ds_string, &in_file_stat);
+ struct cpio_file_stat file_stat;
+
+ stat_to_cpio (&file_stat, &in_file_stat);
+ file_stat.c_name = output_name.ds_string;
+ cpio_create_dir (&file_stat, existing_dir);
}
else if (S_ISCHR (in_file_stat.st_mode) ||
S_ISBLK (in_file_stat.st_mode) ||
diff --git a/src/extern.h b/src/extern.h
index a2a08b7..4f94d40 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -199,6 +199,7 @@ void stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st);
void cpio_to_stat (struct stat *st, struct cpio_file_stat *hdr);
void cpio_safer_name_suffix (char *name, bool link_target,
bool absolute_names, bool strip_leading_dots);
+int cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir);
/* FIXME: These two defines should be defined in paxutils */
#define LG_8 3
@@ -208,7 +209,9 @@ uintmax_t from_ascii (char const *where, size_t digs, unsigned logbase);
#define FROM_OCTAL(f) from_ascii (f, sizeof f, LG_8)
#define FROM_HEX(f) from_ascii (f, sizeof f, LG_16)
-
+
+void delay_cpio_set_stat (struct cpio_file_stat *file_stat,
+ mode_t invert_permissions);
void delay_set_stat (char const *file_name, struct stat *st,
mode_t invert_permissions);
int repair_delayed_set_stat (struct cpio_file_stat *file_hdr);
diff --git a/src/util.c b/src/util.c
index d029f6e..ae6a3de 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1418,21 +1418,31 @@ struct delayed_set_stat
static struct delayed_set_stat *delayed_set_stat_head;
void
-delay_set_stat (char const *file_name, struct stat *st,
- mode_t invert_permissions)
+delay_cpio_set_stat (struct cpio_file_stat *file_stat,
+ mode_t invert_permissions)
{
- size_t file_name_len = strlen (file_name);
+ size_t file_name_len = strlen (file_stat->c_name);
struct delayed_set_stat *data =
xmalloc (sizeof (struct delayed_set_stat) + file_name_len + 1);
data->next = delayed_set_stat_head;
- memset (&data->stat, 0, sizeof data->stat);
- stat_to_cpio (&data->stat, st);
+ memcpy (&data->stat, file_stat, sizeof data->stat);
data->stat.c_name = (char*) (data + 1);
- strcpy (data->stat.c_name, file_name);
+ strcpy (data->stat.c_name, file_stat->c_name);
data->invert_permissions = invert_permissions;
delayed_set_stat_head = data;
}
+void
+delay_set_stat (char const *file_name, struct stat *st,
+ mode_t invert_permissions)
+{
+ struct cpio_file_stat fs;
+
+ stat_to_cpio (&fs, st);
+ fs.c_name = (char*) file_name;
+ delay_cpio_set_stat (&fs, invert_permissions);
+}
+
/* Update the delayed_set_stat info for an intermediate directory
created within the file name of DIR. The intermediate directory turned
out to be the same as this directory, e.g. due to ".." or symbolic
@@ -1500,4 +1510,111 @@ apply_delayed_set_stat ()
}
}
+
+static int
+cpio_mkdir (struct cpio_file_stat *file_hdr, int *setstat_delayed)
+{
+ int rc;
+ mode_t mode = file_hdr->c_mode;
+
+ if (!(file_hdr->c_mode & S_IWUSR))
+ {
+ rc = mkdir (file_hdr->c_name, mode | S_IWUSR);
+ if (rc == 0)
+ {
+ delay_cpio_set_stat (file_hdr, 0);
+ *setstat_delayed = 1;
+ }
+ }
+ else
+ {
+ rc = mkdir (file_hdr->c_name, mode);
+ *setstat_delayed = 0;
+ }
+ return rc;
+}
+
+int
+cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir)
+{
+ int res; /* Result of various function calls. */
+#ifdef HPUX_CDF
+ int cdf_flag; /* True if file is a CDF. */
+ int cdf_char; /* Index of `+' char indicating a CDF. */
+#endif
+ int setstat_delayed = 0;
+
+ if (to_stdout_option)
+ return 0;
+
+ /* Strip any trailing `/'s off the filename; tar puts
+ them on. We might as well do it here in case anybody
+ else does too, since they cause strange things to happen. */
+ strip_trailing_slashes (file_hdr->c_name);
+
+ /* Ignore the current directory. It must already exist,
+ and we don't want to change its permission, ownership
+ or time. */
+ if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0')
+ {
+ return 0;
+ }
+
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from
+ the name before creating it. */
+ cdf_char = strlen (file_hdr->c_name) - 1;
+ if ( (cdf_char > 0) &&
+ (file_hdr->c_mode & 04000) &&
+ (file_hdr->c_name [cdf_char] == '+') )
+ {
+ file_hdr->c_name [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = cpio_mkdir (file_hdr, &setstat_delayed);
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr->c_name);
+ res = cpio_mkdir (file_hdr, &setstat_delayed);
+ }
+ if (res < 0)
+ {
+ /* In some odd cases where the file_hdr->c_name includes `.',
+ the directory may have actually been created by
+ create_all_directories(), so the mkdir will fail
+ because the directory exists. If that's the case,
+ don't complain about it. */
+ struct stat file_stat;
+ if (errno != EEXIST)
+ {
+ mkdir_error (file_hdr->c_name);
+ return -1;
+ }
+ if (lstat (file_hdr->c_name, &file_stat))
+ {
+ stat_error (file_hdr->c_name);
+ return -1;
+ }
+ if (!(S_ISDIR (file_stat.st_mode)))
+ {
+ error (0, 0, _("%s is not a directory"),
+ quotearg_colon (file_hdr->c_name));
+ return -1;
+ }
+ }
+
+ if (!setstat_delayed && repair_delayed_set_stat (file_hdr) == 0)
+ set_perms (-1, file_hdr);
+ return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index aeead8e..b3e8e60 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -48,6 +48,9 @@ TESTSUITE_AT = \
interdir.at\
setstat01.at\
setstat02.at\
+ setstat03.at\
+ setstat04.at\
+ setstat05.at\
symlink.at\
version.at
diff --git a/tests/setstat01.at b/tests/setstat01.at
index 2cd98c2..7fd4d99 100644
--- a/tests/setstat01.at
+++ b/tests/setstat01.at
@@ -24,7 +24,7 @@ AT_KEYWORDS([setstat setstat01])
AT_CHECK([
mkdir dir
-echo "test file" > file
+echo "test file" > dir/file
chmod 500 dir
find dir | cpio -o --quiet > archive
diff --git a/tests/setstat02.at b/tests/setstat02.at
index 9160260..5c45a4f 100644
--- a/tests/setstat02.at
+++ b/tests/setstat02.at
@@ -15,24 +15,27 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
AT_SETUP([delayed setstat (with -depth)])
-AT_KEYWORDS([setstat setstat01])
+AT_KEYWORDS([setstat debian=458079 setstat02])
-# Cpio versions up to 2.10 failed to restore directory permissions, if
-# the directory was already present on dist (e.g. when using find . -depth).
+# Description: Cpio versions up to 2.10 failed to restore directory
+# permissions, if the directory was already present on dist (e.g. when
+# using find . -depth).
#
# References:
# <20090620185721.GA18708@scru.org>
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=458079
+#
+# See also: setstat03, setstat04, setstat05
AT_CHECK([
mkdir dir
-echo "test file" > file
+echo "test file" > dir/file
chmod 500 dir
find dir -depth | cpio -o --quiet > archive
mv dir old
-cpio -i --quiet < archive
+cpio -id --quiet < archive
genfile --stat=mode.777 dir
],
[0],
diff --git a/tests/setstat03.at b/tests/setstat03.at
new file mode 100644
index 0000000..f2139a9
--- a/dev/null
+++ b/tests/setstat03.at
@@ -0,0 +1,46 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([delayed setstat (copy-pass)])
+AT_KEYWORDS([setstat debian=458079 setstat03])
+
+# Description: Cpio versions up to 2.10 failed to restore directory
+# permissions, if the directory was already present on dist (e.g. when
+# using find . -depth).
+# This test case does the same as setstat02, but using copy-pass mode.
+#
+# References:
+# <20090620185721.GA18708@scru.org>
+# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=458079
+#
+# See also: setstat02, setstat04. setstat05
+
+AT_CHECK([
+mkdir dir
+echo "test file" > dir/file
+chmod 500 dir
+mkdir newdir
+
+find dir -depth | cpio -pmaud --quiet newdir
+genfile --stat=mode.777 newdir/dir
+],
+[0],
+[500
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/setstat04.at b/tests/setstat04.at
new file mode 100644
index 0000000..a4e4eb3
--- a/dev/null
+++ b/tests/setstat04.at
@@ -0,0 +1,50 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([delayed setstat (umask)])
+AT_KEYWORDS([setstat debian=458079 setstat04])
+
+# Description: Cpio versions up to 2.10 failed to restore directory
+# permissions, if the directory was already present on dist (e.g. when
+# using find . -depth).
+# This test case verifies whether umask settings do not affect directory
+# permissions.
+#
+# References:
+# <20090620185721.GA18708@scru.org>
+# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=458079
+#
+# See also: setstat02, setstat03, setstat05
+
+AT_CHECK([
+umask 022
+mkdir dir
+echo "test file" > dir/file
+mkdir newdir
+find dir -depth | cpio -o --quiet > archive
+mv dir old
+
+umask 077
+cpio -id --quiet < archive
+genfile --stat=mode.777 dir
+],
+[0],
+[755
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/setstat05.at b/tests/setstat05.at
new file mode 100644
index 0000000..49be4b7
--- a/dev/null
+++ b/tests/setstat05.at
@@ -0,0 +1,47 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2009, 2010 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, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([delayed setstat (umask, copy-pass)])
+AT_KEYWORDS([setstat debian=458079 setstat05])
+
+# Description: Cpio versions up to 2.10 failed to restore directory
+# permissions, if the directory was already present on dist (e.g. when
+# using find . -depth).
+# This test case verifies whether umask settings do not affect directory
+# permissions in copy-pass mode.
+#
+# References:
+# <20090620185721.GA18708@scru.org>
+# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=458079
+#
+# See also: setstat02, setstat03
+
+AT_CHECK([
+umask 022
+mkdir dir
+echo "test file" > dir/file
+mkdir newdir
+umask 077
+find dir -depth | cpio -pmaud --quiet newdir
+genfile --stat=mode.777 newdir/dir
+],
+[0],
+[755
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 4195ea7..8f3330b 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -35,3 +35,6 @@ m4_include([interdir.at])
m4_include([setstat01.at])
m4_include([setstat02.at])
+m4_include([setstat03.at])
+m4_include([setstat04.at])
+m4_include([setstat05.at])

Return to:

Send suggestions and report system problems to the System administrator.