mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-02-14 03:12:10 +02:00
install: allow options -D and -t to be used together
* src/install.c (install_file_in_file_parents): Factor out the creation of any parent directories into ... (mkancesdirs_safe_wd): ... this new function. (install_file_in_dir): Add the parameter 'mkdir_and_install', and call the above new function if it evaluates to true. (main): During parsing of the -t option, move the check whether the target_directory exists down after the option parsing loop, and do not complain about stat(optarg,...) failing if -D was given. Pass 'mkdir_and_install' to install_file_in_dir(). * doc/coreutils.texi (install invocation): Remove the (false) restriction that -D would be ignored together with -t. Instead, clarify install's new bahavior. Fix the node's reference in the top-level @direntry for consistency. * src/install/basic-1.sh: Add tests for the now-allowed combination of the -D and -t options. * NEWS: Mention the improvement.
This commit is contained in:
2
NEWS
2
NEWS
@@ -104,6 +104,8 @@ GNU coreutils NEWS -*- outline -*-
|
||||
causing name look-up errors. Also look-ups are first done outside the chroot,
|
||||
in case the look-up within the chroot fails due to library conflicts etc.
|
||||
|
||||
install now allows the combination of the -D and -t options.
|
||||
|
||||
numfmt supports zero padding of numbers using the standard printf
|
||||
syntax of a leading zero, for example --format="%010f".
|
||||
Also throughput was improved by up to 800% by avoiding redundant processing.
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
* hostid: (coreutils)hostid invocation. Print numeric host identifier.
|
||||
* hostname: (coreutils)hostname invocation. Print or set system name.
|
||||
* id: (coreutils)id invocation. Print user identity.
|
||||
* install: (coreutils)install invocation. Copy and change attributes.
|
||||
* install: (coreutils)install invocation. Copy files and set attributes.
|
||||
* join: (coreutils)join invocation. Join lines on a common field.
|
||||
* kill: (coreutils)kill invocation. Send a signal to processes.
|
||||
* link: (coreutils)link invocation. Make hard links between files.
|
||||
@@ -9071,8 +9071,8 @@ Ignored; for compatibility with old Unix versions of @command{install}.
|
||||
@opindex -D
|
||||
Create any missing parent directories of @var{dest},
|
||||
then copy @var{source} to @var{dest}.
|
||||
This option is ignored if a destination directory is specified
|
||||
via @option{--target-directory=DIR}.
|
||||
Explicitly specifying the @option{--target-directory=@var{dir}} will similarly
|
||||
ensure the presence of that hierarchy before copying @var{source} arguments.
|
||||
|
||||
@item -d
|
||||
@itemx --directory
|
||||
|
||||
@@ -706,8 +706,7 @@ install_file_in_file (const char *from, const char *to,
|
||||
Return true if successful. */
|
||||
|
||||
static bool
|
||||
install_file_in_file_parents (char const *from, char *to,
|
||||
struct cp_options *x)
|
||||
mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x)
|
||||
{
|
||||
bool save_working_directory =
|
||||
! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
|
||||
@@ -737,8 +736,18 @@ install_file_in_file_parents (char const *from, char *to,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return status == EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
|
||||
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
|
||||
Return true if successful. */
|
||||
|
||||
static bool
|
||||
install_file_in_file_parents (char const *from, char *to,
|
||||
const struct cp_options *x)
|
||||
{
|
||||
return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x)
|
||||
&& install_file_in_file (from, to, x));
|
||||
}
|
||||
|
||||
/* Copy file FROM into directory TO_DIR, keeping its same name,
|
||||
@@ -747,11 +756,16 @@ install_file_in_file_parents (char const *from, char *to,
|
||||
|
||||
static bool
|
||||
install_file_in_dir (const char *from, const char *to_dir,
|
||||
const struct cp_options *x)
|
||||
const struct cp_options *x, bool mkdir_and_install)
|
||||
{
|
||||
const char *from_base = last_component (from);
|
||||
char *to = file_name_concat (to_dir, from_base, NULL);
|
||||
bool ret = install_file_in_file (from, to, x);
|
||||
bool ret = true;
|
||||
|
||||
if (mkdir_and_install)
|
||||
ret = mkancesdirs_safe_wd (from, to, (struct cp_options *)x);
|
||||
|
||||
ret = ret && install_file_in_file (from, to, x);
|
||||
free (to);
|
||||
return ret;
|
||||
}
|
||||
@@ -851,16 +865,6 @@ main (int argc, char **argv)
|
||||
if (target_directory)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("multiple target directories specified"));
|
||||
else
|
||||
{
|
||||
struct stat st;
|
||||
if (stat (optarg, &st) != 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to access %s"),
|
||||
quote (optarg));
|
||||
if (! S_ISDIR (st.st_mode))
|
||||
error (EXIT_FAILURE, 0, _("target %s is not a directory"),
|
||||
quote (optarg));
|
||||
}
|
||||
target_directory = optarg;
|
||||
break;
|
||||
case 'T':
|
||||
@@ -915,6 +919,18 @@ main (int argc, char **argv)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("target directory not allowed when installing a directory"));
|
||||
|
||||
if (target_directory)
|
||||
{
|
||||
struct stat st;
|
||||
bool stat_success = stat (target_directory, &st) == 0 ? true : false;
|
||||
if (! mkdir_and_install && ! stat_success)
|
||||
error (EXIT_FAILURE, errno, _("failed to access %s"),
|
||||
quote (target_directory));
|
||||
if (stat_success && ! S_ISDIR (st.st_mode))
|
||||
error (EXIT_FAILURE, 0, _("target %s is not a directory"),
|
||||
quote (target_directory));
|
||||
}
|
||||
|
||||
if (backup_suffix_string)
|
||||
simple_backup_suffix = xstrdup (backup_suffix_string);
|
||||
|
||||
@@ -1020,7 +1036,8 @@ main (int argc, char **argv)
|
||||
int i;
|
||||
dest_info_init (&x);
|
||||
for (i = 0; i < n_files; i++)
|
||||
if (! install_file_in_dir (file[i], target_directory, &x))
|
||||
if (! install_file_in_dir (file[i], target_directory, &x,
|
||||
mkdir_and_install))
|
||||
exit_status = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,4 +112,31 @@ ginstall: creating directory 'sub3/a/b/c'
|
||||
'file' -> 'sub3/a/b/c/file'
|
||||
EOF
|
||||
|
||||
# Test -D together with -t (available since coreutils >= 8.23).
|
||||
# Let ginstall create a completely new destination hierarchy.
|
||||
ginstall -t sub4/a/b/c -Dv file >out 2>&1 || fail=1
|
||||
compare - out <<\EOF || fail=1
|
||||
ginstall: creating directory 'sub4'
|
||||
ginstall: creating directory 'sub4/a'
|
||||
ginstall: creating directory 'sub4/a/b'
|
||||
ginstall: creating directory 'sub4/a/b/c'
|
||||
'file' -> 'sub4/a/b/c/file'
|
||||
EOF
|
||||
|
||||
# Ensure that -D with an already existing file as -t's option argument fails.
|
||||
touch sub4/file_exists || framework_failure_
|
||||
ginstall -t sub4/file_exists -Dv file >out 2>&1 && fail=1
|
||||
compare - out <<\EOF || fail=1
|
||||
ginstall: target 'sub4/file_exists' is not a directory
|
||||
EOF
|
||||
|
||||
# Ensure that -D with an already existing directory for -t's option argument
|
||||
# succeeds.
|
||||
mkdir sub4/dir_exists || framework_failure_
|
||||
touch sub4/dir_exists || framework_failure_
|
||||
ginstall -t sub4/dir_exists -Dv file >out 2>&1 || fail=1
|
||||
compare - out <<\EOF || fail=1
|
||||
'file' -> 'sub4/dir_exists/file'
|
||||
EOF
|
||||
|
||||
Exit $fail
|
||||
|
||||
Reference in New Issue
Block a user