const gboolean is_symlink = (g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK);
const gboolean is_whiteout = (!is_symlink && options->process_whiteouts &&
g_str_has_prefix (destination_name, WHITEOUT_PREFIX));
+ const gboolean is_reg_zerosized = (!is_symlink && g_file_info_get_size (source_info) == 0);
/* First, see if it's a Docker whiteout,
* https://github.com/docker/docker/blob/1a714e76a2cb9008cd19609059e9988ff1660b78/pkg/archive/whiteouts.go
need_copy = FALSE;
}
+ else if (options->force_copy_zerosized && is_reg_zerosized)
+ {
+ need_copy = TRUE;
+ }
else if (!options->force_copy)
{
HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED;
if (can_cache
&& !is_whiteout
&& !is_symlink
+ && !is_reg_zerosized
&& need_copy
&& repo->mode == OSTREE_REPO_MODE_ARCHIVE
&& options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
* succeeded at hardlinking above.
*/
if (options->no_copy_fallback)
- g_assert (is_bare_user_symlink);
+ g_assert (is_bare_user_symlink || is_reg_zerosized);
if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs,
cancellable, error))
return FALSE;
static gboolean opt_disable_fsync;
static gboolean opt_require_hardlinks;
static gboolean opt_force_copy;
+static gboolean opt_force_copy_zerosized;
static gboolean opt_bareuseronly_dirs;
static char *opt_skiplist_file;
static char *opt_selinux_policy;
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
+ { "force-copy-zerosized", 'z', 0, G_OPTION_ARG_NONE, &opt_force_copy_zerosized, "Do not hardlink zero-sized files", NULL },
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
{ "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL },
{ "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" },
* convenient infrastructure for testing C APIs with data.
*/
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks ||
- opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_union_identical ||
+ opt_union_add || opt_force_copy || opt_force_copy_zerosized ||
+ opt_bareuseronly_dirs || opt_union_identical ||
opt_skiplist_file || opt_selinux_policy || opt_selinux_prefix)
{
OstreeRepoCheckoutAtOptions options = { 0, };
options.no_copy_fallback = opt_require_hardlinks;
options.force_copy = opt_force_copy;
+ options.force_copy_zerosized = opt_force_copy_zerosized;
options.bareuseronly_dirs = opt_bareuseronly_dirs;
if (!ostree_repo_checkout_at (repo, &options,
set -euo pipefail
-echo "1..$((83 + ${extra_basic_tests:-0}))"
+echo "1..$((84 + ${extra_basic_tests:-0}))"
CHECKOUT_U_ARG=""
CHECKOUT_H_ARGS="-H"
done
echo "ok checkout union identical conflicts"
+cd ${test_tmpdir}
+rm files -rf && mkdir files
+touch files/anemptyfile
+touch files/anotheremptyfile
+$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-empty-files --tree=dir=files
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} -z tree-with-empty-files tree-with-empty-files
+if files_are_hardlinked tree-with-empty-files/an{,other}emptyfile; then
+ fatal "--force-copy-zerosized failed"
+fi
+rm tree-with-empty-files -rf
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} tree-with-empty-files tree-with-empty-files
+assert_files_hardlinked tree-with-empty-files/an{,other}emptyfile
+rm tree-with-empty-files -rf
+echo "ok checkout --force-copy-zerosized"
+
cd ${test_tmpdir}
rm files -rf && mkdir files
mkdir files/worldwritable-dir