aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS6
-rw-r--r--src/copyin.c34
-rw-r--r--src/extern.h4
-rw-r--r--src/util.c79
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/setstat01.at42
-rw-r--r--tests/setstat02.at44
-rw-r--r--tests/testsuite.at3
8 files changed, 199 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index 87c7111..03c8869 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,12 @@ Please send cpio bug reports to <bug-cpio@gnu.org>.
Version 2.10.90 (Git)
* Fix mt build.
+* In copy-in mode, if directory attributes do not permit writing to it,
+setting them is delayed until the end of run. This allows to correctly
+extract files in such directories.
+* In copy-in mode, permissions of a directory are restored if it
+appears in the file list after files in it (find . -depth). This fixes
+debian bug #458079.
Version 2.10 - Sergey Poznyakoff, 2009-06-20
diff --git a/src/copyin.c b/src/copyin.c
index 59483da..5b7594b 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -566,6 +566,30 @@ 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)
{
@@ -574,7 +598,8 @@ copyin_directory (struct cpio_file_stat *file_hdr, int existing_dir)
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;
@@ -610,14 +635,14 @@ copyin_directory (struct cpio_file_stat *file_hdr, int existing_dir)
cdf_flag = 1;
}
#endif
- res = mkdir (file_hdr->c_name, file_hdr->c_mode);
+ res = copyin_mkdir (file_hdr, &setstat_delayed);
}
else
res = 0;
if (res < 0 && create_dir_flag)
{
create_all_directories (file_hdr->c_name);
- res = mkdir (file_hdr->c_name, file_hdr->c_mode);
+ res = copyin_mkdir (file_hdr, &setstat_delayed);
}
if (res < 0)
{
@@ -645,7 +670,8 @@ copyin_directory (struct cpio_file_stat *file_hdr, int existing_dir)
}
}
- set_perms (-1, file_hdr);
+ if (!setstat_delayed && repair_delayed_set_stat (file_hdr) == 0)
+ set_perms (-1, file_hdr);
}
static void
diff --git a/src/extern.h b/src/extern.h
index a03508b..a832897 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -196,6 +196,7 @@ void set_perms (int fd, struct cpio_file_stat *header);
void set_file_times (int fd, const char *name, unsigned long atime,
unsigned long mtime);
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);
@@ -210,7 +211,6 @@ uintmax_t from_ascii (char const *where, size_t digs, unsigned logbase);
void delay_set_stat (char const *file_name, struct stat *st,
mode_t invert_permissions);
-void repair_delayed_set_stat (char const *dir,
- struct stat *dir_stat_info);
+int repair_delayed_set_stat (struct cpio_file_stat *file_hdr);
void apply_delayed_set_stat (void);
diff --git a/src/util.c b/src/util.c
index 2b765d9..1eb92ae 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1256,9 +1256,9 @@ stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
else if (S_ISNWK (st->st_mode))
hdr->c_mode |= CP_IFNWK;
#endif
+ hdr->c_nlink = st->st_nlink;
hdr->c_uid = CPIO_UID (st->st_uid);
hdr->c_gid = CPIO_GID (st->st_gid);
- hdr->c_nlink = st->st_nlink;
hdr->c_rdev_maj = major (st->st_rdev);
hdr->c_rdev_min = minor (st->st_rdev);
hdr->c_mtime = st->st_mtime;
@@ -1267,6 +1267,49 @@ stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
hdr->c_tar_linkname = NULL;
}
+void
+cpio_to_stat (struct stat *st, struct cpio_file_stat *hdr)
+{
+ memset (st, 0, sizeof (*st));
+ st->st_dev = makedev (hdr->c_dev_maj, hdr->c_dev_min);
+ st->st_ino = hdr->c_ino;
+ st->st_mode = hdr->c_mode & 0777;
+ if (hdr->c_mode & CP_IFREG)
+ st->st_mode |= S_IFREG;
+ else if (hdr->c_mode & CP_IFDIR)
+ st->st_mode |= S_IFDIR;
+#ifdef S_IFBLK
+ else if (hdr->c_mode & CP_IFBLK)
+ st->st_mode |= S_IFBLK;
+#endif
+#ifdef S_IFCHR
+ else if (hdr->c_mode & CP_IFCHR)
+ st->st_mode |= S_IFCHR;
+#endif
+#ifdef S_IFFIFO
+ else if (hdr->c_mode & CP_IFIFO)
+ st->st_mode |= S_IFIFO;
+#endif
+#ifdef S_IFLNK
+ else if (hdr->c_mode & CP_IFLNK)
+ st->st_mode |= S_IFLNK;
+#endif
+#ifdef S_IFSOCK
+ else if (hdr->c_mode & CP_IFSOCK)
+ st->st_mode |= S_IFSOCK;
+#endif
+#ifdef S_IFNWK
+ else if (hdr->c_mode & CP_IFNWK)
+ st->st_mode |= S_IFNWK;
+#endif
+ st->st_nlink = hdr->c_nlink;
+ st->st_uid = CPIO_UID (hdr->c_uid);
+ st->st_gid = CPIO_GID (hdr->c_gid);
+ st->st_rdev = makedev (hdr->c_rdev_maj, hdr->c_rdev_min);
+ st->st_mtime = hdr->c_mtime;
+ st->st_size = hdr->c_filesize;
+}
+
#ifndef HAVE_FCHOWN
# define HAVE_FCHOWN 0
#endif
@@ -1289,7 +1332,7 @@ fchmod_or_chmod (int fd, const char *name, mode_t mode)
if (HAVE_FCHMOD && fd != -1)
return fchmod (fd, mode);
else
- return chmod(name, mode);
+ return chmod (name, mode);
}
void
@@ -1394,9 +1437,8 @@ delay_set_stat (char const *file_name, struct stat *st,
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
links. *DIR_STAT_INFO is the status of the directory. */
-void
-repair_delayed_set_stat (char const *dir,
- struct stat *dir_stat_info)
+int
+repair_inter_delayed_set_stat (struct stat *dir_stat_info)
{
struct delayed_set_stat *data;
for (data = delayed_set_stat_head; data; data = data->next)
@@ -1405,7 +1447,7 @@ repair_delayed_set_stat (char const *dir,
if (stat (data->stat.c_name, &st) != 0)
{
stat_error (data->stat.c_name);
- return;
+ return -1;
}
if (st.st_dev == dir_stat_info->st_dev
@@ -1415,12 +1457,31 @@ repair_delayed_set_stat (char const *dir,
data->invert_permissions =
((dir_stat_info->st_mode ^ st.st_mode)
& MODE_RWX & ~ newdir_umask);
- return;
+ return 0;
}
}
+ return 1;
+}
+
+/* Update the delayed_set_stat info for a directory matching
+ FILE_HDR.
- ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
- quotearg_colon (dir)));
+ Return 0 if such info was found, 1 otherwise. */
+int
+repair_delayed_set_stat (struct cpio_file_stat *file_hdr)
+{
+ struct delayed_set_stat *data;
+ for (data = delayed_set_stat_head; data; data = data->next)
+ {
+ if (strcmp (file_hdr->c_name, data->stat.c_name) == 0)
+ {
+ data->invert_permissions = 0;
+ memcpy (&data->stat, file_hdr,
+ offsetof (struct cpio_file_stat, c_name));
+ return 0;
+ }
+ }
+ return 1;
}
void
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b4ad2ba..9e3b97b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -45,6 +45,8 @@ TESTSUITE_AT = \
testsuite.at\
inout.at\
interdir.at\
+ setstat01.at\
+ setstat02.at\
symlink.at\
version.at
diff --git a/tests/setstat01.at b/tests/setstat01.at
new file mode 100644
index 0000000..7c7b51a
--- /dev/null
+++ b/tests/setstat01.at
@@ -0,0 +1,42 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2009 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])
+AT_KEYWORDS([setstat setstat01])
+
+# In cpio up to 2.10, in copy-in mode, permissions and ownership of
+# created directories were set right after creating them. If directory
+# permissions did not allow writing to it, cpio was unable to populate
+# the directory.
+
+AT_CHECK([
+mkdir dir
+echo "test file" > file
+chmod 500 dir
+
+find dir | cpio -o --quiet > archive
+mv dir old
+
+cpio -i --quiet < archive
+genfile --stat=mode.777 dir
+],
+[0],
+[500
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/setstat02.at b/tests/setstat02.at
new file mode 100644
index 0000000..0b919c6
--- /dev/null
+++ b/tests/setstat02.at
@@ -0,0 +1,44 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+# Copyright (C) 2009 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 (with -depth)])
+AT_KEYWORDS([setstat setstat01])
+
+# 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
+
+AT_CHECK([
+mkdir dir
+echo "test file" > file
+chmod 500 dir
+
+find dir -depth | cpio -o --quiet > archive
+mv dir old
+
+cpio -i --quiet < archive
+genfile --stat=mode.777 dir
+],
+[0],
+[500
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index eea6c3f..16d64dd 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -32,3 +32,6 @@ m4_include([version.at])
m4_include([inout.at])
m4_include([symlink.at])
m4_include([interdir.at])
+
+m4_include([setstat01.at])
+m4_include([setstat02.at])

Return to:

Send suggestions and report system problems to the System administrator.