aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/cpio.texi32
-rw-r--r--src/copyin.c2
-rw-r--r--src/copyout.c2
-rw-r--r--src/copypass.c2
-rw-r--r--src/extern.h2
-rw-r--r--src/global.c2
-rw-r--r--src/main.c7
-rw-r--r--src/util.c18
8 files changed, 67 insertions, 0 deletions
diff --git a/doc/cpio.texi b/doc/cpio.texi
index 1af808a..bcece3c 100644
--- a/doc/cpio.texi
+++ b/doc/cpio.texi
@@ -342,6 +342,38 @@ Set the I/O block size to @var{io-size} bytes.
@itemx --make-directories
Create leading directories where needed.
+@item -D @var{dir}
+@item --directory=@var{dir}
+Change to the directory @var{dir} before starting the operation. This
+can be used, for example, to extract an archive contents in a
+different directory:
+
+@example
+$ cpio -i -D /usr/local < archive
+@end example
+
+@noindent
+or to copy-pass files from one directory to another:
+
+@example
+$ cpio -D /usr/bin -p /usr/local/bin < filelist
+@end example
+
+ The @option{-D} option does not affect file names supplied as
+arguments to another command line options, such as @option{-F}
+or @option{-E}. For example, the following invocation:
+
+@example
+cpio -D /tmp/foo -d -i -F arc
+@end example
+
+@noindent
+instructs @command{cpio} to open the archive file @file{arc} in
+the current working directory, then change to the directory
+@file{/tmp/foo} and extract files to that directory. If
+@file{/tmp/foo} does not exist, it will be created first (the
+@option{-d} option) and then changed to.
+
@item -E @var{file}
@itemx --pattern-file=@var{file}
Read additional patterns specifying filenames to extract or list from
diff --git a/src/copyin.c b/src/copyin.c
index 44b694d..d41b17f 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -1343,6 +1343,8 @@ process_copy_in ()
}
output_is_seekable = true;
+ change_dir ();
+
/* While there is more input in the collection, process the input. */
while (!done)
{
diff --git a/src/copyout.c b/src/copyout.c
index 7e6b624..e9849ff 100644
--- a/src/copyout.c
+++ b/src/copyout.c
@@ -625,6 +625,8 @@ process_copy_out ()
output_is_seekable = S_ISREG (file_stat.st_mode);
}
+ change_dir ();
+
if (append_flag)
{
process_copy_in ();
diff --git a/src/copypass.c b/src/copypass.c
index d249a31..1fcc8b3 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -75,6 +75,8 @@ process_copy_pass ()
output_name.ds_string[dirname_len] = '/';
output_is_seekable = true;
+ change_dir ();
+
/* Copy files with names read from stdin. */
while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
{
diff --git a/src/extern.h b/src/extern.h
index 4f94d40..c25a6ef 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -97,6 +97,7 @@ extern char input_is_seekable;
extern char output_is_seekable;
extern int (*xstat) ();
extern void (*copy_function) ();
+extern char *change_directory_option;
/* copyin.c */
@@ -200,6 +201,7 @@ 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);
+void change_dir (void);
/* FIXME: These two defines should be defined in paxutils */
#define LG_8 3
diff --git a/src/global.c b/src/global.c
index cff9720..29e7afc 100644
--- a/src/global.c
+++ b/src/global.c
@@ -193,3 +193,5 @@ int (*xstat) ();
/* Which copy operation to perform. (-i, -o, -p) */
void (*copy_function) () = 0;
+
+char *change_directory_option;
diff --git a/src/main.c b/src/main.c
index ba1b969..4c1c033 100644
--- a/src/main.c
+++ b/src/main.c
@@ -108,6 +108,9 @@ static struct argp_option options[] = {
{"file", 'F', N_("[[USER@]HOST:]FILE-NAME"), 0,
N_("Use this FILE-NAME instead of standard input or output. Optional USER and HOST specify the user and host names in case of a remote archive"), GRID+1 },
+ {"directory", 'D', N_("DIR"), 0,
+ N_("Change to directory DIR"), GRID+1 },
+
{"force-local", FORCE_LOCAL_OPTION, 0, 0,
N_("Archive file is local, even if its name contains colons"), GRID+1 },
{"format", 'H', N_("FORMAT"), 0,
@@ -325,6 +328,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
create_dir_flag = true;
break;
+ case 'D':
+ change_directory_option = arg;
+ break;
+
case 'f': /* Only copy files not matching patterns. */
copy_matching_files = false;
break;
diff --git a/src/util.c b/src/util.c
index 00953d5..0faccbc 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1618,3 +1618,21 @@ cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir)
return 0;
}
+void
+change_dir ()
+{
+ if (change_directory_option && chdir (change_directory_option))
+ {
+ if (errno == ENOENT && create_dir_flag)
+ {
+ if (make_path (change_directory_option, -1, -1,
+ (warn_option & CPIO_WARN_INTERDIR) ?
+ _("Creating directory `%s'") : NULL))
+ exit (PAXEXIT_FAILURE);
+ if (chdir (change_directory_option) == 0)
+ return;
+ }
+ error (PAXEXIT_FAILURE, errno,
+ _("cannot change to directory `%s'"), change_directory_option);
+ }
+}

Return to:

Send suggestions and report system problems to the System administrator.