aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-07-22 11:34:56 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-07-22 12:55:37 +0300
commit4c7d4359d2dc58126e4e7c6e3dd7cc196322ef28 (patch)
treecfb147da59dd1e5cdfac7eb5638f5ce28ec2675e
parentf40dd3ef902337afd9c5ccc6d69538e155ea26e7 (diff)
downloadcpio-4c7d4359d2dc58126e4e7c6e3dd7cc196322ef28.tar.gz
cpio-4c7d4359d2dc58126e4e7c6e3dd7cc196322ef28.tar.bz2
Provide a tar-like --directory (-D) option.
* src/copyin.c (process_copy_in): Call change_dir. * src/copyout.c (process_copy_out): Likewise. * src/copypass.c (process_copy_pass): Likewise. * src/extern.h (change_directory_option): New extern. (change_dir): New proto. * src/global.c (change_directory_option): New global. * src/main.c (options): New option --directory. (parse_opt): Handle the --directory option. * src/util.c (change_dir): New proto. * doc/cpio.texi: Document the --directory option.
-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
@@ -339,12 +339,44 @@ Use the old portable (ASCII) archive format.
Set the I/O block size to @var{io-size} bytes.
@item -d
@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
@var{file}. The lines of @var{file} are treated as if they had been non-option
arguments to cpio. This option is used in copy-in mode,
diff --git a/src/copyin.c b/src/copyin.c
index 44b694d..d41b17f 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -1340,12 +1340,14 @@ process_copy_in ()
#endif
S_ISCHR (file_stat.st_mode);
input_is_seekable = S_ISREG (file_stat.st_mode);
}
output_is_seekable = true;
+ change_dir ();
+
/* While there is more input in the collection, process the input. */
while (!done)
{
swapping_halfwords = swapping_bytes = false;
/* Start processing the next file by reading the header. */
diff --git a/src/copyout.c b/src/copyout.c
index 7e6b624..e9849ff 100644
--- a/src/copyout.c
+++ b/src/copyout.c
@@ -622,12 +622,14 @@ process_copy_out ()
S_ISBLK (file_stat.st_mode) ||
#endif
S_ISCHR (file_stat.st_mode);
output_is_seekable = S_ISREG (file_stat.st_mode);
}
+ change_dir ();
+
if (append_flag)
{
process_copy_in ();
prepare_append (out_file_des);
}
diff --git a/src/copypass.c b/src/copypass.c
index d249a31..1fcc8b3 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -72,12 +72,14 @@ process_copy_pass ()
ds_init (&input_name, 128);
ds_init (&output_name, dirname_len + 2);
strcpy (output_name.ds_string, directory_name);
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)
{
int link_res = -1;
/* Check for blank line and ignore it if found. */
diff --git a/src/extern.h b/src/extern.h
index 4f94d40..c25a6ef 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -94,12 +94,13 @@ extern char name_end;
extern char input_is_special;
extern char output_is_special;
extern char input_is_seekable;
extern char output_is_seekable;
extern int (*xstat) ();
extern void (*copy_function) ();
+extern char *change_directory_option;
/* copyin.c */
void warn_junk_bytes (long bytes_skipped);
/* FIXME: make read_* static in copyin.c */
void read_in_header (struct cpio_file_stat *file_hdr, int in_des);
@@ -197,12 +198,13 @@ 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);
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
#define LG_16 4
uintmax_t from_ascii (char const *where, size_t digs, unsigned logbase);
diff --git a/src/global.c b/src/global.c
index cff9720..29e7afc 100644
--- a/src/global.c
+++ b/src/global.c
@@ -190,6 +190,8 @@ char *program_name;
/* A pointer to either lstat or stat, depending on whether
dereferencing of symlinks is done for input files. */
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
@@ -105,12 +105,15 @@ static struct argp_option options[] = {
#define GRID 100
{NULL, 0, NULL, 0,
N_("Operation modifiers valid in any mode:"), GRID },
{"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,
N_("Use given archive FORMAT"), GRID+1 },
{NULL, 'B', NULL, 0,
N_("Set the I/O block size to 5120 bytes"), GRID+1 },
@@ -322,12 +325,16 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'd': /* Create directories where needed. */
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;
case 'E': /* Pattern file name. */
pattern_file_name = arg;
diff --git a/src/util.c b/src/util.c
index 00953d5..0faccbc 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1615,6 +1615,24 @@ cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir)
if (!setstat_delayed && repair_delayed_set_stat (file_hdr))
set_perms (-1, file_hdr);
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.