diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h index 2bd2f98487..9ce5c633d9 100644 --- a/src/libostree/ostree-core-private.h +++ b/src/libostree/ostree-core-private.h @@ -34,6 +34,11 @@ G_BEGIN_DECLS #define DEFAULT_DIRECTORY_MODE 0775 #define DEFAULT_REGFILE_MODE 0660 +/* Macros to identify the file mode of an overlayfs whiteout, or a file stat for a whiteout + ∫*/ +#define S_ISWHITEOUT(mode) (S_ISCHR (mode) && ((mode & ~S_IFMT) == 0)) +#define ST_ISWHITEOUT(st) (S_ISWHITEOUT (st.st_mode) && st.st_rdev == 0) + /* This file contains private implementation data format definitions * read by multiple implementation .c files. */ diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index 56b381d918..c836916deb 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -827,7 +827,7 @@ gboolean ostree_break_hardlink (int dfd, return glnx_file_copy_at (dfd, path, &stbuf, dfd, path, copyflags | GLNX_FILE_COPY_OVERWRITE, cancellable, error); - else if (S_ISLNK (stbuf.st_mode)) + else if (S_ISLNK (stbuf.st_mode) || ST_ISWHITEOUT (stbuf)) //WIP:verify break_symhardlink and glnx can handle a char dev return break_symhardlink (dfd, path, &stbuf, copyflags, cancellable, error); else @@ -929,6 +929,8 @@ ostree_checksum_file_from_input (GFileInfo *file_info, return FALSE; } } + // WIP: handle whiteouts in checksum, those have no content?, but we should probably + // avoid trying to read from them *out_csum = g_malloc (OSTREE_SHA256_DIGEST_LEN); ot_checksum_get_digest (&checksum, *out_csum, OSTREE_SHA256_DIGEST_LEN); @@ -1051,6 +1053,8 @@ ostree_checksum_file_at (int dfd, return FALSE; } + // WIP: whiteouts? + const gboolean ignore_xattrs = ((flags & OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS) > 0); @@ -2014,7 +2018,7 @@ file_header_parse (GVariant *metadata, mode = GUINT32_FROM_BE (mode); g_autoptr(GFileInfo) ret_file_info = _ostree_mode_uidgid_to_gfileinfo (mode, uid, gid); - if (S_ISREG (mode)) + if (S_ISREG (mode) || S_ISWHITEOUT(mode)) { ; } @@ -2065,7 +2069,7 @@ zlib_file_header_parse (GVariant *metadata, g_autoptr(GFileInfo) ret_file_info = _ostree_mode_uidgid_to_gfileinfo (mode, uid, gid); g_file_info_set_size (ret_file_info, GUINT64_FROM_BE (size)); - if (S_ISREG (mode)) + if (S_ISREG (mode) || S_ISWHITEOUT (mode)) { ; } @@ -2370,6 +2374,7 @@ _ostree_validate_bareuseronly_mode (guint32 content_mode, } else if (S_ISLNK (content_mode)) ; /* Nothing */ + // WIP: IS_WHITEOUT does need special handling here? else g_assert_not_reached (); @@ -2400,7 +2405,7 @@ gboolean ostree_validate_structureof_file_mode (guint32 mode, GError **error) { - if (!(S_ISREG (mode) || S_ISLNK (mode))) + if (!(S_ISREG (mode) || S_ISLNK (mode) || S_ISWHITEOUT(mode))) return glnx_throw (error, "Invalid file metadata mode %u; not a valid file type", mode); if (!validate_stat_mode_perms (mode, error)) diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 663292a98f..92fe7c4814 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -398,6 +398,14 @@ create_file_copy_from_input_at (OstreeRepo *repo, error)) return FALSE; } + else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SPECIAL) + { + guint32 file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + g_assert(S_ISWHITEOUT(file_mode)); + if (mknodat(destination_dfd, destination_name, file_mode, (dev_t)0) < 0) { + return glnx_throw_errno_prefix (error, "Creating whiteout char device"); + } + } else g_assert_not_reached (); diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index c22864cd06..d8f8f3f11f 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -301,7 +301,7 @@ commit_loose_regfile_object (OstreeRepo *self, return FALSE; } else - g_assert (S_ISLNK (mode)); + g_assert (S_ISLNK (mode) || S_ISWHITEOUT(mode)); } else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) { @@ -969,6 +969,7 @@ write_content_object (OstreeRepo *self, gboolean phys_object_is_symlink = FALSE; switch (object_file_type) { + case G_FILE_TYPE_SPECIAL: // WIP do additional checks for S_ISWHITEOUT ? case G_FILE_TYPE_REGULAR: break; case G_FILE_TYPE_SYMBOLIC_LINK: @@ -3739,6 +3740,8 @@ write_content_to_mtree_internal (OstreeRepo *self, { case G_FILE_TYPE_SYMBOLIC_LINK: case G_FILE_TYPE_REGULAR: + case G_FILE_TYPE_SPECIAL: // WIP should we also check here for S_ISWHITEOUT on mode to + // be more precise? break; default: return glnx_throw (error, "Unsupported file type for file: '%s'", child_relpath); @@ -4090,7 +4093,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self, continue; } - if (S_ISREG (stbuf.st_mode)) + if (S_ISREG (stbuf.st_mode) || S_ISWHITEOUT(stbuf.st_mode)) ; else if (S_ISLNK (stbuf.st_mode)) { diff --git a/src/libostree/ostree-repo-static-delta-compilation.c b/src/libostree/ostree-repo-static-delta-compilation.c index 28b421395d..3532c5775d 100644 --- a/src/libostree/ostree-repo-static-delta-compilation.c +++ b/src/libostree/ostree-repo-static-delta-compilation.c @@ -514,6 +514,11 @@ process_one_object (OstreeRepo *repo, g_memory_input_stream_new_from_data (target, strlen (target), NULL); content_size = strlen (target); } + else if (S_ISWHITEOUT(mode)) + { + // WIP: can a whiteout trigger a delta? + g_assert(0); + } else { g_assert (S_ISREG (mode)); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 90cde65139..ea24598a80 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4322,8 +4322,8 @@ _ostree_repo_load_file_bare (OstreeRepo *self, return glnx_throw_errno_prefix (error, "openat"); } - if (!(S_ISREG (stbuf.st_mode) || S_ISLNK (stbuf.st_mode))) - return glnx_throw (error, "Not a regular file or symlink"); + if (!(S_ISREG (stbuf.st_mode) || S_ISLNK (stbuf.st_mode) || S_ISWHITEOUT (stbuf.st_mode))) + return glnx_throw (error, "Not a regular file, symlink or whiteout"); /* In the non-bare-user case, gather symlink info if requested */ if (self->mode != OSTREE_REPO_MODE_BARE_USER