return ret;
}
+enum copy_status { COPY_FAILED, COPY_OK, COPY_SKIPPED };
+
/* Copy file FROM onto file TO aka TO_DIRFD+TO_RELNAME, creating TO if
- necessary. Return true if successful. */
+ necessary. Return COPY_OK if successful or COPY_SKIPPED if the copy
+ was skipped. */
-static bool
+static enum copy_status
copy_file (char const *from, char const *to,
int to_dirfd, char const *to_relname, const struct cp_options *x)
{
- bool copy_into_self;
-
if (copy_only_if_needed && !need_copy (from, to, to_dirfd, to_relname, x))
- return true;
+ return COPY_SKIPPED;
/* Allow installing from non-regular files like /dev/null.
Charles Karney reported that some Sun version of install allows that
However, since !x->recursive, the call to "copy" will fail if FROM
is a directory. */
- return copy (from, to, to_dirfd, to_relname, 0, x, ©_into_self, NULL);
+ bool copy_into_self;
+ return (copy (from, to, to_dirfd, to_relname, 0, x, ©_into_self, NULL)
+ ? COPY_OK : COPY_FAILED);
}
/* Set the attributes of file or directory NAME aka DIRFD+RELNAME.
error (0, errno, _("cannot stat %s"), quoteaf (from));
return false;
}
- if (! copy_file (from, to, to_dirfd, to_relname, x))
+ enum copy_status copy_status = copy_file (from, to, to_dirfd, to_relname, x);
+ if (copy_status == COPY_FAILED)
return false;
- if (strip_files)
- if (! strip (to))
- {
- if (unlinkat (to_dirfd, to_relname, 0) != 0) /* Cleanup. */
- error (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to));
- return false;
- }
- if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
+ if (copy_status == COPY_OK && strip_files && ! strip (to))
+ {
+ if (unlinkat (to_dirfd, to_relname, 0) != 0) /* Cleanup. */
+ error (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to));
+ return false;
+ }
+ if (x->preserve_timestamps && (copy_status == COPY_SKIPPED || strip_files
+ || ! S_ISREG (from_sb.st_mode))
&& ! change_timestamps (&from_sb, to, to_dirfd, to_relname))
return false;
return change_attributes (to, to_dirfd, to_relname);
error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
"not specified"));
- if (copy_only_if_needed && x.preserve_timestamps)
- {
- error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
- "mutually exclusive"));
- usage (EXIT_FAILURE);
- }
-
if (copy_only_if_needed && strip_files)
{
error (0, 0, _("options --compare (-C) and --strip are mutually "
ginstall -Cv -m$mode2 a b > out || fail=1
compare out out_empty || fail=1
-# options -C and --preserve-timestamps are mutually exclusive
-returns_ 1 ginstall -C --preserve-timestamps a b || fail=1
+# Check -C without --preserve-timestamps with files having the same contents.
+echo a > a || framework_failure_
+echo a > b || framework_failure_
+touch -d 2026-01-01 a || framework_failure_
+test b -nt a || framework_failure_ # Handle systems with bad time.
+ginstall -C a b || fail=1
+test b -nt a || fail=1
+
+# Likewise, but with --preserve-timestamps.
+ginstall -C --preserve-timestamps a b || fail=1
+case $(stat --format=%y b) in
+ 2026-01-01*) ;;
+ *) fail=1 ;;
+esac
+
+# Check -C without --preserve-timestamps with files having differing contents.
+echo b > b || framework_failure_
+ginstall -C a b || fail=1
+test b -nt a || fail=1
+
+# Check -C with --preserve-timestamps with files having differing contents.
+ginstall -C --preserve-timestamps a b || fail=1
+case $(stat --format=%y b) in
+ 2026-01-01*) ;;
+ *) fail=1 ;;
+esac
# options -C and --strip are mutually exclusive
returns_ 1 ginstall -C --strip --strip-program=echo a b || fail=1