New upstream version 2017.13

This commit is contained in:
Simon McVittie 2017-11-04 11:55:24 +00:00
commit 8f7f43a65b
174 changed files with 5474 additions and 2244 deletions

View File

@ -46,6 +46,7 @@ libostree_public_headers += \
src/libostree/ostree-repo-finder-avahi.h \ src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \ src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL) $(NULL)
endif endif

View File

@ -156,6 +156,7 @@ libostree_experimental_headers = \
src/libostree/ostree-repo-finder-avahi.h \ src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \ src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL) $(NULL)
if !ENABLE_EXPERIMENTAL_API if !ENABLE_EXPERIMENTAL_API
libostree_1_la_SOURCES += $(libostree_experimental_headers) libostree_1_la_SOURCES += $(libostree_experimental_headers)
@ -167,6 +168,7 @@ libostree_1_la_SOURCES += \
src/libostree/ostree-repo-finder-avahi.c \ src/libostree/ostree-repo-finder-avahi.c \
src/libostree/ostree-repo-finder-config.c \ src/libostree/ostree-repo-finder-config.c \
src/libostree/ostree-repo-finder-mount.c \ src/libostree/ostree-repo-finder-mount.c \
src/libostree/ostree-repo-finder-override.c \
$(NULL) $(NULL)
if USE_AVAHI if USE_AVAHI

View File

@ -34,11 +34,12 @@ libotutil_la_SOURCES = \
src/libotutil/ot-unix-utils.h \ src/libotutil/ot-unix-utils.h \
src/libotutil/ot-variant-utils.c \ src/libotutil/ot-variant-utils.c \
src/libotutil/ot-variant-utils.h \ src/libotutil/ot-variant-utils.h \
src/libotutil/ot-variant-builder.c \
src/libotutil/ot-variant-builder.h \
src/libotutil/ot-gio-utils.c \ src/libotutil/ot-gio-utils.c \
src/libotutil/ot-gio-utils.h \ src/libotutil/ot-gio-utils.h \
src/libotutil/ot-gpg-utils.c \ src/libotutil/ot-gpg-utils.c \
src/libotutil/ot-gpg-utils.h \ src/libotutil/ot-gpg-utils.h \
src/libotutil/otutil.c \
src/libotutil/otutil.h \ src/libotutil/otutil.h \
src/libotutil/ot-tool-util.c \ src/libotutil/ot-tool-util.c \
src/libotutil/ot-tool-util.h \ src/libotutil/ot-tool-util.h \

View File

@ -69,6 +69,8 @@ _installed_or_uninstalled_test_scripts = \
tests/test-parent.sh \ tests/test-parent.sh \
tests/test-pull-bare.sh \ tests/test-pull-bare.sh \
tests/test-pull-bareuser.sh \ tests/test-pull-bareuser.sh \
tests/test-pull-bareuseronly.sh \
tests/test-pull2-bareuseronly.sh \
tests/test-pull-commit-only.sh \ tests/test-pull-commit-only.sh \
tests/test-pull-depth.sh \ tests/test-pull-depth.sh \
tests/test-pull-mirror-summary.sh \ tests/test-pull-mirror-summary.sh \
@ -159,10 +161,13 @@ endif
dist_installed_test_data = tests/archive-test.sh \ dist_installed_test_data = tests/archive-test.sh \
tests/pull-test.sh \ tests/pull-test.sh \
tests/pull-test2.sh \
tests/admin-test.sh \ tests/admin-test.sh \
tests/basic-test.sh \ tests/basic-test.sh \
tests/pre-endian-deltas-repo-big.tar.xz \ tests/pre-endian-deltas-repo-big.tar.xz \
tests/pre-endian-deltas-repo-little.tar.xz \ tests/pre-endian-deltas-repo-little.tar.xz \
tests/fah-deltadata-old.tar.xz \
tests/fah-deltadata-new.tar.xz \
tests/libtest-core.sh \ tests/libtest-core.sh \
$(NULL) $(NULL)

View File

@ -90,13 +90,24 @@ endif # end ENABLE_RUST
libglnx_srcpath := $(srcdir)/libglnx libglnx_srcpath := $(srcdir)/libglnx
libglnx_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(libglnx_srcpath)" libglnx_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(libglnx_srcpath)"
libglnx_libs := $(OT_DEP_GIO_UNIX_LIBS) libglnx_libs := $(OT_DEP_GIO_UNIX_LIBS)
# See also autogen.sh and https://github.com/ostreedev/ostree/pull/1274/
#
# v2017.12 didn't include test-libglnx-shutil.c, but if you re-run
# autogen.sh (as we do in Debian, to update the Autotools build system)
# it will try to build it.
$(srcdir)/libglnx/Makefile-libglnx.am.inc: $(srcdir)/libglnx/Makefile-libglnx.am
sed -e 's,$$(libglnx_srcpath),libglnx,g' < $< > $@
include libglnx/Makefile-libglnx.am.inc include libglnx/Makefile-libglnx.am.inc
EXTRA_DIST += libglnx/Makefile-libglnx.am EXTRA_DIST += libglnx/Makefile-libglnx.am
noinst_LTLIBRARIES += libglnx.la noinst_LTLIBRARIES += libglnx.la
libbsdiff_srcpath := $(srcdir)/bsdiff libbsdiff_srcpath := $(srcdir)/bsdiff
libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)" libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)"
libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS) libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS)
# See the comment for the similar libglnx bit above
$(srcdir)/bsdiff/Makefile-bsdiff.am.inc: $(srcdir)/bsdiff/Makefile-bsdiff.am
sed -e 's,$$(libbsdiff_srcpath),bsdiff,g' < $< > $@
include bsdiff/Makefile-bsdiff.am.inc include bsdiff/Makefile-bsdiff.am.inc
EXTRA_DIST += bsdiff/Makefile-bsdiff.am EXTRA_DIST += bsdiff/Makefile-bsdiff.am
noinst_LTLIBRARIES += libbsdiff.la noinst_LTLIBRARIES += libbsdiff.la

View File

@ -400,6 +400,7 @@ check_PROGRAMS = $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15)
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-override.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) @ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL)
@ENABLE_RUST_TRUE@am__append_17 = $(BUPSPLIT_RUST_SRCS) @ENABLE_RUST_TRUE@am__append_17 = $(BUPSPLIT_RUST_SRCS)
@ -422,6 +423,7 @@ check_PROGRAMS = $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15)
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.c \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.c \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.c \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.c \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.c \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.c \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-override.c \
@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) @ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL)
@ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__append_23 = \ @ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__append_23 = \
@ -745,12 +747,14 @@ am__libostree_1_la_SOURCES_DIST = \
src/libostree/ostree-repo-finder-avahi.h \ src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \ src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
src/libostree/ostree-bloom.c \ src/libostree/ostree-bloom.c \
src/libostree/ostree-bloom-private.h \ src/libostree/ostree-bloom-private.h \
src/libostree/ostree-repo-finder.c \ src/libostree/ostree-repo-finder.c \
src/libostree/ostree-repo-finder-avahi.c \ src/libostree/ostree-repo-finder-avahi.c \
src/libostree/ostree-repo-finder-config.c \ src/libostree/ostree-repo-finder-config.c \
src/libostree/ostree-repo-finder-mount.c \ src/libostree/ostree-repo-finder-mount.c \
src/libostree/ostree-repo-finder-override.c \
src/libostree/ostree-repo-finder-avahi-parser.c \ src/libostree/ostree-repo-finder-avahi-parser.c \
src/libostree/ostree-repo-finder-avahi-private.h \ src/libostree/ostree-repo-finder-avahi-private.h \
src/libostree/ostree-fetcher.h \ src/libostree/ostree-fetcher.h \
@ -775,6 +779,7 @@ am__objects_4 = $(am__objects_1)
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-config.lo \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-config.lo \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-mount.lo \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-mount.lo \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/libostree_1_la-ostree-repo-finder-override.lo \
@ENABLE_EXPERIMENTAL_API_TRUE@ $(am__objects_1) @ENABLE_EXPERIMENTAL_API_TRUE@ $(am__objects_1)
@ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__objects_7 = src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo \ @ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__objects_7 = src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo \
@ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@ $(am__objects_1) @ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@ $(am__objects_1)
@ -875,9 +880,9 @@ am_libotutil_la_OBJECTS = \
src/libotutil/libotutil_la-ot-opt-utils.lo \ src/libotutil/libotutil_la-ot-opt-utils.lo \
src/libotutil/libotutil_la-ot-unix-utils.lo \ src/libotutil/libotutil_la-ot-unix-utils.lo \
src/libotutil/libotutil_la-ot-variant-utils.lo \ src/libotutil/libotutil_la-ot-variant-utils.lo \
src/libotutil/libotutil_la-ot-variant-builder.lo \
src/libotutil/libotutil_la-ot-gio-utils.lo \ src/libotutil/libotutil_la-ot-gio-utils.lo \
src/libotutil/libotutil_la-ot-gpg-utils.lo \ src/libotutil/libotutil_la-ot-gpg-utils.lo \
src/libotutil/libotutil_la-otutil.lo \
src/libotutil/libotutil_la-ot-tool-util.lo $(am__objects_1) src/libotutil/libotutil_la-ot-tool-util.lo $(am__objects_1)
libotutil_la_OBJECTS = $(am_libotutil_la_OBJECTS) libotutil_la_OBJECTS = $(am_libotutil_la_OBJECTS)
libotutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ libotutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@ -928,7 +933,7 @@ am__EXEEXT_12 = $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_11)
@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__EXEEXT_13 = $(am__EXEEXT_12) @ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__EXEEXT_13 = $(am__EXEEXT_12)
am__EXEEXT_14 = test-libglnx-xattrs$(EXEEXT) \ am__EXEEXT_14 = test-libglnx-xattrs$(EXEEXT) \
test-libglnx-fdio$(EXEEXT) test-libglnx-errors$(EXEEXT) \ test-libglnx-fdio$(EXEEXT) test-libglnx-errors$(EXEEXT) \
test-libglnx-macros$(EXEEXT) test-libglnx-macros$(EXEEXT) test-libglnx-shutil$(EXEEXT)
@BUILDOPT_SYSTEMD_FALSE@am__EXEEXT_15 = ostree-remount$(EXEEXT) @BUILDOPT_SYSTEMD_FALSE@am__EXEEXT_15 = ostree-remount$(EXEEXT)
@ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_16 = $(am__EXEEXT_8) \ @ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_16 = $(am__EXEEXT_8) \
@ENABLE_INSTALLED_TESTS_TRUE@ $(am__EXEEXT_9) $(am__EXEEXT_11) @ENABLE_INSTALLED_TESTS_TRUE@ $(am__EXEEXT_9) $(am__EXEEXT_11)
@ -1131,6 +1136,13 @@ test_libglnx_macros_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(test_libglnx_macros_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(test_libglnx_macros_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@ $(LDFLAGS) -o $@
am_test_libglnx_shutil_OBJECTS = libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.$(OBJEXT)
test_libglnx_shutil_OBJECTS = $(am_test_libglnx_shutil_OBJECTS)
test_libglnx_shutil_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la
test_libglnx_shutil_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(test_libglnx_shutil_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
am_test_libglnx_xattrs_OBJECTS = libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT) am_test_libglnx_xattrs_OBJECTS = libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT)
test_libglnx_xattrs_OBJECTS = $(am_test_libglnx_xattrs_OBJECTS) test_libglnx_xattrs_OBJECTS = $(am_test_libglnx_xattrs_OBJECTS)
test_libglnx_xattrs_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la test_libglnx_xattrs_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la
@ -1381,7 +1393,8 @@ SOURCES = $(libbsdiff_la_SOURCES) $(libbupsplit_la_SOURCES) \
$(ostree_system_generator_SOURCES) \ $(ostree_system_generator_SOURCES) \
$(ostree_trivial_httpd_SOURCES) $(rofiles_fuse_SOURCES) \ $(ostree_trivial_httpd_SOURCES) $(rofiles_fuse_SOURCES) \
$(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \
$(test_libglnx_macros_SOURCES) $(test_libglnx_xattrs_SOURCES) \ $(test_libglnx_macros_SOURCES) $(test_libglnx_shutil_SOURCES) \
$(test_libglnx_xattrs_SOURCES) \
$(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \ $(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \
$(tests_test_bloom_SOURCES) tests/test-bsdiff.c \ $(tests_test_bloom_SOURCES) tests/test-bsdiff.c \
$(tests_test_checksum_SOURCES) \ $(tests_test_checksum_SOURCES) \
@ -1408,7 +1421,8 @@ DIST_SOURCES = $(libbsdiff_la_SOURCES) \
$(am__ostree_trivial_httpd_SOURCES_DIST) \ $(am__ostree_trivial_httpd_SOURCES_DIST) \
$(am__rofiles_fuse_SOURCES_DIST) \ $(am__rofiles_fuse_SOURCES_DIST) \
$(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \
$(test_libglnx_macros_SOURCES) $(test_libglnx_xattrs_SOURCES) \ $(test_libglnx_macros_SOURCES) $(test_libglnx_shutil_SOURCES) \
$(test_libglnx_xattrs_SOURCES) \
$(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \ $(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \
$(tests_test_bloom_SOURCES) tests/test-bsdiff.c \ $(tests_test_bloom_SOURCES) tests/test-bsdiff.c \
$(tests_test_checksum_SOURCES) \ $(tests_test_checksum_SOURCES) \
@ -1477,6 +1491,7 @@ am__libostreeinclude_HEADERS_DIST = src/libostree/ostree.h \
src/libostree/ostree-repo-finder-avahi.h \ src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \ src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
src/libostree/ostree-version.h src/libostree/ostree-version.h
HEADERS = $(libostreeinclude_HEADERS) HEADERS = $(libostreeinclude_HEADERS)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
@ -1683,6 +1698,8 @@ am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \
tests/test-export.sh tests/test-help.sh \ tests/test-export.sh tests/test-help.sh \
tests/test-libarchive.sh tests/test-parent.sh \ tests/test-libarchive.sh tests/test-parent.sh \
tests/test-pull-bare.sh tests/test-pull-bareuser.sh \ tests/test-pull-bare.sh tests/test-pull-bareuser.sh \
tests/test-pull-bareuseronly.sh \
tests/test-pull2-bareuseronly.sh \
tests/test-pull-commit-only.sh tests/test-pull-depth.sh \ tests/test-pull-commit-only.sh tests/test-pull-depth.sh \
tests/test-pull-mirror-summary.sh \ tests/test-pull-mirror-summary.sh \
tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \
@ -2176,7 +2193,7 @@ libglnx_la_SOURCES = \
libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic
libglnx_la_LIBADD = $(libglnx_libs) libglnx_la_LIBADD = $(libglnx_libs)
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil
test_libglnx_xattrs_SOURCES = libglnx/tests/test-libglnx-xattrs.c test_libglnx_xattrs_SOURCES = libglnx/tests/test-libglnx-xattrs.c
test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la
@ -2189,6 +2206,9 @@ test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la
test_libglnx_macros_SOURCES = libglnx/tests/test-libglnx-macros.c test_libglnx_macros_SOURCES = libglnx/tests/test-libglnx-macros.c
test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la
test_libglnx_shutil_SOURCES = libglnx/tests/test-libglnx-shutil.c
test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la
libbsdiff_srcpath := $(srcdir)/bsdiff libbsdiff_srcpath := $(srcdir)/bsdiff
libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)" libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)"
libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS) libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS)
@ -2213,11 +2233,12 @@ libotutil_la_SOURCES = \
src/libotutil/ot-unix-utils.h \ src/libotutil/ot-unix-utils.h \
src/libotutil/ot-variant-utils.c \ src/libotutil/ot-variant-utils.c \
src/libotutil/ot-variant-utils.h \ src/libotutil/ot-variant-utils.h \
src/libotutil/ot-variant-builder.c \
src/libotutil/ot-variant-builder.h \
src/libotutil/ot-gio-utils.c \ src/libotutil/ot-gio-utils.c \
src/libotutil/ot-gio-utils.h \ src/libotutil/ot-gio-utils.h \
src/libotutil/ot-gpg-utils.c \ src/libotutil/ot-gpg-utils.c \
src/libotutil/ot-gpg-utils.h \ src/libotutil/ot-gpg-utils.h \
src/libotutil/otutil.c \
src/libotutil/otutil.h \ src/libotutil/otutil.h \
src/libotutil/ot-tool-util.c \ src/libotutil/ot-tool-util.c \
src/libotutil/ot-tool-util.h \ src/libotutil/ot-tool-util.h \
@ -2336,6 +2357,7 @@ libostree_experimental_headers = \
src/libostree/ostree-repo-finder-avahi.h \ src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \ src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \ src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL) $(NULL)
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym \ symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym \
@ -2492,8 +2514,10 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \
tests/test-commit-sign.sh tests/test-export.sh \ tests/test-commit-sign.sh tests/test-export.sh \
tests/test-help.sh tests/test-libarchive.sh \ tests/test-help.sh tests/test-libarchive.sh \
tests/test-parent.sh tests/test-pull-bare.sh \ tests/test-parent.sh tests/test-pull-bare.sh \
tests/test-pull-bareuser.sh tests/test-pull-commit-only.sh \ tests/test-pull-bareuser.sh tests/test-pull-bareuseronly.sh \
tests/test-pull-depth.sh tests/test-pull-mirror-summary.sh \ tests/test-pull2-bareuseronly.sh \
tests/test-pull-commit-only.sh tests/test-pull-depth.sh \
tests/test-pull-mirror-summary.sh \
tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \
tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \ tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \
tests/test-pull-repeated.sh tests/test-pull-untrusted.sh \ tests/test-pull-repeated.sh tests/test-pull-untrusted.sh \
@ -2544,10 +2568,13 @@ tests_repo_finder_mount_LDADD = $(common_tests_ldadd) libostreetest.la
js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh
dist_installed_test_data = tests/archive-test.sh \ dist_installed_test_data = tests/archive-test.sh \
tests/pull-test.sh \ tests/pull-test.sh \
tests/pull-test2.sh \
tests/admin-test.sh \ tests/admin-test.sh \
tests/basic-test.sh \ tests/basic-test.sh \
tests/pre-endian-deltas-repo-big.tar.xz \ tests/pre-endian-deltas-repo-big.tar.xz \
tests/pre-endian-deltas-repo-little.tar.xz \ tests/pre-endian-deltas-repo-little.tar.xz \
tests/fah-deltadata-old.tar.xz \
tests/fah-deltadata-new.tar.xz \
tests/libtest-core.sh \ tests/libtest-core.sh \
$(NULL) $(NULL)
@ -3109,6 +3136,9 @@ src/libostree/libostree_1_la-ostree-repo-finder-config.lo: \
src/libostree/libostree_1_la-ostree-repo-finder-mount.lo: \ src/libostree/libostree_1_la-ostree-repo-finder-mount.lo: \
src/libostree/$(am__dirstamp) \ src/libostree/$(am__dirstamp) \
src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/$(DEPDIR)/$(am__dirstamp)
src/libostree/libostree_1_la-ostree-repo-finder-override.lo: \
src/libostree/$(am__dirstamp) \
src/libostree/$(DEPDIR)/$(am__dirstamp)
src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: \ src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: \
src/libostree/$(am__dirstamp) \ src/libostree/$(am__dirstamp) \
src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/$(DEPDIR)/$(am__dirstamp)
@ -3185,14 +3215,15 @@ src/libotutil/libotutil_la-ot-unix-utils.lo: \
src/libotutil/libotutil_la-ot-variant-utils.lo: \ src/libotutil/libotutil_la-ot-variant-utils.lo: \
src/libotutil/$(am__dirstamp) \ src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp) src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-ot-variant-builder.lo: \
src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-ot-gio-utils.lo: \ src/libotutil/libotutil_la-ot-gio-utils.lo: \
src/libotutil/$(am__dirstamp) \ src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp) src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-ot-gpg-utils.lo: \ src/libotutil/libotutil_la-ot-gpg-utils.lo: \
src/libotutil/$(am__dirstamp) \ src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp) src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-otutil.lo: src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-ot-tool-util.lo: \ src/libotutil/libotutil_la-ot-tool-util.lo: \
src/libotutil/$(am__dirstamp) \ src/libotutil/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp) src/libotutil/$(DEPDIR)/$(am__dirstamp)
@ -3818,6 +3849,13 @@ libglnx/tests/test_libglnx_macros-test-libglnx-macros.$(OBJEXT): \
test-libglnx-macros$(EXEEXT): $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_DEPENDENCIES) $(EXTRA_test_libglnx_macros_DEPENDENCIES) test-libglnx-macros$(EXEEXT): $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_DEPENDENCIES) $(EXTRA_test_libglnx_macros_DEPENDENCIES)
@rm -f test-libglnx-macros$(EXEEXT) @rm -f test-libglnx-macros$(EXEEXT)
$(AM_V_CCLD)$(test_libglnx_macros_LINK) $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_LDADD) $(LIBS) $(AM_V_CCLD)$(test_libglnx_macros_LINK) $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_LDADD) $(LIBS)
libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.$(OBJEXT): \
libglnx/tests/$(am__dirstamp) \
libglnx/tests/$(DEPDIR)/$(am__dirstamp)
test-libglnx-shutil$(EXEEXT): $(test_libglnx_shutil_OBJECTS) $(test_libglnx_shutil_DEPENDENCIES) $(EXTRA_test_libglnx_shutil_DEPENDENCIES)
@rm -f test-libglnx-shutil$(EXEEXT)
$(AM_V_CCLD)$(test_libglnx_shutil_LINK) $(test_libglnx_shutil_OBJECTS) $(test_libglnx_shutil_LDADD) $(LIBS)
libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT): \ libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT): \
libglnx/tests/$(am__dirstamp) \ libglnx/tests/$(am__dirstamp) \
libglnx/tests/$(DEPDIR)/$(am__dirstamp) libglnx/tests/$(DEPDIR)/$(am__dirstamp)
@ -4229,6 +4267,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/bupsplit.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/bupsplit.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo@am__quote@
@ -4270,6 +4309,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo@am__quote@
@ -4310,8 +4350,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-otutil.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po@am__quote@
@ -4859,6 +4899,13 @@ src/libostree/libostree_1_la-ostree-repo-finder-mount.lo: src/libostree/ostree-r
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-mount.lo `test -f 'src/libostree/ostree-repo-finder-mount.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-mount.c @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-mount.lo `test -f 'src/libostree/ostree-repo-finder-mount.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-mount.c
src/libostree/libostree_1_la-ostree-repo-finder-override.lo: src/libostree/ostree-repo-finder-override.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-override.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-override.lo `test -f 'src/libostree/ostree-repo-finder-override.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-override.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-override.c' object='src/libostree/libostree_1_la-ostree-repo-finder-override.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-override.lo `test -f 'src/libostree/ostree-repo-finder-override.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-override.c
src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: src/libostree/ostree-repo-finder-avahi-parser.c src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: src/libostree/ostree-repo-finder-avahi-parser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo
@ -4992,6 +5039,13 @@ src/libotutil/libotutil_la-ot-variant-utils.lo: src/libotutil/ot-variant-utils.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-variant-utils.lo `test -f 'src/libotutil/ot-variant-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-utils.c @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-variant-utils.lo `test -f 'src/libotutil/ot-variant-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-utils.c
src/libotutil/libotutil_la-ot-variant-builder.lo: src/libotutil/ot-variant-builder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-variant-builder.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Tpo -c -o src/libotutil/libotutil_la-ot-variant-builder.lo `test -f 'src/libotutil/ot-variant-builder.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-builder.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-variant-builder.c' object='src/libotutil/libotutil_la-ot-variant-builder.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-variant-builder.lo `test -f 'src/libotutil/ot-variant-builder.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-builder.c
src/libotutil/libotutil_la-ot-gio-utils.lo: src/libotutil/ot-gio-utils.c src/libotutil/libotutil_la-ot-gio-utils.lo: src/libotutil/ot-gio-utils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-gio-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo -c -o src/libotutil/libotutil_la-ot-gio-utils.lo `test -f 'src/libotutil/ot-gio-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gio-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-gio-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo -c -o src/libotutil/libotutil_la-ot-gio-utils.lo `test -f 'src/libotutil/ot-gio-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gio-utils.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo
@ -5006,13 +5060,6 @@ src/libotutil/libotutil_la-ot-gpg-utils.lo: src/libotutil/ot-gpg-utils.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-gpg-utils.lo `test -f 'src/libotutil/ot-gpg-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gpg-utils.c @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-gpg-utils.lo `test -f 'src/libotutil/ot-gpg-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gpg-utils.c
src/libotutil/libotutil_la-otutil.lo: src/libotutil/otutil.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-otutil.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-otutil.Tpo -c -o src/libotutil/libotutil_la-otutil.lo `test -f 'src/libotutil/otutil.c' || echo '$(srcdir)/'`src/libotutil/otutil.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-otutil.Tpo src/libotutil/$(DEPDIR)/libotutil_la-otutil.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/otutil.c' object='src/libotutil/libotutil_la-otutil.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-otutil.lo `test -f 'src/libotutil/otutil.c' || echo '$(srcdir)/'`src/libotutil/otutil.c
src/libotutil/libotutil_la-ot-tool-util.lo: src/libotutil/ot-tool-util.c src/libotutil/libotutil_la-ot-tool-util.lo: src/libotutil/ot-tool-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-tool-util.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo -c -o src/libotutil/libotutil_la-ot-tool-util.lo `test -f 'src/libotutil/ot-tool-util.c' || echo '$(srcdir)/'`src/libotutil/ot-tool-util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-tool-util.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo -c -o src/libotutil/libotutil_la-ot-tool-util.lo `test -f 'src/libotutil/ot-tool-util.c' || echo '$(srcdir)/'`src/libotutil/ot-tool-util.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo
@ -5951,6 +5998,20 @@ libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj: libglnx/tests/test-li
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj `if test -f 'libglnx/tests/test-libglnx-macros.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-macros.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-macros.c'; fi` @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj `if test -f 'libglnx/tests/test-libglnx-macros.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-macros.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-macros.c'; fi`
libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o: libglnx/tests/test-libglnx-shutil.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o `test -f 'libglnx/tests/test-libglnx-shutil.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-shutil.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-shutil.c' object='libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o `test -f 'libglnx/tests/test-libglnx-shutil.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-shutil.c
libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj: libglnx/tests/test-libglnx-shutil.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj `if test -f 'libglnx/tests/test-libglnx-shutil.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-shutil.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-shutil.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-shutil.c' object='libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj `if test -f 'libglnx/tests/test-libglnx-shutil.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-shutil.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-shutil.c'; fi`
libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o: libglnx/tests/test-libglnx-xattrs.c libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o: libglnx/tests/test-libglnx-xattrs.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o `test -f 'libglnx/tests/test-libglnx-xattrs.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-xattrs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o `test -f 'libglnx/tests/test-libglnx-xattrs.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-xattrs.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po
@ -7333,6 +7394,20 @@ tests/test-pull-bareuser.sh.log: tests/test-pull-bareuser.sh
--log-file $$b.log --trs-file $$b.trs \ --log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT) "$$tst" $(AM_TESTS_FD_REDIRECT)
tests/test-pull-bareuseronly.sh.log: tests/test-pull-bareuseronly.sh
@p='tests/test-pull-bareuseronly.sh'; \
b='tests/test-pull-bareuseronly.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
tests/test-pull2-bareuseronly.sh.log: tests/test-pull2-bareuseronly.sh
@p='tests/test-pull2-bareuseronly.sh'; \
b='tests/test-pull2-bareuseronly.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
tests/test-pull-commit-only.sh.log: tests/test-pull-commit-only.sh tests/test-pull-commit-only.sh.log: tests/test-pull-commit-only.sh
@p='tests/test-pull-commit-only.sh'; \ @p='tests/test-pull-commit-only.sh'; \
b='tests/test-pull-commit-only.sh'; \ b='tests/test-pull-commit-only.sh'; \
@ -7802,6 +7877,13 @@ test-libglnx-macros.log: test-libglnx-macros$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \ --log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT) "$$tst" $(AM_TESTS_FD_REDIRECT)
test-libglnx-shutil.log: test-libglnx-shutil$(EXEEXT)
@p='test-libglnx-shutil$(EXEEXT)'; \
b='test-libglnx-shutil'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
.test.log: .test.log:
@p='$<'; \ @p='$<'; \
$(am__set_b); \ $(am__set_b); \
@ -8292,6 +8374,16 @@ all-local: $(ALL_LOCAL_RULES)
@ENABLE_RUST_TRUE@ cargo vendor -q && \ @ENABLE_RUST_TRUE@ cargo vendor -q && \
@ENABLE_RUST_TRUE@ mkdir .cargo && \ @ENABLE_RUST_TRUE@ mkdir .cargo && \
@ENABLE_RUST_TRUE@ cp cargo-vendor-config .cargo/config) @ENABLE_RUST_TRUE@ cp cargo-vendor-config .cargo/config)
# See also autogen.sh and https://github.com/ostreedev/ostree/pull/1274/
#
# v2017.12 didn't include test-libglnx-shutil.c, but if you re-run
# autogen.sh (as we do in Debian, to update the Autotools build system)
# it will try to build it.
$(srcdir)/libglnx/Makefile-libglnx.am.inc: $(srcdir)/libglnx/Makefile-libglnx.am
sed -e 's,$$(libglnx_srcpath),libglnx,g' < $< > $@
# See the comment for the similar libglnx bit above
$(srcdir)/bsdiff/Makefile-bsdiff.am.inc: $(srcdir)/bsdiff/Makefile-bsdiff.am
sed -e 's,$$(libbsdiff_srcpath),bsdiff,g' < $< > $@
@ENABLE_RUST_TRUE@$(bupsplitpath): Makefile $(BUPSPLIT_RUST_SRCS) @ENABLE_RUST_TRUE@$(bupsplitpath): Makefile $(BUPSPLIT_RUST_SRCS)
@ENABLE_RUST_TRUE@ cd $(top_srcdir)/rust && CARGO_TARGET_DIR=@abs_top_builddir@/target cargo build --verbose $(CARGO_RELEASE_ARGS) @ENABLE_RUST_TRUE@ cd $(top_srcdir)/rust && CARGO_TARGET_DIR=@abs_top_builddir@/target cargo build --verbose $(CARGO_RELEASE_ARGS)

5
aclocal.m4 vendored
View File

@ -23,6 +23,9 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
# Configure paths for GLIB # Configure paths for GLIB
# Owen Taylor 1997-2001 # Owen Taylor 1997-2001
# Increment this whenever this file is changed.
#serial 1
dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject, dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject,
dnl gthread, or gio is specified in MODULES, pass to pkg-config dnl gthread, or gio is specified in MODULES, pass to pkg-config
@ -112,7 +115,7 @@ dnl
#include <stdlib.h> #include <stdlib.h>
int int
main () main (void)
{ {
unsigned int major, minor, micro; unsigned int major, minor, micro;

View File

@ -137,6 +137,7 @@ host_triplet = @host@
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-avahi.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-config.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.h \ @ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-mount.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-repo-finder-override.h \
@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) @ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL)
subdir = apidoc subdir = apidoc

View File

@ -14,7 +14,7 @@
<div class="titlepage"> <div class="titlepage">
<div> <div>
<div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">OSTree API references</p></th></tr></table></div> <div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">OSTree API references</p></th></tr></table></div>
<div><p class="releaseinfo">for OSTree 2017.12</p></div> <div><p class="releaseinfo">for OSTree 2017.13</p></div>
</div> </div>
<hr> <hr>
</div> </div>

View File

@ -307,6 +307,14 @@
</tr> </tr>
<tr> <tr>
<td class="function_type"> <td class="function_type">
<span class="returnvalue">gboolean</span>
</td>
<td class="function_name">
<a class="link" href="ostree-Core-repository-independent-functions.html#ostree-checksum-file-at" title="ostree_checksum_file_at ()">ostree_checksum_file_at</a> <span class="c_punctuation">()</span>
</td>
</tr>
<tr>
<td class="function_type">
<span class="returnvalue">void</span> <span class="returnvalue">void</span>
</td> </td>
<td class="function_name"> <td class="function_name">
@ -1786,6 +1794,69 @@ ostree_checksum_file (<em class="parameter"><code><span class="type">GFile</span
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
<a name="ostree-checksum-file-at"></a><h3>ostree_checksum_file_at ()</h3>
<pre class="programlisting"><span class="returnvalue">gboolean</span>
ostree_checksum_file_at (<em class="parameter"><code><span class="type">int</span> dfd</code></em>,
<em class="parameter"><code>const <span class="type">char</span> *path</code></em>,
<em class="parameter"><code><span class="type">struct stat</span> *stbuf</code></em>,
<em class="parameter"><code><a class="link" href="ostree-Core-repository-independent-functions.html#OstreeObjectType" title="enum OstreeObjectType"><span class="type">OstreeObjectType</span></a> objtype</code></em>,
<em class="parameter"><code><span class="type">OstreeChecksumFlags</span> flags</code></em>,
<em class="parameter"><code><span class="type">char</span> **out_checksum</code></em>,
<em class="parameter"><code><span class="type">GCancellable</span> *cancellable</code></em>,
<em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre>
<p>Compute the OSTree checksum for a given file. This is an fd-relative version
of <a class="link" href="ostree-Core-repository-independent-functions.html#ostree-checksum-file" title="ostree_checksum_file ()"><code class="function">ostree_checksum_file()</code></a> which also takes flags and fills in a caller
allocated buffer.</p>
<div class="refsect3">
<a name="ostree-checksum-file-at.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0">
<colgroup>
<col width="150px" class="parameters_name">
<col class="parameters_description">
<col width="200px" class="parameters_annotations">
</colgroup>
<tbody>
<tr>
<td class="parameter_name"><p>dfd</p></td>
<td class="parameter_description"><p>Directory file descriptor</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>path</p></td>
<td class="parameter_description"><p>Subpath
<em class="parameter"><code>stbuf</code></em>
(allow-none): Optional stat buffer</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>objtype</p></td>
<td class="parameter_description"><p>Object type</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>flags</p></td>
<td class="parameter_description"><p>Flags
<em class="parameter"><code>out_checksum</code></em>
(out) (transfer full): Return location for hex checksum</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>cancellable</p></td>
<td class="parameter_description"><p>Cancellable</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>error</p></td>
<td class="parameter_description"><p>Error</p></td>
<td class="parameter_annotations"> </td>
</tr>
</tbody>
</table></div>
</div>
<p class="since">Since: 2017.13</p>
</div>
<hr>
<div class="refsect2">
<a name="ostree-checksum-file-async"></a><h3>ostree_checksum_file_async ()</h3> <a name="ostree-checksum-file-async"></a><h3>ostree_checksum_file_async ()</h3>
<pre class="programlisting"><span class="returnvalue">void</span> <pre class="programlisting"><span class="returnvalue">void</span>
ostree_checksum_file_async (<em class="parameter"><code><span class="type">GFile</span> *f</code></em>, ostree_checksum_file_async (<em class="parameter"><code><span class="type">GFile</span> *f</code></em>,

View File

@ -769,6 +769,14 @@
</tr> </tr>
<tr> <tr>
<td class="function_type"> <td class="function_type">
<span class="returnvalue">void</span>
</td>
<td class="function_name">
<a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-at-options-set-devino" title="ostree_repo_checkout_at_options_set_devino ()">ostree_repo_checkout_at_options_set_devino</a> <span class="c_punctuation">()</span>
</td>
</tr>
<tr>
<td class="function_type">
<span class="returnvalue">gboolean</span> <span class="returnvalue">gboolean</span>
</td> </td>
<td class="function_name"> <td class="function_name">
@ -1107,6 +1115,10 @@
<td class="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCommitModifierFlags" title="enum OstreeRepoCommitModifierFlags">OstreeRepoCommitModifierFlags</a></td> <td class="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCommitModifierFlags" title="enum OstreeRepoCommitModifierFlags">OstreeRepoCommitModifierFlags</a></td>
</tr> </tr>
<tr> <tr>
<td class="datatype_keyword"> </td>
<td class="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutAtOptions" title="OstreeRepoCheckoutAtOptions">OstreeRepoCheckoutAtOptions</a></td>
</tr>
<tr>
<td class="datatype_keyword">enum</td> <td class="datatype_keyword">enum</td>
<td class="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutMode" title="enum OstreeRepoCheckoutMode">OstreeRepoCheckoutMode</a></td> <td class="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutMode" title="enum OstreeRepoCheckoutMode">OstreeRepoCheckoutMode</a></td>
</tr> </tr>
@ -2187,6 +2199,8 @@ respectively.</p>
is is
set to <em class="parameter"><code>NULL</code></em> set to <em class="parameter"><code>NULL</code></em>
. In either case the function still returns <code class="literal">TRUE</code>.</p> . In either case the function still returns <code class="literal">TRUE</code>.</p>
<p>This method does not verify the signature of the downloaded summary file.
Use <a class="link" href="ostree-OstreeRepo.html#ostree-repo-verify-summary" title="ostree_repo_verify_summary ()"><code class="function">ostree_repo_verify_summary()</code></a> for that.</p>
<p>Parse the summary data into a <span class="type">GVariant</span> using <code class="function">g_variant_new_from_bytes()</code> <p>Parse the summary data into a <span class="type">GVariant</span> using <code class="function">g_variant_new_from_bytes()</code>
with <a class="link" href="ostree-Core-repository-independent-functions.html#OSTREE-SUMMARY-GVARIANT-FORMAT:CAPS" title="OSTREE_SUMMARY_GVARIANT_FORMAT"><span class="type">OSTREE_SUMMARY_GVARIANT_FORMAT</span></a> as the format string.</p> with <a class="link" href="ostree-Core-repository-independent-functions.html#OSTREE-SUMMARY-GVARIANT-FORMAT:CAPS" title="OSTREE_SUMMARY_GVARIANT_FORMAT"><span class="type">OSTREE_SUMMARY_GVARIANT_FORMAT</span></a> as the format string.</p>
<div class="refsect3"> <div class="refsect3">
@ -2759,6 +2773,37 @@ that happened during this transaction. </p></td>
ostree_repo_abort_transaction (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>, ostree_repo_abort_transaction (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>,
<em class="parameter"><code><span class="type">GCancellable</span> *cancellable</code></em>, <em class="parameter"><code><span class="type">GCancellable</span> *cancellable</code></em>,
<em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre> <em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre>
<p>Abort the active transaction; any staged objects and ref changes will be
discarded. You *must* invoke this if you have chosen not to invoke
<a class="link" href="ostree-OstreeRepo.html#ostree-repo-commit-transaction" title="ostree_repo_commit_transaction ()"><code class="function">ostree_repo_commit_transaction()</code></a>. Calling this function when not in a
transaction will do nothing and return successfully.</p>
<div class="refsect3">
<a name="ostree-repo-abort-transaction.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0">
<colgroup>
<col width="150px" class="parameters_name">
<col class="parameters_description">
<col width="200px" class="parameters_annotations">
</colgroup>
<tbody>
<tr>
<td class="parameter_name"><p>self</p></td>
<td class="parameter_description"><p>An <a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a></p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>cancellable</p></td>
<td class="parameter_description"><p>Cancellable</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>error</p></td>
<td class="parameter_description"><p>Error</p></td>
<td class="parameter_annotations"> </td>
</tr>
</tbody>
</table></div>
</div>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
@ -3275,6 +3320,39 @@ ostree_repo_write_metadata_finish (<em class="parameter"><code><a class="link" h
<em class="parameter"><code><span class="type">GAsyncResult</span> *result</code></em>, <em class="parameter"><code><span class="type">GAsyncResult</span> *result</code></em>,
<em class="parameter"><code><span class="type">guchar</span> **out_csum</code></em>, <em class="parameter"><code><span class="type">guchar</span> **out_csum</code></em>,
<em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre> <em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre>
<p>Complete a call to <a class="link" href="ostree-OstreeRepo.html#ostree-repo-write-metadata-async" title="ostree_repo_write_metadata_async ()"><code class="function">ostree_repo_write_metadata_async()</code></a>.</p>
<div class="refsect3">
<a name="ostree-repo-write-metadata-finish.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0">
<colgroup>
<col width="150px" class="parameters_name">
<col class="parameters_description">
<col width="200px" class="parameters_annotations">
</colgroup>
<tbody>
<tr>
<td class="parameter_name"><p>self</p></td>
<td class="parameter_description"><p>Repo</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>result</p></td>
<td class="parameter_description"><p>Result</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>out_csum</p></td>
<td class="parameter_description"><p> Binary checksum value. </p></td>
<td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/out"><span class="acronym">out</span></a>][<a href="http://foldoc.org/array"><span class="acronym">array</span></a> fixed-size=32][<a href="http://foldoc.org/element-type"><span class="acronym">element-type</span></a> guint8]</span></td>
</tr>
<tr>
<td class="parameter_name"><p>error</p></td>
<td class="parameter_description"><p>Error</p></td>
<td class="parameter_annotations"> </td>
</tr>
</tbody>
</table></div>
</div>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
@ -4768,6 +4846,7 @@ should avoid further mutation of the cache.</p>
</tbody> </tbody>
</table></div> </table></div>
</div> </div>
<p class="since">Since: 2017.13</p>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
@ -5322,6 +5401,44 @@ data will be deleted.</p>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
<a name="ostree-repo-checkout-at-options-set-devino"></a><h3>ostree_repo_checkout_at_options_set_devino ()</h3>
<pre class="programlisting"><span class="returnvalue">void</span>
ostree_repo_checkout_at_options_set_devino
(<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutAtOptions" title="OstreeRepoCheckoutAtOptions"><span class="type">OstreeRepoCheckoutAtOptions</span></a> *opts</code></em>,
<em class="parameter"><code><span class="type">OstreeRepoDevInoCache</span> *cache</code></em>);</pre>
<p>This function simply assigns <em class="parameter"><code>cache</code></em>
to the <code class="literal">devino_to_csum_cache</code> member of
<em class="parameter"><code>opts</code></em>
; it's only useful for introspection.</p>
<p>Note that cache does *not* have its refcount incremented - the lifetime of
<em class="parameter"><code>cache</code></em>
must be equal to or greater than that of <em class="parameter"><code>opts</code></em>
.</p>
<div class="refsect3">
<a name="ostree-repo-checkout-at-options-set-devino.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0">
<colgroup>
<col width="150px" class="parameters_name">
<col class="parameters_description">
<col width="200px" class="parameters_annotations">
</colgroup>
<tbody>
<tr>
<td class="parameter_name"><p>opts</p></td>
<td class="parameter_description"><p>Checkout options</p></td>
<td class="parameter_annotations"> </td>
</tr>
<tr>
<td class="parameter_name"><p>cache</p></td>
<td class="parameter_description"><p> Devino cache. </p></td>
<td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/transfer%20none"><span class="acronym">transfer none</span></a>][<a href="http://foldoc.org/nullable"><span class="acronym">nullable</span></a>]</span></td>
</tr>
</tbody>
</table></div>
</div>
</div>
<hr>
<div class="refsect2">
<a name="ostree-repo-checkout-tree"></a><h3>ostree_repo_checkout_tree ()</h3> <a name="ostree-repo-checkout-tree"></a><h3>ostree_repo_checkout_tree ()</h3>
<pre class="programlisting"><span class="returnvalue">gboolean</span> <pre class="programlisting"><span class="returnvalue">gboolean</span>
ostree_repo_checkout_tree (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>, ostree_repo_checkout_tree (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>,
@ -5468,7 +5585,7 @@ cache.</p>
<a name="ostree-repo-checkout-at"></a><h3>ostree_repo_checkout_at ()</h3> <a name="ostree-repo-checkout-at"></a><h3>ostree_repo_checkout_at ()</h3>
<pre class="programlisting"><span class="returnvalue">gboolean</span> <pre class="programlisting"><span class="returnvalue">gboolean</span>
ostree_repo_checkout_at (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>, ostree_repo_checkout_at (<em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepo" title="OstreeRepo"><span class="type">OstreeRepo</span></a> *self</code></em>,
<em class="parameter"><code><span class="type">OstreeRepoCheckoutAtOptions</span> *options</code></em>, <em class="parameter"><code><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutAtOptions" title="OstreeRepoCheckoutAtOptions"><span class="type">OstreeRepoCheckoutAtOptions</span></a> *options</code></em>,
<em class="parameter"><code><span class="type">int</span> destination_dfd</code></em>, <em class="parameter"><code><span class="type">int</span> destination_dfd</code></em>,
<em class="parameter"><code>const <span class="type">char</span> *destination_path</code></em>, <em class="parameter"><code>const <span class="type">char</span> *destination_path</code></em>,
<em class="parameter"><code>const <span class="type">char</span> *commit</code></em>, <em class="parameter"><code>const <span class="type">char</span> *commit</code></em>,
@ -7622,12 +7739,51 @@ in bytes, counting only content objects.</p></td>
</td> </td>
<td class="enum_member_annotations"> </td> <td class="enum_member_annotations"> </td>
</tr> </tr>
<tr>
<td class="enum_member_name"><p><a name="OSTREE-REPO-COMMIT-MODIFIER-FLAGS-CONSUME:CAPS"></a>OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME</p></td>
<td class="enum_member_description">
<p>Delete added files/directories after commit; Since: 2017.13</p>
</td>
<td class="enum_member_annotations"> </td>
</tr>
</tbody> </tbody>
</table></div> </table></div>
</div> </div>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">
<a name="OstreeRepoCheckoutAtOptions"></a><h3>OstreeRepoCheckoutAtOptions</h3>
<pre class="programlisting">typedef struct {
OstreeRepoCheckoutMode mode;
OstreeRepoCheckoutOverwriteMode overwrite_mode;
gboolean enable_uncompressed_cache; /* Deprecated */
gboolean enable_fsync; /* Deprecated */
gboolean process_whiteouts;
gboolean no_copy_fallback;
gboolean force_copy; /* Since: 2017.6 */
gboolean bareuseronly_dirs; /* Since: 2017.7 */
gboolean unused_bools[5];
/* 4 byte hole on 64 bit */
const char *subpath;
OstreeRepoDevInoCache *devino_to_csum_cache;
int unused_ints[6];
gpointer unused_ptrs[5];
OstreeSePolicy *sepolicy; /* Since: 2017.6 */
const char *sepolicy_prefix;
} OstreeRepoCheckoutAtOptions;
</pre>
<p>An extensible options structure controlling checkout. Ensure that
you have entirely zeroed the structure, then set just the desired
options. This is used by <a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-at" title="ostree_repo_checkout_at ()"><code class="function">ostree_repo_checkout_at()</code></a> which
supercedes previous separate enumeration usage in
<a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-tree" title="ostree_repo_checkout_tree ()"><code class="function">ostree_repo_checkout_tree()</code></a> and <a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-tree-at" title="ostree_repo_checkout_tree_at ()"><code class="function">ostree_repo_checkout_tree_at()</code></a>.</p>
</div>
<hr>
<div class="refsect2">
<a name="OstreeRepoCheckoutMode"></a><h3>enum OstreeRepoCheckoutMode</h3> <a name="OstreeRepoCheckoutMode"></a><h3>enum OstreeRepoCheckoutMode</h3>
<div class="refsect3"> <div class="refsect3">
<a name="OstreeRepoCheckoutMode.members"></a><h4>Members</h4> <a name="OstreeRepoCheckoutMode.members"></a><h4>Members</h4>
@ -7678,7 +7834,7 @@ in bytes, counting only content objects.</p></td>
<tr> <tr>
<td class="enum_member_name"><p><a name="OSTREE-REPO-CHECKOUT-OVERWRITE-UNION-FILES:CAPS"></a>OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES</p></td> <td class="enum_member_name"><p><a name="OSTREE-REPO-CHECKOUT-OVERWRITE-UNION-FILES:CAPS"></a>OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES</p></td>
<td class="enum_member_description"> <td class="enum_member_description">
<p>When layering checkouts, <code class="function">unlink()</code> and replace existing files, but do not modify existing directories</p> <p>When layering checkouts, <code class="function">unlink()</code> and replace existing files, but do not modify existing directories (unless whiteouts are enabled, then directories are replaced)</p>
</td> </td>
<td class="enum_member_annotations"> </td> <td class="enum_member_annotations"> </td>
</tr> </tr>

View File

@ -365,6 +365,11 @@ perform locking externally.</p>
<a name="ostree-sysroot-new"></a><h3>ostree_sysroot_new ()</h3> <a name="ostree-sysroot-new"></a><h3>ostree_sysroot_new ()</h3>
<pre class="programlisting"><a class="link" href="ostree-Root-partition-mount-point.html#OstreeSysroot" title="OstreeSysroot"><span class="returnvalue">OstreeSysroot</span></a> * <pre class="programlisting"><a class="link" href="ostree-Root-partition-mount-point.html#OstreeSysroot" title="OstreeSysroot"><span class="returnvalue">OstreeSysroot</span></a> *
ostree_sysroot_new (<em class="parameter"><code><span class="type">GFile</span> *path</code></em>);</pre> ostree_sysroot_new (<em class="parameter"><code><span class="type">GFile</span> *path</code></em>);</pre>
<p>Create a new <a class="link" href="ostree-Root-partition-mount-point.html#OstreeSysroot" title="OstreeSysroot"><span class="type">OstreeSysroot</span></a> object for the sysroot at <em class="parameter"><code>path</code></em>
. If <em class="parameter"><code>path</code></em>
is <code class="literal">NULL</code>,
the current visible root file system is used, equivalent to
<a class="link" href="ostree-Root-partition-mount-point.html#ostree-sysroot-new-default" title="ostree_sysroot_new_default ()"><code class="function">ostree_sysroot_new_default()</code></a>.</p>
<div class="refsect3"> <div class="refsect3">
<a name="ostree-sysroot-new.parameters"></a><h4>Parameters</h4> <a name="ostree-sysroot-new.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0"> <div class="informaltable"><table class="informaltable" width="100%" border="0">
@ -375,7 +380,8 @@ ostree_sysroot_new (<em class="parameter"><code><span class="type">GFile</span>
</colgroup> </colgroup>
<tbody><tr> <tbody><tr>
<td class="parameter_name"><p>path</p></td> <td class="parameter_name"><p>path</p></td>
<td class="parameter_description"><p> Path to a system root directory, or <code class="literal">NULL</code>. </p></td> <td class="parameter_description"><p> Path to a system root directory, or <code class="literal">NULL</code> to use the
current visible root file system. </p></td>
<td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/allow-none"><span class="acronym">allow-none</span></a>]</span></td> <td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/allow-none"><span class="acronym">allow-none</span></a>]</span></td>
</tr></tbody> </tr></tbody>
</table></div> </table></div>
@ -1007,7 +1013,8 @@ ostree_sysroot_get_repo (<em class="parameter"><code><a class="link" href="ostre
<em class="parameter"><code><span class="type">GCancellable</span> *cancellable</code></em>, <em class="parameter"><code><span class="type">GCancellable</span> *cancellable</code></em>,
<em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre> <em class="parameter"><code><span class="type">GError</span> **error</code></em>);</pre>
<p>Retrieve the OSTree repository in sysroot <em class="parameter"><code>self</code></em> <p>Retrieve the OSTree repository in sysroot <em class="parameter"><code>self</code></em>
.</p> . The repo is guaranteed to be open
(see <a class="link" href="ostree-OstreeRepo.html#ostree-repo-open" title="ostree_repo_open ()"><code class="function">ostree_repo_open()</code></a>).</p>
<div class="refsect3"> <div class="refsect3">
<a name="ostree-sysroot-get-repo.parameters"></a><h4>Parameters</h4> <a name="ostree-sysroot-get-repo.parameters"></a><h4>Parameters</h4>
<div class="informaltable"><table class="informaltable" width="100%" border="0"> <div class="informaltable"><table class="informaltable" width="100%" border="0">
@ -1026,7 +1033,7 @@ ostree_sysroot_get_repo (<em class="parameter"><code><a class="link" href="ostre
<td class="parameter_name"><p>out_repo</p></td> <td class="parameter_name"><p>out_repo</p></td>
<td class="parameter_description"><p> Repository in sysroot <em class="parameter"><code>self</code></em> <td class="parameter_description"><p> Repository in sysroot <em class="parameter"><code>self</code></em>
. </p></td> . </p></td>
<td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/out"><span class="acronym">out</span></a>]</span></td> <td class="parameter_annotations"><span class="annotation">[<a href="http://foldoc.org/out"><span class="acronym">out</span></a>][<a href="http://foldoc.org/transfer%20full"><span class="acronym">transfer full</span></a>][<a href="http://foldoc.org/optional"><span class="acronym">optional</span></a>]</span></td>
</tr> </tr>
<tr> <tr>
<td class="parameter_name"><p>cancellable</p></td> <td class="parameter_name"><p>cancellable</p></td>
@ -1041,6 +1048,10 @@ ostree_sysroot_get_repo (<em class="parameter"><code><a class="link" href="ostre
</tbody> </tbody>
</table></div> </table></div>
</div> </div>
<div class="refsect3">
<a name="ostree-sysroot-get-repo.returns"></a><h4>Returns</h4>
<p> <code class="literal">TRUE</code> on success, <code class="literal">FALSE</code> otherwise</p>
</div>
</div> </div>
<hr> <hr>
<div class="refsect2"> <div class="refsect2">

View File

@ -54,6 +54,7 @@
<keyword type="function" name="ostree_raw_file_to_content_stream ()" link="ostree-Core-repository-independent-functions.html#ostree-raw-file-to-content-stream"/> <keyword type="function" name="ostree_raw_file_to_content_stream ()" link="ostree-Core-repository-independent-functions.html#ostree-raw-file-to-content-stream"/>
<keyword type="function" name="ostree_checksum_file_from_input ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-from-input"/> <keyword type="function" name="ostree_checksum_file_from_input ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-from-input"/>
<keyword type="function" name="ostree_checksum_file ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file"/> <keyword type="function" name="ostree_checksum_file ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file"/>
<keyword type="function" name="ostree_checksum_file_at ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-at" since="2017.13"/>
<keyword type="function" name="ostree_checksum_file_async ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-async"/> <keyword type="function" name="ostree_checksum_file_async ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-async"/>
<keyword type="function" name="ostree_checksum_file_async_finish ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-async-finish"/> <keyword type="function" name="ostree_checksum_file_async_finish ()" link="ostree-Core-repository-independent-functions.html#ostree-checksum-file-async-finish"/>
<keyword type="function" name="ostree_create_directory_metadata ()" link="ostree-Core-repository-independent-functions.html#ostree-create-directory-metadata"/> <keyword type="function" name="ostree_create_directory_metadata ()" link="ostree-Core-repository-independent-functions.html#ostree-create-directory-metadata"/>
@ -157,7 +158,7 @@
<keyword type="function" name="OstreeRepoCommitModifierXattrCallback ()" link="ostree-OstreeRepo.html#OstreeRepoCommitModifierXattrCallback"/> <keyword type="function" name="OstreeRepoCommitModifierXattrCallback ()" link="ostree-OstreeRepo.html#OstreeRepoCommitModifierXattrCallback"/>
<keyword type="function" name="ostree_repo_commit_modifier_set_xattr_callback ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-xattr-callback"/> <keyword type="function" name="ostree_repo_commit_modifier_set_xattr_callback ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-xattr-callback"/>
<keyword type="function" name="ostree_repo_commit_modifier_set_sepolicy ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-sepolicy"/> <keyword type="function" name="ostree_repo_commit_modifier_set_sepolicy ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-sepolicy"/>
<keyword type="function" name="ostree_repo_commit_modifier_set_devino_cache ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-devino-cache"/> <keyword type="function" name="ostree_repo_commit_modifier_set_devino_cache ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-set-devino-cache" since="2017.13"/>
<keyword type="function" name="ostree_repo_commit_modifier_ref ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-ref"/> <keyword type="function" name="ostree_repo_commit_modifier_ref ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-ref"/>
<keyword type="function" name="ostree_repo_commit_modifier_unref ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-unref"/> <keyword type="function" name="ostree_repo_commit_modifier_unref ()" link="ostree-OstreeRepo.html#ostree-repo-commit-modifier-unref"/>
<keyword type="function" name="ostree_repo_devino_cache_new ()" link="ostree-OstreeRepo.html#ostree-repo-devino-cache-new"/> <keyword type="function" name="ostree_repo_devino_cache_new ()" link="ostree-OstreeRepo.html#ostree-repo-devino-cache-new"/>
@ -172,6 +173,7 @@
<keyword type="function" name="ostree_repo_write_commit_with_time ()" link="ostree-OstreeRepo.html#ostree-repo-write-commit-with-time"/> <keyword type="function" name="ostree_repo_write_commit_with_time ()" link="ostree-OstreeRepo.html#ostree-repo-write-commit-with-time"/>
<keyword type="function" name="ostree_repo_read_commit_detached_metadata ()" link="ostree-OstreeRepo.html#ostree-repo-read-commit-detached-metadata"/> <keyword type="function" name="ostree_repo_read_commit_detached_metadata ()" link="ostree-OstreeRepo.html#ostree-repo-read-commit-detached-metadata"/>
<keyword type="function" name="ostree_repo_write_commit_detached_metadata ()" link="ostree-OstreeRepo.html#ostree-repo-write-commit-detached-metadata"/> <keyword type="function" name="ostree_repo_write_commit_detached_metadata ()" link="ostree-OstreeRepo.html#ostree-repo-write-commit-detached-metadata"/>
<keyword type="function" name="ostree_repo_checkout_at_options_set_devino ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-at-options-set-devino"/>
<keyword type="function" name="ostree_repo_checkout_tree ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-tree"/> <keyword type="function" name="ostree_repo_checkout_tree ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-tree"/>
<keyword type="function" name="ostree_repo_checkout_tree_at ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-tree-at" deprecated=""/> <keyword type="function" name="ostree_repo_checkout_tree_at ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-tree-at" deprecated=""/>
<keyword type="function" name="ostree_repo_checkout_at ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-at"/> <keyword type="function" name="ostree_repo_checkout_at ()" link="ostree-OstreeRepo.html#ostree-repo-checkout-at"/>
@ -218,6 +220,7 @@
<keyword type="enum" name="enum OstreeRepoCommitFilterResult" link="ostree-OstreeRepo.html#OstreeRepoCommitFilterResult"/> <keyword type="enum" name="enum OstreeRepoCommitFilterResult" link="ostree-OstreeRepo.html#OstreeRepoCommitFilterResult"/>
<keyword type="typedef" name="OstreeRepoCommitModifier" link="ostree-OstreeRepo.html#OstreeRepoCommitModifier"/> <keyword type="typedef" name="OstreeRepoCommitModifier" link="ostree-OstreeRepo.html#OstreeRepoCommitModifier"/>
<keyword type="enum" name="enum OstreeRepoCommitModifierFlags" link="ostree-OstreeRepo.html#OstreeRepoCommitModifierFlags"/> <keyword type="enum" name="enum OstreeRepoCommitModifierFlags" link="ostree-OstreeRepo.html#OstreeRepoCommitModifierFlags"/>
<keyword type="struct" name="OstreeRepoCheckoutAtOptions" link="ostree-OstreeRepo.html#OstreeRepoCheckoutAtOptions"/>
<keyword type="enum" name="enum OstreeRepoCheckoutMode" link="ostree-OstreeRepo.html#OstreeRepoCheckoutMode"/> <keyword type="enum" name="enum OstreeRepoCheckoutMode" link="ostree-OstreeRepo.html#OstreeRepoCheckoutMode"/>
<keyword type="enum" name="enum OstreeRepoCheckoutOverwriteMode" link="ostree-OstreeRepo.html#OstreeRepoCheckoutOverwriteMode"/> <keyword type="enum" name="enum OstreeRepoCheckoutOverwriteMode" link="ostree-OstreeRepo.html#OstreeRepoCheckoutOverwriteMode"/>
<keyword type="enum" name="enum OstreeRepoListObjectsFlags" link="ostree-OstreeRepo.html#OstreeRepoListObjectsFlags"/> <keyword type="enum" name="enum OstreeRepoListObjectsFlags" link="ostree-OstreeRepo.html#OstreeRepoListObjectsFlags"/>
@ -409,6 +412,7 @@
<keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-GENERATE-SIZES:CAPS"/> <keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-GENERATE-SIZES:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-CANONICAL-PERMISSIONS:CAPS"/> <keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-CANONICAL-PERMISSIONS:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-ERROR-ON-UNLABELED:CAPS"/> <keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-ERROR-ON-UNLABELED:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME" link="ostree-OstreeRepo.html#OSTREE-REPO-COMMIT-MODIFIER-FLAGS-CONSUME:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_CHECKOUT_MODE_NONE" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-MODE-NONE:CAPS"/> <keyword type="constant" name="OSTREE_REPO_CHECKOUT_MODE_NONE" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-MODE-NONE:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_CHECKOUT_MODE_USER" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-MODE-USER:CAPS"/> <keyword type="constant" name="OSTREE_REPO_CHECKOUT_MODE_USER" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-MODE-USER:CAPS"/>
<keyword type="constant" name="OSTREE_REPO_CHECKOUT_OVERWRITE_NONE" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-OVERWRITE-NONE:CAPS"/> <keyword type="constant" name="OSTREE_REPO_CHECKOUT_OVERWRITE_NONE" link="ostree-OstreeRepo.html#OSTREE-REPO-CHECKOUT-OVERWRITE-NONE:CAPS"/>

View File

@ -214,6 +214,10 @@
</dt> </dt>
<dd></dd> <dd></dd>
<dt> <dt>
<a class="link" href="ostree-Core-repository-independent-functions.html#ostree-checksum-file-at" title="ostree_checksum_file_at ()">ostree_checksum_file_at</a>, function in <a class="link" href="ostree-Core-repository-independent-functions.html" title="Core repository-independent functions">Core repository-independent functions</a>
</dt>
<dd></dd>
<dt>
<a class="link" href="ostree-Core-repository-independent-functions.html#ostree-checksum-file-from-input" title="ostree_checksum_file_from_input ()">ostree_checksum_file_from_input</a>, function in <a class="link" href="ostree-Core-repository-independent-functions.html" title="Core repository-independent functions">Core repository-independent functions</a> <a class="link" href="ostree-Core-repository-independent-functions.html#ostree-checksum-file-from-input" title="ostree_checksum_file_from_input ()">ostree_checksum_file_from_input</a>, function in <a class="link" href="ostree-Core-repository-independent-functions.html" title="Core repository-independent functions">Core repository-independent functions</a>
</dt> </dt>
<dd></dd> <dd></dd>
@ -598,6 +602,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
</dt> </dt>
<dd></dd> <dd></dd>
<dt> <dt>
<a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutAtOptions" title="OstreeRepoCheckoutAtOptions">OstreeRepoCheckoutAtOptions</a>, struct in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a>
</dt>
<dd></dd>
<dt>
<a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutMode" title="enum OstreeRepoCheckoutMode">OstreeRepoCheckoutMode</a>, enum in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a> <a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutMode" title="enum OstreeRepoCheckoutMode">OstreeRepoCheckoutMode</a>, enum in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a>
</dt> </dt>
<dd></dd> <dd></dd>
@ -690,6 +698,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
</dt> </dt>
<dd></dd> <dd></dd>
<dt> <dt>
<a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-at-options-set-devino" title="ostree_repo_checkout_at_options_set_devino ()">ostree_repo_checkout_at_options_set_devino</a>, function in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a>
</dt>
<dd></dd>
<dt>
<a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-gc" title="ostree_repo_checkout_gc ()">ostree_repo_checkout_gc</a>, function in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a> <a class="link" href="ostree-OstreeRepo.html#ostree-repo-checkout-gc" title="ostree_repo_checkout_gc ()">ostree_repo_checkout_gc</a>, function in <a class="link" href="ostree-OstreeRepo.html" title="OstreeRepo: Content-addressed object store">OstreeRepo</a>
</dt> </dt>
<dd></dd> <dd></dd>

View File

@ -76,6 +76,15 @@ ostree_repo_finder_mount_new
ostree_repo_finder_mount_get_type ostree_repo_finder_mount_get_type
</SECTION> </SECTION>
<SECTION>
<FILE>ostree-repo-finder-override</FILE>
OstreeRepoFinderOverride
ostree_repo_finder_override_new
ostree_repo_finder_override_add_uri
<SUBSECTION Standard>
ostree_repo_finder_override_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>ostree-misc-experimental</FILE> <FILE>ostree-misc-experimental</FILE>
ostree_repo_get_collection_id ostree_repo_get_collection_id

View File

@ -135,6 +135,7 @@ ostree_raw_file_to_archive_z2_stream_with_options
ostree_raw_file_to_content_stream ostree_raw_file_to_content_stream
ostree_checksum_file_from_input ostree_checksum_file_from_input
ostree_checksum_file ostree_checksum_file
ostree_checksum_file_at
ostree_checksum_file_async ostree_checksum_file_async
ostree_checksum_file_async_finish ostree_checksum_file_async_finish
ostree_create_directory_metadata ostree_create_directory_metadata
@ -370,6 +371,8 @@ ostree_repo_write_commit
ostree_repo_write_commit_with_time ostree_repo_write_commit_with_time
ostree_repo_read_commit_detached_metadata ostree_repo_read_commit_detached_metadata
ostree_repo_write_commit_detached_metadata ostree_repo_write_commit_detached_metadata
OstreeRepoCheckoutAtOptions
ostree_repo_checkout_at_options_set_devino
OstreeRepoCheckoutMode OstreeRepoCheckoutMode
OstreeRepoCheckoutOverwriteMode OstreeRepoCheckoutOverwriteMode
ostree_repo_checkout_tree ostree_repo_checkout_tree

View File

@ -16,6 +16,7 @@ ostree_repo_finder_avahi_get_type
ostree_repo_finder_config_get_type ostree_repo_finder_config_get_type
ostree_repo_finder_get_type ostree_repo_finder_get_type
ostree_repo_finder_mount_get_type ostree_repo_finder_mount_get_type
ostree_repo_finder_override_get_type
ostree_repo_finder_result_get_type ostree_repo_finder_result_get_type
ostree_repo_get_type ostree_repo_get_type
ostree_repo_transaction_stats_get_type ostree_repo_transaction_stats_get_type

View File

@ -1 +1 @@
2017.12 2017.13

View File

@ -31,7 +31,8 @@ fi
if ! test -f libglnx/README.md || ! test -f bsdiff/README.md; then if ! test -f libglnx/README.md || ! test -f bsdiff/README.md; then
git submodule update --init git submodule update --init
fi fi
# Workaround automake bug with subdir-objects and computed paths # Workaround automake bug with subdir-objects and computed paths; if
# changing this, please also change Makefile.am.
sed -e 's,$(libglnx_srcpath),libglnx,g' < libglnx/Makefile-libglnx.am >libglnx/Makefile-libglnx.am.inc sed -e 's,$(libglnx_srcpath),libglnx,g' < libglnx/Makefile-libglnx.am >libglnx/Makefile-libglnx.am.inc
sed -e 's,$(libbsdiff_srcpath),bsdiff,g' < bsdiff/Makefile-bsdiff.am >bsdiff/Makefile-bsdiff.am.inc sed -e 's,$(libbsdiff_srcpath),bsdiff,g' < bsdiff/Makefile-bsdiff.am >bsdiff/Makefile-bsdiff.am.inc

View File

@ -745,6 +745,7 @@ _ostree_checkout() {
_ostree_checksum() { _ostree_checksum() {
local boolean_options=" local boolean_options="
$main_boolean_options $main_boolean_options
--ignore-xattrs
" "
case "$cur" in case "$cur" in
@ -773,6 +774,7 @@ _ostree_commit() {
--link-checkout-speedup --link-checkout-speedup
--no-xattrs --no-xattrs
--orphan --orphan
--consume
--skip-if-unchanged --skip-if-unchanged
--table-output --table-output
--tar-autocreate-parents --tar-autocreate-parents

View File

@ -1,8 +1,6 @@
AC_DEFUN([LIBGLNX_CONFIGURE], AC_DEFUN([LIBGLNX_CONFIGURE],
[ [
AC_CHECK_DECLS([ AC_CHECK_DECLS([renameat2, memfd_create],
renameat2,
],
[], [], [[ [], [], [[
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>

View File

@ -30,8 +30,9 @@
/* Define if we have avahi-client.pc and avahi-glib.pc */ /* Define if we have avahi-client.pc and avahi-glib.pc */
#undef HAVE_AVAHI #undef HAVE_AVAHI
/* Define to 1 if you have the declaration of `', and to 0 if you don't. */ /* Define to 1 if you have the declaration of `memfd_create', and to 0 if you
#undef HAVE_DECL_ don't. */
#undef HAVE_DECL_MEMFD_CREATE
/* Define to 1 if you have the declaration of `renameat2', and to 0 if you /* Define to 1 if you have the declaration of `renameat2', and to 0 if you
don't. */ don't. */

32
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for libostree 2017.12. # Generated by GNU Autoconf 2.69 for libostree 2017.13.
# #
# Report bugs to <walters@verbum.org>. # Report bugs to <walters@verbum.org>.
# #
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='libostree' PACKAGE_NAME='libostree'
PACKAGE_TARNAME='libostree' PACKAGE_TARNAME='libostree'
PACKAGE_VERSION='2017.12' PACKAGE_VERSION='2017.13'
PACKAGE_STRING='libostree 2017.12' PACKAGE_STRING='libostree 2017.13'
PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_BUGREPORT='walters@verbum.org'
PACKAGE_URL='' PACKAGE_URL=''
@ -1540,7 +1540,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures libostree 2017.12 to adapt to many kinds of systems. \`configure' configures libostree 2017.13 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1610,7 +1610,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of libostree 2017.12:";; short | recursive ) echo "Configuration of libostree 2017.13:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1851,7 +1851,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
libostree configure 2017.12 libostree configure 2017.13
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2266,7 +2266,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by libostree $as_me 2017.12, which was It was created by libostree $as_me 2017.13, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -3134,7 +3134,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='libostree' PACKAGE='libostree'
VERSION='2017.12' VERSION='2017.13'
# Some tools Automake needs. # Some tools Automake needs.
@ -5868,9 +5868,9 @@ test -n "$YACC" || YACC="yacc"
YEAR_VERSION=2017 YEAR_VERSION=2017
RELEASE_VERSION=12 RELEASE_VERSION=13
PACKAGE_VERSION=2017.12 PACKAGE_VERSION=2017.13
if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then :
@ -13731,7 +13731,7 @@ fi
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_RENAMEAT2 $ac_have_decl #define HAVE_DECL_RENAMEAT2 $ac_have_decl
_ACEOF _ACEOF
ac_fn_c_check_decl "$LINENO" "" "ac_cv_have_decl_" " ac_fn_c_check_decl "$LINENO" "memfd_create" "ac_cv_have_decl_memfd_create" "
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mount.h> #include <sys/mount.h>
@ -13741,14 +13741,14 @@ ac_fn_c_check_decl "$LINENO" "" "ac_cv_have_decl_" "
#include <linux/random.h> #include <linux/random.h>
" "
if test "x$ac_cv_have_decl_" = xyes; then : if test "x$ac_cv_have_decl_memfd_create" = xyes; then :
ac_have_decl=1 ac_have_decl=1
else else
ac_have_decl=0 ac_have_decl=0
fi fi
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_ $ac_have_decl #define HAVE_DECL_MEMFD_CREATE $ac_have_decl
_ACEOF _ACEOF
@ -14155,7 +14155,7 @@ else
#include <stdlib.h> #include <stdlib.h>
int int
main () main (void)
{ {
unsigned int major, minor, micro; unsigned int major, minor, micro;
@ -18168,7 +18168,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by libostree $as_me 2017.12, which was This file was extended by libostree $as_me 2017.13, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -18234,7 +18234,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
libostree config.status 2017.12 libostree config.status 2017.13
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -4,7 +4,7 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check
dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl in test-symbols.sh, and also set is_release_build=yes below. Then make
dnl another post-release commit to bump the version, and set is_release_build=no. dnl another post-release commit to bump the version, and set is_release_build=no.
m4_define([year_version], [2017]) m4_define([year_version], [2017])
m4_define([release_version], [12]) m4_define([release_version], [13])
m4_define([package_version], [year_version.release_version]) m4_define([package_version], [year_version.release_version])
AC_INIT([libostree], [package_version], [walters@verbum.org]) AC_INIT([libostree], [package_version], [walters@verbum.org])
is_release_build=yes is_release_build=yes

View File

@ -53,7 +53,7 @@ libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic
libglnx_la_LIBADD = $(libglnx_libs) libglnx_la_LIBADD = $(libglnx_libs)
libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil
TESTS += $(libglnx_tests) TESTS += $(libglnx_tests)
check_PROGRAMS += $(libglnx_tests) check_PROGRAMS += $(libglnx_tests)
@ -72,3 +72,7 @@ test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la
test_libglnx_macros_SOURCES = libglnx/tests/test-libglnx-macros.c test_libglnx_macros_SOURCES = libglnx/tests/test-libglnx-macros.c
test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la
test_libglnx_shutil_SOURCES = libglnx/tests/test-libglnx-shutil.c
test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la

View File

@ -37,7 +37,7 @@ applicable.
For local allocation macros, you should start using the `g_auto` For local allocation macros, you should start using the `g_auto`
macros from GLib. A backport is included in libglnx. There are a few macros from GLib. A backport is included in libglnx. There are a few
APIs not defined in GLib yet, such as `glnx_fd_close`. APIs not defined in GLib yet, such as `glnx_autofd`.
`gs_transfer_out_value` is replaced by `g_steal_pointer`. `gs_transfer_out_value` is replaced by `g_steal_pointer`.

View File

@ -99,7 +99,7 @@ glnx_dirfd_iterator_init_at (int dfd,
GLnxDirFdIterator *out_dfd_iter, GLnxDirFdIterator *out_dfd_iter,
GError **error) GError **error)
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_opendirat (dfd, path, follow, &fd, error)) if (!glnx_opendirat (dfd, path, follow, &fd, error))
return FALSE; return FALSE;
@ -190,15 +190,12 @@ glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
struct dirent *ret_dent;
g_return_val_if_fail (out_dent, FALSE); g_return_val_if_fail (out_dent, FALSE);
if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error)) if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error))
return FALSE; return FALSE;
ret_dent = *out_dent; struct dirent *ret_dent = *out_dent;
if (ret_dent) if (ret_dent)
{ {
@ -265,20 +262,16 @@ glnx_fdrel_abspath (int dfd,
void void
glnx_gen_temp_name (gchar *tmpl) glnx_gen_temp_name (gchar *tmpl)
{ {
size_t len; g_return_if_fail (tmpl != NULL);
char *XXXXXX; const size_t len = strlen (tmpl);
int i; g_return_if_fail (len >= 6);
static const char letters[] = static const char letters[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static const int NLETTERS = sizeof (letters) - 1; static const int NLETTERS = sizeof (letters) - 1;
g_return_if_fail (tmpl != NULL); char *XXXXXX = tmpl + (len - 6);
len = strlen (tmpl); for (int i = 0; i < 6; i++)
g_return_if_fail (len >= 6);
XXXXXX = tmpl + (len - 6);
for (i = 0; i < 6; i++)
XXXXXX[i] = letters[g_random_int_range(0, NLETTERS)]; XXXXXX[i] = letters[g_random_int_range(0, NLETTERS)];
} }
@ -326,7 +319,7 @@ glnx_mkdtempat (int dfd, const char *tmpl, int mode,
} }
/* And open it */ /* And open it */
glnx_fd_close int ret_dfd = -1; glnx_autofd int ret_dfd = -1;
if (!glnx_opendirat (dfd, path, FALSE, &ret_dfd, error)) if (!glnx_opendirat (dfd, path, FALSE, &ret_dfd, error))
{ {
/* If we fail to open, let's try to clean up */ /* If we fail to open, let's try to clean up */
@ -382,8 +375,7 @@ _glnx_tmpdir_free (GLnxTmpDir *tmpd,
if (!(tmpd && tmpd->initialized)) if (!(tmpd && tmpd->initialized))
return TRUE; return TRUE;
g_assert_cmpint (tmpd->fd, !=, -1); g_assert_cmpint (tmpd->fd, !=, -1);
(void) close (tmpd->fd); glnx_close_fd (&tmpd->fd);
tmpd->fd = -1;
g_assert (tmpd->path); g_assert (tmpd->path);
g_assert_cmpint (tmpd->src_dfd, !=, -1); g_assert_cmpint (tmpd->src_dfd, !=, -1);
g_autofree char *path = tmpd->path; /* Take ownership */ g_autofree char *path = tmpd->path; /* Take ownership */

View File

@ -141,7 +141,14 @@ glnx_renameat2_exchange (int olddirfd, const char *oldpath,
#endif #endif
/* Fallback */ /* Fallback */
{ const char *old_tmp_name = glnx_strjoina (oldpath, ".XXXXXX"); { char *old_tmp_name_buf = glnx_strjoina (oldpath, ".XXXXXX");
/* This obviously isn't race-free, but doing better gets tricky, since if
* we're here the kernel isn't likely to support RENAME_NOREPLACE either.
* Anyways, upgrade the kernel. Failing that, avoid use of this function in
* shared subdirectories like /tmp.
*/
glnx_gen_temp_name (old_tmp_name_buf);
const char *old_tmp_name = old_tmp_name_buf;
/* Move old out of the way */ /* Move old out of the way */
if (renameat (olddirfd, oldpath, olddirfd, old_tmp_name) < 0) if (renameat (olddirfd, oldpath, olddirfd, old_tmp_name) < 0)
@ -168,11 +175,7 @@ glnx_tmpfile_clear (GLnxTmpfile *tmpf)
return; return;
if (!tmpf->initialized) if (!tmpf->initialized)
return; return;
if (tmpf->fd != -1) glnx_close_fd (&tmpf->fd);
{
if (close (tmpf->fd) < 0)
g_assert (errno != EBADF);
}
/* If ->path is set, we're likely aborting due to an error. Clean it up */ /* If ->path is set, we're likely aborting due to an error. Clean it up */
if (tmpf->path) if (tmpf->path)
{ {
@ -188,9 +191,8 @@ open_tmpfile_core (int dfd, const char *subpath,
GLnxTmpfile *out_tmpf, GLnxTmpfile *out_tmpf,
GError **error) GError **error)
{ {
/* Picked this to match mkstemp() */
const guint mode = 0600; const guint mode = 0600;
glnx_fd_close int fd = -1;
int count;
dfd = glnx_dirfd_canonicalize (dfd); dfd = glnx_dirfd_canonicalize (dfd);
@ -201,7 +203,8 @@ open_tmpfile_core (int dfd, const char *subpath,
* link_tmpfile() below to rename the result after writing the file * link_tmpfile() below to rename the result after writing the file
* in full. */ * in full. */
#if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT) #if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT)
fd = openat (dfd, subpath, O_TMPFILE|flags, mode); {
glnx_autofd int fd = openat (dfd, subpath, O_TMPFILE|flags, mode);
if (fd == -1 && !(G_IN_SET(errno, ENOSYS, EISDIR, EOPNOTSUPP))) if (fd == -1 && !(G_IN_SET(errno, ENOSYS, EISDIR, EOPNOTSUPP)))
return glnx_throw_errno_prefix (error, "open(O_TMPFILE)"); return glnx_throw_errno_prefix (error, "open(O_TMPFILE)");
if (fd != -1) if (fd != -1)
@ -217,17 +220,18 @@ open_tmpfile_core (int dfd, const char *subpath,
out_tmpf->path = NULL; out_tmpf->path = NULL;
return TRUE; return TRUE;
} }
}
/* Fallthrough */ /* Fallthrough */
#endif #endif
{ g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL);
const guint count_max = 100; const guint count_max = 100;
{ g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL);
for (count = 0; count < count_max; count++) for (int count = 0; count < count_max; count++)
{ {
glnx_gen_temp_name (tmp); glnx_gen_temp_name (tmp);
fd = openat (dfd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, mode); glnx_autofd int fd = openat (dfd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, mode);
if (fd < 0) if (fd < 0)
{ {
if (errno == EEXIST) if (errno == EEXIST)
@ -246,7 +250,7 @@ open_tmpfile_core (int dfd, const char *subpath,
} }
} }
g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
"Exhausted %u attempts to create temporary file", count); "Exhausted %u attempts to create temporary file", count_max);
return FALSE; return FALSE;
} }
@ -356,9 +360,9 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
char *dnbuf = strdupa (target); char *dnbuf = strdupa (target);
const char *dn = dirname (dnbuf); const char *dn = dirname (dnbuf);
char *tmpname_buf = glnx_strjoina (dn, "/tmp.XXXXXX"); char *tmpname_buf = glnx_strjoina (dn, "/tmp.XXXXXX");
guint count;
const guint count_max = 100;
const guint count_max = 100;
guint count;
for (count = 0; count < count_max; count++) for (count = 0; count < count_max; count++)
{ {
glnx_gen_temp_name (tmpname_buf); glnx_gen_temp_name (tmpname_buf);
@ -569,7 +573,7 @@ glnx_file_get_contents_utf8_at (int dfd,
{ {
dfd = glnx_dirfd_canonicalize (dfd); dfd = glnx_dirfd_canonicalize (dfd);
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd, subpath, TRUE, &fd, error)) if (!glnx_openat_rdonly (dfd, subpath, TRUE, &fd, error))
return NULL; return NULL;
@ -599,17 +603,13 @@ glnx_readlinkat_malloc (int dfd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
size_t l = 100;
dfd = glnx_dirfd_canonicalize (dfd); dfd = glnx_dirfd_canonicalize (dfd);
size_t l = 100;
for (;;) for (;;)
{ {
g_autofree char *c = NULL; g_autofree char *c = g_malloc (l);
ssize_t n; ssize_t n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1));
c = g_malloc (l);
n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1));
if (n < 0) if (n < 0)
return glnx_null_throw_errno_prefix (error, "readlinkat"); return glnx_null_throw_errno_prefix (error, "readlinkat");
@ -679,18 +679,15 @@ copy_symlink_at (int src_dfd,
int int
glnx_loop_write(int fd, const void *buf, size_t nbytes) glnx_loop_write(int fd, const void *buf, size_t nbytes)
{ {
const uint8_t *p = buf; g_return_val_if_fail (fd >= 0, -1);
g_return_val_if_fail (buf, -1);
g_return_val_if_fail(fd >= 0, -1);
g_return_val_if_fail(buf, -1);
errno = 0; errno = 0;
const uint8_t *p = buf;
while (nbytes > 0) while (nbytes > 0)
{ {
ssize_t k; ssize_t k = write(fd, p, nbytes);
k = write(fd, p, nbytes);
if (k < 0) if (k < 0)
{ {
if (errno == EINTR) if (errno == EINTR)
@ -926,7 +923,7 @@ glnx_file_copy_at (int src_dfd,
/* Regular file path below here */ /* Regular file path below here */
glnx_fd_close int src_fd = -1; glnx_autofd int src_fd = -1;
if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error)) if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error))
return FALSE; return FALSE;

View File

@ -299,7 +299,7 @@ glnx_fstatat (int dfd,
* glnx_fstatat_allow_noent: * glnx_fstatat_allow_noent:
* @dfd: Directory FD to stat beneath * @dfd: Directory FD to stat beneath
* @path: Path to stat beneath @dfd * @path: Path to stat beneath @dfd
* @buf: (out caller-allocates): Return location for stat details * @buf: (out caller-allocates) (allow-none): Return location for stat details
* @flags: Flags to pass to fstatat() * @flags: Flags to pass to fstatat()
* @error: Return location for a #GError, or %NULL * @error: Return location for a #GError, or %NULL
* *
@ -318,15 +318,12 @@ glnx_fstatat_allow_noent (int dfd,
int flags, int flags,
GError **error) GError **error)
{ {
if (TEMP_FAILURE_RETRY (fstatat (dfd, path, out_buf, flags)) != 0) G_GNUC_UNUSED struct stat unused_stbuf;
if (TEMP_FAILURE_RETRY (fstatat (dfd, path, out_buf ? out_buf : &unused_stbuf, flags)) != 0)
{ {
if (errno != ENOENT) if (errno != ENOENT)
{ return glnx_throw_errno_prefix (error, "fstatat(%s)", path);
int errsv = errno; /* Note we preserve errno as ENOENT */
(void) glnx_throw_errno_prefix (error, "fstatat(%s)", path);
errno = errsv;
return FALSE;
}
} }
else else
errno = 0; errno = 0;

View File

@ -42,14 +42,30 @@ glnx_local_obj_unref (void *v)
} }
#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) #define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref)))
static inline void static inline int
glnx_cleanup_close_fdp (int *fdp) glnx_steal_fd (int *fdp)
{ {
int fd, errsv; int fd = *fdp;
*fdp = -1;
return fd;
}
/**
* glnx_close_fd:
* @fdp: Pointer to fd
*
* Effectively `close (glnx_steal_fd (&fd))`. Also
* asserts that `close()` did not raise `EBADF` - encountering
* that error is usually a critical bug in the program.
*/
static inline void
glnx_close_fd (int *fdp)
{
int errsv;
g_assert (fdp); g_assert (fdp);
fd = *fdp; int fd = glnx_steal_fd (fdp);
if (fd >= 0) if (fd >= 0)
{ {
errsv = errno; errsv = errno;
@ -62,16 +78,14 @@ glnx_cleanup_close_fdp (int *fdp)
/** /**
* glnx_fd_close: * glnx_fd_close:
* *
* Deprecated in favor of `glnx_autofd`.
*/
#define glnx_fd_close __attribute__((cleanup(glnx_close_fd)))
/**
* glnx_autofd:
*
* Call close() on a variable location when it goes out of scope. * Call close() on a variable location when it goes out of scope.
*/ */
#define glnx_fd_close __attribute__((cleanup(glnx_cleanup_close_fdp))) #define glnx_autofd __attribute__((cleanup(glnx_close_fd)))
static inline int
glnx_steal_fd (int *fdp)
{
int fd = *fdp;
*fdp = -1;
return fd;
}
G_END_DECLS G_END_DECLS

View File

@ -61,7 +61,7 @@
*/ */
gboolean gboolean
glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_lock, GError **error) { glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_lock, GError **error) {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
g_autofree char *t = NULL; g_autofree char *t = NULL;
int r; int r;
@ -119,8 +119,7 @@ glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_loc
if (st.st_nlink > 0) if (st.st_nlink > 0)
break; break;
(void) close(fd); glnx_close_fd (&fd);
fd = -1;
} }
/* Note that if this is not AT_FDCWD, the caller takes responsibility /* Note that if this is not AT_FDCWD, the caller takes responsibility
@ -174,9 +173,7 @@ void glnx_release_lock_file(GLnxLockFile *f) {
f->path = NULL; f->path = NULL;
} }
if (f->fd != -1) glnx_close_fd (&f->fd);
(void) close (f->fd);
f->fd = -1;
f->operation = 0; f->operation = 0;
f->initialized = FALSE; f->initialized = FALSE;
} }

View File

@ -18,7 +18,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>. along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/ ***/
/* Missing glibc definitions to access certain kernel APIs */ /* Missing glibc definitions to access certain kernel APIs.
This file is last updated from systemd git:
commit 71e5200f94b22589922704aa4abdf95d4fe2e528
Author: Daniel Mack <daniel@zonque.org>
AuthorDate: Tue Oct 18 17:57:10 2016 +0200
Commit: Lennart Poettering <lennart@poettering.net>
CommitDate: Fri Sep 22 15:24:54 2017 +0200
Add abstraction model for BPF programs
*/
#if !HAVE_DECL_RENAMEAT2 #if !HAVE_DECL_RENAMEAT2
# ifndef __NR_renameat2 # ifndef __NR_renameat2
@ -26,6 +37,8 @@
# define __NR_renameat2 316 # define __NR_renameat2 316
# elif defined __arm__ # elif defined __arm__
# define __NR_renameat2 382 # define __NR_renameat2 382
# elif defined __aarch64__
# define __NR_renameat2 276
# elif defined _MIPS_SIM # elif defined _MIPS_SIM
# if _MIPS_SIM == _MIPS_SIM_ABI32 # if _MIPS_SIM == _MIPS_SIM_ABI32
# define __NR_renameat2 4351 # define __NR_renameat2 4351
@ -38,6 +51,12 @@
# endif # endif
# elif defined __i386__ # elif defined __i386__
# define __NR_renameat2 353 # define __NR_renameat2 353
# elif defined __powerpc64__
# define __NR_renameat2 357
# elif defined __s390__ || defined __s390x__
# define __NR_renameat2 347
# elif defined __arc__
# define __NR_renameat2 276
# else # else
# warning "__NR_renameat2 unknown for your architecture" # warning "__NR_renameat2 unknown for your architecture"
# endif # endif
@ -53,6 +72,45 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha
} }
#endif #endif
#if !HAVE_DECL_MEMFD_CREATE
# ifndef __NR_memfd_create
# if defined __x86_64__
# define __NR_memfd_create 319
# elif defined __arm__
# define __NR_memfd_create 385
# elif defined __aarch64__
# define __NR_memfd_create 279
# elif defined __s390__
# define __NR_memfd_create 350
# elif defined _MIPS_SIM
# if _MIPS_SIM == _MIPS_SIM_ABI32
# define __NR_memfd_create 4354
# endif
# if _MIPS_SIM == _MIPS_SIM_NABI32
# define __NR_memfd_create 6318
# endif
# if _MIPS_SIM == _MIPS_SIM_ABI64
# define __NR_memfd_create 5314
# endif
# elif defined __i386__
# define __NR_memfd_create 356
# elif defined __arc__
# define __NR_memfd_create 279
# else
# warning "__NR_memfd_create unknown for your architecture"
# endif
# endif
static inline int memfd_create(const char *name, unsigned int flags) {
# ifdef __NR_memfd_create
return syscall(__NR_memfd_create, name, flags);
# else
errno = ENOSYS;
return -1;
# endif
}
#endif
/* Copied from systemd git: /* Copied from systemd git:
commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca
Author: Yu Watanabe <watanabe.yu+github@gmail.com> Author: Yu Watanabe <watanabe.yu+github@gmail.com>

View File

@ -19,7 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>. along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/ ***/
/* Missing glibc definitions to access certain kernel APIs */ /* Missing glibc definitions to access certain kernel APIs.
This file is last updated from systemd git:
commit 71e5200f94b22589922704aa4abdf95d4fe2e528
Author: Daniel Mack <daniel@zonque.org>
AuthorDate: Tue Oct 18 17:57:10 2016 +0200
Commit: Lennart Poettering <lennart@poettering.net>
CommitDate: Fri Sep 22 15:24:54 2017 +0200
Add abstraction model for BPF programs
*/
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@ -29,22 +39,30 @@
#include <uchar.h> #include <uchar.h>
#include <unistd.h> #include <unistd.h>
#if defined(__i386__) || defined(__x86_64__) /* The precise definition of __O_TMPFILE is arch specific; use the
* values defined by the kernel (note: some are hexa, some are octal,
/* The precise definition of __O_TMPFILE is arch specific, so let's * duplicated as-is from the kernel definitions):
* just define this on x86 where we know the value. */ * - alpha, parisc, sparc: each has a specific value;
* - others: they use the "generic" value.
*/
#ifndef __O_TMPFILE #ifndef __O_TMPFILE
#if defined(__alpha__)
#define __O_TMPFILE 0100000000
#elif defined(__parisc__) || defined(__hppa__)
#define __O_TMPFILE 0400000000
#elif defined(__sparc__) || defined(__sparc64__)
#define __O_TMPFILE 0x2000000
#else
#define __O_TMPFILE 020000000 #define __O_TMPFILE 020000000
#endif #endif
#endif
/* a horrid kludge trying to make sure that this will fail on old kernels */ /* a horrid kludge trying to make sure that this will fail on old kernels */
#ifndef O_TMPFILE #ifndef O_TMPFILE
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#endif #endif
#endif
#ifndef RENAME_NOREPLACE #ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0) #define RENAME_NOREPLACE (1 << 0)
#endif #endif
@ -52,4 +70,26 @@
#define RENAME_EXCHANGE (1 << 1) #define RENAME_EXCHANGE (1 << 1)
#endif #endif
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
#endif
#ifndef F_ADD_SEALS
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
#define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif
#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#include "glnx-missing-syscall.h" #include "glnx-missing-syscall.h"

View File

@ -84,14 +84,12 @@ glnx_shutil_rm_rf_at (int dfd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int target_dfd = -1;
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
dfd = glnx_dirfd_canonicalize (dfd); dfd = glnx_dirfd_canonicalize (dfd);
/* With O_NOFOLLOW first */ /* With O_NOFOLLOW first */
target_dfd = openat (dfd, path, glnx_autofd int target_dfd =
O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); openat (dfd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (target_dfd == -1) if (target_dfd == -1)
{ {
@ -110,6 +108,7 @@ glnx_shutil_rm_rf_at (int dfd,
} }
else else
{ {
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
if (!glnx_dirfd_iterator_init_take_fd (&target_dfd, &dfd_iter, error)) if (!glnx_dirfd_iterator_init_take_fd (&target_dfd, &dfd_iter, error))
return FALSE; return FALSE;

View File

@ -25,6 +25,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#include <glnx-macros.h> #include <glnx-macros.h>
#include <glnx-missing.h>
#include <glnx-local-alloc.h> #include <glnx-local-alloc.h>
#include <glnx-backport-autocleanups.h> #include <glnx-backport-autocleanups.h>
#include <glnx-backports.h> #include <glnx-backports.h>

View File

@ -1,8 +1,6 @@
AC_DEFUN([LIBGLNX_CONFIGURE], AC_DEFUN([LIBGLNX_CONFIGURE],
[ [
AC_CHECK_DECLS([ AC_CHECK_DECLS([renameat2, memfd_create],
renameat2,
],
[], [], [[ [], [], [[
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>

View File

@ -32,8 +32,8 @@ static gboolean
renameat_test_setup (int *out_srcfd, int *out_destfd, renameat_test_setup (int *out_srcfd, int *out_destfd,
GError **error) GError **error)
{ {
glnx_fd_close int srcfd = -1; glnx_autofd int srcfd = -1;
glnx_fd_close int destfd = -1; glnx_autofd int destfd = -1;
(void) glnx_shutil_rm_rf_at (AT_FDCWD, "srcdir", NULL, NULL); (void) glnx_shutil_rm_rf_at (AT_FDCWD, "srcdir", NULL, NULL);
if (mkdir ("srcdir", 0755) < 0) if (mkdir ("srcdir", 0755) < 0)
@ -62,8 +62,8 @@ static void
test_renameat2_noreplace (void) test_renameat2_noreplace (void)
{ {
_GLNX_TEST_DECLARE_ERROR(local_error, error); _GLNX_TEST_DECLARE_ERROR(local_error, error);
glnx_fd_close int srcfd = -1; glnx_autofd int srcfd = -1;
glnx_fd_close int destfd = -1; glnx_autofd int destfd = -1;
struct stat stbuf; struct stat stbuf;
if (!renameat_test_setup (&srcfd, &destfd, error)) if (!renameat_test_setup (&srcfd, &destfd, error))
@ -92,8 +92,8 @@ test_renameat2_exchange (void)
{ {
_GLNX_TEST_DECLARE_ERROR(local_error, error); _GLNX_TEST_DECLARE_ERROR(local_error, error);
glnx_fd_close int srcfd = -1; glnx_autofd int srcfd = -1;
glnx_fd_close int destfd = -1; glnx_autofd int destfd = -1;
if (!renameat_test_setup (&srcfd, &destfd, error)) if (!renameat_test_setup (&srcfd, &destfd, error))
return; return;
@ -161,13 +161,22 @@ test_fstatat (void)
return; return;
g_assert_cmpint (errno, ==, ENOENT); g_assert_cmpint (errno, ==, ENOENT);
g_assert_no_error (local_error); g_assert_no_error (local_error);
/* test NULL parameter for stat */
if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", NULL, 0, error))
return;
g_assert_cmpint (errno, ==, 0);
g_assert_no_error (local_error);
if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", NULL, 0, error))
return;
g_assert_cmpint (errno, ==, ENOENT);
g_assert_no_error (local_error);
} }
static void static void
test_filecopy (void) test_filecopy (void)
{ {
_GLNX_TEST_DECLARE_ERROR(local_error, error); _GLNX_TEST_DECLARE_ERROR(local_error, error);
g_auto(GLnxTmpfile) tmpf = { 0, };
const char foo[] = "foo"; const char foo[] = "foo";
struct stat stbuf; struct stat stbuf;

View File

@ -0,0 +1,63 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "libglnx.h"
#include <glib.h>
#include <stdlib.h>
#include <gio/gio.h>
#include <err.h>
#include <string.h>
#include "libglnx-testlib.h"
static void
test_mkdir_p_enoent (void)
{
_GLNX_TEST_DECLARE_ERROR(local_error, error);
glnx_autofd int dfd = -1;
if (!glnx_ensure_dir (AT_FDCWD, "test", 0755, error))
return;
if (!glnx_opendirat (AT_FDCWD, "test", FALSE, &dfd, error))
return;
if (rmdir ("test") < 0)
return (void) glnx_throw_errno_prefix (error, "rmdir(%s)", "test");
/* This should fail with ENOENT. */
glnx_shutil_mkdir_p_at (dfd, "blah/baz", 0755, NULL, error);
g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
g_clear_error (&local_error);
}
int
main (int argc,
char **argv)
{
int ret;
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/mkdir-p/enoent", test_mkdir_p_enoent);
ret = g_test_run();
return ret;
}

View File

@ -82,7 +82,7 @@ do_write_run (GLnxDirFdIterator *dfd_iter, GError **error)
{ {
guint32 randname_v = g_random_int (); guint32 randname_v = g_random_int ();
g_autofree char *randname = g_strdup_printf ("file%u", randname_v); g_autofree char *randname = g_strdup_printf ("file%u", randname_v);
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
again: again:
fd = openat (dfd_iter->fd, randname, O_CREAT | O_EXCL, 0644); fd = openat (dfd_iter->fd, randname, O_CREAT | O_EXCL, 0644);
@ -113,7 +113,7 @@ do_write_run (GLnxDirFdIterator *dfd_iter, GError **error)
if (!dent) if (!dent)
break; break;
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error))
return FALSE; return FALSE;
@ -157,7 +157,7 @@ do_read_run (GLnxDirFdIterator *dfd_iter,
if (!dent) if (!dent)
break; break;
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error))
return FALSE; return FALSE;

View File

@ -61,6 +61,19 @@ Boston, MA 02111-1307, USA.
</para> </para>
</refsect1> </refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--ignore-xattrs</option></term>
<listitem><para>
Ignore extended attributes when checksumming.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>Example</title> <title>Example</title>
<para><command>$ ostree checksum file1</command></para> <para><command>$ ostree checksum file1</command></para>

View File

@ -167,6 +167,17 @@ Boston, MA 02111-1307, USA.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--consume</option></term>
<listitem><para>
When committing from a local directory (i.e. not an archive or --tree=ref),
assume ownership of the content. This may simply involve deleting it,
but if possible, the content may simply be <literal>rename()</literal>ed
into the repository rather than creating a new copy.
</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--statoverride</option>="PATH"</term> <term><option>--statoverride</option>="PATH"</term>

View File

@ -18,8 +18,8 @@
***/ ***/
/* Add new symbols here. Release commits should copy this section into -released.sym. */ /* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2017.13 { LIBOSTREE_2017.14 {
} LIBOSTREE_2017.12; } LIBOSTREE_2017.13;
/* Stub section for the stable release *after* this development one; don't /* Stub section for the stable release *after* this development one; don't
* edit this other than to update the last number. This is just a copy/paste * edit this other than to update the last number. This is just a copy/paste

View File

@ -82,3 +82,10 @@ LIBOSTREE_2017.12_EXPERIMENTAL {
global: global:
ostree_repo_resolve_collection_ref; ostree_repo_resolve_collection_ref;
} LIBOSTREE_2017.8_EXPERIMENTAL; } LIBOSTREE_2017.8_EXPERIMENTAL;
LIBOSTREE_2017.13_EXPERIMENTAL {
global:
ostree_repo_finder_override_add_uri;
ostree_repo_finder_override_get_type;
ostree_repo_finder_override_new;
} LIBOSTREE_2017.12_EXPERIMENTAL;

View File

@ -436,6 +436,12 @@ global:
ostree_repo_hash; ostree_repo_hash;
} LIBOSTREE_2017.11; } LIBOSTREE_2017.11;
LIBOSTREE_2017.13 {
global:
ostree_checksum_file_at;
ostree_repo_checkout_at_options_set_devino;
} LIBOSTREE_2017.12;
/* NOTE: Only add more content here in release commits! See the /* NOTE: Only add more content here in release commits! See the
* comments at the top of this file. * comments at the top of this file.
*/ */

View File

@ -66,6 +66,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinder, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderAvahi, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderAvahi, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderConfig, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderConfig, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderMount, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderMount, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderOverride, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, ostree_repo_finder_result_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, ostree_repo_finder_result_free)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, ostree_repo_finder_result_freev, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, ostree_repo_finder_result_freev, NULL)
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */

View File

@ -76,7 +76,7 @@
struct _OstreeBloom struct _OstreeBloom
{ {
guint ref_count; guint ref_count;
gsize n_bytes; gsize n_bytes; /* 0 < n_bytes <= G_MAXSIZE / 8 */
gboolean is_mutable; /* determines which of [im]mutable_bytes is accessed */ gboolean is_mutable; /* determines which of [im]mutable_bytes is accessed */
union union
{ {
@ -117,6 +117,7 @@ ostree_bloom_new (gsize n_bytes,
g_autoptr(OstreeBloom) bloom = NULL; g_autoptr(OstreeBloom) bloom = NULL;
g_return_val_if_fail (n_bytes > 0, NULL); g_return_val_if_fail (n_bytes > 0, NULL);
g_return_val_if_fail (n_bytes <= G_MAXSIZE / 8, NULL);
g_return_val_if_fail (k > 0, NULL); g_return_val_if_fail (k > 0, NULL);
g_return_val_if_fail (hash_func != NULL, NULL); g_return_val_if_fail (hash_func != NULL, NULL);
@ -159,6 +160,7 @@ ostree_bloom_new_from_bytes (GBytes *bytes,
g_return_val_if_fail (bytes != NULL, NULL); g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (g_bytes_get_size (bytes) > 0, NULL); g_return_val_if_fail (g_bytes_get_size (bytes) > 0, NULL);
g_return_val_if_fail (g_bytes_get_size (bytes) <= G_MAXSIZE / 8, NULL);
g_return_val_if_fail (k > 0, NULL); g_return_val_if_fail (k > 0, NULL);
g_return_val_if_fail (hash_func != NULL, NULL); g_return_val_if_fail (hash_func != NULL, NULL);

View File

@ -416,7 +416,7 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
} }
/* Now let's fdatasync() for the new file */ /* Now let's fdatasync() for the new file */
{ glnx_fd_close int new_config_fd = -1; { glnx_autofd int new_config_fd = -1;
if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error)) if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error))
return FALSE; return FALSE;

View File

@ -25,12 +25,13 @@
#include <string.h> #include <string.h>
static const char syslinux_config_path[] = "boot/syslinux/syslinux.cfg";
struct _OstreeBootloaderSyslinux struct _OstreeBootloaderSyslinux
{ {
GObject parent_instance; GObject parent_instance;
OstreeSysroot *sysroot; OstreeSysroot *sysroot;
GFile *config_path;
}; };
typedef GObjectClass OstreeBootloaderSyslinuxClass; typedef GObjectClass OstreeBootloaderSyslinuxClass;
@ -46,8 +47,11 @@ _ostree_bootloader_syslinux_query (OstreeBootloader *bootloader,
GError **error) GError **error)
{ {
OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader);
struct stat stbuf;
*out_is_active = g_file_query_file_type (self->config_path, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_SYMBOLIC_LINK; if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, syslinux_config_path, &stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE;
*out_is_active = (errno == 0);
return TRUE; return TRUE;
} }
@ -107,12 +111,12 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
{ {
OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader);
g_autoptr(GFile) new_config_path = g_autofree char *new_config_path =
ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", bootversion); g_strdup_printf ("boot/loader.%d/syslinux.cfg", bootversion);
/* This should follow the symbolic link to the current bootversion. */ /* This should follow the symbolic link to the current bootversion. */
g_autofree char *config_contents = g_autofree char *config_contents =
glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, glnx_file_get_contents_utf8_at (self->sysroot->sysroot_fd, syslinux_config_path, NULL,
cancellable, error); cancellable, error);
if (!config_contents) if (!config_contents)
return FALSE; return FALSE;
@ -206,11 +210,9 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
return FALSE; return FALSE;
g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines); g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines);
g_autoptr(GBytes) new_config_contents_bytes = if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path,
g_bytes_new_static (new_config_contents, (guint8*)new_config_contents, strlen (new_config_contents),
strlen (new_config_contents)); GLNX_FILE_REPLACE_DATASYNC_NEW,
if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
@ -223,7 +225,6 @@ _ostree_bootloader_syslinux_finalize (GObject *object)
OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (object); OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (object);
g_clear_object (&self->sysroot); g_clear_object (&self->sysroot);
g_clear_object (&self->config_path);
G_OBJECT_CLASS (_ostree_bootloader_syslinux_parent_class)->finalize (object); G_OBJECT_CLASS (_ostree_bootloader_syslinux_parent_class)->finalize (object);
} }
@ -254,6 +255,5 @@ _ostree_bootloader_syslinux_new (OstreeSysroot *sysroot)
{ {
OstreeBootloaderSyslinux *self = g_object_new (OSTREE_TYPE_BOOTLOADER_SYSLINUX, NULL); OstreeBootloaderSyslinux *self = g_object_new (OSTREE_TYPE_BOOTLOADER_SYSLINUX, NULL);
self->sysroot = g_object_ref (sysroot); self->sysroot = g_object_ref (sysroot);
self->config_path = g_file_resolve_relative_path (self->sysroot->path, "boot/syslinux/syslinux.cfg");
return self; return self;
} }

View File

@ -29,12 +29,13 @@
#include <string.h> #include <string.h>
static const char uboot_config_path[] = "boot/loader/uEnv.txt";
struct _OstreeBootloaderUboot struct _OstreeBootloaderUboot
{ {
GObject parent_instance; GObject parent_instance;
OstreeSysroot *sysroot; OstreeSysroot *sysroot;
GFile *config_path;
}; };
typedef GObjectClass OstreeBootloaderUbootClass; typedef GObjectClass OstreeBootloaderUbootClass;
@ -50,8 +51,11 @@ _ostree_bootloader_uboot_query (OstreeBootloader *bootloader,
GError **error) GError **error)
{ {
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader); OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader);
struct stat stbuf;
*out_is_active = g_file_query_file_type (self->config_path, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_REGULAR; if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, uboot_config_path, &stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE;
*out_is_active = (errno == 0);
return TRUE; return TRUE;
} }
@ -69,8 +73,8 @@ append_system_uenv (OstreeBootloaderUboot *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int uenv_fd = -1; glnx_autofd int uenv_fd = -1;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; g_autoptr(OstreeKernelArgs) kargs = NULL;
const char *uenv_path = NULL; const char *uenv_path = NULL;
const char *ostree_arg = NULL; const char *ostree_arg = NULL;
@ -156,36 +160,26 @@ _ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader,
GError **error) GError **error)
{ {
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader); OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader);
g_autoptr(GFile) new_config_path = NULL;
g_autofree char *config_contents = NULL;
g_autofree char *new_config_contents = NULL;
g_autoptr(GPtrArray) new_lines = NULL;
/* This should follow the symbolic link to the current bootversion. */ /* This should follow the symbolic link to the current bootversion. */
config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, g_autofree char *config_contents =
glnx_file_get_contents_utf8_at (self->sysroot->sysroot_fd, uboot_config_path, NULL,
cancellable, error); cancellable, error);
if (!config_contents) if (!config_contents)
return FALSE; return FALSE;
new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/uEnv.txt", g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free);
bootversion);
new_lines = g_ptr_array_new_with_free_func (g_free);
if (!create_config_from_boot_loader_entries (self, bootversion, new_lines, if (!create_config_from_boot_loader_entries (self, bootversion, new_lines,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
new_config_contents = _ostree_sysroot_join_lines (new_lines); g_autofree char *new_config_path = g_strdup_printf ("boot/loader.%d/uEnv.txt", bootversion);
{ g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines);
g_autoptr(GBytes) new_config_contents_bytes = if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path,
g_bytes_new_static (new_config_contents, (guint8*)new_config_contents, strlen (new_config_contents),
strlen (new_config_contents)); GLNX_FILE_REPLACE_DATASYNC_NEW,
if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
}
return TRUE; return TRUE;
} }
@ -196,7 +190,6 @@ _ostree_bootloader_uboot_finalize (GObject *object)
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (object); OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (object);
g_clear_object (&self->sysroot); g_clear_object (&self->sysroot);
g_clear_object (&self->config_path);
G_OBJECT_CLASS (_ostree_bootloader_uboot_parent_class)->finalize (object); G_OBJECT_CLASS (_ostree_bootloader_uboot_parent_class)->finalize (object);
} }
@ -227,6 +220,5 @@ _ostree_bootloader_uboot_new (OstreeSysroot *sysroot)
{ {
OstreeBootloaderUboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_UBOOT, NULL); OstreeBootloaderUboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_UBOOT, NULL);
self->sysroot = g_object_ref (sysroot); self->sysroot = g_object_ref (sysroot);
self->config_path = g_file_resolve_relative_path (self->sysroot->path, "boot/loader/uEnv.txt");
return self; return self;
} }

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "ostree-core.h" #include "ostree-core.h"
#include "otutil.h"
#include <sys/stat.h> #include <sys/stat.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -67,20 +68,12 @@ G_BEGIN_DECLS
#define _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT G_VARIANT_TYPE ("(tuuuusa(ayay))") #define _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT G_VARIANT_TYPE ("(tuuuusa(ayay))")
GVariant *_ostree_file_header_new (GFileInfo *file_info, GBytes *_ostree_file_header_new (GFileInfo *file_info,
GVariant *xattrs); GVariant *xattrs);
GVariant *_ostree_zlib_file_header_new (GFileInfo *file_info, GBytes *_ostree_zlib_file_header_new (GFileInfo *file_info,
GVariant *xattrs); GVariant *xattrs);
gboolean _ostree_write_variant_with_size (GOutputStream *output,
GVariant *variant,
guint64 alignment_offset,
gsize *out_bytes_written,
GChecksum *checksum,
GCancellable *cancellable,
GError **error);
gboolean gboolean
_ostree_make_temporary_symlink_at (int tmp_dirfd, _ostree_make_temporary_symlink_at (int tmp_dirfd,
const char *target, const char *target,
@ -90,6 +83,7 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
GFileInfo * _ostree_stbuf_to_gfileinfo (const struct stat *stbuf); GFileInfo * _ostree_stbuf_to_gfileinfo (const struct stat *stbuf);
gboolean _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b); gboolean _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b);
gboolean _ostree_stbuf_equal (struct stat *stbuf_a, struct stat *stbuf_b);
GFileInfo * _ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid); GFileInfo * _ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid);
static inline void static inline void
@ -134,6 +128,11 @@ static inline char * _ostree_get_commitpartial_path (const char *checksum)
return g_strconcat ("state/", checksum, ".commitpartial", NULL); return g_strconcat ("state/", checksum, ".commitpartial", NULL);
} }
gboolean
_ostree_validate_ref_fragment (const char *fragment,
GError **error);
gboolean gboolean
_ostree_validate_bareuseronly_mode (guint32 mode, _ostree_validate_bareuseronly_mode (guint32 mode,
const char *checksum, const char *checksum,
@ -147,6 +146,12 @@ _ostree_validate_bareuseronly_mode_finfo (GFileInfo *finfo,
return _ostree_validate_bareuseronly_mode (content_mode, checksum, error); return _ostree_validate_bareuseronly_mode (content_mode, checksum, error);
} }
gboolean
_ostree_compare_object_checksum (OstreeObjectType objtype,
const char *expected,
const char *actual,
GError **error);
gboolean gboolean
_ostree_parse_delta_name (const char *delta_name, _ostree_parse_delta_name (const char *delta_name,
char **out_from, char **out_from,
@ -218,6 +223,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderConfig, g_object_unref)
#include "ostree-repo-finder-mount.h" #include "ostree-repo-finder-mount.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderMount, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderMount, g_object_unref)
#include "ostree-repo-finder-override.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderOverride, g_object_unref)
#endif #endif
G_END_DECLS G_END_DECLS

View File

@ -39,6 +39,8 @@ G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2); G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3); G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3);
static GBytes *variant_to_lenprefixed_buffer (GVariant *variant);
#define ALIGN_VALUE(this, boundary) \ #define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
@ -140,7 +142,10 @@ ostree_validate_checksum_string (const char *sha256,
return ostree_validate_structureof_checksum_string (sha256, error); return ostree_validate_structureof_checksum_string (sha256, error);
} }
#define OSTREE_REF_FRAGMENT_REGEXP "[-._\\w\\d]+" /* This used to allow leading - and ., but was changed in
* https://github.com/ostreedev/ostree/pull/1286
*/
#define OSTREE_REF_FRAGMENT_REGEXP "[\\w\\d][-._\\w\\d]*"
#define OSTREE_REF_REGEXP "(?:" OSTREE_REF_FRAGMENT_REGEXP "/)*" OSTREE_REF_FRAGMENT_REGEXP #define OSTREE_REF_REGEXP "(?:" OSTREE_REF_FRAGMENT_REGEXP "/)*" OSTREE_REF_FRAGMENT_REGEXP
#define OSTREE_REMOTE_NAME_REGEXP OSTREE_REF_FRAGMENT_REGEXP #define OSTREE_REMOTE_NAME_REGEXP OSTREE_REF_FRAGMENT_REGEXP
@ -194,6 +199,26 @@ ostree_parse_refspec (const char *refspec,
return TRUE; return TRUE;
} }
gboolean
_ostree_validate_ref_fragment (const char *fragment,
GError **error)
{
static GRegex *regex;
static gsize regex_initialized;
if (g_once_init_enter (&regex_initialized))
{
regex = g_regex_new ("^" OSTREE_REF_FRAGMENT_REGEXP "$", 0, 0, NULL);
g_assert (regex);
g_once_init_leave (&regex_initialized, 1);
}
g_autoptr(GMatchInfo) match = NULL;
if (!g_regex_match (regex, fragment, 0, &match))
return glnx_throw (error, "Invalid ref fragment '%s'", fragment);
return TRUE;
}
/** /**
* ostree_validate_rev: * ostree_validate_rev:
* @rev: A revision string * @rev: A revision string
@ -283,192 +308,103 @@ ostree_validate_collection_id (const char *collection_id, GError **error)
return TRUE; return TRUE;
} }
GVariant * /* The file header is part of the "object stream" format
* that's not compressed. It's comprised of uid,gid,mode,
* and possibly symlink targets from @file_info, as well
* as @xattrs (which if NULL, is taken to be the empty set).
*/
GBytes *
_ostree_file_header_new (GFileInfo *file_info, _ostree_file_header_new (GFileInfo *file_info,
GVariant *xattrs) GVariant *xattrs)
{ {
guint32 uid;
guint32 gid; guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
guint32 mode; guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid");
guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
const char *symlink_target; const char *symlink_target;
GVariant *ret;
g_autoptr(GVariant) tmp_xattrs = NULL;
uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid");
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK)
symlink_target = g_file_info_get_symlink_target (file_info); symlink_target = g_file_info_get_symlink_target (file_info);
else else
symlink_target = ""; symlink_target = "";
g_autoptr(GVariant) tmp_xattrs = NULL;
if (xattrs == NULL) if (xattrs == NULL)
tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
ret = g_variant_new ("(uuuus@a(ayay))", GUINT32_TO_BE (uid), g_autoptr(GVariant) ret = g_variant_new ("(uuuus@a(ayay))", GUINT32_TO_BE (uid),
GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0, GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0,
symlink_target, xattrs ? xattrs : tmp_xattrs); symlink_target, xattrs ?: tmp_xattrs);
g_variant_ref_sink (ret); return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret));
return ret;
} }
/* /* Like _ostree_file_header_new(), but used for the compressed format in archive
* ostree_zlib_file_header_new: * repositories. This format hence lives on disk; normally the uncompressed
* @file_info: a #GFileInfo * stream format doesn't. Instead for "bare" repositories, the file data is
* @xattrs: (allow-none): Optional extended attribute array * stored directly, or for the special case of bare-user repositories, as a
* * user.ostreemeta xattr.
* Returns: (transfer full): A new #GVariant containing file header for an archive repository
*/ */
GVariant * GBytes *
_ostree_zlib_file_header_new (GFileInfo *file_info, _ostree_zlib_file_header_new (GFileInfo *file_info,
GVariant *xattrs) GVariant *xattrs)
{ {
guint64 size; guint64 size = g_file_info_get_size (file_info);
guint32 uid; guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
guint32 gid; guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid");
guint32 mode; guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
const char *symlink_target; const char *symlink_target;
GVariant *ret;
g_autoptr(GVariant) tmp_xattrs = NULL;
size = g_file_info_get_size (file_info);
uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid");
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK)
symlink_target = g_file_info_get_symlink_target (file_info); symlink_target = g_file_info_get_symlink_target (file_info);
else else
symlink_target = ""; symlink_target = "";
g_autoptr(GVariant) tmp_xattrs = NULL;
if (xattrs == NULL) if (xattrs == NULL)
tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
ret = g_variant_new ("(tuuuus@a(ayay))", g_autoptr(GVariant) ret = g_variant_new ("(tuuuus@a(ayay))",
GUINT64_TO_BE (size), GUINT32_TO_BE (uid), GUINT64_TO_BE (size), GUINT32_TO_BE (uid),
GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0, GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0,
symlink_target, xattrs ? xattrs : tmp_xattrs); symlink_target, xattrs ?: tmp_xattrs);
g_variant_ref_sink (ret); return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret));
return ret;
} }
static gboolean /* Serialize a variant to a buffer prefixed with its length. The variant will
write_padding (GOutputStream *output, * have an 8-byte alignment so it can be safely used with `mmap()`.
guint alignment, */
gsize offset, static GBytes *
gsize *out_bytes_written, variant_to_lenprefixed_buffer (GVariant *variant)
GChecksum *checksum,
GCancellable *cancellable,
GError **error)
{ {
guint bits; /* This string is really a binary memory buffer */
guint padding_len; g_autoptr(GString) buf = g_string_new (NULL);
guchar padding_nuls[8] = {0, 0, 0, 0, 0, 0, 0, 0}; /* Write variant size */
const guint64 variant_size = g_variant_get_size (variant);
g_assert (variant_size < G_MAXUINT32);
const guint32 variant_size_u32_be = GUINT32_TO_BE((guint32) variant_size);
g_string_append_len (buf, (char*)&variant_size_u32_be, sizeof (variant_size_u32_be));
const gsize alignment_offset = sizeof (variant_size_u32_be);
/* Write NULs for alignment. At the moment this is a constant 4 bytes (i.e.
* align to 8, since the length is 4 bytes). For now, I decided to keep some
* of the (now legacy) more generic logic here in case we want to revive it
* later.
*/
const guint alignment = 8;
const guchar padding_nuls[8] = {0, 0, 0, 0, 0, 0, 0, 0};
guint bits;
if (alignment == 8) if (alignment == 8)
bits = ((offset) & 7); bits = alignment_offset & 7; /* mod 8 */
else else
bits = ((offset) & 3); bits = alignment_offset & 3; /* mod 4 */
const guint padding_len = alignment - bits;
if (bits > 0) if (bits > 0)
{ g_string_append_len (buf, (char*)padding_nuls, padding_len);
padding_len = alignment - bits;
if (!ot_gio_write_update_checksum (output, (guchar*)padding_nuls, padding_len,
out_bytes_written, checksum,
cancellable, error))
return FALSE;
}
return TRUE; g_string_append_len (buf, (char*)g_variant_get_data (variant), g_variant_get_size (variant));
} return g_string_free_to_bytes (g_steal_pointer (&buf));
/*
* _ostree_write_variant_with_size:
* @output: Stream
* @variant: A variant
* @alignment_offset: Used to determine whether or not we should write padding bytes
* @out_bytes_written: (out): Number of bytes written
* @checksum: (allow-none): If provided, update with written data
* @cancellable: Cancellable
* @error: Error
*
* Use this function for serializing a chain of 1 or more variants
* into a stream; the @alignment_offset parameter is used to ensure
* that each variant begins on an 8-byte alignment so it can be safely
* accessed.
*/
gboolean
_ostree_write_variant_with_size (GOutputStream *output,
GVariant *variant,
guint64 alignment_offset,
gsize *out_bytes_written,
GChecksum *checksum,
GCancellable *cancellable,
GError **error)
{
guint64 variant_size;
guint32 variant_size_u32_be;
gsize bytes_written;
gsize ret_bytes_written = 0;
/* Write variant size */
variant_size = g_variant_get_size (variant);
g_assert (variant_size < G_MAXUINT32);
variant_size_u32_be = GUINT32_TO_BE((guint32) variant_size);
bytes_written = 0;
if (!ot_gio_write_update_checksum (output, &variant_size_u32_be, 4,
&bytes_written, checksum,
cancellable, error))
return FALSE;
ret_bytes_written += bytes_written;
alignment_offset += bytes_written;
bytes_written = 0;
/* Pad to offset of 8, write variant */
if (!write_padding (output, 8, alignment_offset, &bytes_written, checksum,
cancellable, error))
return FALSE;
ret_bytes_written += bytes_written;
bytes_written = 0;
if (!ot_gio_write_update_checksum (output, g_variant_get_data (variant),
variant_size, &bytes_written, checksum,
cancellable, error))
return FALSE;
ret_bytes_written += bytes_written;
if (out_bytes_written)
*out_bytes_written = ret_bytes_written;
return TRUE;
}
/*
* write_file_header_update_checksum:
* @out: Stream
* @variant: A variant, should be a file header
* @checksum: (allow-none): If provided, update with written data
* @cancellable: Cancellable
* @error: Error
*
* Write a file header variant to the provided @out stream, optionally
* updating @checksum.
*/
static gboolean
write_file_header_update_checksum (GOutputStream *out,
GVariant *header,
GChecksum *checksum,
GCancellable *cancellable,
GError **error)
{
gsize bytes_written;
if (!_ostree_write_variant_with_size (out, header, 0, &bytes_written, checksum,
cancellable, error))
return FALSE;
return TRUE;
} }
/* /*
@ -476,54 +412,38 @@ write_file_header_update_checksum (GOutputStream *out,
* @file_header: A file header * @file_header: A file header
* @input: File raw content stream * @input: File raw content stream
* @out_input: (out): Serialized object stream * @out_input: (out): Serialized object stream
* @out_header_size: (out): Length of the header
* @cancellable: Cancellable * @cancellable: Cancellable
* @error: Error * @error: Error
* *
* Combines @file_header and @input into a single stream. * Combines @file_header and @input into a single stream.
*/ */
static gboolean static gboolean
header_and_input_to_stream (GVariant *file_header, header_and_input_to_stream (GBytes *file_header,
GInputStream *input, GInputStream *input,
GInputStream **out_input, GInputStream **out_input,
guint64 *out_header_size,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gpointer header_data; /* Our result stream chain */
gsize header_size; g_autoptr(GPtrArray) streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
g_autoptr(GInputStream) ret_input = NULL;
g_autoptr(GPtrArray) streams = NULL;
g_autoptr(GOutputStream) header_out_stream = NULL;
g_autoptr(GInputStream) header_in_stream = NULL;
header_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); /* Append the header to the chain */
g_autoptr(GInputStream) header_in_stream = g_memory_input_stream_new_from_bytes (file_header);
if (!_ostree_write_variant_with_size (header_out_stream, file_header, 0, NULL, NULL,
cancellable, error))
return FALSE;
if (!g_output_stream_close (header_out_stream, cancellable, error))
return FALSE;
header_size = g_memory_output_stream_get_data_size ((GMemoryOutputStream*) header_out_stream);
header_data = g_memory_output_stream_steal_data ((GMemoryOutputStream*) header_out_stream);
header_in_stream = g_memory_input_stream_new_from_data (header_data, header_size, g_free);
streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
g_ptr_array_add (streams, g_object_ref (header_in_stream)); g_ptr_array_add (streams, g_object_ref (header_in_stream));
/* And if we have an input stream, append that */
if (input) if (input)
g_ptr_array_add (streams, g_object_ref (input)); g_ptr_array_add (streams, g_object_ref (input));
ret_input = (GInputStream*)ostree_chain_input_stream_new (streams); /* Return the result stream */
g_autoptr(GInputStream) ret_input = (GInputStream*)ostree_chain_input_stream_new (streams);
ot_transfer_out_value (out_input, &ret_input); ot_transfer_out_value (out_input, &ret_input);
if (out_header_size)
*out_header_size = header_size;
return TRUE; return TRUE;
} }
/* Convert file metadata + file content into an archive-format stream. */
gboolean gboolean
_ostree_raw_file_to_archive_stream (GInputStream *input, _ostree_raw_file_to_archive_stream (GInputStream *input,
GFileInfo *file_info, GFileInfo *file_info,
@ -533,21 +453,17 @@ _ostree_raw_file_to_archive_stream (GInputStream *input,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autoptr(GVariant) file_header = NULL;
g_autoptr(GInputStream) zlib_input = NULL; g_autoptr(GInputStream) zlib_input = NULL;
file_header = _ostree_zlib_file_header_new (file_info, xattrs);
if (input != NULL) if (input != NULL)
{ {
g_autoptr(GConverter) zlib_compressor = NULL; g_autoptr(GConverter) zlib_compressor =
G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, compression_level));
zlib_compressor = G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, compression_level));
zlib_input = g_converter_input_stream_new (input, zlib_compressor); zlib_input = g_converter_input_stream_new (input, zlib_compressor);
} }
g_autoptr(GBytes) file_header = _ostree_zlib_file_header_new (file_info, xattrs);
return header_and_input_to_stream (file_header, return header_and_input_to_stream (file_header,
zlib_input, zlib_input,
out_input, out_input,
NULL,
cancellable, cancellable,
error); error);
} }
@ -640,19 +556,15 @@ ostree_raw_file_to_content_stream (GInputStream *input,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autoptr(GVariant) file_header = NULL; g_autoptr(GBytes) file_header = _ostree_file_header_new (file_info, xattrs);
guint64 header_size;
file_header = _ostree_file_header_new (file_info, xattrs);
if (!header_and_input_to_stream (file_header, if (!header_and_input_to_stream (file_header,
input, input,
out_input, out_input,
&header_size,
cancellable, cancellable,
error)) error))
return FALSE; return FALSE;
if (out_length) if (out_length)
*out_length = header_size + g_file_info_get_size (file_info); *out_length = g_bytes_get_size (file_header) + g_file_info_get_size (file_info);
return TRUE; return TRUE;
} }
@ -781,7 +693,7 @@ ostree_content_file_parse_at (gboolean compressed,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (parent_dfd, path, TRUE, &fd, error)) if (!glnx_openat_rdonly (parent_dfd, path, TRUE, &fd, error))
return FALSE; return FALSE;
@ -859,37 +771,35 @@ ostree_checksum_file_from_input (GFileInfo *file_info,
GError **error) GError **error)
{ {
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); g_auto(OtChecksum) checksum = { 0, };
ot_checksum_init (&checksum);
if (OSTREE_OBJECT_TYPE_IS_META (objtype)) if (OSTREE_OBJECT_TYPE_IS_META (objtype))
{ {
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE; return FALSE;
} }
else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
{ {
g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs); g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs);
g_checksum_update (checksum, g_variant_get_data (dirmeta), ot_checksum_update (&checksum, g_variant_get_data (dirmeta),
g_variant_get_size (dirmeta)); g_variant_get_size (dirmeta));
} }
else else
{ {
g_autoptr(GVariant) file_header = NULL; g_autoptr(GBytes) file_header = _ostree_file_header_new (file_info, xattrs);
file_header = _ostree_file_header_new (file_info, xattrs); ot_checksum_update_bytes (&checksum, file_header);
if (!write_file_header_update_checksum (NULL, file_header, checksum,
cancellable, error))
return FALSE;
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
{ {
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE; return FALSE;
} }
} }
*out_csum = ot_csum_from_gchecksum (checksum); *out_csum = g_malloc (OSTREE_SHA256_DIGEST_LEN);
ot_checksum_get_digest (&checksum, *out_csum, OSTREE_SHA256_DIGEST_LEN);
return TRUE; return TRUE;
} }
@ -945,6 +855,81 @@ ostree_checksum_file (GFile *f,
return TRUE; return TRUE;
} }
/**
* ostree_checksum_file_at:
* @dfd: Directory file descriptor
* @path: Subpath
* @stbuf (allow-none): Optional stat buffer
* @objtype: Object type
* @flags: Flags
* @out_checksum (out) (transfer full): Return location for hex checksum
* @cancellable: Cancellable
* @error: Error
*
* Compute the OSTree checksum for a given file. This is an fd-relative version
* of ostree_checksum_file() which also takes flags and fills in a caller
* allocated buffer.
*
* Since: 2017.13
*/
gboolean
ostree_checksum_file_at (int dfd,
const char *path,
struct stat *stbuf,
OstreeObjectType objtype,
OstreeChecksumFlags flags,
char **out_checksum,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (out_checksum != NULL, FALSE);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
struct stat local_stbuf;
if (stbuf == NULL)
{
stbuf = &local_stbuf;
if (!glnx_fstatat (dfd, path, stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE;
}
g_autoptr(GFileInfo) file_info = _ostree_stbuf_to_gfileinfo (stbuf);
g_autoptr(GInputStream) in = NULL;
if (S_ISREG (stbuf->st_mode))
{
glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd, path, FALSE, &fd, error))
return FALSE;
in = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE);
}
else if (S_ISLNK (stbuf->st_mode))
{
if (!ot_readlinkat_gfile_info (dfd, path, file_info, cancellable, error))
return FALSE;
}
const gboolean ignore_xattrs =
((flags & OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS) > 0);
g_autoptr(GVariant) xattrs = NULL;
if (!ignore_xattrs && objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (!glnx_dfd_name_get_all_xattrs (dfd, path, &xattrs, cancellable, error))
return FALSE;
}
g_autofree guchar *csum_bytes = NULL;
if (!ostree_checksum_file_from_input (file_info, xattrs, in, objtype,
&csum_bytes, cancellable, error))
return FALSE;
*out_checksum = ostree_checksum_from_bytes (csum_bytes);
return TRUE;
}
typedef struct { typedef struct {
GFile *f; GFile *f;
OstreeObjectType objtype; OstreeObjectType objtype;
@ -1042,6 +1027,22 @@ ostree_checksum_file_async_finish (GFile *f,
return TRUE; return TRUE;
} }
/* Common helper to compare checksums for an object, so we have a consistent
* error message.
*/
gboolean
_ostree_compare_object_checksum (OstreeObjectType objtype,
const char *expected,
const char *actual,
GError **error)
{
if (!g_str_equal (expected, actual))
return glnx_throw (error, "Corrupted %s object; checksum expected='%s' actual='%s'",
ostree_object_type_to_string (objtype),
expected, actual);
return TRUE;
}
/** /**
* ostree_create_directory_metadata: * ostree_create_directory_metadata:
* @dir_info: a #GFileInfo containing directory information * @dir_info: a #GFileInfo containing directory information
@ -1614,10 +1615,31 @@ _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b)
return TRUE; return TRUE;
} }
/* Same motives as _ostree_gfileinfo_equal(), but for stat structs. */
gboolean
_ostree_stbuf_equal (struct stat *stbuf_a, struct stat *stbuf_b)
{
/* trivial case */
if (stbuf_a == stbuf_b)
return TRUE;
if (stbuf_a->st_mode != stbuf_b->st_mode)
return FALSE;
if (S_ISREG (stbuf_a->st_mode) && (stbuf_a->st_size != stbuf_b->st_size))
return FALSE;
if (stbuf_a->st_uid != stbuf_b->st_uid)
return FALSE;
if (stbuf_a->st_gid != stbuf_b->st_gid)
return FALSE;
return TRUE;
}
/* Many parts of libostree only care about mode,uid,gid - this creates
* a new GFileInfo with those fields see.
*/
GFileInfo * GFileInfo *
_ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid) _ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid)
{ {
struct stat stbuf; struct stat stbuf = { 0, };
stbuf.st_mode = mode; stbuf.st_mode = mode;
stbuf.st_uid = uid; stbuf.st_uid = uid;
stbuf.st_gid = gid; stbuf.st_gid = gid;

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <sys/stat.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <ostree-types.h> #include <ostree-types.h>
@ -227,6 +228,23 @@ typedef enum {
* Since: 2017.7 * Since: 2017.7
*/ */
#define OSTREE_COMMIT_META_KEY_ENDOFLIFE "ostree.endoflife" #define OSTREE_COMMIT_META_KEY_ENDOFLIFE "ostree.endoflife"
/**
* OSTREE_COMMIT_META_KEY_SOURCE_TITLE:
*
* GVariant type `s`. This should hold a relatively short single line value
* containing a human-readable "source" for a commit, intended to be displayed
* near the origin ref. This is particularly useful for systems that inject
* content into an OSTree commit from elsewhere - for example, generating from
* an OCI or qcow2 image. Or if generating from packages, the enabled repository
* names and their versions.
*
* Try to keep this key short (e.g. < 80 characters) and human-readable; if you
* desire machine readable data, consider injecting separate metadata keys.
*
* Since: 2017.13
*/
#define OSTREE_COMMIT_META_KEY_SOURCE_TITLE "ostree.source-title"
/** /**
* OSTREE_COMMIT_META_KEY_REF_BINDING: * OSTREE_COMMIT_META_KEY_REF_BINDING:
* *
@ -420,6 +438,26 @@ gboolean ostree_checksum_file (GFile *f,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
/**
* OstreeChecksumFlags:
*
* Since: 2017.13
*/
typedef enum {
OSTREE_CHECKSUM_FLAGS_NONE = 0,
OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS = (1 << 0),
} OstreeChecksumFlags;
_OSTREE_PUBLIC
gboolean ostree_checksum_file_at (int dfd,
const char *path,
struct stat *stbuf,
OstreeObjectType objtype,
OstreeChecksumFlags flags,
char **out_checksum,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC _OSTREE_PUBLIC
void ostree_checksum_file_async (GFile *f, void ostree_checksum_file_async (GFile *f,
OstreeObjectType objtype, OstreeObjectType objtype,

View File

@ -269,13 +269,13 @@ ensure_tmpfile (FetcherRequest *req, GError **error)
{ {
if (!req->tmpf.initialized) if (!req->tmpf.initialized)
{ {
if (!glnx_open_tmpfile_linkable_at (req->fetcher->tmpdir_dfd, ".", if (!_ostree_fetcher_tmpf_from_flags (req->flags, req->fetcher->tmpdir_dfd,
O_WRONLY | O_CLOEXEC, &req->tmpf, &req->tmpf, error))
error))
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
/* Check for completed transfers, and remove their easy handles */ /* Check for completed transfers, and remove their easy handles */
static void static void
check_multi_info (OstreeFetcher *fetcher) check_multi_info (OstreeFetcher *fetcher)
@ -378,25 +378,19 @@ check_multi_info (OstreeFetcher *fetcher)
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
GError **error = &local_error; GError **error = &local_error;
g_autofree char *tmpfile_path =
ostree_fetcher_generate_url_tmpname (eff_url);
if (!ensure_tmpfile (req, error)) if (!ensure_tmpfile (req, error))
{ {
g_task_return_error (task, g_steal_pointer (&local_error)); g_task_return_error (task, g_steal_pointer (&local_error));
} }
/* This should match the libsoup chmod */ else if (lseek (req->tmpf.fd, 0, SEEK_SET) < 0)
else if (fchmod (req->tmpf.fd, 0644) < 0)
{ {
glnx_set_error_from_errno (error); glnx_set_error_from_errno (error);
g_task_return_error (task, g_steal_pointer (&local_error)); g_task_return_error (task, g_steal_pointer (&local_error));
} }
else if (!glnx_link_tmpfile_at (&req->tmpf, GLNX_LINK_TMPFILE_REPLACE,
fetcher->tmpdir_dfd, tmpfile_path,
error))
g_task_return_error (task, g_steal_pointer (&local_error));
else else
{ {
g_task_return_pointer (task, g_steal_pointer (&tmpfile_path), g_free); /* We return the tmpfile in the _finish wrapper */
g_task_return_boolean (task, TRUE);
} }
} }
} }
@ -693,7 +687,7 @@ adopt_steal_mainctx (OstreeFetcher *self,
guint64 readytime = g_source_get_ready_time (self->timer_event); guint64 readytime = g_source_get_ready_time (self->timer_event);
guint64 curtime = g_source_get_time (self->timer_event); guint64 curtime = g_source_get_time (self->timer_event);
guint64 timeout_micros = curtime - readytime; guint64 timeout_micros = curtime - readytime;
if (timeout_micros < 0) if (curtime < readytime)
timeout_micros = 0; timeout_micros = 0;
update_timeout_cb (self->multi, timeout_micros / 1000, self); update_timeout_cb (self->multi, timeout_micros / 1000, self);
} }
@ -706,7 +700,7 @@ static void
initiate_next_curl_request (FetcherRequest *req, initiate_next_curl_request (FetcherRequest *req,
GTask *task) GTask *task)
{ {
CURLMcode rc; CURLcode rc;
OstreeFetcher *self = req->fetcher; OstreeFetcher *self = req->fetcher;
if (req->easy) if (req->easy)
@ -802,8 +796,8 @@ initiate_next_curl_request (FetcherRequest *req,
curl_easy_setopt (req->easy, CURLOPT_WRITEDATA, task); curl_easy_setopt (req->easy, CURLOPT_WRITEDATA, task);
curl_easy_setopt (req->easy, CURLOPT_PROGRESSDATA, task); curl_easy_setopt (req->easy, CURLOPT_PROGRESSDATA, task);
rc = curl_multi_add_handle (self->multi, req->easy); CURLMcode multi_rc = curl_multi_add_handle (self->multi, req->easy);
g_assert (rc == CURLM_OK); g_assert (multi_rc == CURLM_OK);
} }
static void static void
@ -887,26 +881,21 @@ _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
gboolean gboolean
_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result, GAsyncResult *result,
char **out_filename, GLnxTmpfile *out_tmpf,
GError **error) GError **error)
{ {
GTask *task;
FetcherRequest *req;
gpointer ret;
g_return_val_if_fail (g_task_is_valid (result, self), FALSE); g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE); g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE);
task = (GTask*)result; GTask *task = (GTask*)result;
req = g_task_get_task_data (task); FetcherRequest *req = g_task_get_task_data (task);
ret = g_task_propagate_pointer (task, error); if (!g_task_propagate_boolean (task, error))
if (!ret)
return FALSE; return FALSE;
g_assert (!req->is_membuf); g_assert (!req->is_membuf);
g_assert (out_filename); *out_tmpf = req->tmpf;
*out_filename = ret; req->tmpf.initialized = FALSE; /* Transfer ownership */
return TRUE; return TRUE;
} }

View File

@ -905,11 +905,8 @@ on_stream_read (GObject *object,
{ {
if (!pending->is_membuf) if (!pending->is_membuf)
{ {
if (!glnx_open_tmpfile_linkable_at (pending->thread_closure->base_tmpdir_dfd, ".", if (!_ostree_fetcher_tmpf_from_flags (pending->flags, pending->thread_closure->base_tmpdir_dfd,
O_WRONLY | O_CLOEXEC, &pending->tmpf, &local_error)) &pending->tmpf, &local_error))
goto out;
/* This should match the libcurl chmod */
if (!glnx_fchmod (pending->tmpf.fd, 0644, &local_error))
goto out; goto out;
pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE); pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE);
} }
@ -943,18 +940,13 @@ on_stream_read (GObject *object,
} }
else else
{ {
g_autofree char *uristring = if (lseek (pending->tmpf.fd, 0, SEEK_SET) < 0)
soup_uri_to_string (soup_request_get_uri (pending->request), FALSE); {
g_autofree char *tmpfile_path = glnx_set_error_from_errno (&local_error);
ostree_fetcher_generate_url_tmpname (uristring);
if (!glnx_link_tmpfile_at (&pending->tmpf, GLNX_LINK_TMPFILE_REPLACE,
pending->thread_closure->base_tmpdir_dfd, tmpfile_path,
&local_error))
g_task_return_error (task, g_steal_pointer (&local_error)); g_task_return_error (task, g_steal_pointer (&local_error));
}
else else
g_task_return_pointer (task, g_task_return_boolean (task, TRUE);
g_steal_pointer (&tmpfile_path),
(GDestroyNotify) g_free);
} }
remove_pending (pending); remove_pending (pending);
} }
@ -1174,7 +1166,7 @@ _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
gboolean gboolean
_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result, GAsyncResult *result,
char **out_filename, GLnxTmpfile *out_tmpf,
GError **error) GError **error)
{ {
GTask *task; GTask *task;
@ -1192,8 +1184,8 @@ _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
return FALSE; return FALSE;
g_assert (!pending->is_membuf); g_assert (!pending->is_membuf);
g_assert (out_filename); *out_tmpf = pending->tmpf;
*out_filename = ret; pending->tmpf.initialized = FALSE; /* Transfer ownership */
return TRUE; return TRUE;
} }

View File

@ -25,14 +25,23 @@
G_BEGIN_DECLS G_BEGIN_DECLS
/* FIXME - delete this and replace by having fetchers simply static inline gboolean
* return O_TMPFILE fds, not file paths. _ostree_fetcher_tmpf_from_flags (OstreeFetcherRequestFlags flags,
*/ int dfd,
static inline char * GLnxTmpfile *tmpf,
ostree_fetcher_generate_url_tmpname (const char *url) GError **error)
{ {
return g_compute_checksum_for_string (G_CHECKSUM_SHA256, if ((flags & OSTREE_FETCHER_REQUEST_LINKABLE) > 0)
url, strlen (url)); {
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE;
}
else if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE;
if (!glnx_fchmod (tmpf->fd, 0644, error))
return FALSE;
return TRUE;
} }
gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher, gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher,

View File

@ -55,7 +55,8 @@ typedef enum {
typedef enum { typedef enum {
OSTREE_FETCHER_REQUEST_NUL_TERMINATION = (1 << 0), OSTREE_FETCHER_REQUEST_NUL_TERMINATION = (1 << 0),
OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT = (1 << 1) OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT = (1 << 1),
OSTREE_FETCHER_REQUEST_LINKABLE = (1 << 2),
} OstreeFetcherRequestFlags; } OstreeFetcherRequestFlags;
void void
@ -124,7 +125,7 @@ void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result, GAsyncResult *result,
char **out_filename, GLnxTmpfile *out_tmpf,
GError **error); GError **error);
void _ostree_fetcher_request_to_membuf (OstreeFetcher *self, void _ostree_fetcher_request_to_membuf (OstreeFetcher *self,

View File

@ -177,7 +177,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
for (guint i = 0; i < self->key_ascii_files->len; i++) for (guint i = 0; i < self->key_ascii_files->len; i++)
{ {
const char *path = self->key_ascii_files->pdata[i]; const char *path = self->key_ascii_files->pdata[i];
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
g_auto(gpgme_data_t) kdata = NULL; g_auto(gpgme_data_t) kdata = NULL;
if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error)) if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error))
@ -272,6 +272,9 @@ _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
{ {
g_return_if_fail (G_IS_FILE (path)); g_return_if_fail (G_IS_FILE (path));
g_autofree gchar *path_str = g_file_get_path (path);
g_debug ("Adding GPG keyring file %s to verifier", path_str);
self->keyrings = g_list_append (self->keyrings, g_object_ref (path)); self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
} }
@ -280,8 +283,11 @@ _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
*/ */
void void
_ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self,
GBytes *keyring) GBytes *keyring,
const char *data_source)
{ {
g_debug ("Adding GPG keyring data from %s to verifier", data_source);
g_ptr_array_add (self->keyring_data, g_bytes_ref (keyring)); g_ptr_array_add (self->keyring_data, g_bytes_ref (keyring));
} }
@ -289,6 +295,8 @@ void
_ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self,
const char *path) const char *path)
{ {
g_debug ("Adding GPG key ASCII file %s to verifier", path);
if (!self->key_ascii_files) if (!self->key_ascii_files)
self->key_ascii_files = g_ptr_array_new_with_free_func (g_free); self->key_ascii_files = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (self->key_ascii_files, g_strdup (path)); g_ptr_array_add (self->key_ascii_files, g_strdup (path));
@ -319,6 +327,8 @@ _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self,
&dfd_iter, error)) &dfd_iter, error))
return FALSE; return FALSE;
g_debug ("Adding GPG keyring dir %s to verifier", path);
while (TRUE) while (TRUE)
{ {
struct dirent *dent; struct dirent *dent;
@ -345,7 +355,7 @@ _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self,
if (g_str_equal (name, "secring.gpg")) if (g_str_equal (name, "secring.gpg"))
continue; continue;
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd_iter.fd, dent->d_name, TRUE, &fd, error)) if (!glnx_openat_rdonly (dfd_iter.fd, dent->d_name, TRUE, &fd, error))
return FALSE; return FALSE;

View File

@ -65,7 +65,8 @@ gboolean _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *s
GError **error); GError **error);
void _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, void _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self,
GBytes *data); GBytes *data,
const char *data_source);
void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
GFile *path); GFile *path);

View File

@ -164,7 +164,7 @@ _ostree_impl_system_generator (const char *ostree_cmdline,
/* Prepare to write to the output unit dir; we use the "normal" dir /* Prepare to write to the output unit dir; we use the "normal" dir
* that overrides /usr, but not /etc. * that overrides /usr, but not /etc.
*/ */
glnx_fd_close int normal_dir_dfd = -1; glnx_autofd int normal_dir_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error)) if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error))
return FALSE; return FALSE;

View File

@ -81,7 +81,7 @@ _ostree_kernel_args_new (void)
} }
void void
_ostree_kernel_arg_autofree (OstreeKernelArgs *kargs) _ostree_kernel_args_free (OstreeKernelArgs *kargs)
{ {
if (!kargs) if (!kargs)
return; return;
@ -90,12 +90,6 @@ _ostree_kernel_arg_autofree (OstreeKernelArgs *kargs)
g_free (kargs); g_free (kargs);
} }
void
_ostree_kernel_args_cleanup (void *loc)
{
_ostree_kernel_arg_autofree (*((OstreeKernelArgs**)loc));
}
void void
_ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs,
char *arg) char *arg)

View File

@ -19,15 +19,15 @@
#pragma once #pragma once
#include <gio/gio.h> #include "libglnx.h"
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _OstreeKernelArgs OstreeKernelArgs; typedef struct _OstreeKernelArgs OstreeKernelArgs;
void _ostree_kernel_args_free (OstreeKernelArgs *kargs);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeKernelArgs, _ostree_kernel_args_free);
OstreeKernelArgs *_ostree_kernel_args_new (void); OstreeKernelArgs *_ostree_kernel_args_new (void);
void _ostree_kernel_args_free (OstreeKernelArgs *kargs);
void _ostree_kernel_args_cleanup (void *loc);
void _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, void _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs,
char *key); char *key);
void _ostree_kernel_args_replace (OstreeKernelArgs *kargs, void _ostree_kernel_args_replace (OstreeKernelArgs *kargs,

View File

@ -228,8 +228,24 @@ create_file_copy_from_input_at (OstreeRepo *repo,
return glnx_throw_errno_prefix (error, "symlinkat"); return glnx_throw_errno_prefix (error, "symlinkat");
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES:
{ {
/* Unioning? Let's unlink and try again */ /* For unioning, we further bifurcate a bit; for the "process whiteouts"
(void) unlinkat (destination_dfd, destination_name, 0); * mode which is really "Docker/OCI", we need to match their semantics
* and handle replacing a directory with a symlink. See also equivalent
* bits for regular files in checkout_file_hardlink().
*/
if (options->process_whiteouts)
{
if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error))
return FALSE;
}
else
{
if (unlinkat (destination_dfd, destination_name, 0) < 0)
{
if (G_UNLIKELY (errno != ENOENT))
return glnx_throw_errno_prefix (error, "unlinkat(%s)", destination_name);
}
}
if (symlinkat (target, destination_dfd, destination_name) < 0) if (symlinkat (target, destination_dfd, destination_name) < 0)
return glnx_throw_errno_prefix (error, "symlinkat"); return glnx_throw_errno_prefix (error, "symlinkat");
} }
@ -309,6 +325,16 @@ create_file_copy_from_input_at (OstreeRepo *repo,
/* Handled above */ /* Handled above */
break; break;
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES:
/* Special case OCI/Docker - see similar code in checkout_file_hardlink()
* and above for symlinks.
*/
if (options->process_whiteouts)
{
if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error))
return FALSE;
/* Inherit the NOREPLACE default...we deleted whatever's there */
}
else
replace_mode = GLNX_LINK_TMPFILE_REPLACE; replace_mode = GLNX_LINK_TMPFILE_REPLACE;
break; break;
case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES:
@ -374,6 +400,7 @@ hardlink_add_tmp_name (OstreeRepo *self,
static gboolean static gboolean
checkout_file_hardlink (OstreeRepo *self, checkout_file_hardlink (OstreeRepo *self,
const char *checksum,
OstreeRepoCheckoutAtOptions *options, OstreeRepoCheckoutAtOptions *options,
const char *loose_path, const char *loose_path,
int destination_dfd, int destination_dfd,
@ -436,10 +463,28 @@ checkout_file_hardlink (OstreeRepo *self,
if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf,
AT_SYMLINK_NOFOLLOW, error)) AT_SYMLINK_NOFOLLOW, error))
return FALSE; return FALSE;
const gboolean is_identical = gboolean is_identical =
(src_stbuf.st_dev == dest_stbuf.st_dev && (src_stbuf.st_dev == dest_stbuf.st_dev &&
src_stbuf.st_ino == dest_stbuf.st_ino); src_stbuf.st_ino == dest_stbuf.st_ino);
if (!is_identical && (_ostree_stbuf_equal (&src_stbuf, &dest_stbuf)))
{
/* As a last resort, do a checksum comparison. This is the case currently
* with rpm-ostree pkg layering where we overlay from the pkgcache repo onto
* a tree checked out from the system repo. Once those are united, we
* shouldn't hit this anymore. https://github.com/ostreedev/ostree/pull/1258
* */
OstreeChecksumFlags flags = 0;
if (self->disable_xattrs)
flags |= OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS;
g_autofree char *actual_checksum = NULL;
if (!ostree_checksum_file_at (destination_dfd, destination_name,
&dest_stbuf, OSTREE_OBJECT_TYPE_FILE,
flags, &actual_checksum, cancellable, error))
return FALSE;
is_identical = g_str_equal (checksum, actual_checksum);
}
if (is_identical) if (is_identical)
ret_result = HARDLINK_RESULT_SKIP_EXISTED; ret_result = HARDLINK_RESULT_SKIP_EXISTED;
else if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) else if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
@ -448,7 +493,15 @@ checkout_file_hardlink (OstreeRepo *self,
/* Make a link with a temp name */ /* Make a link with a temp name */
if (!hardlink_add_tmp_name (self, srcfd, loose_path, tmpname, cancellable, error)) if (!hardlink_add_tmp_name (self, srcfd, loose_path, tmpname, cancellable, error))
return FALSE; return FALSE;
/* Rename it into place */ /* For OCI/Docker mode, we need to handle replacing a directory with a regular
* file. See also the equivalent code for symlinks above.
*/
if (options->process_whiteouts)
{
if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error))
return FALSE;
}
/* Rename it into place - for non-OCI this will overwrite files but not directories */
if (!glnx_renameat (self->tmp_dir_fd, tmpname, destination_dfd, destination_name, error)) if (!glnx_renameat (self->tmp_dir_fd, tmpname, destination_dfd, destination_name, error))
return FALSE; return FALSE;
ret_result = HARDLINK_RESULT_LINKED; ret_result = HARDLINK_RESULT_LINKED;
@ -563,6 +616,7 @@ checkout_one_file_at (OstreeRepo *repo,
the cache, which is in "bare" form */ the cache, which is in "bare" form */
_ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE); _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE);
if (!checkout_file_hardlink (current_repo, if (!checkout_file_hardlink (current_repo,
checksum,
options, options,
loose_path_buf, loose_path_buf,
destination_dfd, destination_name, destination_dfd, destination_name,
@ -652,7 +706,7 @@ checkout_one_file_at (OstreeRepo *repo,
} }
g_mutex_unlock (&repo->cache_lock); g_mutex_unlock (&repo->cache_lock);
if (!checkout_file_hardlink (repo, options, loose_path_buf, if (!checkout_file_hardlink (repo, checksum, options, loose_path_buf,
destination_dfd, destination_name, destination_dfd, destination_name,
FALSE, &hardlink_res, FALSE, &hardlink_res,
cancellable, error)) cancellable, error))
@ -782,7 +836,7 @@ checkout_tree_at_recurse (OstreeRepo *self,
} }
} }
glnx_fd_close int destination_dfd = -1; glnx_autofd int destination_dfd = -1;
if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE,
&destination_dfd, error)) &destination_dfd, error))
return FALSE; return FALSE;
@ -947,7 +1001,7 @@ checkout_tree_at (OstreeRepo *self,
* exists. * exists.
*/ */
int destination_dfd = destination_parent_fd; int destination_dfd = destination_parent_fd;
glnx_fd_close int destination_dfd_owned = -1; glnx_autofd int destination_dfd_owned = -1;
if (strcmp (destination_name, ".") != 0) if (strcmp (destination_name, ".") != 0)
{ {
if (mkdirat (destination_parent_fd, destination_name, 0700) < 0 if (mkdirat (destination_parent_fd, destination_name, 0700) < 0
@ -1156,6 +1210,24 @@ ostree_repo_checkout_at (OstreeRepo *self,
return TRUE; return TRUE;
} }
/**
* ostree_repo_checkout_at_options_set_devino:
* @opts: Checkout options
* @cache: (transfer none) (nullable): Devino cache
*
* This function simply assigns @cache to the `devino_to_csum_cache` member of
* @opts; it's only useful for introspection.
*
* Note that cache does *not* have its refcount incremented - the lifetime of
* @cache must be equal to or greater than that of @opts.
*/
void
ostree_repo_checkout_at_options_set_devino (OstreeRepoCheckoutAtOptions *opts,
OstreeRepoDevInoCache *cache)
{
opts->devino_to_csum_cache = cache;
}
static guint static guint
devino_hash (gconstpointer a) devino_hash (gconstpointer a)
{ {

View File

@ -38,6 +38,22 @@
#include "ostree-checksum-input-stream.h" #include "ostree-checksum-input-stream.h"
#include "ostree-varint.h" #include "ostree-varint.h"
/* In most cases, we write into a staging dir for commit, but we also allow
* direct writes into objects/ for e.g. hardlink imports.
*/
static int
commit_dest_dfd (OstreeRepo *self)
{
if (self->in_transaction)
return self->commit_stagedir.fd;
else
return self->objects_dir_fd;
}
/* The objects/ directory has a two-character directory prefix for checksums
* to avoid putting lots of files in a single directory. This technique
* is quite old, but Git also uses it for example.
*/
gboolean gboolean
_ostree_repo_ensure_loose_objdir_at (int dfd, _ostree_repo_ensure_loose_objdir_at (int dfd,
const char *loose_path, const char *loose_path,
@ -60,6 +76,7 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
return TRUE; return TRUE;
} }
/* This GVariant is the header for content objects (regfiles and symlinks) */
static GVariant * static GVariant *
create_file_metadata (guint32 uid, create_file_metadata (guint32 uid,
guint32 gid, guint32 gid,
@ -82,6 +99,7 @@ create_file_metadata (guint32 uid,
return ret_metadata; return ret_metadata;
} }
/* bare-user repositories store file metadata as a user xattr */
gboolean gboolean
_ostree_write_bareuser_metadata (int fd, _ostree_write_bareuser_metadata (int fd,
guint32 uid, guint32 uid,
@ -137,12 +155,7 @@ _ostree_repo_commit_tmpf_final (OstreeRepo *self,
char tmpbuf[_OSTREE_LOOSE_PATH_MAX]; char tmpbuf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (tmpbuf, checksum, objtype, self->mode); _ostree_loose_path (tmpbuf, checksum, objtype, self->mode);
int dest_dfd; int dest_dfd = commit_dest_dfd (self);
if (self->in_transaction)
dest_dfd = self->commit_stagedir.fd;
else
dest_dfd = self->objects_dir_fd;
if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf, if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
@ -158,8 +171,8 @@ _ostree_repo_commit_tmpf_final (OstreeRepo *self,
/* Given a dfd+path combination (may be regular file or symlink), /* Given a dfd+path combination (may be regular file or symlink),
* rename it into place. * rename it into place.
*/ */
gboolean static gboolean
_ostree_repo_commit_path_final (OstreeRepo *self, commit_path_final (OstreeRepo *self,
const char *checksum, const char *checksum,
OstreeObjectType objtype, OstreeObjectType objtype,
OtCleanupUnlinkat *tmp_path, OtCleanupUnlinkat *tmp_path,
@ -170,12 +183,7 @@ _ostree_repo_commit_path_final (OstreeRepo *self,
char tmpbuf[_OSTREE_LOOSE_PATH_MAX]; char tmpbuf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (tmpbuf, checksum, objtype, self->mode); _ostree_loose_path (tmpbuf, checksum, objtype, self->mode);
int dest_dfd; int dest_dfd = commit_dest_dfd (self);
if (self->in_transaction)
dest_dfd = self->commit_stagedir.fd;
else
dest_dfd = self->objects_dir_fd;
if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf, if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
@ -295,6 +303,7 @@ commit_loose_regfile_object (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* This is used by OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES */
typedef struct typedef struct
{ {
goffset unpacked; goffset unpacked;
@ -395,35 +404,26 @@ add_size_index_to_metadata (OstreeRepo *self,
return g_variant_ref_sink (g_variant_builder_end (builder)); return g_variant_ref_sink (g_variant_builder_end (builder));
} }
/* Combines a check for whether or not we already have the object with /* Create a tmpfile for writing a bare file. Currently just used
* allocating a tempfile if we don't. Used by the static delta code. * by the static delta code, but will likely later be extended
* to be used also by the dfd_iter commit path.
*/ */
gboolean gboolean
_ostree_repo_open_content_bare (OstreeRepo *self, _ostree_repo_open_content_bare (OstreeRepo *self,
const char *checksum, const char *checksum,
guint64 content_len, guint64 content_len,
GLnxTmpfile *out_tmpf, GLnxTmpfile *out_tmpf,
gboolean *out_have_object,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean have_obj;
if (!_ostree_repo_has_loose_object (self, checksum, OSTREE_OBJECT_TYPE_FILE, &have_obj,
cancellable, error))
return FALSE;
/* Do we already have this object? */
*out_have_object = have_obj;
if (have_obj)
{
/* Make sure the tempfile is unset */
out_tmpf->initialized = 0;
return TRUE;
}
return glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY|O_CLOEXEC, return glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY|O_CLOEXEC,
out_tmpf, error); out_tmpf, error);
} }
/* Used by static deltas, which have a separate "push" flow for
* regfile objects distinct from the "pull" model used by
* write_content_object().
*/
gboolean gboolean
_ostree_repo_commit_trusted_content_bare (OstreeRepo *self, _ostree_repo_commit_trusted_content_bare (OstreeRepo *self,
const char *checksum, const char *checksum,
@ -446,6 +446,10 @@ _ostree_repo_commit_trusted_content_bare (OstreeRepo *self,
cancellable, error); cancellable, error);
} }
/* Allocate an O_TMPFILE, write everything from @input to it, but
* not exceeding @length. Used for every object in archive repos,
* and content objects in all bare-type repos.
*/
static gboolean static gboolean
create_regular_tmpfile_linkable_with_content (OstreeRepo *self, create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
guint64 length, guint64 length,
@ -498,7 +502,12 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Write a content object. */ /* The main driver for writing a content (regfile or symlink) object.
* There are a variety of tricky cases here; for example, bare-user
* repos store symlinks as regular files. Computing checksums
* is optional; if @out_csum is `NULL`, we assume the caller already
* knows the checksum.
*/
static gboolean static gboolean
write_content_object (OstreeRepo *self, write_content_object (OstreeRepo *self,
const char *expected_checksum, const char *expected_checksum,
@ -611,7 +620,6 @@ write_content_object (OstreeRepo *self,
} }
else else
{ {
g_autoptr(GVariant) file_meta = NULL;
g_autoptr(GConverter) zlib_compressor = NULL; g_autoptr(GConverter) zlib_compressor = NULL;
g_autoptr(GOutputStream) compressed_out_stream = NULL; g_autoptr(GOutputStream) compressed_out_stream = NULL;
g_autoptr(GOutputStream) temp_out = NULL; g_autoptr(GOutputStream) temp_out = NULL;
@ -626,11 +634,15 @@ write_content_object (OstreeRepo *self,
return FALSE; return FALSE;
temp_out = g_unix_output_stream_new (tmpf.fd, FALSE); temp_out = g_unix_output_stream_new (tmpf.fd, FALSE);
file_meta = _ostree_zlib_file_header_new (file_info, xattrs); g_autoptr(GBytes) file_meta_header = _ostree_zlib_file_header_new (file_info, xattrs);
gsize file_meta_len;
const guint8* file_meta_buf = g_bytes_get_data (file_meta_header, &file_meta_len);
if (!_ostree_write_variant_with_size (temp_out, file_meta, 0, NULL, NULL, { gsize bytes_written;
if (!g_output_stream_write_all (temp_out, file_meta_buf, file_meta_len, &bytes_written,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
}
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
{ {
@ -660,10 +672,12 @@ write_content_object (OstreeRepo *self,
else else
{ {
actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input); actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input);
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0) if (expected_checksum)
return glnx_throw (error, "Corrupted %s object %s (actual checksum is %s)", {
ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE), if (!_ostree_compare_object_checksum (OSTREE_OBJECT_TYPE_FILE, expected_checksum, actual_checksum,
expected_checksum, actual_checksum); error))
return FALSE;
}
} }
g_assert (actual_checksum != NULL); /* Pacify static analysis */ g_assert (actual_checksum != NULL); /* Pacify static analysis */
@ -723,9 +737,8 @@ write_content_object (OstreeRepo *self,
g_assert_not_reached (); g_assert_not_reached ();
} }
if (!_ostree_repo_commit_path_final (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE, if (!commit_path_final (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE,
&tmp_unlinker, &tmp_unlinker, cancellable, error))
cancellable, error))
return FALSE; return FALSE;
} }
else else
@ -766,6 +779,114 @@ write_content_object (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* A fast path for local commits to `bare` or `bare-user-only`
* repos - we basically checksum the file and do a renameat()
* into place.
*
* This could be enhanced down the line to handle cases where we have a modified
* stat struct in place; e.g. for `bare` we could do the `chown`, or chmod etc.,
* and reset the xattrs.
*
* We could also do this for bare-user, would just involve adding the xattr (and
* potentially deleting other ones...not sure if we'd really want e.g. the
* security.selinux xattr on setuid binaries and the like to live on).
*/
static gboolean
adopt_and_commit_regfile (OstreeRepo *self,
int dfd,
const char *name,
GFileInfo *finfo,
GVariant *xattrs,
char *out_checksum_buf,
GCancellable *cancellable,
GError **error)
{
g_assert (G_IN_SET (self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER_ONLY));
g_autoptr(GBytes) header = _ostree_file_header_new (finfo, xattrs);
g_auto(OtChecksum) hasher = { 0, };
ot_checksum_init (&hasher);
ot_checksum_update_bytes (&hasher, header);
glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd, name, FALSE, &fd, error))
return FALSE;
(void)posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
/* See also https://gist.github.com/cgwalters/0df0d15199009664549618c2188581f0
* and https://github.com/coreutils/coreutils/blob/master/src/ioblksize.h
* Turns out bigger block size is better; down the line we should use their
* same heuristics.
*/
char buf[16*1024];
while (TRUE)
{
ssize_t bytes_read = read (fd, buf, sizeof (buf));
if (bytes_read < 0)
return glnx_throw_errno_prefix (error, "read");
if (bytes_read == 0)
break;
ot_checksum_update (&hasher, (guint8*)buf, bytes_read);
}
ot_checksum_get_hexdigest (&hasher, out_checksum_buf, OSTREE_SHA256_STRING_LEN+1);
const char *checksum = out_checksum_buf;
/* TODO: dedup this with commit_path_final() */
char loose_path[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (loose_path, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode);
const guint32 src_dev = g_file_info_get_attribute_uint32 (finfo, "unix::device");
const guint64 src_inode = g_file_info_get_attribute_uint64 (finfo, "unix::inode");
int dest_dfd = commit_dest_dfd (self);
if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, loose_path,
cancellable, error))
return FALSE;
struct stat dest_stbuf;
if (!glnx_fstatat_allow_noent (dest_dfd, loose_path, &dest_stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE;
/* Is the source actually the same device/inode? This can happen with hardlink
* checkouts, which is a bit overly conservative for bare-user-only right now.
* If so, we can't use renameat() since from `man 2 renameat`:
*
* "If oldpath and newpath are existing hard links referring to the same file,
* then rename() does nothing, and returns a success status."
*/
if (errno != ENOENT
&& src_dev == dest_stbuf.st_dev
&& src_inode == dest_stbuf.st_ino)
{
if (!glnx_unlinkat (dfd, name, 0, error))
return FALSE;
/* Early return */
return TRUE;
}
/* For bare-user-only we need to canonicalize perms */
if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
{
const guint32 src_mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
if (fchmod (fd, src_mode & 0755) < 0)
return glnx_throw_errno_prefix (error, "fchmod");
}
if (renameat (dfd, name, dest_dfd, loose_path) == -1)
{
if (errno != EEXIST)
return glnx_throw_errno_prefix (error, "Storing file '%s'", name);
/* We took ownership here, so delete it */
if (!glnx_unlinkat (dfd, name, 0, error))
return FALSE;
}
return TRUE;
}
/* Main driver for writing a metadata (non-content) object. */
static gboolean static gboolean
write_metadata_object (OstreeRepo *self, write_metadata_object (OstreeRepo *self,
OstreeObjectType objtype, OstreeObjectType objtype,
@ -790,14 +911,19 @@ write_metadata_object (OstreeRepo *self,
* *original* sha256 to say what commit was being killed. * *original* sha256 to say what commit was being killed.
*/ */
const gboolean is_tombstone = (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT); const gboolean is_tombstone = (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT);
g_autofree char *actual_checksum = NULL; char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
if (is_tombstone) if (is_tombstone)
{ {
actual_checksum = g_strdup (expected_checksum); memcpy (actual_checksum, expected_checksum, sizeof (actual_checksum));
} }
else else
{ {
actual_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, buf); OtChecksum checksum = { 0, };
ot_checksum_init (&checksum);
gsize len;
const guint8*bufdata = g_bytes_get_data (buf, &len);
ot_checksum_update (&checksum, bufdata, len);
ot_checksum_get_hexdigest (&checksum, actual_checksum, sizeof (actual_checksum));
gboolean have_obj; gboolean have_obj;
if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj, if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj,
cancellable, error)) cancellable, error))
@ -817,10 +943,11 @@ write_metadata_object (OstreeRepo *self,
return TRUE; return TRUE;
} }
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0) if (expected_checksum)
return glnx_throw (error, "Corrupted %s object %s (actual checksum is %s)", {
ostree_object_type_to_string (objtype), if (!_ostree_compare_object_checksum (objtype, expected_checksum, actual_checksum, error))
expected_checksum, actual_checksum); return FALSE;
}
} }
/* Ok, checksum is known, let's get the data */ /* Ok, checksum is known, let's get the data */
@ -888,6 +1015,9 @@ write_metadata_object (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Look in a single subdirectory of objects/, building up the
* (device,inode) checksum map.
*/
static gboolean static gboolean
scan_one_loose_devino (OstreeRepo *self, scan_one_loose_devino (OstreeRepo *self,
int object_dir_fd, int object_dir_fd,
@ -969,6 +1099,7 @@ scan_one_loose_devino (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Used by ostree_repo_scan_hardlinks(); see that function for more information. */
static gboolean static gboolean
scan_loose_devino (OstreeRepo *self, scan_loose_devino (OstreeRepo *self,
GHashTable *devino_cache, GHashTable *devino_cache,
@ -995,6 +1126,8 @@ scan_loose_devino (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Loook up a (device,inode) pair in our cache, and see if it maps to a known
* checksum. */
static const char * static const char *
devino_cache_lookup (OstreeRepo *self, devino_cache_lookup (OstreeRepo *self,
OstreeRepoCommitModifier *modifier, OstreeRepoCommitModifier *modifier,
@ -1122,6 +1255,12 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Called for commit, to iterate over the "staging" directory and rename all the
* objects into the primary objects/ location. Notably this is called only after
* syncfs() has potentially been invoked to ensure that all objects have been
* written to disk. In the future we may enhance this; see
* https://github.com/ostreedev/ostree/issues/1184
*/
static gboolean static gboolean
rename_pending_loose_objects (OstreeRepo *self, rename_pending_loose_objects (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
@ -1189,7 +1328,7 @@ rename_pending_loose_objects (OstreeRepo *self,
/* Ensure that in the case of a power cut all the directory metadata that /* Ensure that in the case of a power cut all the directory metadata that
we want has reached the disk. In particular, we want this before we we want has reached the disk. In particular, we want this before we
update the refs to point to these objects. */ update the refs to point to these objects. */
glnx_fd_close int target_dir_fd = -1; glnx_autofd int target_dir_fd = -1;
loose_objpath[2] = 0; loose_objpath[2] = 0;
@ -1217,6 +1356,12 @@ rename_pending_loose_objects (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Look in repo/tmp and delete files that are older than a day (by default).
* This used to be primarily used by the libsoup fetcher which stored partially
* written objects. In practice now that that isn't done anymore, we should
* use different logic here. Some more information in
* https://github.com/ostreedev/ostree/issues/713
*/
static gboolean static gboolean
cleanup_tmpdir (OstreeRepo *self, cleanup_tmpdir (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
@ -1560,6 +1705,17 @@ ostree_repo_commit_transaction (OstreeRepo *self,
return TRUE; return TRUE;
} }
/**
* ostree_repo_abort_transaction:
* @self: An #OstreeRepo
* @cancellable: Cancellable
* @error: Error
*
* Abort the active transaction; any staged objects and ref changes will be
* discarded. You *must* invoke this if you have chosen not to invoke
* ostree_repo_commit_transaction(). Calling this function when not in a
* transaction will do nothing and return successfully.
*/
gboolean gboolean
ostree_repo_abort_transaction (OstreeRepo *self, ostree_repo_abort_transaction (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
@ -1814,6 +1970,15 @@ ostree_repo_write_metadata_async (OstreeRepo *self,
g_object_unref (asyncdata->result); g_object_unref (asyncdata->result);
} }
/**
* ostree_repo_write_metadata_finish:
* @self: Repo
* @result: Result
* @out_csum: (out) (array fixed-size=32) (element-type guint8): Binary checksum value
* @error: Error
*
* Complete a call to ostree_repo_write_metadata_async().
*/
gboolean gboolean
ostree_repo_write_metadata_finish (OstreeRepo *self, ostree_repo_write_metadata_finish (OstreeRepo *self,
GAsyncResult *result, GAsyncResult *result,
@ -1835,6 +2000,9 @@ ostree_repo_write_metadata_finish (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* Write an object of type OSTREE_OBJECT_TYPE_DIR_META, using @file_info and @xattrs.
* Return its (binary) checksum in @out_csum.
*/
gboolean gboolean
_ostree_repo_write_directory_meta (OstreeRepo *self, _ostree_repo_write_directory_meta (OstreeRepo *self,
GFileInfo *file_info, GFileInfo *file_info,
@ -1843,13 +2011,11 @@ _ostree_repo_write_directory_meta (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autoptr(GVariant) dirmeta = NULL;
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE; return FALSE;
dirmeta = ostree_create_directory_metadata (file_info, xattrs); g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs);
return ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_DIR_META, NULL, return ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_DIR_META, NULL,
dirmeta, out_csum, cancellable, error); dirmeta, out_csum, cancellable, error);
} }
@ -2152,26 +2318,29 @@ ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
char buf[_OSTREE_LOOSE_PATH_MAX]; char buf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); _ostree_loose_path (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode);
g_autoptr(GVariant) ret_metadata = NULL; if (self->commit_stagedir.initialized)
if (self->commit_stagedir.initialized && {
!ot_util_variant_map_at (self->commit_stagedir.fd, buf, glnx_autofd int fd = -1;
G_VARIANT_TYPE ("a{sv}"), if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, buf, &fd, error))
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error)) return FALSE;
return glnx_prefix_error (error, "Unable to read existing detached metadata"); if (fd != -1)
return ot_variant_read_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), TRUE,
out_metadata, error);
}
if (ret_metadata == NULL && glnx_autofd int fd = -1;
!ot_util_variant_map_at (self->objects_dir_fd, buf, if (!ot_openat_ignore_enoent (self->objects_dir_fd, buf, &fd, error))
G_VARIANT_TYPE ("a{sv}"), return FALSE;
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error)) if (fd != -1)
return glnx_prefix_error (error, "Unable to read existing detached metadata"); return ot_variant_read_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), TRUE,
out_metadata, error);
if (ret_metadata == NULL && self->parent_repo) if (self->parent_repo)
return ostree_repo_read_commit_detached_metadata (self->parent_repo, return ostree_repo_read_commit_detached_metadata (self->parent_repo,
checksum, checksum, out_metadata,
out_metadata, cancellable, error);
cancellable, /* Nothing found */
error); *out_metadata = NULL;
ot_transfer_out_value (out_metadata, &ret_metadata);
return TRUE; return TRUE;
} }
@ -2230,6 +2399,9 @@ ostree_repo_write_commit_detached_metadata (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* This generates an in-memory OSTREE_OBJECT_TYPE_DIR_TREE variant, using the
* content objects and subdirectories. The input hashes will be sorted
*/
static GVariant * static GVariant *
create_tree_variant_from_hashes (GHashTable *file_checksums, create_tree_variant_from_hashes (GHashTable *file_checksums,
GHashTable *dir_contents_checksums, GHashTable *dir_contents_checksums,
@ -2341,6 +2513,7 @@ _ostree_repo_commit_modifier_apply (OstreeRepo *self,
return result; return result;
} }
/* Convert @path into a string */
static char * static char *
ptrarray_path_join (GPtrArray *path) ptrarray_path_join (GPtrArray *path)
{ {
@ -2370,6 +2543,7 @@ get_final_xattrs (OstreeRepo *self,
GFile *path, GFile *path,
int dfd, int dfd,
const char *dfd_subpath, const char *dfd_subpath,
GVariant *source_xattrs,
GVariant **out_xattrs, GVariant **out_xattrs,
gboolean *out_modified, gboolean *out_modified,
GCancellable *cancellable, GCancellable *cancellable,
@ -2385,7 +2559,9 @@ get_final_xattrs (OstreeRepo *self,
g_autoptr(GVariant) original_xattrs = NULL; g_autoptr(GVariant) original_xattrs = NULL;
if (!skip_xattrs && !self->disable_xattrs) if (!skip_xattrs && !self->disable_xattrs)
{ {
if (path && OSTREE_IS_REPO_FILE (path)) if (source_xattrs)
original_xattrs = g_variant_ref (source_xattrs);
else if (path && OSTREE_IS_REPO_FILE (path))
{ {
if (!ostree_repo_file_get_xattrs (OSTREE_REPO_FILE (path), &original_xattrs, if (!ostree_repo_file_get_xattrs (OSTREE_REPO_FILE (path), &original_xattrs,
cancellable, error)) cancellable, error))
@ -2494,6 +2670,11 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
typedef enum {
WRITE_DIR_CONTENT_FLAGS_NONE = 0,
WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT = 1,
} WriteDirContentFlags;
/* Given either a dir_enum or a dfd_iter, writes the directory entry to the mtree. For /* Given either a dir_enum or a dfd_iter, writes the directory entry to the mtree. For
* subdirs, we go back through either write_dfd_iter_to_mtree_internal (dfd_iter case) or * subdirs, we go back through either write_dfd_iter_to_mtree_internal (dfd_iter case) or
* write_directory_to_mtree_internal (dir_enum case) which will do the actual dirmeta + * write_directory_to_mtree_internal (dir_enum case) which will do the actual dirmeta +
@ -2503,6 +2684,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
OstreeRepoFile *repo_dir, OstreeRepoFile *repo_dir,
GFileEnumerator *dir_enum, GFileEnumerator *dir_enum,
GLnxDirFdIterator *dfd_iter, GLnxDirFdIterator *dfd_iter,
WriteDirContentFlags writeflags,
GFileInfo *child_info, GFileInfo *child_info,
OstreeMutableTree *mtree, OstreeMutableTree *mtree,
OstreeRepoCommitModifier *modifier, OstreeRepoCommitModifier *modifier,
@ -2512,24 +2694,62 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
{ {
g_assert (dir_enum != NULL || dfd_iter != NULL); g_assert (dir_enum != NULL || dfd_iter != NULL);
GFileType file_type = g_file_info_get_file_type (child_info);
const char *name = g_file_info_get_name (child_info); const char *name = g_file_info_get_name (child_info);
g_ptr_array_add (path, (char*)name); g_ptr_array_add (path, (char*)name);
g_autofree char *child_relpath = ptrarray_path_join (path); g_autofree char *child_relpath = ptrarray_path_join (path);
/* See if we have a devino hit; this is used below. Further, for bare-user
* repos we'll reload our file info from the object (specifically the
* ostreemeta xattr). The on-disk state is not normally what we want to
* commit. Basically we're making sure that we pick up "real" uid/gid and any
* xattrs there.
*/
const char *loose_checksum = NULL;
g_autoptr(GVariant) source_xattrs = NULL;
if (dfd_iter != NULL && (file_type != G_FILE_TYPE_DIRECTORY))
{
guint32 dev = g_file_info_get_attribute_uint32 (child_info, "unix::device");
guint64 inode = g_file_info_get_attribute_uint64 (child_info, "unix::inode");
loose_checksum = devino_cache_lookup (self, modifier, dev, inode);
if (loose_checksum && self->mode == OSTREE_REPO_MODE_BARE_USER)
{
child_info = NULL;
if (!ostree_repo_load_file (self, loose_checksum, NULL, &child_info, &source_xattrs,
cancellable, error))
return FALSE;
}
}
g_autoptr(GFileInfo) modified_info = NULL; g_autoptr(GFileInfo) modified_info = NULL;
OstreeRepoCommitFilterResult filter_result = OstreeRepoCommitFilterResult filter_result =
_ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info); _ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info);
const gboolean child_info_was_modified = !_ostree_gfileinfo_equal (child_info, modified_info); const gboolean child_info_was_modified = !_ostree_gfileinfo_equal (child_info, modified_info);
/* We currently only honor the CONSUME flag in the dfd_iter case to avoid even
* more complexity in this function, and it'd mostly only be useful when
* operating on local filesystems anyways.
*/
const gboolean delete_after_commit = dfd_iter && modifier &&
(modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME);
const gboolean canonical_permissions = modifier &&
(modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS);
if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW)
{ {
g_ptr_array_remove_index (path, path->len - 1); g_ptr_array_remove_index (path, path->len - 1);
if (delete_after_commit)
{
g_assert (dfd_iter);
if (!glnx_shutil_rm_rf_at (dfd_iter->fd, name, cancellable, error))
return FALSE;
}
/* Note: early return */ /* Note: early return */
return TRUE; return TRUE;
} }
GFileType file_type = g_file_info_get_file_type (child_info);
switch (file_type) switch (file_type)
{ {
case G_FILE_TYPE_DIRECTORY: case G_FILE_TYPE_DIRECTORY:
@ -2568,6 +2788,12 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
modifier, path, modifier, path,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
if (delete_after_commit)
{
if (!glnx_unlinkat (dfd_iter->fd, name, AT_REMOVEDIR, error))
return FALSE;
}
} }
} }
else if (repo_dir) else if (repo_dir)
@ -2581,67 +2807,139 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
} }
else else
{ {
guint64 file_obj_length; glnx_autofd int file_input_fd = -1;
g_autoptr(GInputStream) file_input = NULL;
g_autoptr(GInputStream) file_object_input = NULL; /* Open the file now, since it's better for reading xattrs
g_autofree guchar *child_file_csum = NULL; * rather than using the /proc/self/fd links.
g_autofree char *tmp_checksum = NULL; *
* TODO: Do this lazily, since for e.g. bare-user-only repos
* we don't have xattrs and don't need to open every file
* for things that have devino cache hits.
*/
if (file_type == G_FILE_TYPE_REGULAR && dfd_iter != NULL)
{
if (!glnx_openat_rdonly (dfd_iter->fd, name, FALSE, &file_input_fd, error))
return FALSE;
}
g_autoptr(GVariant) xattrs = NULL; g_autoptr(GVariant) xattrs = NULL;
gboolean xattrs_were_modified; gboolean xattrs_were_modified;
if (!get_final_xattrs (self, modifier, child_relpath, child_info, child, if (dir_enum != NULL)
dfd_iter != NULL ? dfd_iter->fd : -1, name, &xattrs,
&xattrs_were_modified, cancellable, error))
return FALSE;
/* only check the devino cache if the file info & xattrs were not modified */
const char *loose_checksum = NULL;
if (!child_info_was_modified && !xattrs_were_modified)
{ {
guint32 dev = g_file_info_get_attribute_uint32 (child_info, "unix::device"); if (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
guint64 inode = g_file_info_get_attribute_uint64 (child_info, "unix::inode"); -1, name, source_xattrs, &xattrs, &xattrs_were_modified,
loose_checksum = devino_cache_lookup (self, modifier, dev, inode); cancellable, error))
return FALSE;
}
else
{
/* These contortions are basically so we use glnx_fd_get_all_xattrs()
* for regfiles, and glnx_dfd_name_get_all_xattrs() for symlinks.
*/
int xattr_fd_arg = (file_input_fd != -1) ? file_input_fd : dfd_iter->fd;
const char *xattr_path_arg = (file_input_fd != -1) ? NULL : name;
if (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
xattr_fd_arg, xattr_path_arg, source_xattrs,
&xattrs, &xattrs_were_modified,
cancellable, error))
return FALSE;
} }
if (loose_checksum) /* Used below to see whether we can do a fast path commit */
const gboolean modified_file_meta = child_info_was_modified || xattrs_were_modified;
/* A big prerequisite list of conditions for whether or not we can
* "adopt", i.e. just checksum and rename() into place
*/
const gboolean can_adopt_basic =
file_type == G_FILE_TYPE_REGULAR
&& dfd_iter != NULL
&& delete_after_commit
&& ((writeflags & WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT) > 0);
gboolean can_adopt = can_adopt_basic;
/* If basic prerquisites are met, check repo mode specific ones */
if (can_adopt)
{
/* For bare repos, we could actually chown/reset the xattrs, but let's
* do the basic optimizations here first.
*/
if (self->mode == OSTREE_REPO_MODE_BARE)
can_adopt = !modified_file_meta;
else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
can_adopt = canonical_permissions;
else
/* This covers bare-user and archive. See comments in adopt_and_commit_regfile()
* for notes on adding bare-user later here.
*/
can_adopt = FALSE;
}
gboolean did_adopt = FALSE;
/* The very fast path - we have a devino cache hit, nothing to write */
if (loose_checksum && !modified_file_meta)
{ {
if (!ostree_mutable_tree_replace_file (mtree, name, loose_checksum, if (!ostree_mutable_tree_replace_file (mtree, name, loose_checksum,
error)) error))
return FALSE; return FALSE;
} }
/* Next fast path - we can "adopt" the file */
else if (can_adopt)
{
char checksum[OSTREE_SHA256_STRING_LEN+1];
if (!adopt_and_commit_regfile (self, dfd_iter->fd, name, modified_info, xattrs,
checksum, cancellable, error))
return FALSE;
if (!ostree_mutable_tree_replace_file (mtree, name, checksum, error))
return FALSE;
did_adopt = TRUE;
}
else else
{ {
if (g_file_info_get_file_type (modified_info) == G_FILE_TYPE_REGULAR) g_autoptr(GInputStream) file_input = NULL;
if (file_type == G_FILE_TYPE_REGULAR)
{ {
if (child != NULL) if (dir_enum != NULL)
{ {
g_assert (child != NULL);
file_input = (GInputStream*)g_file_read (child, cancellable, error); file_input = (GInputStream*)g_file_read (child, cancellable, error);
if (!file_input) if (!file_input)
return FALSE; return FALSE;
} }
else else
{ {
if (!ot_openat_read_stream (dfd_iter->fd, name, FALSE, /* We already opened the fd above */
&file_input, cancellable, error)) file_input = g_unix_input_stream_new (file_input_fd, FALSE);
return FALSE;
} }
} }
g_autoptr(GInputStream) file_object_input = NULL;
guint64 file_obj_length;
if (!ostree_raw_file_to_content_stream (file_input, if (!ostree_raw_file_to_content_stream (file_input,
modified_info, xattrs, modified_info, xattrs,
&file_object_input, &file_obj_length, &file_object_input, &file_obj_length,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
g_autofree guchar *child_file_csum = NULL;
if (!ostree_repo_write_content (self, NULL, file_object_input, file_obj_length, if (!ostree_repo_write_content (self, NULL, file_object_input, file_obj_length,
&child_file_csum, cancellable, error)) &child_file_csum, cancellable, error))
return FALSE; return FALSE;
g_free (tmp_checksum); char tmp_checksum[OSTREE_SHA256_STRING_LEN+1];
tmp_checksum = ostree_checksum_from_bytes (child_file_csum); ostree_checksum_inplace_from_bytes (child_file_csum, tmp_checksum);
if (!ostree_mutable_tree_replace_file (mtree, name, tmp_checksum, if (!ostree_mutable_tree_replace_file (mtree, name, tmp_checksum,
error)) error))
return FALSE; return FALSE;
} }
/* Process delete_after_commit. In the adoption case though, we already
* took ownership of the file above, usually via a renameat().
*/
if (delete_after_commit && !did_adopt)
{
if (!glnx_unlinkat (dfd_iter->fd, name, 0, error))
return FALSE;
}
} }
g_ptr_array_remove_index (path, path->len - 1); g_ptr_array_remove_index (path, path->len - 1);
@ -2701,7 +2999,7 @@ write_directory_to_mtree_internal (OstreeRepo *self,
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{ {
if (!get_final_xattrs (self, modifier, relpath, child_info, dir, -1, NULL, if (!get_final_xattrs (self, modifier, relpath, child_info, dir, -1, NULL,
&xattrs, NULL, cancellable, error)) NULL, &xattrs, NULL, cancellable, error))
return FALSE; return FALSE;
g_autofree guchar *child_file_csum = NULL; g_autofree guchar *child_file_csum = NULL;
@ -2736,6 +3034,7 @@ write_directory_to_mtree_internal (OstreeRepo *self,
break; break;
if (!write_directory_content_to_mtree_internal (self, repo_dir, dir_enum, NULL, if (!write_directory_content_to_mtree_internal (self, repo_dir, dir_enum, NULL,
WRITE_DIR_CONTENT_FLAGS_NONE,
child_info, child_info,
mtree, modifier, path, mtree, modifier, path,
cancellable, error)) cancellable, error))
@ -2786,7 +3085,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{ {
if (!get_final_xattrs (self, modifier, relpath, modified_info, NULL, src_dfd_iter->fd, if (!get_final_xattrs (self, modifier, relpath, modified_info, NULL, src_dfd_iter->fd,
NULL, &xattrs, NULL, cancellable, error)) NULL, NULL, &xattrs, NULL, cancellable, error))
return FALSE; return FALSE;
if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum, if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum,
@ -2804,6 +3103,11 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
return TRUE; return TRUE;
} }
/* See if this dir is on the same device; if so we can adopt (if enabled) */
WriteDirContentFlags flags = 0;
if (dir_stbuf.st_dev == self->device)
flags |= WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT;
while (TRUE) while (TRUE)
{ {
struct dirent *dent; struct dirent *dent;
@ -2836,7 +3140,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
} }
if (!write_directory_content_to_mtree_internal (self, NULL, NULL, src_dfd_iter, if (!write_directory_content_to_mtree_internal (self, NULL, NULL, src_dfd_iter,
child_info, flags, child_info,
mtree, modifier, path, mtree, modifier, path,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
@ -2922,6 +3226,19 @@ ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
/* And now finally remove the toplevel; see also the handling for this flag in
* the write_dfd_iter_to_mtree_internal() function. As a special case we don't
* try to remove `.` (since we'd get EINVAL); that's what's used in
* rpm-ostree.
*/
const gboolean delete_after_commit = modifier &&
(modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME);
if (delete_after_commit && !g_str_equal (path, "."))
{
if (!glnx_unlinkat (dfd, path, AT_REMOVEDIR, error))
return FALSE;
}
return TRUE; return TRUE;
} }
@ -3118,6 +3435,8 @@ ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier
* *
* This function will add a reference to @cache without copying - you * This function will add a reference to @cache without copying - you
* should avoid further mutation of the cache. * should avoid further mutation of the cache.
*
* Since: 2017.13
*/ */
void void
ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier, ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier,
@ -3255,7 +3574,7 @@ import_one_object_direct (OstreeRepo *dest_repo,
if (linkat (src_repo->objects_dir_fd, loose_path_buf, dest_dfd, loose_path_buf, 0) != 0) if (linkat (src_repo->objects_dir_fd, loose_path_buf, dest_dfd, loose_path_buf, 0) != 0)
{ {
if (errno == EEXIST) if (errno == EEXIST)
return TRUE; did_hardlink = TRUE;
else if (errno == EMLINK || errno == EXDEV || errno == EPERM) else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
{ {
/* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do
@ -3292,7 +3611,7 @@ import_one_object_direct (OstreeRepo *dest_repo,
* that basically just optionally does chown(). Perhaps * that basically just optionally does chown(). Perhaps
* in the future we should add flags for those things? * in the future we should add flags for those things?
*/ */
glnx_fd_close int src_fd = -1; glnx_autofd int src_fd = -1;
if (!glnx_openat_rdonly (src_repo->objects_dir_fd, loose_path_buf, if (!glnx_openat_rdonly (src_repo->objects_dir_fd, loose_path_buf,
FALSE, &src_fd, error)) FALSE, &src_fd, error))
return FALSE; return FALSE;

View File

@ -429,7 +429,7 @@ fill_refs_and_checksums_from_summary_map (GVariantIter *summary_map,
g_autofree gchar *ref_name = NULL; g_autofree gchar *ref_name = NULL;
g_autoptr(GVariant) checksum_variant = NULL; g_autoptr(GVariant) checksum_variant = NULL;
while (g_variant_iter_next (summary_map, "(s(t@aya{sv}))", while (g_variant_iter_loop (summary_map, "(s(t@aya{sv}))",
(gpointer *) &ref_name, NULL, (gpointer *) &ref_name, NULL,
(gpointer *) &checksum_variant, NULL)) (gpointer *) &checksum_variant, NULL))
{ {
@ -466,7 +466,7 @@ fill_refs_and_checksums_from_summary (GVariant *summary,
{ {
g_autoptr(GVariant) ref_map_v = NULL; g_autoptr(GVariant) ref_map_v = NULL;
g_autoptr(GVariant) additional_metadata_v = NULL; g_autoptr(GVariant) additional_metadata_v = NULL;
GVariantIter ref_map; g_autoptr(GVariantIter) ref_map = NULL;
g_auto(GVariantDict) additional_metadata = OT_VARIANT_BUILDER_INITIALIZER; g_auto(GVariantDict) additional_metadata = OT_VARIANT_BUILDER_INITIALIZER;
const gchar *collection_id; const gchar *collection_id;
g_autoptr(GVariantIter) collection_map = NULL; g_autoptr(GVariantIter) collection_map = NULL;
@ -474,7 +474,7 @@ fill_refs_and_checksums_from_summary (GVariant *summary,
ref_map_v = g_variant_get_child_value (summary, 0); ref_map_v = g_variant_get_child_value (summary, 0);
additional_metadata_v = g_variant_get_child_value (summary, 1); additional_metadata_v = g_variant_get_child_value (summary, 1);
g_variant_iter_init (&ref_map, ref_map_v); ref_map = g_variant_iter_new (ref_map_v);
g_variant_dict_init (&additional_metadata, additional_metadata_v); g_variant_dict_init (&additional_metadata, additional_metadata_v);
/* If the summary file specifies a collection ID (to apply to all the refs in its /* If the summary file specifies a collection ID (to apply to all the refs in its
@ -485,10 +485,12 @@ fill_refs_and_checksums_from_summary (GVariant *summary,
{ {
if (!ostree_validate_collection_id (collection_id, error)) if (!ostree_validate_collection_id (collection_id, error))
return FALSE; return FALSE;
if (!fill_refs_and_checksums_from_summary_map (&ref_map, collection_id, refs_and_checksums, error)) if (!fill_refs_and_checksums_from_summary_map (ref_map, collection_id, refs_and_checksums, error))
return FALSE; return FALSE;
} }
g_clear_pointer (&ref_map, (GDestroyNotify) g_variant_iter_free);
/* Repeat for the other collections listed in the summary. */ /* Repeat for the other collections listed in the summary. */
if (g_variant_dict_lookup (&additional_metadata, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &collection_map)) if (g_variant_dict_lookup (&additional_metadata, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &collection_map))
{ {
@ -496,7 +498,7 @@ fill_refs_and_checksums_from_summary (GVariant *summary,
{ {
if (!ostree_validate_collection_id (collection_id, error)) if (!ostree_validate_collection_id (collection_id, error))
return FALSE; return FALSE;
if (!fill_refs_and_checksums_from_summary_map (&ref_map, collection_id, refs_and_checksums, error)) if (!fill_refs_and_checksums_from_summary_map (ref_map, collection_id, refs_and_checksums, error))
return FALSE; return FALSE;
} }
} }

View File

@ -23,6 +23,7 @@
#include "config.h" #include "config.h"
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixmounts.h>
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
#include <libglnx.h> #include <libglnx.h>
@ -235,8 +236,7 @@ scan_repo (int dfd,
{ {
g_debug ("Ignoring repository %s on mount %s as its on a different file system from the mount", g_debug ("Ignoring repository %s on mount %s as its on a different file system from the mount",
path, mount_name); path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error)); return glnx_throw (error, "Repository is on a different file system from the mount");
return FALSE;
} }
/* Exclude repositories which resolve to @parent_repo. */ /* Exclude repositories which resolve to @parent_repo. */
@ -245,8 +245,7 @@ scan_repo (int dfd,
{ {
g_debug ("Ignoring repository %s on mount %s as it is the same as the one we are resolving", g_debug ("Ignoring repository %s on mount %s as it is the same as the one we are resolving",
path, mount_name); path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error)); return glnx_throw (error, "Repository is the same as the one we are resolving");
return FALSE;
} }
/* List the repos refs and return them. */ /* List the repos refs and return them. */
@ -328,9 +327,9 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
g_autofree gchar *mount_name = NULL; g_autofree gchar *mount_name = NULL;
g_autoptr(GFile) mount_root = NULL; g_autoptr(GFile) mount_root = NULL;
g_autofree gchar *mount_root_path = NULL; g_autofree gchar *mount_root_path = NULL;
glnx_fd_close int mount_root_dfd = -1; glnx_autofd int mount_root_dfd = -1;
struct stat mount_root_stbuf; struct stat mount_root_stbuf;
glnx_fd_close int repos_dfd = -1; glnx_autofd int repos_dfd = -1;
gsize i; gsize i;
g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */ g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */
GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */ GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */
@ -357,6 +356,23 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
continue; continue;
} }
#if GLIB_CHECK_VERSION(2, 55, 0)
G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* remove once GLIB_VERSION_MAX_ALLOWED ≥ 2.56 */
g_autoptr(GUnixMountEntry) mount_entry = g_unix_mount_at (mount_root_path, NULL);
if (mount_entry != NULL &&
(g_unix_is_system_fs_type (g_unix_mount_get_fs_type (mount_entry)) ||
g_unix_is_system_device_path (g_unix_mount_get_device_path (mount_entry))))
{
g_debug ("Ignoring mount %s as its file system type (%s) or device "
"path (%s) indicate its a system mount.",
mount_name, g_unix_mount_get_fs_type (mount_entry),
g_unix_mount_get_device_path (mount_entry));
continue;
}
G_GNUC_END_IGNORE_DEPRECATIONS
#endif /* GLib 2.56.0 */
/* stat() the mount root so we can later check whether the resolved /* stat() the mount root so we can later check whether the resolved
* repositories for individual refs are on the same device (to avoid the * repositories for individual refs are on the same device (to avoid the
* symlinks for them pointing outside the mount root). */ * symlinks for them pointing outside the mount root). */

View File

@ -0,0 +1,322 @@
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors:
* - Philip Withnall <withnall@endlessm.com>
*/
#include "config.h"
#include <fcntl.h>
#include <gio/gio.h>
#include <glib.h>
#include <glib-object.h>
#include <libglnx.h>
#include "ostree-autocleanups.h"
#include "ostree-remote-private.h"
#include "ostree-repo.h"
#include "ostree-repo-private.h"
#include "ostree-repo-finder.h"
#include "ostree-repo-finder-override.h"
/**
* SECTION:ostree-repo-finder-override
* @title: OstreeRepoFinderOverride
* @short_description: Finds remote repositories from a list of repository URIs
* @stability: Unstable
* @include: libostree/ostree-repo-finder-override.h
*
* #OstreeRepoFinderOverride is an implementation of #OstreeRepoFinder which
* looks refs up in a list of remotes given by their URI, and returns the URIs
* which contain the refs. Duplicate remote URIs are combined into a single
* #OstreeRepoFinderResult which lists multiple refs.
*
* Each result is given an #OstreeRepoFinderResult.priority value of 20, which
* ranks its results above those from the other default #OstreeRepoFinder
* implementations.
*
* Results can only be returned for a ref if a remote and keyring are configured
* locally for the collection ID of that ref, otherwise there would be no keys
* available to verify signatures on commits for that ref.
*
* This is intended to be used for user-provided overrides and testing software
* which uses #OstreeRepoFinder. For production use, #OstreeRepoFinderConfig is
* recommended instead.
*
* Since: 2017.13
*/
static void ostree_repo_finder_override_iface_init (OstreeRepoFinderInterface *iface);
struct _OstreeRepoFinderOverride
{
GObject parent_instance;
GPtrArray *override_uris; /* (owned) (element-type utf8) */
};
G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderOverride, ostree_repo_finder_override, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (OSTREE_TYPE_REPO_FINDER, ostree_repo_finder_override_iface_init))
static gint
results_compare_cb (gconstpointer a,
gconstpointer b)
{
const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a);
const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b);
return ostree_repo_finder_result_compare (result_a, result_b);
}
/* This must return a valid remote name (suitable for use in a refspec). */
static gchar *
uri_and_keyring_to_name (const gchar *uri,
const gchar *keyring)
{
g_autofree gchar *escaped_uri = g_uri_escape_string (uri, NULL, FALSE);
g_autofree gchar *escaped_keyring = g_uri_escape_string (keyring, NULL, FALSE);
/* FIXME: Need a better separator than `_`, since its not escaped in the input. */
g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring);
for (gsize i = 0; out[i] != '\0'; i++)
{
if (out[i] == '%')
out[i] = '_';
}
g_return_val_if_fail (ostree_validate_remote_name (out, NULL), NULL);
return g_steal_pointer (&out);
}
/* Version of ostree_repo_remote_list_collection_refs() which takes an
* #OstreeRemote. */
static gboolean
repo_remote_list_collection_refs (OstreeRepo *repo,
const gchar *remote_uri,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error)
{
g_autofree gchar *name = uri_and_keyring_to_name (remote_uri, "");
g_autoptr(OstreeRemote) remote = ostree_remote_new (name);
g_key_file_set_string (remote->options, remote->group, "url", remote_uri);
gboolean remote_already_existed = _ostree_repo_add_remote (repo, remote);
gboolean success = ostree_repo_remote_list_collection_refs (repo,
remote->name,
out_all_refs,
cancellable,
error);
if (!remote_already_existed)
_ostree_repo_remove_remote (repo, remote);
return success;
}
static void
ostree_repo_finder_override_resolve_async (OstreeRepoFinder *finder,
const OstreeCollectionRef * const *refs,
OstreeRepo *parent_repo,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
OstreeRepoFinderOverride *self = OSTREE_REPO_FINDER_OVERRIDE (finder);
g_autoptr(GTask) task = NULL;
g_autoptr(GPtrArray) results = NULL;
const gint priority = 20; /* arbitrarily chosen; higher priority than the others */
gsize i, j;
g_autoptr(GHashTable) repo_remote_to_refs = NULL; /* (element-type OstreeRemote GHashTable) */
GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */
GHashTableIter iter;
const gchar *remote_uri;
OstreeRemote *remote;
task = g_task_new (finder, cancellable, callback, user_data);
g_task_set_source_tag (task, ostree_repo_finder_override_resolve_async);
results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free);
repo_remote_to_refs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
(GDestroyNotify) ostree_remote_unref,
(GDestroyNotify) g_hash_table_unref);
g_debug ("%s: Checking %u overrides", G_STRFUNC, self->override_uris->len);
for (i = 0; i < self->override_uris->len; i++)
{
g_autoptr(GError) local_error = NULL;
g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */
const gchar *checksum;
gboolean resolved_a_ref = FALSE;
remote_uri = self->override_uris->pdata[i];
if (!repo_remote_list_collection_refs (parent_repo, remote_uri,
&remote_refs, cancellable,
&local_error))
{
g_debug ("Ignoring remote %s due to error loading its refs: %s",
remote_uri, local_error->message);
g_clear_error (&local_error);
continue;
}
for (j = 0; refs[j] != NULL; j++)
{
g_autoptr(OstreeRemote) keyring_remote = NULL;
/* Look up the GPG keyring for this ref. */
keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo,
refs[j]->collection_id,
cancellable, &local_error);
if (keyring_remote == NULL)
{
g_debug ("Ignoring ref (%s, %s) due to missing keyring: %s",
refs[j]->collection_id, refs[j]->ref_name, local_error->message);
g_clear_error (&local_error);
continue;
}
if (g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum))
{
g_autoptr(OstreeRemote) remote = NULL;
/* The requested ref is listed in the refs for this remote. Add
* the remote to the results, and the ref to its
* @supported_ref_to_checksum. */
g_debug ("Resolved ref (%s, %s) to remote %s.",
refs[j]->collection_id, refs[j]->ref_name, remote_uri);
resolved_a_ref = TRUE;
/* Build an #OstreeRemote. Use the escaped URI, since remote->name
* is used in file paths, so needs to not contain special characters. */
g_autofree gchar *name = uri_and_keyring_to_name (remote_uri, keyring_remote->name);
remote = ostree_remote_new_dynamic (name, keyring_remote->name);
/* gpg-verify-summary is false since we use the unsigned summary file support. */
g_key_file_set_string (remote->options, remote->group, "url", remote_uri);
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE);
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE);
supported_ref_to_checksum = g_hash_table_lookup (repo_remote_to_refs, remote);
if (supported_ref_to_checksum == NULL)
{
supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash,
ostree_collection_ref_equal,
NULL, g_free);
g_hash_table_insert (repo_remote_to_refs, ostree_remote_ref (remote), supported_ref_to_checksum /* transfer */);
}
g_hash_table_insert (supported_ref_to_checksum,
(gpointer) refs[j], g_strdup (checksum));
}
}
if (!resolved_a_ref)
g_debug ("Ignoring remote %s due to it not advertising any of the requested refs.",
remote_uri);
}
/* Aggregate the results. */
g_hash_table_iter_init (&iter, repo_remote_to_refs);
while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum))
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
g_ptr_array_sort (results, results_compare_cb);
g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref);
}
static GPtrArray *
ostree_repo_finder_override_resolve_finish (OstreeRepoFinder *finder,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, finder), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
static void
ostree_repo_finder_override_init (OstreeRepoFinderOverride *self)
{
self->override_uris = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
}
static void
ostree_repo_finder_override_finalize (GObject *object)
{
OstreeRepoFinderOverride *self = OSTREE_REPO_FINDER_OVERRIDE (object);
g_clear_pointer (&self->override_uris, g_ptr_array_unref);
G_OBJECT_CLASS (ostree_repo_finder_override_parent_class)->finalize (object);
}
static void
ostree_repo_finder_override_class_init (OstreeRepoFinderOverrideClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ostree_repo_finder_override_finalize;
}
static void
ostree_repo_finder_override_iface_init (OstreeRepoFinderInterface *iface)
{
iface->resolve_async = ostree_repo_finder_override_resolve_async;
iface->resolve_finish = ostree_repo_finder_override_resolve_finish;
}
/**
* ostree_repo_finder_override_new:
*
* Create a new #OstreeRepoFinderOverride.
*
* Returns: (transfer full): a new #OstreeRepoFinderOverride
* Since: 2017.13
*/
OstreeRepoFinderOverride *
ostree_repo_finder_override_new (void)
{
return g_object_new (OSTREE_TYPE_REPO_FINDER_OVERRIDE, NULL);
}
/**
* ostree_repo_finder_override_add_uri:
* @uri: URI to add to the repo finder
*
* Add the given @uri to the set of URIs which the repo finder will search for
* matching refs when ostree_repo_finder_resolve_async() is called on it.
*
* Since: 2017.13
*/
void
ostree_repo_finder_override_add_uri (OstreeRepoFinderOverride *self,
const gchar *uri)
{
g_return_if_fail (OSTREE_IS_REPO_FINDER_OVERRIDE (self));
g_return_if_fail (uri != NULL);
g_ptr_array_add (self->override_uris, g_strdup (uri));
}

View File

@ -0,0 +1,58 @@
/*
* Copyright © 2017 Endless Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors:
* - Philip Withnall <withnall@endlessm.com>
*/
#pragma once
#include <gio/gio.h>
#include <glib.h>
#include <glib-object.h>
#include "ostree-repo-finder.h"
#include "ostree-types.h"
G_BEGIN_DECLS
#define OSTREE_TYPE_REPO_FINDER_OVERRIDE (ostree_repo_finder_override_get_type ())
/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44):
_OSTREE_PUBLIC
G_DECLARE_FINAL_TYPE (OstreeRepoFinderOverride, ostree_repo_finder_override, OSTREE, REPO_FINDER_OVERRIDE, GObject) */
_OSTREE_PUBLIC
GType ostree_repo_finder_override_get_type (void);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct _OstreeRepoFinderOverride OstreeRepoFinderOverride;
typedef struct { GObjectClass parent_class; } OstreeRepoFinderOverrideClass;
static inline OstreeRepoFinderOverride *OSTREE_REPO_FINDER_OVERRIDE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_override_get_type (), OstreeRepoFinderOverride); }
static inline gboolean OSTREE_IS_REPO_FINDER_OVERRIDE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_override_get_type ()); }
G_GNUC_END_IGNORE_DEPRECATIONS
_OSTREE_PUBLIC
OstreeRepoFinderOverride *ostree_repo_finder_override_new (void);
_OSTREE_PUBLIC
void ostree_repo_finder_override_add_uri (OstreeRepoFinderOverride *self,
const gchar *uri);
G_END_DECLS

View File

@ -365,20 +365,11 @@ _ostree_repo_commit_tmpf_final (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean
_ostree_repo_commit_path_final (OstreeRepo *self,
const char *checksum,
OstreeObjectType objtype,
OtCleanupUnlinkat *tmp_path,
GCancellable *cancellable,
GError **error);
gboolean gboolean
_ostree_repo_open_content_bare (OstreeRepo *self, _ostree_repo_open_content_bare (OstreeRepo *self,
const char *checksum, const char *checksum,
guint64 content_len, guint64 content_len,
GLnxTmpfile *out_tmpf, GLnxTmpfile *out_tmpf,
gboolean *out_have_object,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);

View File

@ -105,11 +105,12 @@ typedef struct {
GVariant *summary; GVariant *summary;
GHashTable *summary_deltas_checksums; GHashTable *summary_deltas_checksums;
GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */
GHashTable *gpg_verified_commits; /* Set<checksum> of commits that have been verified */
GPtrArray *static_delta_superblocks; GPtrArray *static_delta_superblocks;
GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */
GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */
GHashTable *scanned_metadata; /* Maps object name to itself */ GHashTable *scanned_metadata; /* Maps object name to itself */
GHashTable *fetched_detached_metadata; /* Set<checksum> */ GHashTable *fetched_detached_metadata; /* Map<checksum,GVariant> */
GHashTable *requested_metadata; /* Maps object name to itself */ GHashTable *requested_metadata; /* Maps object name to itself */
GHashTable *requested_content; /* Maps checksum to itself */ GHashTable *requested_content; /* Maps checksum to itself */
GHashTable *requested_fallback_content; /* Maps checksum to itself */ GHashTable *requested_fallback_content; /* Maps checksum to itself */
@ -142,6 +143,7 @@ typedef struct {
guint64 start_time; guint64 start_time;
gboolean is_mirror; gboolean is_mirror;
gboolean trusted_http_direct;
gboolean is_commit_only; gboolean is_commit_only;
OstreeRepoImportFlags importflags; OstreeRepoImportFlags importflags;
@ -191,6 +193,13 @@ typedef struct {
OstreeCollectionRef *requested_ref; /* (nullable) */ OstreeCollectionRef *requested_ref; /* (nullable) */
} ScanObjectQueueData; } ScanObjectQueueData;
static void
variant_or_null_unref (gpointer data)
{
if (data)
g_variant_unref (data);
}
static void start_fetch (OtPullData *pull_data, FetchObjectData *fetch); static void start_fetch (OtPullData *pull_data, FetchObjectData *fetch);
static void start_fetch_deltapart (OtPullData *pull_data, static void start_fetch_deltapart (OtPullData *pull_data,
FetchStaticDeltaData *fetch); FetchStaticDeltaData *fetch);
@ -209,8 +218,8 @@ static void queue_scan_one_metadata_object_c (OtPullData *pull_da
guint recursion_depth, guint recursion_depth,
const OstreeCollectionRef *ref); const OstreeCollectionRef *ref);
static gboolean scan_one_metadata_object_c (OtPullData *pull_data, static gboolean scan_one_metadata_object (OtPullData *pull_data,
const guchar *csum, const char *checksum,
OstreeObjectType objtype, OstreeObjectType objtype,
const char *path, const char *path,
guint recursion_depth, guint recursion_depth,
@ -218,6 +227,14 @@ static gboolean scan_one_metadata_object_c (OtPullData *pull_dat
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
static void scan_object_queue_data_free (ScanObjectQueueData *scan_data); static void scan_object_queue_data_free (ScanObjectQueueData *scan_data);
static gboolean
gpg_verify_unwritten_commit (OtPullData *pull_data,
const char *checksum,
GVariant *commit,
GVariant *detached_metadata,
GCancellable *cancellable,
GError **error);
static gboolean static gboolean
update_progress (gpointer user_data) update_progress (gpointer user_data)
@ -450,6 +467,11 @@ scan_object_queue_data_free (ScanObjectQueueData *scan_data)
g_free (scan_data); g_free (scan_data);
} }
/* Called out of the main loop to process the "scan object queue", which is a
* queue of metadata objects (commits and dirtree, but not dirmeta) to parse to
* look for further objects. Basically wraps execution of
* `scan_one_metadata_object()`.
*/
static gboolean static gboolean
idle_worker (gpointer user_data) idle_worker (gpointer user_data)
{ {
@ -464,14 +486,11 @@ idle_worker (gpointer user_data)
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
scan_one_metadata_object_c (pull_data, char checksum[OSTREE_SHA256_STRING_LEN+1];
scan_data->csum, ostree_checksum_inplace_from_bytes (scan_data->csum, checksum);
scan_data->objtype, scan_one_metadata_object (pull_data, checksum, scan_data->objtype,
scan_data->path, scan_data->path, scan_data->recursion_depth,
scan_data->recursion_depth, scan_data->requested_ref, pull_data->cancellable, &error);
scan_data->requested_ref,
pull_data->cancellable,
&error);
check_outstanding_requests_handle_error (pull_data, &error); check_outstanding_requests_handle_error (pull_data, &error);
scan_object_queue_data_free (scan_data); scan_object_queue_data_free (scan_data);
@ -544,7 +563,7 @@ write_commitpartial_for (OtPullData *pull_data,
GError **error) GError **error)
{ {
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum); g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum);
glnx_fd_close int fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); glnx_autofd int fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644);
if (fd == -1) if (fd == -1)
{ {
if (errno != EEXIST) if (errno != EEXIST)
@ -844,7 +863,7 @@ fetch_ref_contents (OtPullData *pull_data,
{ {
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API #ifdef OSTREE_ENABLE_EXPERIMENTAL_API
if (!ostree_repo_resolve_collection_ref (pull_data->remote_repo_local, if (!ostree_repo_resolve_collection_ref (pull_data->remote_repo_local,
ref, TRUE /* ignore enoent */, ref, FALSE,
OSTREE_REPO_RESOLVE_REV_EXT_NONE, OSTREE_REPO_RESOLVE_REV_EXT_NONE,
&ret_contents, cancellable, error)) &ret_contents, cancellable, error))
return FALSE; return FALSE;
@ -855,7 +874,7 @@ fetch_ref_contents (OtPullData *pull_data,
else if (pull_data->remote_repo_local != NULL) else if (pull_data->remote_repo_local != NULL)
{ {
if (!ostree_repo_resolve_rev_ext (pull_data->remote_repo_local, if (!ostree_repo_resolve_rev_ext (pull_data->remote_repo_local,
ref->ref_name, TRUE /* ignore enoent */, ref->ref_name, FALSE,
OSTREE_REPO_RESOLVE_REV_EXT_NONE, OSTREE_REPO_RESOLVE_REV_EXT_NONE,
&ret_contents, error)) &ret_contents, error))
return FALSE; return FALSE;
@ -874,14 +893,13 @@ fetch_ref_contents (OtPullData *pull_data,
filename, &ret_contents, filename, &ret_contents,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
g_strchomp (ret_contents);
} }
/* Validate and return. */ g_assert (ret_contents);
if (ret_contents != NULL)
g_strchomp (ret_contents);
if (ret_contents == NULL || if (!ostree_validate_checksum_string (ret_contents, error))
!ostree_validate_checksum_string (ret_contents, error))
return glnx_prefix_error (error, "Fetching checksum for ref (%s, %s)", return glnx_prefix_error (error, "Fetching checksum for ref (%s, %s)",
ref->collection_id ? ref->collection_id : "(empty)", ref->collection_id ? ref->collection_id : "(empty)",
ref->ref_name); ref->ref_name);
@ -987,13 +1005,8 @@ content_fetch_on_write_complete (GObject *object,
checksum_obj = ostree_object_to_string (checksum, objtype); checksum_obj = ostree_object_to_string (checksum, objtype);
g_debug ("write of %s complete", checksum_obj); g_debug ("write of %s complete", checksum_obj);
if (strcmp (checksum, expected_checksum) != 0) if (!_ostree_compare_object_checksum (objtype, expected_checksum, checksum, error))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted content object; checksum expected='%s' actual='%s'",
expected_checksum, checksum);
goto out; goto out;
}
pull_data->n_fetched_content++; pull_data->n_fetched_content++;
/* Was this a delta fallback? */ /* Was this a delta fallback? */
@ -1017,17 +1030,18 @@ content_fetch_on_complete (GObject *object,
GError **error = &local_error; GError **error = &local_error;
GCancellable *cancellable = NULL; GCancellable *cancellable = NULL;
guint64 length; guint64 length;
g_auto(GLnxTmpfile) tmpf = { 0, };
g_autoptr(GInputStream) tmpf_input = NULL;
g_autoptr(GFileInfo) file_info = NULL; g_autoptr(GFileInfo) file_info = NULL;
g_autoptr(GVariant) xattrs = NULL; g_autoptr(GVariant) xattrs = NULL;
g_autoptr(GInputStream) file_in = NULL; g_autoptr(GInputStream) file_in = NULL;
g_autoptr(GInputStream) object_input = NULL; g_autoptr(GInputStream) object_input = NULL;
g_auto(OtCleanupUnlinkat) tmp_unlinker = { _ostree_fetcher_get_dfd (fetcher), NULL };
const char *checksum; const char *checksum;
g_autofree char *checksum_obj = NULL; g_autofree char *checksum_obj = NULL;
OstreeObjectType objtype; OstreeObjectType objtype;
gboolean free_fetch_data = TRUE; gboolean free_fetch_data = TRUE;
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmp_unlinker.path, error)) if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error))
goto out; goto out;
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype); ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
@ -1039,48 +1053,31 @@ content_fetch_on_complete (GObject *object,
const gboolean verifying_bareuseronly = const gboolean verifying_bareuseronly =
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0; (pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0;
/* If we're mirroring and writing into an archive repo, and both checksum and /* See comments where we set this variable; this is implementing
* bareuseronly are turned off, we can directly copy the content rather than * the --trusted-http/OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP flags.
* paying the cost of exploding it, checksumming, and re-gzip.
*/ */
const gboolean mirroring_into_archive = if (pull_data->trusted_http_direct)
pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE;
const gboolean import_trusted = !verifying_bareuseronly &&
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_TRUSTED) > 0;
if (mirroring_into_archive && import_trusted)
{ {
gboolean have_object; g_assert (!verifying_bareuseronly);
if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum, if (!_ostree_repo_commit_tmpf_final (pull_data->repo, checksum, objtype,
&have_object, &tmpf, cancellable, error))
cancellable, error))
goto out; goto out;
if (!have_object)
{
if (!_ostree_repo_commit_path_final (pull_data->repo, checksum, objtype,
&tmp_unlinker,
cancellable, error))
goto out;
}
pull_data->n_fetched_content++; pull_data->n_fetched_content++;
} }
else else
{ {
struct stat stbuf;
if (!glnx_fstat (tmpf.fd, &stbuf, error))
goto out;
/* Non-mirroring path */ /* Non-mirroring path */
tmpf_input = g_unix_input_stream_new (glnx_steal_fd (&tmpf.fd), TRUE);
/* If it appears corrupted, we'll delete it below */ /* If it appears corrupted, we'll delete it below */
if (!ostree_content_file_parse_at (TRUE, _ostree_fetcher_get_dfd (fetcher), if (!ostree_content_stream_parse (TRUE, tmpf_input, stbuf.st_size, FALSE,
tmp_unlinker.path, FALSE,
&file_in, &file_info, &xattrs, &file_in, &file_info, &xattrs,
cancellable, error)) cancellable, error))
goto out; goto out;
/* Also, delete it now that we've opened it, we'll hold
* a reference to the fd. If we fail to validate or write, then
* the temp space will be cleaned up.
*/
ot_cleanup_unlinkat (&tmp_unlinker);
if (verifying_bareuseronly) if (verifying_bareuseronly)
{ {
if (!_ostree_validate_bareuseronly_mode_finfo (file_info, checksum, error)) if (!_ostree_validate_bareuseronly_mode_finfo (file_info, checksum, error))
@ -1160,13 +1157,12 @@ meta_fetch_on_complete (GObject *object,
FetchObjectData *fetch_data = user_data; FetchObjectData *fetch_data = user_data;
OtPullData *pull_data = fetch_data->pull_data; OtPullData *pull_data = fetch_data->pull_data;
g_autoptr(GVariant) metadata = NULL; g_autoptr(GVariant) metadata = NULL;
g_auto(OtCleanupUnlinkat) tmp_unlinker = { _ostree_fetcher_get_dfd (fetcher), NULL }; g_auto(GLnxTmpfile) tmpf = { 0, };
const char *checksum; const char *checksum;
g_autofree char *checksum_obj = NULL; g_autofree char *checksum_obj = NULL;
OstreeObjectType objtype; OstreeObjectType objtype;
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
GError **error = &local_error; GError **error = &local_error;
glnx_fd_close int fd = -1;
gboolean free_fetch_data = TRUE; gboolean free_fetch_data = TRUE;
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype); ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
@ -1174,7 +1170,7 @@ meta_fetch_on_complete (GObject *object,
g_debug ("fetch of %s%s complete", checksum_obj, g_debug ("fetch of %s%s complete", checksum_obj,
fetch_data->is_detached_meta ? " (detached)" : ""); fetch_data->is_detached_meta ? " (detached)" : "");
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmp_unlinker.path, error)) if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error))
{ {
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{ {
@ -1185,7 +1181,7 @@ meta_fetch_on_complete (GObject *object,
/* Now that we've at least tried to fetch it, we can proceed to /* Now that we've at least tried to fetch it, we can proceed to
* scan/fetch the commit object */ * scan/fetch the commit object */
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (checksum)); g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL);
if (!fetch_data->object_is_stored) if (!fetch_data->object_is_stored)
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref); enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref);
@ -1217,17 +1213,9 @@ meta_fetch_on_complete (GObject *object,
if (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT)
goto out; goto out;
if (!glnx_openat_rdonly (_ostree_fetcher_get_dfd (fetcher), tmp_unlinker.path, TRUE, &fd, error))
goto out;
/* Now delete it, keeping the fd open as the last reference; see comment in
* corresponding content fetch path.
*/
ot_cleanup_unlinkat (&tmp_unlinker);
if (fetch_data->is_detached_meta) if (fetch_data->is_detached_meta)
{ {
if (!ot_util_variant_map_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), if (!ot_variant_read_fd (tmpf.fd, 0, G_VARIANT_TYPE ("a{sv}"),
FALSE, &metadata, error)) FALSE, &metadata, error))
goto out; goto out;
@ -1235,7 +1223,7 @@ meta_fetch_on_complete (GObject *object,
pull_data->cancellable, error)) pull_data->cancellable, error))
goto out; goto out;
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (checksum)); g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), g_steal_pointer (&metadata));
if (!fetch_data->object_is_stored) if (!fetch_data->object_is_stored)
enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref); enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref);
@ -1244,13 +1232,40 @@ meta_fetch_on_complete (GObject *object,
} }
else else
{ {
if (!ot_util_variant_map_fd (fd, 0, ostree_metadata_variant_type (objtype), if (!ot_variant_read_fd (tmpf.fd, 0, ostree_metadata_variant_type (objtype),
FALSE, &metadata, error)) FALSE, &metadata, error))
goto out; goto out;
/* Write the commitpartial file now while we're still fetching data */ /* For commit objects, compute the hash and check the GPG signature before
* writing to the repo, and also write the .commitpartial to say that
* we're still processing this commit.
*/
if (objtype == OSTREE_OBJECT_TYPE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{ {
/* Verify checksum */
OtChecksum hasher = { 0, };
ot_checksum_init (&hasher);
{ g_autoptr(GBytes) bytes = g_variant_get_data_as_bytes (metadata);
ot_checksum_update_bytes (&hasher, bytes);
}
char hexdigest[OSTREE_SHA256_STRING_LEN+1];
ot_checksum_get_hexdigest (&hasher, hexdigest, sizeof (hexdigest));
if (!_ostree_compare_object_checksum (objtype, checksum, hexdigest, error))
goto out;
/* Do GPG verification. `detached_data` may be NULL if no detached
* metadata was found during pull; that's handled by
* gpg_verify_unwritten_commit(). If we ever change the pull code to
* not always fetch detached metadata, this bit will have to learn how
* to look up from the disk state as well, or insert the on-disk
* metadata into this hash.
*/
GVariant *detached_data = g_hash_table_lookup (pull_data->fetched_detached_metadata, checksum);
if (!gpg_verify_unwritten_commit (pull_data, checksum, metadata, detached_data,
pull_data->cancellable, error))
goto out;
if (!write_commitpartial_for (pull_data, checksum, error)) if (!write_commitpartial_for (pull_data, checksum, error))
goto out; goto out;
} }
@ -1313,27 +1328,20 @@ static_deltapart_fetch_on_complete (GObject *object,
OstreeFetcher *fetcher = (OstreeFetcher *)object; OstreeFetcher *fetcher = (OstreeFetcher *)object;
FetchStaticDeltaData *fetch_data = user_data; FetchStaticDeltaData *fetch_data = user_data;
OtPullData *pull_data = fetch_data->pull_data; OtPullData *pull_data = fetch_data->pull_data;
g_autofree char *temp_path = NULL; g_auto(GLnxTmpfile) tmpf = { 0, };
g_autoptr(GInputStream) in = NULL; g_autoptr(GInputStream) in = NULL;
g_autoptr(GVariant) part = NULL; g_autoptr(GVariant) part = NULL;
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
GError **error = &local_error; GError **error = &local_error;
glnx_fd_close int fd = -1;
gboolean free_fetch_data = TRUE; gboolean free_fetch_data = TRUE;
g_debug ("fetch static delta part %s complete", fetch_data->expected_checksum); g_debug ("fetch static delta part %s complete", fetch_data->expected_checksum);
if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &temp_path, error)) if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error))
goto out; goto out;
if (!glnx_openat_rdonly (_ostree_fetcher_get_dfd (fetcher), temp_path, TRUE, &fd, error)) /* Transfer ownership of the fd */
goto out; in = g_unix_input_stream_new (glnx_steal_fd (&tmpf.fd), TRUE);
/* From here on, if we fail to apply the delta, we'll re-fetch it */
if (!glnx_unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0, error))
goto out;
in = g_unix_input_stream_new (fd, FALSE);
/* TODO - make async */ /* TODO - make async */
if (!_ostree_static_delta_part_open (in, NULL, 0, fetch_data->expected_checksum, if (!_ostree_static_delta_part_open (in, NULL, 0, fetch_data->expected_checksum,
@ -1377,6 +1385,14 @@ process_verify_result (OtPullData *pull_data,
if (!ostree_gpg_verify_result_require_valid_signature (result, error)) if (!ostree_gpg_verify_result_require_valid_signature (result, error))
return FALSE; return FALSE;
/* We now check both *before* writing the commit, and after. Because the
* behavior used to be only verifiying after writing, we need to handle
* the case of "written but not verified". But we also don't want to check
* twice, as that'd result in duplicate signals.
*/
g_hash_table_add (pull_data->gpg_verified_commits, g_strdup (checksum));
return TRUE; return TRUE;
} }
@ -1390,24 +1406,15 @@ gpg_verify_unwritten_commit (OtPullData *pull_data,
{ {
if (pull_data->gpg_verify) if (pull_data->gpg_verify)
{ {
g_autoptr(OstreeGpgVerifyResult) result = NULL; /* Shouldn't happen, but see comment in process_verify_result() */
if (g_hash_table_contains (pull_data->gpg_verified_commits, checksum))
return TRUE;
g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit); g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit);
g_autoptr(OstreeGpgVerifyResult) result =
if (!detached_metadata) _ostree_repo_gpg_verify_with_metadata (pull_data->repo, signed_data,
{ detached_metadata, pull_data->remote_name,
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, NULL, NULL, cancellable, error);
"Commit %s: no detached metadata found for GPG verification",
checksum);
return FALSE;
}
result = _ostree_repo_gpg_verify_with_metadata (pull_data->repo,
signed_data,
detached_metadata,
pull_data->remote_name,
NULL, NULL,
cancellable,
error);
if (!process_verify_result (pull_data, checksum, result, error)) if (!process_verify_result (pull_data, checksum, result, error))
return FALSE; return FALSE;
} }
@ -1431,6 +1438,10 @@ static char *
get_real_remote_repo_collection_id (OstreeRepo *repo, get_real_remote_repo_collection_id (OstreeRepo *repo,
const gchar *remote_name) const gchar *remote_name)
{ {
/* remote_name == NULL can happen for pull-local */
if (!remote_name)
return NULL;
g_autofree gchar *remote_collection_id = NULL; g_autofree gchar *remote_collection_id = NULL;
if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL, if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL,
&remote_collection_id, NULL) || &remote_collection_id, NULL) ||
@ -1586,7 +1597,11 @@ scan_commit_object (OtPullData *pull_data,
GINT_TO_POINTER (depth)); GINT_TO_POINTER (depth));
} }
if (pull_data->gpg_verify) /* See comment in process_verify_result() - we now gpg check before writing,
* but also ensure we've done it here if not already.
*/
if (pull_data->gpg_verify &&
!g_hash_table_contains (pull_data->gpg_verified_commits, checksum))
{ {
g_autoptr(OstreeGpgVerifyResult) result = NULL; g_autoptr(OstreeGpgVerifyResult) result = NULL;
@ -1753,9 +1768,13 @@ queue_scan_one_metadata_object_c (OtPullData *pull_data,
ensure_idle_queued (pull_data); ensure_idle_queued (pull_data);
} }
/* Called out of the main loop to look at metadata objects which can have
* further references (commit, dirtree). See also idle_worker() which drives
* execution of this function.
*/
static gboolean static gboolean
scan_one_metadata_object_c (OtPullData *pull_data, scan_one_metadata_object (OtPullData *pull_data,
const guchar *csum, const char *checksum,
OstreeObjectType objtype, OstreeObjectType objtype,
const char *path, const char *path,
guint recursion_depth, guint recursion_depth,
@ -1763,8 +1782,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autofree char *tmp_checksum = ostree_checksum_from_bytes (csum); g_autoptr(GVariant) object = ostree_object_name_serialize (checksum, objtype);
g_autoptr(GVariant) object = ostree_object_name_serialize (tmp_checksum, objtype);
/* It may happen that we've already looked at this object (think shared /* It may happen that we've already looked at this object (think shared
* dirtree subtrees), if that's the case, we're done */ * dirtree subtrees), if that's the case, we're done */
@ -1774,7 +1792,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
gboolean is_requested = g_hash_table_lookup (pull_data->requested_metadata, object) != NULL; gboolean is_requested = g_hash_table_lookup (pull_data->requested_metadata, object) != NULL;
/* Determine if we already have the object */ /* Determine if we already have the object */
gboolean is_stored; gboolean is_stored;
if (!ostree_repo_has_object (pull_data->repo, objtype, tmp_checksum, &is_stored, if (!ostree_repo_has_object (pull_data->repo, objtype, checksum, &is_stored,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
@ -1784,19 +1802,19 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (objtype == OSTREE_OBJECT_TYPE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{ {
/* mark as partial to ensure we scan the commit below */ /* mark as partial to ensure we scan the commit below */
if (!write_commitpartial_for (pull_data, tmp_checksum, error)) if (!write_commitpartial_for (pull_data, checksum, error))
return FALSE; return FALSE;
} }
if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local, if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local,
objtype, tmp_checksum, pull_data->importflags, objtype, checksum, pull_data->importflags,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
/* The import API will fetch both the commit and detached metadata, so /* The import API will fetch both the commit and detached metadata, so
* add it to the hash to avoid re-fetching it below. * add it to the hash to avoid re-fetching it below.
*/ */
if (objtype == OSTREE_OBJECT_TYPE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (tmp_checksum)); g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL);
pull_data->n_imported_metadata++; pull_data->n_imported_metadata++;
is_stored = TRUE; is_stored = TRUE;
is_requested = TRUE; is_requested = TRUE;
@ -1809,7 +1827,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
OstreeRepo *refd_repo = pull_data->localcache_repos->pdata[i]; OstreeRepo *refd_repo = pull_data->localcache_repos->pdata[i];
gboolean localcache_repo_has_obj; gboolean localcache_repo_has_obj;
if (!ostree_repo_has_object (refd_repo, objtype, tmp_checksum, if (!ostree_repo_has_object (refd_repo, objtype, checksum,
&localcache_repo_has_obj, cancellable, error)) &localcache_repo_has_obj, cancellable, error))
return FALSE; return FALSE;
if (!localcache_repo_has_obj) if (!localcache_repo_has_obj)
@ -1817,16 +1835,16 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (objtype == OSTREE_OBJECT_TYPE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{ {
/* mark as partial to ensure we scan the commit below */ /* mark as partial to ensure we scan the commit below */
if (!write_commitpartial_for (pull_data, tmp_checksum, error)) if (!write_commitpartial_for (pull_data, checksum, error))
return FALSE; return FALSE;
} }
if (!_ostree_repo_import_object (pull_data->repo, refd_repo, if (!_ostree_repo_import_object (pull_data->repo, refd_repo,
objtype, tmp_checksum, pull_data->importflags, objtype, checksum, pull_data->importflags,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
/* See comment above */ /* See comment above */
if (objtype == OSTREE_OBJECT_TYPE_COMMIT) if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (pull_data->fetched_detached_metadata, g_strdup (tmp_checksum)); g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL);
is_stored = TRUE; is_stored = TRUE;
is_requested = TRUE; is_requested = TRUE;
pull_data->n_imported_metadata++; pull_data->n_imported_metadata++;
@ -1841,18 +1859,18 @@ scan_one_metadata_object_c (OtPullData *pull_data,
g_hash_table_add (pull_data->requested_metadata, g_variant_ref (object)); g_hash_table_add (pull_data->requested_metadata, g_variant_ref (object));
do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT); do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT);
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, do_fetch_detached, FALSE, ref); enqueue_one_object_request (pull_data, checksum, objtype, path, do_fetch_detached, FALSE, ref);
} }
else if (is_stored && objtype == OSTREE_OBJECT_TYPE_COMMIT) else if (is_stored && objtype == OSTREE_OBJECT_TYPE_COMMIT)
{ {
/* Even though we already have the commit, we always try to (re)fetch the /* Even though we already have the commit, we always try to (re)fetch the
* detached metadata before scanning it, in case new signatures appear. * detached metadata before scanning it, in case new signatures appear.
* https://github.com/projectatomic/rpm-ostree/issues/630 */ * https://github.com/projectatomic/rpm-ostree/issues/630 */
if (!g_hash_table_contains (pull_data->fetched_detached_metadata, tmp_checksum)) if (!g_hash_table_contains (pull_data->fetched_detached_metadata, checksum))
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, TRUE, TRUE, ref); enqueue_one_object_request (pull_data, checksum, objtype, path, TRUE, TRUE, ref);
else else
{ {
if (!scan_commit_object (pull_data, tmp_checksum, recursion_depth, ref, if (!scan_commit_object (pull_data, checksum, recursion_depth, ref,
pull_data->cancellable, error)) pull_data->cancellable, error))
return FALSE; return FALSE;
@ -1862,7 +1880,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
} }
else if (is_stored && objtype == OSTREE_OBJECT_TYPE_DIR_TREE) else if (is_stored && objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
{ {
if (!scan_dirtree_object (pull_data, tmp_checksum, path, recursion_depth, if (!scan_dirtree_object (pull_data, checksum, path, recursion_depth,
pull_data->cancellable, error)) pull_data->cancellable, error))
return FALSE; return FALSE;
@ -1975,6 +1993,8 @@ start_fetch (OtPullData *pull_data,
else else
expected_max_size = 0; expected_max_size = 0;
if (!is_meta && pull_data->trusted_http_direct)
flags |= OSTREE_FETCHER_REQUEST_LINKABLE;
_ostree_fetcher_request_to_tmpfile (pull_data->fetcher, mirrorlist, _ostree_fetcher_request_to_tmpfile (pull_data->fetcher, mirrorlist,
obj_subpath, flags, expected_max_size, obj_subpath, flags, expected_max_size,
is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
@ -2441,34 +2461,28 @@ on_superblock_fetched (GObject *src,
} }
else else
{ {
g_autofree gchar *delta = NULL;
g_autofree guchar *ret_csum = NULL;
guchar *summary_csum;
g_autoptr (GInputStream) summary_is = NULL;
g_autoptr(GVariant) delta_superblock = NULL; g_autoptr(GVariant) delta_superblock = NULL;
g_autofree gchar *delta = g_strconcat (from_revision ? from_revision : "", from_revision ? "-" : "", to_revision, NULL);
const guchar *expected_summary_digest = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta);
guint8 actual_summary_digest[OSTREE_SHA256_DIGEST_LEN];
summary_is = g_memory_input_stream_new_from_data (g_bytes_get_data (delta_superblock_data, NULL), g_auto(OtChecksum) hasher = { 0, };
g_bytes_get_size (delta_superblock_data), ot_checksum_init (&hasher);
NULL); ot_checksum_update_bytes (&hasher, delta_superblock_data);
ot_checksum_get_digest (&hasher, actual_summary_digest, sizeof (actual_summary_digest));
if (!ot_gio_checksum_stream (summary_is, &ret_csum, pull_data->cancellable, error))
goto out;
delta = g_strconcat (from_revision ? from_revision : "", from_revision ? "-" : "", to_revision, NULL);
summary_csum = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta);
/* At this point we've GPG verified the data, so in theory /* At this point we've GPG verified the data, so in theory
* could trust that they provided the right data, but let's * could trust that they provided the right data, but let's
* make this a hard error. * make this a hard error.
*/ */
if (pull_data->gpg_verify_summary && !summary_csum) if (pull_data->gpg_verify_summary && !expected_summary_digest)
{ {
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
goto out; goto out;
} }
if (summary_csum && memcmp (summary_csum, ret_csum, 32)) if (expected_summary_digest && memcmp (expected_summary_digest, actual_summary_digest, sizeof (actual_summary_digest)))
{ {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid checksum for static delta %s", delta); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid checksum for static delta %s", delta);
goto out; goto out;
@ -2520,7 +2534,7 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
return TRUE; return TRUE;
const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig");
glnx_fd_close int prev_fd = -1; glnx_autofd int prev_fd = -1;
if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error)) if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error))
return FALSE; return FALSE;
if (prev_fd < 0) if (prev_fd < 0)
@ -2533,7 +2547,7 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
if (g_bytes_compare (old_sig_contents, summary_sig) == 0) if (g_bytes_compare (old_sig_contents, summary_sig) == 0)
{ {
const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote);
glnx_fd_close int summary_fd = -1; glnx_autofd int summary_fd = -1;
GBytes *summary_data; GBytes *summary_data;
@ -3031,7 +3045,7 @@ initiate_delta_request (OtPullData *pull_data,
_ostree_fetcher_request_to_membuf (pull_data->fetcher, _ostree_fetcher_request_to_membuf (pull_data->fetcher,
pull_data->content_mirrorlist, pull_data->content_mirrorlist,
delta_name, 0, delta_name, OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
OSTREE_MAX_METADATA_SIZE, OSTREE_MAX_METADATA_SIZE,
0, pull_data->cancellable, 0, pull_data->cancellable,
on_superblock_fetched, fdata); on_superblock_fetched, fdata);
@ -3302,10 +3316,12 @@ ostree_repo_pull_with_options (OstreeRepo *self,
pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal,
(GDestroyNotify)NULL, (GDestroyNotify)NULL,
(GDestroyNotify)g_variant_unref); (GDestroyNotify)g_variant_unref);
pull_data->gpg_verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
(GDestroyNotify)g_variant_unref, NULL); (GDestroyNotify)g_variant_unref, NULL);
pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL); (GDestroyNotify)g_free, (GDestroyNotify)variant_or_null_unref);
pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal, pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL); (GDestroyNotify)g_free, NULL);
pull_data->requested_fallback_content = g_hash_table_new_full (g_str_hash, g_str_equal, pull_data->requested_fallback_content = g_hash_table_new_full (g_str_hash, g_str_equal,
@ -3532,8 +3548,12 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri); g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri);
/* NB: we don't support local mirrors in mirrorlists, so if this passes, it /* NB: we don't support local mirrors in mirrorlists, so if this passes, it
* means that we're not using mirrorlists (see also fetch_mirrorlist()) */ * means that we're not using mirrorlists (see also fetch_mirrorlist())
if (g_str_equal (first_scheme, "file")) * Also, we explicitly disable the "local repo" path if static deltas
* were explicitly requested to be required; this is going to happen
* most often for testing deltas without setting up a HTTP server.
*/
if (g_str_equal (first_scheme, "file") && !pull_data->require_static_deltas)
{ {
g_autofree char *path = _ostree_fetcher_uri_get_path (first_uri); g_autofree char *path = _ostree_fetcher_uri_get_path (first_uri);
g_autoptr(GFile) remote_repo_path = g_file_new_for_path (path); g_autoptr(GFile) remote_repo_path = g_file_new_for_path (path);
@ -3583,6 +3603,11 @@ ostree_repo_pull_with_options (OstreeRepo *self,
*/ */
if ((flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) == 0) if ((flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) == 0)
pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED; pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED;
/* Shouldn't be referenced in this path, but just in case. See below
* for more information.
*/
pull_data->trusted_http_direct = FALSE;
} }
else else
{ {
@ -3593,6 +3618,18 @@ ostree_repo_pull_with_options (OstreeRepo *self,
*/ */
if (flags & OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP) if (flags & OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP)
pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED; pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED;
const gboolean verifying_bareuseronly =
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0;
/* If we're mirroring and writing into an archive repo, and both checksum and
* bareuseronly are turned off, we can directly copy the content rather than
* paying the cost of exploding it, checksumming, and re-gzip.
*/
const gboolean mirroring_into_archive =
pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE;
const gboolean import_trusted = !verifying_bareuseronly &&
(pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_TRUSTED) > 0;
pull_data->trusted_http_direct = mirroring_into_archive && import_trusted;
} }
/* We can't use static deltas if pulling into an archive repo. */ /* We can't use static deltas if pulling into an archive repo. */
@ -3824,6 +3861,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
while (g_variant_iter_loop (collection_refs_iter, "(&s&s&s)", &collection_id, &ref_name, &checksum)) while (g_variant_iter_loop (collection_refs_iter, "(&s&s&s)", &collection_id, &ref_name, &checksum))
{ {
if (!ostree_validate_rev (ref_name, error))
goto out;
g_hash_table_insert (requested_refs_to_fetch, g_hash_table_insert (requested_refs_to_fetch,
ostree_collection_ref_new (collection_id, ref_name), ostree_collection_ref_new (collection_id, ref_name),
(*checksum != '\0') ? g_strdup (checksum) : NULL); (*checksum != '\0') ? g_strdup (checksum) : NULL);
@ -4248,6 +4287,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->gpg_verified_commits, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref);

View File

@ -150,7 +150,7 @@ find_ref_in_remotes (OstreeRepo *self,
GError **error) GError **error)
{ {
g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
glnx_fd_close int ret_fd = -1; glnx_autofd int ret_fd = -1;
if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error))
return FALSE; return FALSE;
@ -158,7 +158,7 @@ find_ref_in_remotes (OstreeRepo *self,
while (TRUE) while (TRUE)
{ {
struct dirent *dent = NULL; struct dirent *dent = NULL;
glnx_fd_close int remote_dfd = -1; glnx_autofd int remote_dfd = -1;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, error)) if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, error))
return FALSE; return FALSE;
@ -234,7 +234,7 @@ resolve_refspec (OstreeRepo *self,
{ {
__attribute__((unused)) GCancellable *cancellable = NULL; __attribute__((unused)) GCancellable *cancellable = NULL;
g_autofree char *ret_rev = NULL; g_autofree char *ret_rev = NULL;
glnx_fd_close int target_fd = -1; glnx_autofd int target_fd = -1;
g_return_val_if_fail (ref != NULL, FALSE); g_return_val_if_fail (ref != NULL, FALSE);
@ -560,6 +560,14 @@ enumerate_refs_recurse (OstreeRepo *repo,
if (dent == NULL) if (dent == NULL)
break; break;
/* https://github.com/ostreedev/ostree/issues/1285
* Ignore any files that don't appear to be valid fragments; e.g.
* Red Hat has a tool that drops .rsync_info files into each
* directory it syncs.
**/
if (!_ostree_validate_ref_fragment (dent->d_name, NULL))
continue;
g_string_append (base_path, dent->d_name); g_string_append (base_path, dent->d_name);
if (dent->d_type == DT_DIR) if (dent->d_type == DT_DIR)
@ -637,7 +645,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
{ {
if (S_ISDIR (stbuf.st_mode)) if (S_ISDIR (stbuf.st_mode))
{ {
glnx_fd_close int base_fd = -1; glnx_autofd int base_fd = -1;
g_autoptr(GString) base_path = g_string_new (""); g_autoptr(GString) base_path = g_string_new ("");
if (!cut_prefix) if (!cut_prefix)
g_string_printf (base_path, "%s/", ref_prefix); g_string_printf (base_path, "%s/", ref_prefix);
@ -652,7 +660,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
} }
else else
{ {
glnx_fd_close int prefix_dfd = -1; glnx_autofd int prefix_dfd = -1;
if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error)) if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error))
return FALSE; return FALSE;
@ -667,7 +675,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
{ {
g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
g_autoptr(GString) base_path = g_string_new (""); g_autoptr(GString) base_path = g_string_new ("");
glnx_fd_close int refs_heads_dfd = -1; glnx_autofd int refs_heads_dfd = -1;
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
return FALSE; return FALSE;
@ -687,7 +695,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
while (TRUE) while (TRUE)
{ {
struct dirent *dent; struct dirent *dent;
glnx_fd_close int remote_dfd = -1; glnx_autofd int remote_dfd = -1;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
return FALSE; return FALSE;
@ -992,7 +1000,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int dfd = -1; glnx_autofd int dfd = -1;
g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE); g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE);
g_return_val_if_fail (!(rev != NULL && alias != NULL), FALSE); g_return_val_if_fail (!(rev != NULL && alias != NULL), FALSE);
@ -1016,7 +1024,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
} }
else if (remote == NULL && ref->collection_id != NULL) else if (remote == NULL && ref->collection_id != NULL)
{ {
glnx_fd_close int refs_mirrors_dfd = -1; glnx_autofd int refs_mirrors_dfd = -1;
/* refs/mirrors might not exist in older repositories, so create it. */ /* refs/mirrors might not exist in older repositories, so create it. */
if (!glnx_shutil_mkdir_p_at_open (self->repo_dir_fd, "refs/mirrors", 0777, if (!glnx_shutil_mkdir_p_at_open (self->repo_dir_fd, "refs/mirrors", 0777,
@ -1039,7 +1047,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
} }
else else
{ {
glnx_fd_close int refs_remotes_dfd = -1; glnx_autofd int refs_remotes_dfd = -1;
if (!glnx_opendirat (self->repo_dir_fd, "refs/remotes", TRUE, if (!glnx_opendirat (self->repo_dir_fd, "refs/remotes", TRUE,
&refs_remotes_dfd, error)) &refs_remotes_dfd, error))
@ -1212,7 +1220,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
if (main_collection_id != NULL && if (main_collection_id != NULL &&
(match_collection_id == NULL || g_strcmp0 (match_collection_id, main_collection_id) == 0)) (match_collection_id == NULL || g_strcmp0 (match_collection_id, main_collection_id) == 0))
{ {
glnx_fd_close int refs_heads_dfd = -1; glnx_autofd int refs_heads_dfd = -1;
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
return FALSE; return FALSE;
@ -1237,7 +1245,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
while (refs_dir_exists) while (refs_dir_exists)
{ {
struct dirent *dent; struct dirent *dent;
glnx_fd_close int subdir_fd = -1; glnx_autofd int subdir_fd = -1;
const gchar *current_collection_id; const gchar *current_collection_id;
g_autofree gchar *remote_collection_id = NULL; g_autofree gchar *remote_collection_id = NULL;

View File

@ -37,7 +37,14 @@
#define CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT (30) #define CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT (30)
typedef enum {
DELTAOPT_FLAG_NONE = (1 << 0),
DELTAOPT_FLAG_DISABLE_BSDIFF = (1 << 1),
DELTAOPT_FLAG_VERBOSE = (1 << 2)
} DeltaOpts;
typedef struct { typedef struct {
guint64 compressed_size;
guint64 uncompressed_size; guint64 uncompressed_size;
GPtrArray *objects; GPtrArray *objects;
GString *payload; GString *payload;
@ -46,6 +53,8 @@ typedef struct {
GPtrArray *modes; GPtrArray *modes;
GHashTable *xattr_set; /* GVariant(ayay) -> offset */ GHashTable *xattr_set; /* GVariant(ayay) -> offset */
GPtrArray *xattrs; GPtrArray *xattrs;
GLnxTmpfile part_tmpf;
GVariant *header;
} OstreeStaticDeltaPartBuilder; } OstreeStaticDeltaPartBuilder;
typedef struct { typedef struct {
@ -60,13 +69,47 @@ typedef struct {
guint n_bsdiff; guint n_bsdiff;
guint n_fallback; guint n_fallback;
gboolean swap_endian; gboolean swap_endian;
int parts_dfd;
DeltaOpts delta_opts;
} OstreeStaticDeltaBuilder; } OstreeStaticDeltaBuilder;
typedef enum { /* Get an input stream for a GVariant */
DELTAOPT_FLAG_NONE = (1 << 0), static GInputStream *
DELTAOPT_FLAG_DISABLE_BSDIFF = (1 << 1), variant_to_inputstream (GVariant *variant)
DELTAOPT_FLAG_VERBOSE = (1 << 2) {
} DeltaOpts; GMemoryInputStream *ret = (GMemoryInputStream*)
g_memory_input_stream_new_from_data (g_variant_get_data (variant),
g_variant_get_size (variant),
NULL);
g_object_set_data_full ((GObject*)ret, "ot-variant-data",
g_variant_ref (variant), (GDestroyNotify) g_variant_unref);
return (GInputStream*)ret;
}
static GBytes *
objtype_checksum_array_new (GPtrArray *objects)
{
guint i;
GByteArray *ret = g_byte_array_new ();
for (i = 0; i < objects->len; i++)
{
GVariant *serialized_key = objects->pdata[i];
OstreeObjectType objtype;
const char *checksum;
guint8 csum[OSTREE_SHA256_DIGEST_LEN];
guint8 objtype_v;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
objtype_v = (guint8) objtype;
ostree_checksum_inplace_to_bytes (checksum, csum);
g_byte_array_append (ret, &objtype_v, 1);
g_byte_array_append (ret, csum, sizeof (csum));
}
return g_byte_array_free_to_bytes (ret);
}
static void static void
ostree_static_delta_part_builder_unref (OstreeStaticDeltaPartBuilder *part_builder) ostree_static_delta_part_builder_unref (OstreeStaticDeltaPartBuilder *part_builder)
@ -81,6 +124,9 @@ ostree_static_delta_part_builder_unref (OstreeStaticDeltaPartBuilder *part_build
g_ptr_array_unref (part_builder->modes); g_ptr_array_unref (part_builder->modes);
g_hash_table_unref (part_builder->xattr_set); g_hash_table_unref (part_builder->xattr_set);
g_ptr_array_unref (part_builder->xattrs); g_ptr_array_unref (part_builder->xattrs);
glnx_tmpfile_clear (&part_builder->part_tmpf);
if (part_builder->header)
g_variant_unref (part_builder->header);
g_free (part_builder); g_free (part_builder);
} }
@ -162,10 +208,123 @@ xattr_chunk_equals (const void *one, const void *two)
return memcmp (g_variant_get_data (v1), g_variant_get_data (v2), l1) == 0; return memcmp (g_variant_get_data (v1), g_variant_get_data (v2), l1) == 0;
} }
static gboolean
finish_part (OstreeStaticDeltaBuilder *builder, GError **error)
{
OstreeStaticDeltaPartBuilder *part_builder = builder->parts->pdata[builder->parts->len - 1];
g_autofree guchar *part_checksum = NULL;
g_autoptr(GBytes) objtype_checksum_array = NULL;
g_autoptr(GBytes) checksum_bytes = NULL;
g_autoptr(GOutputStream) part_temp_outstream = NULL;
g_autoptr(GInputStream) part_in = NULL;
g_autoptr(GInputStream) part_payload_in = NULL;
g_autoptr(GMemoryOutputStream) part_payload_out = NULL;
g_autoptr(GConverterOutputStream) part_payload_compressor = NULL;
g_autoptr(GConverter) compressor = NULL;
g_autoptr(GVariant) delta_part_content = NULL;
g_autoptr(GVariant) delta_part = NULL;
g_autoptr(GVariant) delta_part_header = NULL;
g_auto(GVariantBuilder) mode_builder = OT_VARIANT_BUILDER_INITIALIZER;
g_auto(GVariantBuilder) xattr_builder = OT_VARIANT_BUILDER_INITIALIZER;
guint8 compression_type_char;
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uuu)"));
g_variant_builder_init (&xattr_builder, G_VARIANT_TYPE ("aa(ayay)"));
guint j;
for (j = 0; j < part_builder->modes->len; j++)
g_variant_builder_add_value (&mode_builder, part_builder->modes->pdata[j]);
for (j = 0; j < part_builder->xattrs->len; j++)
g_variant_builder_add_value (&xattr_builder, part_builder->xattrs->pdata[j]);
{
g_autoptr(GBytes) payload_b;
g_autoptr(GBytes) operations_b;
payload_b = g_string_free_to_bytes (part_builder->payload);
part_builder->payload = NULL;
operations_b = g_string_free_to_bytes (part_builder->operations);
part_builder->operations = NULL;
delta_part_content = g_variant_new ("(a(uuu)aa(ayay)@ay@ay)",
&mode_builder, &xattr_builder,
ot_gvariant_new_ay_bytes (payload_b),
ot_gvariant_new_ay_bytes (operations_b));
g_variant_ref_sink (delta_part_content);
}
/* Hardcode xz for now */
compressor = (GConverter*)_ostree_lzma_compressor_new (NULL);
compression_type_char = 'x';
part_payload_in = variant_to_inputstream (delta_part_content);
part_payload_out = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
part_payload_compressor = (GConverterOutputStream*)g_converter_output_stream_new ((GOutputStream*)part_payload_out, compressor);
{
gssize n_bytes_written = g_output_stream_splice ((GOutputStream*)part_payload_compressor, part_payload_in,
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
NULL, error);
if (n_bytes_written < 0)
return FALSE;
}
g_clear_pointer (&delta_part_content, g_variant_unref);
{ g_autoptr(GBytes) payload = g_memory_output_stream_steal_as_bytes (part_payload_out);
delta_part = g_variant_ref_sink (g_variant_new ("(y@ay)",
compression_type_char,
ot_gvariant_new_ay_bytes (payload)));
}
if (!glnx_open_tmpfile_linkable_at (builder->parts_dfd, ".", O_RDWR | O_CLOEXEC,
&part_builder->part_tmpf, error))
return FALSE;
part_temp_outstream = g_unix_output_stream_new (part_builder->part_tmpf.fd, FALSE);
part_in = variant_to_inputstream (delta_part);
if (!ot_gio_splice_get_checksum (part_temp_outstream, part_in,
&part_checksum,
NULL, error))
return FALSE;
checksum_bytes = g_bytes_new (part_checksum, OSTREE_SHA256_DIGEST_LEN);
objtype_checksum_array = objtype_checksum_array_new (part_builder->objects);
delta_part_header = g_variant_new ("(u@aytt@ay)",
maybe_swap_endian_u32 (builder->swap_endian, OSTREE_DELTAPART_VERSION),
ot_gvariant_new_ay_bytes (checksum_bytes),
maybe_swap_endian_u64 (builder->swap_endian, (guint64) g_variant_get_size (delta_part)),
maybe_swap_endian_u64 (builder->swap_endian, part_builder->uncompressed_size),
ot_gvariant_new_ay_bytes (objtype_checksum_array));
g_variant_ref_sink (delta_part_header);
part_builder->header = g_variant_ref (delta_part_header);
part_builder->compressed_size = g_variant_get_size (delta_part);
if (builder->delta_opts & DELTAOPT_FLAG_VERBOSE)
{
g_printerr ("part %u n:%u compressed:%" G_GUINT64_FORMAT " uncompressed:%" G_GUINT64_FORMAT "\n",
builder->parts->len, part_builder->objects->len,
part_builder->compressed_size,
part_builder->uncompressed_size);
}
return TRUE;
}
static OstreeStaticDeltaPartBuilder * static OstreeStaticDeltaPartBuilder *
allocate_part (OstreeStaticDeltaBuilder *builder) allocate_part (OstreeStaticDeltaBuilder *builder, GError **error)
{ {
OstreeStaticDeltaPartBuilder *part = g_new0 (OstreeStaticDeltaPartBuilder, 1); OstreeStaticDeltaPartBuilder *part = g_new0 (OstreeStaticDeltaPartBuilder, 1);
if (builder->parts->len > 0)
{
if (!finish_part (builder, error))
return NULL;
}
part->objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); part->objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
part->payload = g_string_new (NULL); part->payload = g_string_new (NULL);
part->operations = g_string_new (NULL); part->operations = g_string_new (NULL);
@ -221,31 +380,6 @@ write_unique_variant_chunk (OstreeStaticDeltaPartBuilder *current_part,
return offset; return offset;
} }
static GBytes *
objtype_checksum_array_new (GPtrArray *objects)
{
guint i;
GByteArray *ret = g_byte_array_new ();
for (i = 0; i < objects->len; i++)
{
GVariant *serialized_key = objects->pdata[i];
OstreeObjectType objtype;
const char *checksum;
guint8 csum[OSTREE_SHA256_DIGEST_LEN];
guint8 objtype_v;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
objtype_v = (guint8) objtype;
ostree_checksum_inplace_to_bytes (checksum, csum);
g_byte_array_append (ret, &objtype_v, 1);
g_byte_array_append (ret, csum, sizeof (csum));
}
return g_byte_array_free_to_bytes (ret);
}
static gboolean static gboolean
splice_stream_to_payload (OstreeStaticDeltaPartBuilder *current_part, splice_stream_to_payload (OstreeStaticDeltaPartBuilder *current_part,
GInputStream *istream, GInputStream *istream,
@ -338,7 +472,10 @@ process_one_object (OstreeRepo *repo,
if (current_part->objects->len > 0 && if (current_part->objects->len > 0 &&
current_part->payload->len + content_size > builder->max_chunk_size_bytes) current_part->payload->len + content_size > builder->max_chunk_size_bytes)
{ {
*current_part_val = current_part = allocate_part (builder); current_part = allocate_part (builder, error);
if (current_part == NULL)
return FALSE;
*current_part_val = current_part;
} }
guint64 compressed_size; guint64 compressed_size;
@ -514,8 +651,8 @@ try_content_rollsum (OstreeRepo *repo,
if (opts & DELTAOPT_FLAG_VERBOSE) if (opts & DELTAOPT_FLAG_VERBOSE)
{ {
g_printerr ("rollsum for %s; crcs=%u bufs=%u total=%u matchsize=%llu\n", g_printerr ("rollsum for %s -> %s; crcs=%u bufs=%u total=%u matchsize=%llu\n",
to, matches->crcmatches, from, to, matches->crcmatches,
matches->bufmatches, matches->bufmatches,
matches->total, (unsigned long long)matches->match_size); matches->total, (unsigned long long)matches->match_size);
} }
@ -577,7 +714,10 @@ process_one_rollsum (OstreeRepo *repo,
if (current_part->objects->len > 0 && if (current_part->objects->len > 0 &&
current_part->payload->len > builder->max_chunk_size_bytes) current_part->payload->len > builder->max_chunk_size_bytes)
{ {
*current_part_val = current_part = allocate_part (builder); current_part = allocate_part (builder, error);
if (current_part == NULL)
return FALSE;
*current_part_val = current_part;
} }
g_autoptr(GBytes) tmp_to = NULL; g_autoptr(GBytes) tmp_to = NULL;
@ -692,7 +832,10 @@ process_one_bsdiff (OstreeRepo *repo,
if (current_part->objects->len > 0 && if (current_part->objects->len > 0 &&
current_part->payload->len > builder->max_chunk_size_bytes) current_part->payload->len > builder->max_chunk_size_bytes)
{ {
*current_part_val = current_part = allocate_part (builder); current_part = allocate_part (builder, error);
if (current_part == NULL)
return FALSE;
*current_part_val = current_part;
} }
g_autoptr(GBytes) tmp_from = NULL; g_autoptr(GBytes) tmp_from = NULL;
@ -763,6 +906,20 @@ process_one_bsdiff (OstreeRepo *repo,
_ostree_write_varuint64 (current_part->operations, current_part->payload->len); _ostree_write_varuint64 (current_part->operations, current_part->payload->len);
_ostree_write_varuint64 (current_part->operations, payload_size); _ostree_write_varuint64 (current_part->operations, payload_size);
/* A bit too verbose to print by default...but leaving this #if 0'd out to
* use later. One approach I've been thinking about is to optionally
* output e.g. a JSON file as we build the deltas. Alternatively, we could
* try to reverse engineer things more in the "show" path, but that gets
* hard/messy as it's quite optimized for execution now.
*/
#if 0
g_printerr ("bspatch %s [%llu] → %s [%llu] bsdiff:%llu (%f)\n",
bsdiff_content->from_checksum, (unsigned long long)tmp_from_len,
to_checksum, (unsigned long long)tmp_to_len,
(unsigned long long)payload_size,
((double)payload_size)/tmp_to_len);
#endif
g_string_append_len (current_part->payload, payload, payload_size); g_string_append_len (current_part->payload, payload, payload_size);
} }
g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE); g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE);
@ -964,7 +1121,9 @@ generate_delta_lowlatency (OstreeRepo *repo,
g_hash_table_size (modified_regfile_content)); g_hash_table_size (modified_regfile_content));
} }
current_part = allocate_part (builder); current_part = allocate_part (builder, error);
if (current_part == NULL)
return FALSE;
/* Pack the metadata first */ /* Pack the metadata first */
g_hash_table_iter_init (&hashiter, new_reachable_metadata); g_hash_table_iter_init (&hashiter, new_reachable_metadata);
@ -1000,12 +1159,20 @@ generate_delta_lowlatency (OstreeRepo *repo,
/* Now do bsdiff'ed objects */ /* Now do bsdiff'ed objects */
const guint n_bsdiff = g_hash_table_size (bsdiff_optimized_content_objects);
if (n_bsdiff > 0)
{
const guint mod = n_bsdiff / 10;
g_hash_table_iter_init (&hashiter, bsdiff_optimized_content_objects); g_hash_table_iter_init (&hashiter, bsdiff_optimized_content_objects);
while (g_hash_table_iter_next (&hashiter, &key, &value)) while (g_hash_table_iter_next (&hashiter, &key, &value))
{ {
const char *checksum = key; const char *checksum = key;
ContentBsdiff *bsdiff = value; ContentBsdiff *bsdiff = value;
if (opts & DELTAOPT_FLAG_VERBOSE &&
(mod == 0 || builder->n_bsdiff % mod == 0))
g_printerr ("processing bsdiff: [%u/%u]\n", builder->n_bsdiff, n_bsdiff);
if (!process_one_bsdiff (repo, builder, &current_part, if (!process_one_bsdiff (repo, builder, &current_part,
checksum, bsdiff, checksum, bsdiff,
cancellable, error)) cancellable, error))
@ -1013,6 +1180,7 @@ generate_delta_lowlatency (OstreeRepo *repo,
builder->n_bsdiff++; builder->n_bsdiff++;
} }
}
/* Scan for large objects, so we can fall back to plain HTTP-based /* Scan for large objects, so we can fall back to plain HTTP-based
* fetch. * fetch.
@ -1080,6 +1248,9 @@ generate_delta_lowlatency (OstreeRepo *repo,
return FALSE; return FALSE;
} }
if (!finish_part (builder, error))
return FALSE;
return TRUE; return TRUE;
} }
@ -1186,24 +1357,24 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
guint min_fallback_size; guint min_fallback_size;
guint max_bsdiff_size; guint max_bsdiff_size;
guint max_chunk_size; guint max_chunk_size;
g_auto(GVariantBuilder) metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
DeltaOpts delta_opts = DELTAOPT_FLAG_NONE; DeltaOpts delta_opts = DELTAOPT_FLAG_NONE;
guint64 total_compressed_size = 0; guint64 total_compressed_size = 0;
guint64 total_uncompressed_size = 0; guint64 total_uncompressed_size = 0;
g_autoptr(GVariantBuilder) part_headers = NULL; g_autoptr(GVariantBuilder) part_headers = NULL;
g_autoptr(GPtrArray) part_temp_paths = NULL; g_autoptr(GPtrArray) part_temp_paths = NULL;
g_autoptr(GVariant) delta_descriptor = NULL;
g_autoptr(GVariant) to_commit = NULL; g_autoptr(GVariant) to_commit = NULL;
const char *opt_filename; const char *opt_filename;
g_autofree char *descriptor_name = NULL; g_autofree char *descriptor_name = NULL;
glnx_fd_close int descriptor_dfd = -1; glnx_autofd int descriptor_dfd = -1;
g_autoptr(GVariant) fallback_headers = NULL; g_autoptr(GVariant) fallback_headers = NULL;
g_autoptr(GVariant) detached = NULL; g_autoptr(GVariant) detached = NULL;
gboolean inline_parts; gboolean inline_parts;
guint endianness = G_BYTE_ORDER; guint endianness = G_BYTE_ORDER;
glnx_fd_close int tmp_dfd = -1; glnx_autofd int tmp_dfd = -1;
builder.parts = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_static_delta_part_builder_unref); builder.parts = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_static_delta_part_builder_unref);
builder.fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); builder.fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
g_auto(GLnxTmpfile) descriptor_tmpf = { 0, };
g_autoptr(OtVariantBuilder) descriptor_builder = NULL;
if (!g_variant_lookup (params, "min-fallback-size", "u", &min_fallback_size)) if (!g_variant_lookup (params, "min-fallback-size", "u", &min_fallback_size))
min_fallback_size = 4; min_fallback_size = 4;
@ -1245,45 +1416,6 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
&to_commit, error)) &to_commit, error))
goto out; goto out;
/* Ignore optimization flags */
if (!generate_delta_lowlatency (self, from, to, delta_opts, &builder,
cancellable, error))
goto out;
/* NOTE: Add user-supplied metadata first. This is used by at least
* xdg-app as a way to provide MIME content sniffing, since the
* metadata appears first in the file.
*/
g_variant_builder_init (&metadata_builder, G_VARIANT_TYPE ("a{sv}"));
if (metadata != NULL)
{
GVariantIter iter;
GVariant *item;
g_variant_iter_init (&iter, metadata);
while ((item = g_variant_iter_next_value (&iter)))
{
g_variant_builder_add (&metadata_builder, "@{sv}", item);
g_variant_unref (item);
}
}
{ guint8 endianness_char;
switch (endianness)
{
case G_LITTLE_ENDIAN:
endianness_char = 'l';
break;
case G_BIG_ENDIAN:
endianness_char = 'B';
break;
default:
g_assert_not_reached ();
}
g_variant_builder_add (&metadata_builder, "{sv}", "ostree.endianness", g_variant_new_byte (endianness_char));
}
if (opt_filename) if (opt_filename)
{ {
g_autofree char *dnbuf = g_strdup (opt_filename); g_autofree char *dnbuf = g_strdup (opt_filename);
@ -1301,120 +1433,14 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
} }
} }
part_headers = g_variant_builder_new (G_VARIANT_TYPE ("a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT)); builder.parts_dfd = tmp_dfd;
part_temp_paths = g_ptr_array_new_with_free_func ((GDestroyNotify)glnx_tmpfile_clear); builder.delta_opts = delta_opts;
for (i = 0; i < builder.parts->len; i++)
{
OstreeStaticDeltaPartBuilder *part_builder = builder.parts->pdata[i];
g_autoptr(GBytes) payload_b;
g_autoptr(GBytes) operations_b;
g_autofree guchar *part_checksum = NULL;
g_autoptr(GBytes) objtype_checksum_array = NULL;
g_autoptr(GBytes) checksum_bytes = NULL;
g_autoptr(GOutputStream) part_temp_outstream = NULL;
g_autoptr(GInputStream) part_in = NULL;
g_autoptr(GInputStream) part_payload_in = NULL;
g_autoptr(GMemoryOutputStream) part_payload_out = NULL;
g_autoptr(GConverterOutputStream) part_payload_compressor = NULL;
g_autoptr(GConverter) compressor = NULL;
g_autoptr(GVariant) delta_part_content = NULL;
g_autoptr(GVariant) delta_part = NULL;
g_autoptr(GVariant) delta_part_header = NULL;
g_auto(GVariantBuilder) mode_builder = OT_VARIANT_BUILDER_INITIALIZER;
g_auto(GVariantBuilder) xattr_builder = OT_VARIANT_BUILDER_INITIALIZER;
guint8 compression_type_char;
g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uuu)")); /* Ignore optimization flags */
g_variant_builder_init (&xattr_builder, G_VARIANT_TYPE ("aa(ayay)")); if (!generate_delta_lowlatency (self, from, to, delta_opts, &builder,
{ guint j;
for (j = 0; j < part_builder->modes->len; j++)
g_variant_builder_add_value (&mode_builder, part_builder->modes->pdata[j]);
for (j = 0; j < part_builder->xattrs->len; j++)
g_variant_builder_add_value (&xattr_builder, part_builder->xattrs->pdata[j]);
}
payload_b = g_string_free_to_bytes (part_builder->payload);
part_builder->payload = NULL;
operations_b = g_string_free_to_bytes (part_builder->operations);
part_builder->operations = NULL;
/* FIXME - avoid duplicating memory here */
delta_part_content = g_variant_new ("(a(uuu)aa(ayay)@ay@ay)",
&mode_builder, &xattr_builder,
ot_gvariant_new_ay_bytes (payload_b),
ot_gvariant_new_ay_bytes (operations_b));
g_variant_ref_sink (delta_part_content);
/* Hardcode xz for now */
compressor = (GConverter*)_ostree_lzma_compressor_new (NULL);
compression_type_char = 'x';
part_payload_in = ot_variant_read (delta_part_content);
part_payload_out = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
part_payload_compressor = (GConverterOutputStream*)g_converter_output_stream_new ((GOutputStream*)part_payload_out, compressor);
{
gssize n_bytes_written = g_output_stream_splice ((GOutputStream*)part_payload_compressor, part_payload_in,
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error);
if (n_bytes_written < 0)
goto out;
}
/* FIXME - avoid duplicating memory here */
{ g_autoptr(GBytes) payload = g_memory_output_stream_steal_as_bytes (part_payload_out);
delta_part = g_variant_ref_sink (g_variant_new ("(y@ay)",
compression_type_char,
ot_gvariant_new_ay_bytes (payload)));
}
if (inline_parts)
{
g_autofree char *part_relpath = _ostree_get_relative_static_delta_part_path (from, to, i);
g_variant_builder_add (&metadata_builder, "{sv}", part_relpath, delta_part);
}
else
{
GLnxTmpfile *part_tmpf = g_new0 (GLnxTmpfile, 1);
if (!glnx_open_tmpfile_linkable_at (tmp_dfd, ".", O_WRONLY | O_CLOEXEC,
part_tmpf, error))
goto out;
/* Transfer tempfile ownership */
part_temp_outstream = g_unix_output_stream_new (part_tmpf->fd, FALSE);
g_ptr_array_add (part_temp_paths, g_steal_pointer (&part_tmpf));
}
part_in = ot_variant_read (delta_part);
if (!ot_gio_splice_get_checksum (part_temp_outstream, part_in,
&part_checksum,
cancellable, error)) cancellable, error))
goto out; goto out;
checksum_bytes = g_bytes_new (part_checksum, OSTREE_SHA256_DIGEST_LEN);
objtype_checksum_array = objtype_checksum_array_new (part_builder->objects);
delta_part_header = g_variant_new ("(u@aytt@ay)",
maybe_swap_endian_u32 (builder.swap_endian, OSTREE_DELTAPART_VERSION),
ot_gvariant_new_ay_bytes (checksum_bytes),
maybe_swap_endian_u64 (builder.swap_endian, (guint64) g_variant_get_size (delta_part)),
maybe_swap_endian_u64 (builder.swap_endian, part_builder->uncompressed_size),
ot_gvariant_new_ay_bytes (objtype_checksum_array));
g_variant_builder_add_value (part_headers, g_variant_ref (delta_part_header));
total_compressed_size += g_variant_get_size (delta_part);
total_uncompressed_size += part_builder->uncompressed_size;
if (delta_opts & DELTAOPT_FLAG_VERBOSE)
{
g_printerr ("part %u n:%u compressed:%" G_GUINT64_FORMAT " uncompressed:%" G_GUINT64_FORMAT "\n",
i, part_builder->objects->len,
(guint64)g_variant_get_size (delta_part),
part_builder->uncompressed_size);
}
}
if (opt_filename) if (opt_filename)
{ {
g_autofree char *dnbuf = g_strdup (opt_filename); g_autofree char *dnbuf = g_strdup (opt_filename);
@ -1438,24 +1464,92 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
descriptor_name = g_strdup (basename (descriptor_relpath)); descriptor_name = g_strdup (basename (descriptor_relpath));
} }
for (i = 0; i < part_temp_paths->len; i++) if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC,
&descriptor_tmpf, error))
goto out;
descriptor_builder = ot_variant_builder_new (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), descriptor_tmpf.fd);
/* Open the metadata dict */
if (!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("a{sv}"), error))
goto out;
/* NOTE: Add user-supplied metadata first. This is used by at least
* flatpak as a way to provide MIME content sniffing, since the
* metadata appears first in the file.
*/
if (metadata != NULL)
{
GVariantIter iter;
GVariant *item;
g_variant_iter_init (&iter, metadata);
while ((item = g_variant_iter_next_value (&iter)))
{
if (!ot_variant_builder_add_value (descriptor_builder, item, error))
goto out;
g_variant_unref (item);
}
}
{ guint8 endianness_char;
switch (endianness)
{
case G_LITTLE_ENDIAN:
endianness_char = 'l';
break;
case G_BIG_ENDIAN:
endianness_char = 'B';
break;
default:
g_assert_not_reached ();
}
if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", "ostree.endianness", g_variant_new_byte (endianness_char)))
goto out;
}
part_headers = g_variant_builder_new (G_VARIANT_TYPE ("a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT));
part_temp_paths = g_ptr_array_new_with_free_func ((GDestroyNotify)glnx_tmpfile_clear);
for (i = 0; i < builder.parts->len; i++)
{
OstreeStaticDeltaPartBuilder *part_builder = builder.parts->pdata[i];
if (inline_parts)
{
g_autofree char *part_relpath = _ostree_get_relative_static_delta_part_path (from, to, i);
lseek (part_builder->part_tmpf.fd, 0, SEEK_SET);
if (!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("{sv}"), error) ||
!ot_variant_builder_add (descriptor_builder, error, "s", part_relpath) ||
!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("v"), error) ||
!ot_variant_builder_add_from_fd (descriptor_builder, G_VARIANT_TYPE ("(yay)"), part_builder->part_tmpf.fd, part_builder->compressed_size, error) ||
!ot_variant_builder_close (descriptor_builder, error) ||
!ot_variant_builder_close (descriptor_builder, error))
goto out;
}
else
{ {
g_autofree char *partstr = g_strdup_printf ("%u", i); g_autofree char *partstr = g_strdup_printf ("%u", i);
/* Take ownership of the path/fd here */
g_auto(GLnxTmpfile) tmpf = *((GLnxTmpfile*)part_temp_paths->pdata[i]);
g_clear_pointer (&(part_temp_paths->pdata[i]), g_free);
if (fchmod (tmpf.fd, 0644) < 0) if (fchmod (part_builder->part_tmpf.fd, 0644) < 0)
{ {
glnx_set_error_from_errno (error); glnx_set_error_from_errno (error);
goto out; goto out;
} }
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, if (!glnx_link_tmpfile_at (&part_builder->part_tmpf, GLNX_LINK_TMPFILE_REPLACE,
descriptor_dfd, partstr, error)) descriptor_dfd, partstr, error))
goto out; goto out;
} }
g_variant_builder_add_value (part_headers, g_variant_ref (part_builder->header));
total_compressed_size += part_builder->compressed_size;
total_uncompressed_size += part_builder->uncompressed_size;
}
if (!get_fallback_headers (self, &builder, &fallback_headers, if (!get_fallback_headers (self, &builder, &fallback_headers,
cancellable, error)) cancellable, error))
goto out; goto out;
@ -1466,9 +1560,14 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
if (detached) if (detached)
{ {
g_autofree char *detached_key = _ostree_get_relative_static_delta_path (from, to, "commitmeta"); g_autofree char *detached_key = _ostree_get_relative_static_delta_path (from, to, "commitmeta");
g_variant_builder_add (&metadata_builder, "{sv}", detached_key, detached); if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", detached_key, detached))
goto out;
} }
/* Close metadata dict */
if (!ot_variant_builder_close (descriptor_builder, error))
goto out;
/* Generate OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ /* Generate OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */
{ {
GDateTime *now = g_date_time_new_now_utc (); GDateTime *now = g_date_time_new_now_utc ();
@ -1477,17 +1576,26 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
/* floating */ GVariant *to_csum_v = /* floating */ GVariant *to_csum_v =
ostree_checksum_to_bytes_v (to); ostree_checksum_to_bytes_v (to);
delta_descriptor = g_variant_ref_sink (g_variant_new ("(@a{sv}t@ay@ay@" OSTREE_COMMIT_GVARIANT_STRING "@ay"
"a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT if (!ot_variant_builder_add (descriptor_builder, error, "t",
"@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")", GUINT64_TO_BE (g_date_time_to_unix (now))) ||
g_variant_builder_end (&metadata_builder), !ot_variant_builder_add_value (descriptor_builder,
GUINT64_TO_BE (g_date_time_to_unix (now)), from_csum_v, error) ||
from_csum_v, !ot_variant_builder_add_value (descriptor_builder,
to_csum_v, to_csum_v, error) ||
to_commit, !ot_variant_builder_add_value (descriptor_builder,
ot_gvariant_new_bytearray ((guchar*)"", 0), to_commit, error) ||
part_headers, !ot_variant_builder_add_value (descriptor_builder,
fallback_headers)); ot_gvariant_new_bytearray ((guchar*)"", 0), error) ||
!ot_variant_builder_add_value (descriptor_builder,
g_variant_builder_end (part_headers), error) ||
!ot_variant_builder_add_value (descriptor_builder,
fallback_headers, error))
goto out;
if (!ot_variant_builder_end (descriptor_builder, error))
goto out;
g_date_time_unref (now); g_date_time_unref (now);
} }
@ -1503,10 +1611,14 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff); g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff);
} }
if (!glnx_file_replace_contents_at (descriptor_dfd, descriptor_name, if (fchmod (descriptor_tmpf.fd, 0644) < 0)
g_variant_get_data (delta_descriptor), {
g_variant_get_size (delta_descriptor), glnx_set_error_from_errno (error);
0, cancellable, error)) goto out;
}
if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
descriptor_dfd, descriptor_name, error))
goto out; goto out;
ret = TRUE; ret = TRUE;

View File

@ -224,7 +224,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
const char *dir_or_file_path = gs_file_get_path_cached (dir_or_file); const char *dir_or_file_path = gs_file_get_path_cached (dir_or_file);
/* First, try opening it as a directory */ /* First, try opening it as a directory */
glnx_fd_close int dfd = glnx_opendirat_with_errno (AT_FDCWD, dir_or_file_path, TRUE); glnx_autofd int dfd = glnx_opendirat_with_errno (AT_FDCWD, dir_or_file_path, TRUE);
if (dfd < 0) if (dfd < 0)
{ {
if (errno != ENOTDIR) if (errno != ENOTDIR)
@ -241,12 +241,12 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
else else
basename = g_strdup ("superblock"); basename = g_strdup ("superblock");
glnx_fd_close int meta_fd = openat (dfd, basename, O_RDONLY | O_CLOEXEC); glnx_autofd int meta_fd = openat (dfd, basename, O_RDONLY | O_CLOEXEC);
if (meta_fd < 0) if (meta_fd < 0)
return glnx_throw_errno_prefix (error, "openat(%s)", basename); return glnx_throw_errno_prefix (error, "openat(%s)", basename);
g_autoptr(GVariant) meta = NULL; g_autoptr(GVariant) meta = NULL;
if (!ot_util_variant_map_fd (meta_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), if (!ot_variant_read_fd (meta_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT),
FALSE, &meta, error)) FALSE, &meta, error))
return FALSE; return FALSE;
@ -377,7 +377,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
else else
{ {
g_autofree char *relpath = g_strdup_printf ("%u", i); /* TODO avoid malloc here */ g_autofree char *relpath = g_strdup_printf ("%u", i); /* TODO avoid malloc here */
glnx_fd_close int part_fd = openat (dfd, relpath, O_RDONLY | O_CLOEXEC); glnx_autofd int part_fd = openat (dfd, relpath, O_RDONLY | O_CLOEXEC);
if (part_fd < 0) if (part_fd < 0)
return glnx_throw_errno_prefix (error, "Opening deltapart '%s'", relpath); return glnx_throw_errno_prefix (error, "Opening deltapart '%s'", relpath);
@ -448,7 +448,7 @@ _ostree_static_delta_part_open (GInputStream *part_in,
int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in); int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in);
/* No compression, no checksums - a fast path */ /* No compression, no checksums - a fast path */
if (!ot_util_variant_map_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), if (!ot_variant_read_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0),
trusted, &ret_part, error)) trusted, &ret_part, error))
return FALSE; return FALSE;
} }
@ -525,7 +525,7 @@ show_one_part (OstreeRepo *self,
g_print ("PartMeta%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n", g_print ("PartMeta%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n",
i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize); i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize);
glnx_fd_close gint part_fd = openat (self->repo_dir_fd, part_path, O_RDONLY | O_CLOEXEC); glnx_autofd int part_fd = openat (self->repo_dir_fd, part_path, O_RDONLY | O_CLOEXEC);
if (part_fd < 0) if (part_fd < 0)
return glnx_throw_errno_prefix (error, "openat(%s)", part_path); return glnx_throw_errno_prefix (error, "openat(%s)", part_path);
g_autoptr(GInputStream) part_in = g_unix_input_stream_new (part_fd, FALSE); g_autoptr(GInputStream) part_in = g_unix_input_stream_new (part_fd, FALSE);
@ -767,9 +767,12 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to); superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
if (!ot_util_variant_map_at (self->repo_dir_fd, superblock_path, glnx_autofd int superblock_fd = -1;
if (!glnx_openat_rdonly (self->repo_dir_fd, superblock_path, TRUE, &superblock_fd, error))
return FALSE;
if (!ot_variant_read_fd (superblock_fd, 0,
(GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT, (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
OT_VARIANT_MAP_TRUSTED, &delta_superblock, error)) TRUE, &delta_superblock, error))
return FALSE; return FALSE;
g_print ("Delta: %s\n", delta_id); g_print ("Delta: %s\n", delta_id);

View File

@ -58,7 +58,7 @@ typedef struct {
GLnxTmpfile tmpf; GLnxTmpfile tmpf;
guint64 content_size; guint64 content_size;
GOutputStream *content_out; GOutputStream *content_out;
GChecksum *content_checksum; OtChecksum content_checksum;
char checksum[OSTREE_SHA256_STRING_LEN+1]; char checksum[OSTREE_SHA256_STRING_LEN+1];
char *read_source_object; char *read_source_object;
int read_source_fd; int read_source_fd;
@ -229,6 +229,9 @@ _ostree_static_delta_part_execute (OstreeRepo *repo,
state->oplen--; state->oplen--;
state->opdata++; state->opdata++;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto out;
switch (opcode) switch (opcode)
{ {
case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE: case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE:
@ -277,7 +280,7 @@ _ostree_static_delta_part_execute (OstreeRepo *repo,
out: out:
glnx_tmpfile_clear (&state->tmpf); glnx_tmpfile_clear (&state->tmpf);
g_clear_object (&state->content_out); g_clear_object (&state->content_out);
g_clear_pointer (&state->content_checksum, g_checksum_free); ot_checksum_clear (&state->content_checksum);
return ret; return ret;
} }
@ -385,8 +388,8 @@ content_out_write (OstreeRepo *repo,
{ {
gsize bytes_written; gsize bytes_written;
if (state->content_checksum) if (state->content_checksum.initialized)
g_checksum_update (state->content_checksum, buf, len); ot_checksum_update (&state->content_checksum, buf, len);
/* Ignore bytes_written since we discard partial content */ /* Ignore bytes_written since we discard partial content */
if (!g_output_stream_write_all (state->content_out, if (!g_output_stream_write_all (state->content_out,
@ -501,14 +504,10 @@ handle_untrusted_content_checksum (OstreeRepo *repo,
GError **error) GError **error)
{ {
g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid); g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid);
g_autoptr(GVariant) header = _ostree_file_header_new (finfo, state->xattrs); g_autoptr(GBytes) header = _ostree_file_header_new (finfo, state->xattrs);
state->content_checksum = g_checksum_new (G_CHECKSUM_SHA256); ot_checksum_init (&state->content_checksum);
ot_checksum_update_bytes (&state->content_checksum, header);
gsize bytes_written;
if (!_ostree_write_variant_with_size (NULL, header, 0, &bytes_written, state->content_checksum,
cancellable, error))
return FALSE;
return TRUE; return TRUE;
} }
@ -582,18 +581,20 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
/* Fast path for regular files to bare repositories */ /* Fast path for regular files to bare repositories */
if (S_ISREG (state->mode) && if (S_ISREG (state->mode) &&
(repo->mode == OSTREE_REPO_MODE_BARE || _ostree_repo_mode_is_bare (repo->mode))
repo->mode == OSTREE_REPO_MODE_BARE_USER))
{ {
if (!_ostree_repo_open_content_bare (repo, state->checksum, if (!ostree_repo_has_object (repo, OSTREE_OBJECT_TYPE_FILE, state->checksum,
state->content_size, &state->have_obj, cancellable, error))
&state->tmpf,
&state->have_obj,
cancellable, error))
goto out; goto out;
if (!state->have_obj) if (!state->have_obj)
{ {
if (!_ostree_repo_open_content_bare (repo, state->checksum,
state->content_size,
&state->tmpf,
cancellable, error))
goto out;
state->content_out = g_unix_output_stream_new (state->tmpf.fd, FALSE); state->content_out = g_unix_output_stream_new (state->tmpf.fd, FALSE);
if (!handle_untrusted_content_checksum (repo, state, cancellable, error)) if (!handle_untrusted_content_checksum (repo, state, cancellable, error))
goto out; goto out;
@ -684,14 +685,19 @@ dispatch_open (OstreeRepo *repo,
if (state->stats_only) if (state->stats_only)
return TRUE; /* Early return */ return TRUE; /* Early return */
if (!ostree_repo_has_object (repo, OSTREE_OBJECT_TYPE_FILE, state->checksum,
&state->have_obj, cancellable, error))
return FALSE;
if (!state->have_obj)
{
if (!_ostree_repo_open_content_bare (repo, state->checksum, if (!_ostree_repo_open_content_bare (repo, state->checksum,
state->content_size, state->content_size,
&state->tmpf, &state->tmpf,
&state->have_obj,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
if (!state->have_obj)
state->content_out = g_unix_output_stream_new (state->tmpf.fd, FALSE); state->content_out = g_unix_output_stream_new (state->tmpf.fd, FALSE);
}
if (!handle_untrusted_content_checksum (repo, state, cancellable, error)) if (!handle_untrusted_content_checksum (repo, state, cancellable, error))
return FALSE; return FALSE;
@ -705,7 +711,7 @@ dispatch_write (OstreeRepo *repo,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
GLNX_AUTO_PREFIX_ERROR("opcode open-splice-and-close", error); GLNX_AUTO_PREFIX_ERROR("opcode write", error);
guint64 content_size; guint64 content_size;
guint64 content_offset; guint64 content_offset;
@ -721,15 +727,13 @@ dispatch_write (OstreeRepo *repo,
{ {
if (state->read_source_fd != -1) if (state->read_source_fd != -1)
{ {
if (lseek (state->read_source_fd, content_offset, SEEK_SET) == -1)
return glnx_throw_errno_prefix (error, "lseek");
while (content_size > 0) while (content_size > 0)
{ {
char buf[4096]; char buf[4096];
gssize bytes_read; gssize bytes_read;
do do
bytes_read = read (state->read_source_fd, buf, MIN(sizeof(buf), content_size)); bytes_read = pread (state->read_source_fd, buf, MIN(sizeof(buf), content_size), content_offset);
while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); while (G_UNLIKELY (bytes_read == -1 && errno == EINTR));
if (bytes_read == -1) if (bytes_read == -1)
return glnx_throw_errno_prefix (error, "read"); return glnx_throw_errno_prefix (error, "read");
@ -741,6 +745,7 @@ dispatch_write (OstreeRepo *repo,
return FALSE; return FALSE;
content_size -= bytes_read; content_size -= bytes_read;
content_offset += bytes_read;
} }
} }
else else
@ -766,11 +771,7 @@ dispatch_set_read_source (OstreeRepo *repo,
GLNX_AUTO_PREFIX_ERROR("opcode set-read-source", error); GLNX_AUTO_PREFIX_ERROR("opcode set-read-source", error);
guint64 source_offset; guint64 source_offset;
if (state->read_source_fd != -1) glnx_close_fd (&state->read_source_fd);
{
(void) close (state->read_source_fd);
state->read_source_fd = -1;
}
if (!read_varuint64 (state, &source_offset, error)) if (!read_varuint64 (state, &source_offset, error))
return FALSE; return FALSE;
@ -803,12 +804,7 @@ dispatch_unset_read_source (OstreeRepo *repo,
if (state->stats_only) if (state->stats_only)
return TRUE; /* Early return */ return TRUE; /* Early return */
if (state->read_source_fd != -1) glnx_close_fd (&state->read_source_fd);
{
(void) close (state->read_source_fd);
state->read_source_fd = -1;
}
g_clear_pointer (&state->read_source_object, g_free); g_clear_pointer (&state->read_source_object, g_free);
return TRUE; return TRUE;
@ -820,16 +816,17 @@ dispatch_close (OstreeRepo *repo,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
GLNX_AUTO_PREFIX_ERROR("opcode open-splice-and-close", error); GLNX_AUTO_PREFIX_ERROR("opcode close", error);
if (state->content_out) if (state->content_out)
{ {
if (!g_output_stream_flush (state->content_out, cancellable, error)) if (!g_output_stream_flush (state->content_out, cancellable, error))
return FALSE; return FALSE;
if (state->content_checksum) if (state->content_checksum.initialized)
{ {
const char *actual_checksum = g_checksum_get_string (state->content_checksum); char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
ot_checksum_get_hexdigest (&state->content_checksum, actual_checksum, sizeof (actual_checksum));
if (strcmp (actual_checksum, state->checksum) != 0) if (strcmp (actual_checksum, state->checksum) != 0)
return glnx_throw (error, "Corrupted object %s (actual checksum is %s)", return glnx_throw (error, "Corrupted object %s (actual checksum is %s)",
@ -848,7 +845,7 @@ dispatch_close (OstreeRepo *repo,
return FALSE; return FALSE;
g_clear_pointer (&state->xattrs, g_variant_unref); g_clear_pointer (&state->xattrs, g_variant_unref);
g_clear_pointer (&state->content_checksum, g_checksum_free); ot_checksum_clear (&state->content_checksum);
state->checksum_index++; state->checksum_index++;
state->output_target = NULL; state->output_target = NULL;

View File

@ -488,18 +488,13 @@ ostree_repo_finalize (GObject *object)
g_free (self->stagedir_prefix); g_free (self->stagedir_prefix);
g_clear_object (&self->repodir_fdrel); g_clear_object (&self->repodir_fdrel);
g_clear_object (&self->repodir); g_clear_object (&self->repodir);
if (self->repo_dir_fd != -1) glnx_close_fd (&self->repo_dir_fd);
(void) close (self->repo_dir_fd);
glnx_tmpdir_unset (&self->commit_stagedir); glnx_tmpdir_unset (&self->commit_stagedir);
glnx_release_lock_file (&self->commit_stagedir_lock); glnx_release_lock_file (&self->commit_stagedir_lock);
if (self->tmp_dir_fd != -1) glnx_close_fd (&self->tmp_dir_fd);
(void) close (self->tmp_dir_fd); glnx_close_fd (&self->cache_dir_fd);
if (self->cache_dir_fd != -1) glnx_close_fd (&self->objects_dir_fd);
(void) close (self->cache_dir_fd); glnx_close_fd (&self->uncompressed_objects_dir_fd);
if (self->objects_dir_fd != -1)
(void) close (self->objects_dir_fd);
if (self->uncompressed_objects_dir_fd != -1)
(void) close (self->uncompressed_objects_dir_fd);
g_clear_object (&self->sysroot_dir); g_clear_object (&self->sysroot_dir);
g_weak_ref_clear (&self->sysroot); g_weak_ref_clear (&self->sysroot);
g_free (self->remotes_config_dir); g_free (self->remotes_config_dir);
@ -734,7 +729,7 @@ ostree_repo_open_at (int dfd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int repo_dfd = -1; glnx_autofd int repo_dfd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
return NULL; return NULL;
@ -1463,7 +1458,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
gpgme_import_status_t import_status; gpgme_import_status_t import_status;
g_autofree char *source_tmp_dir = NULL; g_autofree char *source_tmp_dir = NULL;
g_autofree char *target_tmp_dir = NULL; g_autofree char *target_tmp_dir = NULL;
glnx_fd_close int target_temp_fd = -1; glnx_autofd int target_temp_fd = -1;
g_autoptr(GPtrArray) keys = NULL; g_autoptr(GPtrArray) keys = NULL;
struct stat stbuf; struct stat stbuf;
gpgme_error_t gpg_error; gpgme_error_t gpg_error;
@ -1596,7 +1591,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
} }
else if (errno == ENOENT) else if (errno == ENOENT)
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
/* Create an empty pubring.gpg file prior to importing keys. This /* Create an empty pubring.gpg file prior to importing keys. This
* prevents gpg2 from creating a pubring.kbx file in the new keybox * prevents gpg2 from creating a pubring.kbx file in the new keybox
@ -1711,6 +1706,9 @@ out:
* @NULL. Likewise if the summary file is not signed, @out_signatures is * @NULL. Likewise if the summary file is not signed, @out_signatures is
* set to @NULL. In either case the function still returns %TRUE. * set to @NULL. In either case the function still returns %TRUE.
* *
* This method does not verify the signature of the downloaded summary file.
* Use ostree_repo_verify_summary() for that.
*
* Parse the summary data into a #GVariant using g_variant_new_from_bytes() * Parse the summary data into a #GVariant using g_variant_new_from_bytes()
* with #OSTREE_SUMMARY_GVARIANT_FORMAT as the format string. * with #OSTREE_SUMMARY_GVARIANT_FORMAT as the format string.
* *
@ -1812,7 +1810,7 @@ repo_create_at_internal (int dfd,
return FALSE; return FALSE;
if (errno == 0) if (errno == 0)
{ {
glnx_fd_close int repo_dfd = -1; glnx_autofd int repo_dfd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
return FALSE; return FALSE;
@ -1828,7 +1826,7 @@ repo_create_at_internal (int dfd,
return glnx_throw_errno_prefix (error, "mkdirat"); return glnx_throw_errno_prefix (error, "mkdirat");
} }
glnx_fd_close int repo_dfd = -1; glnx_autofd int repo_dfd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
return FALSE; return FALSE;
@ -1919,7 +1917,7 @@ ostree_repo_create (OstreeRepo *self,
g_variant_builder_add (builder, "{s@v}", "collection-id", g_variant_builder_add (builder, "{s@v}", "collection-id",
g_variant_new_variant (g_variant_new_string (self->collection_id))); g_variant_new_variant (g_variant_new_string (self->collection_id)));
glnx_fd_close int repo_dir_fd = -1; glnx_autofd int repo_dir_fd = -1;
if (!repo_create_at_internal (AT_FDCWD, repopath, mode, if (!repo_create_at_internal (AT_FDCWD, repopath, mode,
g_variant_builder_end (builder), g_variant_builder_end (builder),
&repo_dir_fd, &repo_dir_fd,
@ -1963,7 +1961,7 @@ ostree_repo_create_at (int dfd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int repo_dfd = -1; glnx_autofd int repo_dfd = -1;
if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd, if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd,
cancellable, error)) cancellable, error))
return NULL; return NULL;
@ -2528,14 +2526,12 @@ ostree_repo_set_cache_dir (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
int fd; glnx_autofd int fd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &fd, error)) if (!glnx_opendirat (dfd, path, TRUE, &fd, error))
return FALSE; return FALSE;
if (self->cache_dir_fd != -1) glnx_close_fd (&self->cache_dir_fd);
close (self->cache_dir_fd); self->cache_dir_fd = glnx_steal_fd (&fd);
self->cache_dir_fd = fd;
return TRUE; return TRUE;
} }
@ -2807,16 +2803,17 @@ load_metadata_internal (OstreeRepo *self,
GVariant **out_variant, GVariant **out_variant,
GInputStream **out_stream, GInputStream **out_stream,
guint64 *out_size, guint64 *out_size,
OstreeRepoCommitState *out_state,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
struct stat stbuf; glnx_autofd int fd = -1;
glnx_fd_close int fd = -1;
g_autoptr(GInputStream) ret_stream = NULL; g_autoptr(GInputStream) ret_stream = NULL;
g_autoptr(GVariant) ret_variant = NULL; g_autoptr(GVariant) ret_variant = NULL;
g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (objtype), FALSE); g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (objtype), FALSE);
g_return_val_if_fail (objtype == OSTREE_OBJECT_TYPE_COMMIT || out_state == NULL, FALSE);
/* Special caching for dirmeta objects, since they're commonly referenced many /* Special caching for dirmeta objects, since they're commonly referenced many
* times. * times.
@ -2853,36 +2850,14 @@ load_metadata_internal (OstreeRepo *self,
if (fd != -1) if (fd != -1)
{ {
struct stat stbuf;
if (!glnx_fstat (fd, &stbuf, error)) if (!glnx_fstat (fd, &stbuf, error))
return FALSE; return FALSE;
if (out_variant) if (out_variant)
{ {
/* http://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access */ if (!ot_variant_read_fd (fd, 0, ostree_metadata_variant_type (objtype), TRUE,
if (stbuf.st_size > 16*1024) &ret_variant, error))
{
GMappedFile *mfile;
mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
if (!mfile)
return FALSE; return FALSE;
ret_variant = g_variant_new_from_data (ostree_metadata_variant_type (objtype),
g_mapped_file_get_contents (mfile),
g_mapped_file_get_length (mfile),
TRUE,
(GDestroyNotify) g_mapped_file_unref,
mfile);
g_variant_ref_sink (ret_variant);
}
else
{
g_autoptr(GBytes) data = glnx_fd_readall_bytes (fd, cancellable, error);
if (!data)
return FALSE;
ret_variant = g_variant_new_from_bytes (ostree_metadata_variant_type (objtype),
data, TRUE);
g_variant_ref_sink (ret_variant);
}
/* Now, let's put it in the cache */ /* Now, let's put it in the cache */
if (is_dirmeta_cachable) if (is_dirmeta_cachable)
@ -2904,11 +2879,24 @@ load_metadata_internal (OstreeRepo *self,
if (out_size) if (out_size)
*out_size = stbuf.st_size; *out_size = stbuf.st_size;
if (out_state)
{
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (sha256);
*out_state = 0;
if (!glnx_fstatat_allow_noent (self->repo_dir_fd, commitpartial_path, NULL, 0, error))
return FALSE;
if (errno == 0)
*out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL;
}
} }
else if (self->parent_repo) else if (self->parent_repo)
{ {
if (!ostree_repo_load_variant (self->parent_repo, objtype, sha256, &ret_variant, error)) /* Directly recurse to simplify out parameters */
return FALSE; return load_metadata_internal (self->parent_repo, objtype, sha256, error_if_not_found,
out_variant, out_stream, out_size, out_state,
cancellable, error);
} }
else if (error_if_not_found) else if (error_if_not_found)
{ {
@ -2952,7 +2940,7 @@ repo_load_file_archive (OstreeRepo *self,
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode);
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd, if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd,
error)) error))
return FALSE; return FALSE;
@ -3008,7 +2996,7 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
} }
struct stat stbuf; struct stat stbuf;
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
g_autofree char *ret_symlink = NULL; g_autofree char *ret_symlink = NULL;
g_autoptr(GVariant) ret_xattrs = NULL; g_autoptr(GVariant) ret_xattrs = NULL;
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
@ -3082,7 +3070,7 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
ret_symlink = g_strndup (targetbuf, target_size); ret_symlink = g_strndup (targetbuf, target_size);
} }
/* In the symlink case, we don't want to return the bare-user fd */ /* In the symlink case, we don't want to return the bare-user fd */
(void) close (glnx_steal_fd (&fd)); glnx_close_fd (&fd);
} }
} }
else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
@ -3158,7 +3146,7 @@ ostree_repo_load_file (OstreeRepo *self,
cancellable, error); cancellable, error);
else else
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
struct stat stbuf; struct stat stbuf;
g_autofree char *symlink_target = NULL; g_autofree char *symlink_target = NULL;
g_autoptr(GVariant) ret_xattrs = NULL; g_autoptr(GVariant) ret_xattrs = NULL;
@ -3220,7 +3208,7 @@ ostree_repo_load_object_stream (OstreeRepo *self,
if (OSTREE_OBJECT_TYPE_IS_META (objtype)) if (OSTREE_OBJECT_TYPE_IS_META (objtype))
{ {
if (!load_metadata_internal (self, objtype, checksum, TRUE, NULL, if (!load_metadata_internal (self, objtype, checksum, TRUE, NULL,
&ret_input, &size, &ret_input, &size, NULL,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
} }
@ -3516,7 +3504,7 @@ ostree_repo_load_variant_if_exists (OstreeRepo *self,
GError **error) GError **error)
{ {
return load_metadata_internal (self, objtype, sha256, FALSE, return load_metadata_internal (self, objtype, sha256, FALSE,
out_variant, NULL, NULL, NULL, error); out_variant, NULL, NULL, NULL, NULL, error);
} }
/** /**
@ -3538,7 +3526,7 @@ ostree_repo_load_variant (OstreeRepo *self,
GError **error) GError **error)
{ {
return load_metadata_internal (self, objtype, sha256, TRUE, return load_metadata_internal (self, objtype, sha256, TRUE,
out_variant, NULL, NULL, NULL, error); out_variant, NULL, NULL, NULL, NULL, error);
} }
/** /**
@ -3561,31 +3549,8 @@ ostree_repo_load_commit (OstreeRepo *self,
OstreeRepoCommitState *out_state, OstreeRepoCommitState *out_state,
GError **error) GError **error)
{ {
if (out_variant) return load_metadata_internal (self, OSTREE_OBJECT_TYPE_COMMIT, checksum, TRUE,
{ out_variant, NULL, NULL, out_state, NULL, error);
if (!load_metadata_internal (self, OSTREE_OBJECT_TYPE_COMMIT, checksum, TRUE,
out_variant, NULL, NULL, NULL, error))
return FALSE;
}
if (out_state)
{
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum);
struct stat stbuf;
*out_state = 0;
if (fstatat (self->repo_dir_fd, commitpartial_path, &stbuf, 0) == 0)
{
*out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL;
}
else if (errno != ENOENT)
{
return glnx_throw_errno_prefix (error, "fstatat(%s)", commitpartial_path);
}
}
return TRUE;
} }
/** /**
@ -4119,7 +4084,9 @@ ostree_repo_sign_commit (OstreeRepo *self,
* pass the homedir so that the signing key can be imported, allowing * pass the homedir so that the signing key can be imported, allowing
* subkey signatures to be recognised. */ * subkey signatures to be recognised. */
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
g_autoptr(GFile) verify_keydir = g_file_new_for_path (homedir); g_autoptr(GFile) verify_keydir = NULL;
if (homedir != NULL)
verify_keydir = g_file_new_for_path (homedir);
g_autoptr(OstreeGpgVerifyResult) result g_autoptr(OstreeGpgVerifyResult) result
=_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata,
NULL, verify_keydir, NULL, NULL, verify_keydir, NULL,
@ -4202,15 +4169,24 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autoptr(GBytes) summary_data = ot_file_mapat_bytes (self->repo_dir_fd, "summary", error); glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (self->repo_dir_fd, "summary", TRUE, &fd, error))
return FALSE;
g_autoptr(GBytes) summary_data = ot_fd_readall_or_mmap (fd, 0, error);
if (!summary_data) if (!summary_data)
return FALSE; return FALSE;
/* Note that fd is reused below */
glnx_close_fd (&fd);
g_autoptr(GVariant) existing_signatures = NULL; g_autoptr(GVariant) existing_signatures = NULL;
if (!ot_util_variant_map_at (self->repo_dir_fd, "summary.sig", if (!ot_openat_ignore_enoent (self->repo_dir_fd, "summary.sig", &fd, error))
G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING),
OT_VARIANT_MAP_ALLOW_NOENT, &existing_signatures, error))
return FALSE; return FALSE;
if (fd != -1)
{
if (!ot_variant_read_fd (fd, 0, G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING),
FALSE, &existing_signatures, error))
return FALSE;
}
g_autoptr(GVariant) new_metadata = NULL; g_autoptr(GVariant) new_metadata = NULL;
for (guint i = 0; key_id[i]; i++) for (guint i = 0; key_id[i]; i++)
@ -4250,7 +4226,7 @@ find_keyring (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote->keyring, &fd, error)) if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote->keyring, &fd, error))
return FALSE; return FALSE;
@ -4328,7 +4304,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
if (keyring_data != NULL) if (keyring_data != NULL)
{ {
_ostree_gpg_verifier_add_keyring_data (verifier, keyring_data); _ostree_gpg_verifier_add_keyring_data (verifier, keyring_data, remote->keyring);
add_global_keyring_dir = FALSE; add_global_keyring_dir = FALSE;
} }
@ -4759,23 +4735,21 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
return FALSE; return FALSE;
g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to); g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to);
glnx_fd_close int superblock_file_fd = -1; glnx_autofd int superblock_file_fd = -1;
if (!glnx_openat_rdonly (self->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error)) if (!glnx_openat_rdonly (self->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error))
return FALSE; return FALSE;
g_autoptr(GInputStream) in_stream = g_unix_input_stream_new (superblock_file_fd, FALSE); g_autoptr(GBytes) superblock_content = ot_fd_readall_or_mmap (superblock_file_fd, 0, error);
if (!in_stream) if (!superblock_content)
return FALSE; return FALSE;
g_auto(OtChecksum) hasher = { 0, };
ot_checksum_init (&hasher);
ot_checksum_update_bytes (&hasher, superblock_content);
guint8 digest[OSTREE_SHA256_DIGEST_LEN];
ot_checksum_get_digest (&hasher, digest, sizeof (digest));
g_autofree guchar *csum = NULL; g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (digest, sizeof (digest)));
if (!ot_gio_checksum_stream (in_stream,
&csum,
cancellable,
error))
return FALSE;
g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (csum, 32));
} }
if (delta_names->len > 0) if (delta_names->len > 0)
@ -4960,7 +4934,6 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
while (!ret_tmpdir.initialized) while (!ret_tmpdir.initialized)
{ {
struct dirent *dent; struct dirent *dent;
glnx_fd_close int existing_tmpdir_fd = -1;
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
@ -4977,7 +4950,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
dent->d_type != DT_DIR) dent->d_type != DT_DIR)
continue; continue;
glnx_fd_close int target_dfd = -1; glnx_autofd int target_dfd = -1;
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, FALSE, if (!glnx_opendirat (dfd_iter.fd, dent->d_name, FALSE,
&target_dfd, &local_error)) &target_dfd, &local_error))
{ {

View File

@ -630,6 +630,7 @@ typedef OstreeRepoCommitFilterResult (*OstreeRepoCommitFilter) (OstreeRepo *r
* @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES: Generate size information. * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES: Generate size information.
* @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS: Canonicalize permissions for bare-user-only mode. * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS: Canonicalize permissions for bare-user-only mode.
* @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED: Emit an error if configured SELinux policy does not provide a label * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED: Emit an error if configured SELinux policy does not provide a label
* @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME: Delete added files/directories after commit; Since: 2017.13
*/ */
typedef enum { typedef enum {
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE = 0, OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE = 0,
@ -637,6 +638,7 @@ typedef enum {
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES = (1 << 1), OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES = (1 << 1),
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS = (1 << 2), OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS = (1 << 2),
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED = (1 << 3), OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED = (1 << 3),
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME = (1 << 4),
} OstreeRepoCommitModifierFlags; } OstreeRepoCommitModifierFlags;
/** /**
@ -846,7 +848,7 @@ typedef enum {
/** /**
* OstreeRepoCheckoutOverwriteMode: * OstreeRepoCheckoutOverwriteMode:
* @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options
* @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories (unless whiteouts are enabled, then directories are replaced)
* @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories
* @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: Like UNION_FILES, but error if files are not identical (requires hardlink checkouts) * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: Like UNION_FILES, but error if files are not identical (requires hardlink checkouts)
*/ */
@ -909,6 +911,9 @@ OstreeRepoDevInoCache * ostree_repo_devino_cache_ref (OstreeRepoDevInoCache *cac
_OSTREE_PUBLIC _OSTREE_PUBLIC
void ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache); void ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
void ostree_repo_checkout_at_options_set_devino (OstreeRepoCheckoutAtOptions *opts, OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC _OSTREE_PUBLIC
gboolean ostree_repo_checkout_at (OstreeRepo *self, gboolean ostree_repo_checkout_at (OstreeRepo *self,
OstreeRepoCheckoutAtOptions *options, OstreeRepoCheckoutAtOptions *options,

View File

@ -203,7 +203,7 @@ get_policy_checksum (char **out_csum,
g_autofree char *best_policy = NULL; g_autofree char *best_policy = NULL;
int best_version = 0; int best_version = 0;
glnx_fd_close int bindir_dfd = -1; glnx_autofd int bindir_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error)) if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error))
return FALSE; return FALSE;

View File

@ -282,7 +282,7 @@ cleanup_old_deployments (OstreeSysroot *self,
if (!g_hash_table_lookup (active_deployment_dirs, deployment_path)) if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
{ {
struct stat stbuf; struct stat stbuf;
glnx_fd_close int deployment_fd = -1; glnx_autofd int deployment_fd = -1;
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
&deployment_fd, error)) &deployment_fd, error))

View File

@ -118,6 +118,7 @@ hardlink_or_copy_at (int src_dfd,
return TRUE; return TRUE;
} }
/* Copy ownership, mode, and xattrs from source directory to destination */
static gboolean static gboolean
dirfd_copy_attributes_and_xattrs (int src_parent_dfd, dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
const char *src_name, const char *src_name,
@ -163,7 +164,7 @@ copy_dir_recurse (int src_parent_dfd,
GError **error) GError **error)
{ {
g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, }; g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, };
glnx_fd_close int dest_dfd = -1; glnx_autofd int dest_dfd = -1;
struct dirent *dent; struct dirent *dent;
if (!glnx_dirfd_iterator_init_at (src_parent_dfd, name, TRUE, &src_dfd_iter, error)) if (!glnx_dirfd_iterator_init_at (src_parent_dfd, name, TRUE, &src_dfd_iter, error))
@ -212,6 +213,9 @@ copy_dir_recurse (int src_parent_dfd,
return TRUE; return TRUE;
} }
/* If a chain of directories is added, this function will ensure
* they're created.
*/
static gboolean static gboolean
ensure_directory_from_template (int orig_etc_fd, ensure_directory_from_template (int orig_etc_fd,
int modified_etc_fd, int modified_etc_fd,
@ -222,8 +226,8 @@ ensure_directory_from_template (int orig_etc_fd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int src_dfd = -1; glnx_autofd int src_dfd = -1;
glnx_fd_close int target_dfd = -1; glnx_autofd int target_dfd = -1;
g_assert (path != NULL); g_assert (path != NULL);
g_assert (*path != '/' && *path != '\0'); g_assert (*path != '/' && *path != '\0');
@ -274,12 +278,9 @@ ensure_directory_from_template (int orig_etc_fd,
return TRUE; return TRUE;
} }
/** /* Copy (relative) @path from @modified_etc_fd to @new_etc_fd, overwriting any
* copy_modified_config_file: * existing file there. The @path may refer to a regular file, a symbolic link,
* * or a directory. Directories will be copied recursively.
* Copy @file from @modified_etc to @new_etc, overwriting any existing
* file there. The @file may refer to a regular file, a symbolic
* link, or a directory. Directories will be copied recursively.
*/ */
static gboolean static gboolean
copy_modified_config_file (int orig_etc_fd, copy_modified_config_file (int orig_etc_fd,
@ -296,7 +297,7 @@ copy_modified_config_file (int orig_etc_fd,
if (!glnx_fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW, error)) if (!glnx_fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW, error))
return glnx_prefix_error (error, "Reading modified config file"); return glnx_prefix_error (error, "Reading modified config file");
glnx_fd_close int dest_parent_dfd = -1; glnx_autofd int dest_parent_dfd = -1;
if (strchr (path, '/') != NULL) if (strchr (path, '/') != NULL)
{ {
g_autofree char *parent = g_path_get_dirname (path); g_autofree char *parent = g_path_get_dirname (path);
@ -392,7 +393,7 @@ merge_configuration_from (OstreeSysroot *sysroot,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int owned_merge_deployment_dfd = -1; glnx_autofd int owned_merge_deployment_dfd = -1;
const OstreeSysrootDebugFlags flags = sysroot->debug_flags; const OstreeSysrootDebugFlags flags = sysroot->debug_flags;
g_assert (merge_deployment != NULL && new_deployment != NULL); g_assert (merge_deployment != NULL && new_deployment != NULL);
@ -442,13 +443,13 @@ merge_configuration_from (OstreeSysroot *sysroot,
_ostree_sysroot_emit_journal_msg (sysroot, msg); _ostree_sysroot_emit_journal_msg (sysroot, msg);
} }
glnx_fd_close int orig_etc_fd = -1; glnx_autofd int orig_etc_fd = -1;
if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error)) if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error))
return FALSE; return FALSE;
glnx_fd_close int modified_etc_fd = -1; glnx_autofd int modified_etc_fd = -1;
if (!glnx_opendirat (merge_deployment_dfd, "etc", TRUE, &modified_etc_fd, error)) if (!glnx_opendirat (merge_deployment_dfd, "etc", TRUE, &modified_etc_fd, error))
return FALSE; return FALSE;
glnx_fd_close int new_etc_fd = -1; glnx_autofd int new_etc_fd = -1;
if (!glnx_opendirat (new_deployment_dfd, "etc", TRUE, &new_etc_fd, error)) if (!glnx_opendirat (new_deployment_dfd, "etc", TRUE, &new_etc_fd, error))
return FALSE; return FALSE;
@ -490,11 +491,9 @@ merge_configuration_from (OstreeSysroot *sysroot,
return TRUE; return TRUE;
} }
/** /* Look up @revision in the repository, and check it out in
* checkout_deployment_tree:
*
* Look up @revision in the repository, and check it out in
* /ostree/deploy/OS/deploy/${treecsum}.${deployserial}. * /ostree/deploy/OS/deploy/${treecsum}.${deployserial}.
* A dfd for the result is returned in @out_deployment_dfd.
*/ */
static gboolean static gboolean
checkout_deployment_tree (OstreeSysroot *sysroot, checkout_deployment_tree (OstreeSysroot *sysroot,
@ -509,7 +508,7 @@ checkout_deployment_tree (OstreeSysroot *sysroot,
const char *csum = ostree_deployment_get_csum (deployment); const char *csum = ostree_deployment_get_csum (deployment);
g_autofree char *checkout_target_name = NULL; g_autofree char *checkout_target_name = NULL;
g_autofree char *osdeploy_path = NULL; g_autofree char *osdeploy_path = NULL;
glnx_fd_close int osdeploy_dfd = -1; glnx_autofd int osdeploy_dfd = -1;
int ret_fd; int ret_fd;
osdeploy_path = g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL); osdeploy_path = g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL);
@ -676,6 +675,9 @@ selinux_relabel_dir (OstreeSysroot *sysroot,
return ret; return ret;
} }
/* Handles SELinux labeling for /var; this is slated to be deleted. See
* https://github.com/ostreedev/ostree/pull/872
*/
static gboolean static gboolean
selinux_relabel_var_if_needed (OstreeSysroot *sysroot, selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
OstreeSePolicy *sepolicy, OstreeSePolicy *sepolicy,
@ -730,6 +732,11 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
return TRUE; return TRUE;
} }
/* OSTree implements a "3 way" merge model for /etc. For a bit more information
* on this, see the manual. This function uses the configuration for
* @previous_deployment, and writes the merged configuration into @deployment's
* /etc. If available, we also load the SELinux policy from the new root.
*/
static gboolean static gboolean
merge_configuration (OstreeSysroot *sysroot, merge_configuration (OstreeSysroot *sysroot,
OstreeRepo *repo, OstreeRepo *repo,
@ -820,6 +827,7 @@ merge_configuration (OstreeSysroot *sysroot,
return TRUE; return TRUE;
} }
/* Write the origin file for a deployment. */
static gboolean static gboolean
write_origin_file_internal (OstreeSysroot *sysroot, write_origin_file_internal (OstreeSysroot *sysroot,
OstreeDeployment *deployment, OstreeDeployment *deployment,
@ -891,8 +899,7 @@ typedef struct {
static void static void
_ostree_kernel_layout_free (OstreeKernelLayout *layout) _ostree_kernel_layout_free (OstreeKernelLayout *layout)
{ {
if (layout->boot_dfd != -1) glnx_close_fd (&layout->boot_dfd);
(void) close (layout->boot_dfd);
g_free (layout->kernel_srcpath); g_free (layout->kernel_srcpath);
g_free (layout->kernel_namever); g_free (layout->kernel_namever);
g_free (layout->initramfs_srcpath); g_free (layout->initramfs_srcpath);
@ -981,16 +988,17 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd,
} }
/* We found a module directory, compute the checksum */ /* We found a module directory, compute the checksum */
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); g_auto(OtChecksum) checksum = { 0, };
glnx_fd_close int fd = -1; ot_checksum_init (&checksum);
glnx_autofd int fd = -1;
/* Checksum the kernel */ /* Checksum the kernel */
if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error)) if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error))
return FALSE; return FALSE;
g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE);
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE; return FALSE;
g_clear_object (&in); g_clear_object (&in);
(void) close (fd); fd = -1; glnx_close_fd (&fd);
/* Look for an initramfs, but it's optional; since there wasn't any precedent /* Look for an initramfs, but it's optional; since there wasn't any precedent
* for this, let's be a bit conservative and support both `initramfs.img` and * for this, let's be a bit conservative and support both `initramfs.img` and
@ -1014,11 +1022,13 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd,
ret_layout->initramfs_srcpath = g_strdup (initramfs_path); ret_layout->initramfs_srcpath = g_strdup (initramfs_path);
ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver); ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver);
in = g_unix_input_stream_new (fd, FALSE); in = g_unix_input_stream_new (fd, FALSE);
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE; return FALSE;
} }
ret_layout->bootcsum = g_strdup (g_checksum_get_string (checksum)); char hexdigest[OSTREE_SHA256_STRING_LEN+1];
ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest));
ret_layout->bootcsum = g_strdup (hexdigest);
*out_layout = g_steal_pointer (&ret_layout); *out_layout = g_steal_pointer (&ret_layout);
return TRUE; return TRUE;
@ -1227,8 +1237,8 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
int sockpair[2]; int sockpair[2];
if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0) if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0)
return glnx_throw_errno_prefix (error, "socketpair"); return glnx_throw_errno_prefix (error, "socketpair");
glnx_fd_close int sock_parent = sockpair[0]; glnx_autofd int sock_parent = sockpair[0];
glnx_fd_close int sock_watchdog = sockpair[1]; glnx_autofd int sock_watchdog = sockpair[1];
pid_t pid = fork (); pid_t pid = fork ();
if (pid < 0) if (pid < 0)
@ -1238,7 +1248,7 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
char c = '!'; char c = '!';
if (pid == 0) /* Child watchdog/unfreezer process. */ if (pid == 0) /* Child watchdog/unfreezer process. */
{ {
(void) close (glnx_steal_fd (&sock_parent)); glnx_close_fd (&sock_parent);
/* Daemonize, and mask SIGINT/SIGTERM, so we're likely to survive e.g. /* Daemonize, and mask SIGINT/SIGTERM, so we're likely to survive e.g.
* someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of * someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of
* `ostree admin upgrade`. We don't daemonize though if testing so * `ostree admin upgrade`. We don't daemonize though if testing so
@ -1291,11 +1301,16 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
} }
if (debug_fifreeze) if (debug_fifreeze)
g_printerr ("fifreeze watchdog was run\n"); g_printerr ("fifreeze watchdog was run\n");
exit (EXIT_SUCCESS); /* We use _exit() rather than exit() to avoid tripping over any shared
* libraries in process that aren't fork() safe; for example gjs/spidermonkey:
* https://github.com/ostreedev/ostree/issues/1262
* This doesn't help for the err()/errx() calls above, but eh...
*/
_exit (EXIT_SUCCESS);
} }
else /* Parent process. */ else /* Parent process. */
{ {
(void) close (glnx_steal_fd (&sock_watchdog)); glnx_close_fd (&sock_watchdog);
/* Wait for the watchdog to say it's set up; mainly that it's /* Wait for the watchdog to say it's set up; mainly that it's
* masked SIGTERM successfully. * masked SIGTERM successfully.
*/ */
@ -1321,11 +1336,15 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
/* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */ /* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */
if (ioctl (rootfs_dfd, FIFREEZE, 0) != 0) if (ioctl (rootfs_dfd, FIFREEZE, 0) != 0)
{ {
/* Not supported, or we're running in the unit tests (as non-root)? /* Not supported, we're running in the unit tests (as non-root), or
* the filesystem is already frozen (EBUSY).
* OK, let's just do a syncfs. * OK, let's just do a syncfs.
*/ */
if (G_IN_SET (errno, EOPNOTSUPP, EPERM)) if (G_IN_SET (errno, EOPNOTSUPP, EPERM, EBUSY))
{ {
/* Warn if the filesystem was already frozen */
if (errno == EBUSY)
g_debug ("Filesystem already frozen, falling back to syncfs");
if (TEMP_FAILURE_RETRY (syncfs (rootfs_dfd)) != 0) if (TEMP_FAILURE_RETRY (syncfs (rootfs_dfd)) != 0)
return glnx_throw_errno_prefix (error, "syncfs"); return glnx_throw_errno_prefix (error, "syncfs");
/* Write the completion, and return */ /* Write the completion, and return */
@ -1338,7 +1357,13 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
} }
/* And finally thaw, then signal our completion to the watchdog */ /* And finally thaw, then signal our completion to the watchdog */
if (TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)) != 0) if (TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)) != 0)
{
/* Warn but don't error if the filesystem was already thawed */
if (errno == EINVAL)
g_debug ("Filesystem already thawed");
else
return glnx_throw_errno_prefix (error, "ioctl(FITHAW)"); return glnx_throw_errno_prefix (error, "ioctl(FITHAW)");
}
if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) if (write (sock_parent, &c, sizeof (c)) != sizeof (c))
return glnx_throw_errno_prefix (error, "write(watchdog FITHAW complete)"); return glnx_throw_errno_prefix (error, "write(watchdog FITHAW complete)");
} }
@ -1369,7 +1394,7 @@ full_system_sync (OstreeSysroot *self,
out_stats->root_syncfs_msec = (end_msec - start_msec); out_stats->root_syncfs_msec = (end_msec - start_msec);
start_msec = g_get_monotonic_time () / 1000; start_msec = g_get_monotonic_time () / 1000;
glnx_fd_close int boot_dfd = -1; glnx_autofd int boot_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error))
return FALSE; return FALSE;
if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error)) if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error))
@ -1391,6 +1416,12 @@ full_system_sync (OstreeSysroot *self,
return TRUE; return TRUE;
} }
/* Write out the "bootlinks", which are symlinks pointing to deployments.
* We might be generating a new bootversion (i.e. updating the bootloader config),
* or we might just be generating a "sub-bootversion".
*
* These new links are made active by swap_bootlinks().
*/
static gboolean static gboolean
create_new_bootlinks (OstreeSysroot *self, create_new_bootlinks (OstreeSysroot *self,
int bootversion, int bootversion,
@ -1398,7 +1429,7 @@ create_new_bootlinks (OstreeSysroot *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int ostree_dfd = -1; glnx_autofd int ostree_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error))
return FALSE; return FALSE;
@ -1423,7 +1454,7 @@ create_new_bootlinks (OstreeSysroot *self,
if (!glnx_shutil_mkdir_p_at (ostree_dfd, ostree_subbootdir_name, 0755, cancellable, error)) if (!glnx_shutil_mkdir_p_at (ostree_dfd, ostree_subbootdir_name, 0755, cancellable, error))
return FALSE; return FALSE;
glnx_fd_close int ostree_subbootdir_dfd = -1; glnx_autofd int ostree_subbootdir_dfd = -1;
if (!glnx_opendirat (ostree_dfd, ostree_subbootdir_name, FALSE, &ostree_subbootdir_dfd, error)) if (!glnx_opendirat (ostree_dfd, ostree_subbootdir_name, FALSE, &ostree_subbootdir_dfd, error))
return FALSE; return FALSE;
@ -1451,6 +1482,8 @@ create_new_bootlinks (OstreeSysroot *self,
return TRUE; return TRUE;
} }
/* Rename into place symlinks created via create_new_bootlinks().
*/
static gboolean static gboolean
swap_bootlinks (OstreeSysroot *self, swap_bootlinks (OstreeSysroot *self,
int bootversion, int bootversion,
@ -1458,7 +1491,7 @@ swap_bootlinks (OstreeSysroot *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int ostree_dfd = -1; glnx_autofd int ostree_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error))
return FALSE; return FALSE;
@ -1512,10 +1545,9 @@ parse_os_release (const char *contents,
return ret; return ret;
} }
/* /* Given @deployment, prepare it to be booted; basically copying its
* install_deployment_kernel: * kernel/initramfs into /boot/ostree (if needed) and writing out an entry in
* * /boot/loader/entries.
* Write out an entry in /boot/loader/entries for @deployment.
*/ */
static gboolean static gboolean
install_deployment_kernel (OstreeSysroot *sysroot, install_deployment_kernel (OstreeSysroot *sysroot,
@ -1530,7 +1562,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{ {
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment); OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment); g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment);
glnx_fd_close int deployment_dfd = -1; glnx_autofd int deployment_dfd = -1;
if (!glnx_opendirat (sysroot->sysroot_fd, deployment_dirpath, FALSE, if (!glnx_opendirat (sysroot->sysroot_fd, deployment_dirpath, FALSE,
&deployment_dfd, error)) &deployment_dfd, error))
return FALSE; return FALSE;
@ -1541,7 +1573,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
cancellable, error)) cancellable, error))
return FALSE; return FALSE;
glnx_fd_close int boot_dfd = -1; glnx_autofd int boot_dfd = -1;
if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error)) if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error))
return FALSE; return FALSE;
@ -1555,7 +1587,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error)) if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error))
return FALSE; return FALSE;
glnx_fd_close int bootcsum_dfd = -1; glnx_autofd int bootcsum_dfd = -1;
if (!glnx_opendirat (boot_dfd, bootcsumdir, TRUE, &bootcsum_dfd, error)) if (!glnx_opendirat (boot_dfd, bootcsumdir, TRUE, &bootcsum_dfd, error))
return FALSE; return FALSE;
@ -1680,13 +1712,13 @@ install_deployment_kernel (OstreeSysroot *sysroot,
g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d", g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d",
new_bootversion, osname, bootcsum, new_bootversion, osname, bootcsum,
ostree_deployment_get_bootserial (deployment)); ostree_deployment_get_bootserial (deployment));
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = _ostree_kernel_args_from_string (val); g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_from_string (val);
_ostree_kernel_args_replace_take (kargs, ostree_kernel_arg); _ostree_kernel_args_replace_take (kargs, ostree_kernel_arg);
ostree_kernel_arg = NULL; ostree_kernel_arg = NULL;
g_autofree char *options_key = _ostree_kernel_args_to_string (kargs); g_autofree char *options_key = _ostree_kernel_args_to_string (kargs);
ostree_bootconfig_parser_set (bootconfig, "options", options_key); ostree_bootconfig_parser_set (bootconfig, "options", options_key);
glnx_fd_close int bootconf_dfd = -1; glnx_autofd int bootconf_dfd = -1;
if (!glnx_opendirat (boot_dfd, bootconfdir, TRUE, &bootconf_dfd, error)) if (!glnx_opendirat (boot_dfd, bootconfdir, TRUE, &bootconf_dfd, error))
return FALSE; return FALSE;
@ -1698,6 +1730,10 @@ install_deployment_kernel (OstreeSysroot *sysroot,
return TRUE; return TRUE;
} }
/* We generate the symlink on disk, then potentially do a syncfs() to ensure
* that it (and everything else we wrote) has hit disk. Only after that do we
* rename it into place.
*/
static gboolean static gboolean
prepare_new_bootloader_link (OstreeSysroot *sysroot, prepare_new_bootloader_link (OstreeSysroot *sysroot,
int current_bootversion, int current_bootversion,
@ -1719,6 +1755,7 @@ prepare_new_bootloader_link (OstreeSysroot *sysroot,
return TRUE; return TRUE;
} }
/* Update the /boot/loader symlink to point to /boot/loader.$new_bootversion */
static gboolean static gboolean
swap_bootloader (OstreeSysroot *sysroot, swap_bootloader (OstreeSysroot *sysroot,
int current_bootversion, int current_bootversion,
@ -1726,7 +1763,7 @@ swap_bootloader (OstreeSysroot *sysroot,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
glnx_fd_close int boot_dfd = -1; glnx_autofd int boot_dfd = -1;
g_assert ((current_bootversion == 0 && new_bootversion == 1) || g_assert ((current_bootversion == 0 && new_bootversion == 1) ||
(current_bootversion == 1 && new_bootversion == 0)); (current_bootversion == 1 && new_bootversion == 0));
@ -1778,6 +1815,15 @@ assign_bootserials (GPtrArray *deployments)
return ret; return ret;
} }
/* OSTree implements a special optimization where we want to avoid touching
* the bootloader configuration if the kernel layout hasn't changed. This is
* handled by the ostree= kernel argument referring to a "bootlink". But
* we *do* need to update the bootloader configuration if the kernel arguments
* change.
*
* Hence, this function determines if @a and @b are fully compatible from a
* bootloader perspective.
*/
static gboolean static gboolean
deployment_bootconfigs_equal (OstreeDeployment *a, deployment_bootconfigs_equal (OstreeDeployment *a,
OstreeDeployment *b) OstreeDeployment *b)
@ -1793,8 +1839,8 @@ deployment_bootconfigs_equal (OstreeDeployment *a,
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b); OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
const char *a_boot_options = ostree_bootconfig_parser_get (a_bootconfig, "options"); const char *a_boot_options = ostree_bootconfig_parser_get (a_bootconfig, "options");
const char *b_boot_options = ostree_bootconfig_parser_get (b_bootconfig, "options"); const char *b_boot_options = ostree_bootconfig_parser_get (b_bootconfig, "options");
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *a_kargs = NULL; g_autoptr(OstreeKernelArgs) a_kargs = NULL;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *b_kargs = NULL; g_autoptr(OstreeKernelArgs) b_kargs = NULL;
g_autofree char *a_boot_options_without_ostree = NULL; g_autofree char *a_boot_options_without_ostree = NULL;
g_autofree char *b_boot_options_without_ostree = NULL; g_autofree char *b_boot_options_without_ostree = NULL;
@ -1841,6 +1887,11 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self,
return TRUE; return TRUE;
} }
/* Detect whether or not @path refers to a read-only mountpoint. This is
* currently just used to handle a potentially read-only /boot by transiently
* remounting it read-write. In the future we might also do this for e.g.
* /sysroot.
*/
static gboolean static gboolean
is_ro_mount (const char *path) is_ro_mount (const char *path)
{ {
@ -2207,7 +2258,7 @@ allocate_deployserial (OstreeSysroot *self,
g_autoptr(GPtrArray) tmp_current_deployments = g_autoptr(GPtrArray) tmp_current_deployments =
g_ptr_array_new_with_free_func (g_object_unref); g_ptr_array_new_with_free_func (g_object_unref);
glnx_fd_close int deploy_dfd = -1; glnx_autofd int deploy_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error))
return FALSE; return FALSE;
@ -2262,7 +2313,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
osname = ostree_deployment_get_osname (self->booted_deployment); osname = ostree_deployment_get_osname (self->booted_deployment);
const char *osdeploypath = glnx_strjoina ("ostree/deploy/", osname); const char *osdeploypath = glnx_strjoina ("ostree/deploy/", osname);
glnx_fd_close int os_deploy_dfd = -1; glnx_autofd int os_deploy_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error))
return FALSE; return FALSE;
@ -2283,7 +2334,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
ostree_deployment_set_origin (new_deployment, origin); ostree_deployment_set_origin (new_deployment, origin);
/* Check out the userspace tree onto the filesystem */ /* Check out the userspace tree onto the filesystem */
glnx_fd_close int deployment_dfd = -1; glnx_autofd int deployment_dfd = -1;
if (!checkout_deployment_tree (self, repo, new_deployment, &deployment_dfd, if (!checkout_deployment_tree (self, repo, new_deployment, &deployment_dfd,
cancellable, error)) cancellable, error))
{ {
@ -2349,7 +2400,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
*/ */
if (override_kernel_argv) if (override_kernel_argv)
{ {
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; g_autoptr(OstreeKernelArgs) kargs = NULL;
g_autofree char *new_options = NULL; g_autofree char *new_options = NULL;
kargs = _ostree_kernel_args_new (); kargs = _ostree_kernel_args_new ();
@ -2380,22 +2431,16 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
guint i; g_autoptr(OstreeDeployment) new_deployment = ostree_deployment_clone (deployment);
g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (new_deployment);
g_autoptr(OstreeDeployment) new_deployment = NULL;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
g_autofree char *new_options = NULL;
OstreeBootconfigParser *new_bootconfig;
new_deployment = ostree_deployment_clone (deployment); g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new ();
new_bootconfig = ostree_deployment_get_bootconfig (new_deployment);
kargs = _ostree_kernel_args_new ();
_ostree_kernel_args_append_argv (kargs, new_kargs); _ostree_kernel_args_append_argv (kargs, new_kargs);
new_options = _ostree_kernel_args_to_string (kargs); g_autofree char *new_options = _ostree_kernel_args_to_string (kargs);
ostree_bootconfig_parser_set (new_bootconfig, "options", new_options); ostree_bootconfig_parser_set (new_bootconfig, "options", new_options);
for (i = 0; i < self->deployments->len; i++) g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
for (guint i = 0; i < self->deployments->len; i++)
{ {
OstreeDeployment *cur = self->deployments->pdata[i]; OstreeDeployment *cur = self->deployments->pdata[i];
if (cur == deployment) if (cur == deployment)
@ -2435,7 +2480,7 @@ ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
return FALSE; return FALSE;
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &fd, error)) if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &fd, error))
return FALSE; return FALSE;

View File

@ -22,6 +22,7 @@
#include "otutil.h" #include "otutil.h"
#include <sys/file.h> #include <sys/file.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <err.h>
#include <sys/wait.h> #include <sys/wait.h>
#include "ostree.h" #include "ostree.h"
@ -201,7 +202,12 @@ ostree_sysroot_init (OstreeSysroot *self)
/** /**
* ostree_sysroot_new: * ostree_sysroot_new:
* @path: (allow-none): Path to a system root directory, or %NULL * @path: (allow-none): Path to a system root directory, or %NULL to use the
* current visible root file system
*
* Create a new #OstreeSysroot object for the sysroot at @path. If @path is %NULL,
* the current visible root file system is used, equivalent to
* ostree_sysroot_new_default().
* *
* Returns: (transfer full): An accessor object for an system root located at @path * Returns: (transfer full): An accessor object for an system root located at @path
*/ */
@ -291,11 +297,7 @@ _ostree_sysroot_bump_mtime (OstreeSysroot *self,
void void
ostree_sysroot_unload (OstreeSysroot *self) ostree_sysroot_unload (OstreeSysroot *self)
{ {
if (self->sysroot_fd != -1) glnx_close_fd (&self->sysroot_fd);
{
(void) close (self->sysroot_fd);
self->sysroot_fd = -1;
}
} }
/** /**
@ -633,7 +635,7 @@ parse_deployment (OstreeSysroot *self,
&treecsum, &deployserial, error)) &treecsum, &deployserial, error))
return FALSE; return FALSE;
glnx_fd_close int deployment_dfd = -1; glnx_autofd int deployment_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE, if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE,
&deployment_dfd, error)) &deployment_dfd, error))
return FALSE; return FALSE;
@ -981,11 +983,14 @@ ostree_sysroot_get_deployment_origin_path (GFile *deployment_path)
/** /**
* ostree_sysroot_get_repo: * ostree_sysroot_get_repo:
* @self: Sysroot * @self: Sysroot
* @out_repo: (out): Repository in sysroot @self * @out_repo: (out) (transfer full) (optional): Repository in sysroot @self
* @cancellable: Cancellable * @cancellable: Cancellable
* @error: Error * @error: Error
* *
* Retrieve the OSTree repository in sysroot @self. * Retrieve the OSTree repository in sysroot @self. The repo is guaranteed to be open
* (see ostree_repo_open()).
*
* Returns: %TRUE on success, %FALSE otherwise
*/ */
gboolean gboolean
ostree_sysroot_get_repo (OstreeSysroot *self, ostree_sysroot_get_repo (OstreeSysroot *self,
@ -1125,7 +1130,7 @@ find_booted_deployment (OstreeSysroot *self,
if (root_stbuf.st_dev == self_stbuf.st_dev && if (root_stbuf.st_dev == self_stbuf.st_dev &&
root_stbuf.st_ino == self_stbuf.st_ino) root_stbuf.st_ino == self_stbuf.st_ino)
{ {
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kernel_args = NULL; g_autoptr(OstreeKernelArgs) kernel_args = NULL;
if (!parse_kernel_commandline (&kernel_args, cancellable, error)) if (!parse_kernel_commandline (&kernel_args, cancellable, error))
return FALSE; return FALSE;
@ -1433,7 +1438,7 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0) if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0)
return glnx_throw_errno_prefix (error, "Creating %s", deploydir); return glnx_throw_errno_prefix (error, "Creating %s", deploydir);
glnx_fd_close int dfd = -1; glnx_autofd int dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error)) if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error))
return FALSE; return FALSE;
@ -1615,7 +1620,7 @@ clone_deployment (OstreeSysroot *sysroot,
/* Copy the bootloader config options */ /* Copy the bootloader config options */
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment); OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = _ostree_kernel_args_new (); g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new ();
_ostree_kernel_args_append_argv (kargs, previous_args); _ostree_kernel_args_append_argv (kargs, previous_args);
/* Deploy the copy */ /* Deploy the copy */
@ -1689,7 +1694,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return FALSE; return FALSE;
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
glnx_fd_close int deployment_dfd = -1; glnx_autofd int deployment_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error))
return FALSE; return FALSE;
@ -1698,6 +1703,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return FALSE; return FALSE;
const char *ovl_options = NULL; const char *ovl_options = NULL;
static const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
switch (unlocked_state) switch (unlocked_state)
{ {
case OSTREE_DEPLOYMENT_UNLOCKED_NONE: case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
@ -1705,7 +1711,6 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
break; break;
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
{ {
const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
/* Create the overlayfs directories in the deployment root /* Create the overlayfs directories in the deployment root
* directly for hotfixes. The ostree-prepare-root.c helper * directly for hotfixes. The ostree-prepare-root.c helper
* is also set up to detect and mount these. * is also set up to detect and mount these.
@ -1763,11 +1768,15 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return glnx_throw_errno_prefix (error, "fork"); return glnx_throw_errno_prefix (error, "fork");
else if (mount_child == 0) else if (mount_child == 0)
{ {
/* Child process. Do NOT use any GLib API here. */ /* Child process. Do NOT use any GLib API here; it's not generally fork() safe.
*
* TODO: report errors across a pipe (or use the journal?) rather than
* spewing to stderr.
*/
if (fchdir (deployment_dfd) < 0) if (fchdir (deployment_dfd) < 0)
exit (EXIT_FAILURE); err (1, "fchdir");
if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0) if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0)
exit (EXIT_FAILURE); err (1, "mount");
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
} }
else else
@ -1778,7 +1787,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0) if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0)
return glnx_throw_errno_prefix (error, "waitpid() on mount helper"); return glnx_throw_errno_prefix (error, "waitpid() on mount helper");
if (!g_spawn_check_exit_status (estatus, error)) if (!g_spawn_check_exit_status (estatus, error))
return glnx_throw_errno_prefix (error, "overlayfs mount helper"); return glnx_prefix_error (error, "Failed overlayfs mount");
} }
} }

View File

@ -43,7 +43,7 @@
* *
* Since: 2017.4 * Since: 2017.4
*/ */
#define OSTREE_RELEASE_VERSION (12) #define OSTREE_RELEASE_VERSION (13)
/** /**
* OSTREE_VERSION * OSTREE_VERSION
@ -52,7 +52,7 @@
* *
* Since: 2017.4 * Since: 2017.4
*/ */
#define OSTREE_VERSION (2017.12) #define OSTREE_VERSION (2017.13)
/** /**
* OSTREE_VERSION_S: * OSTREE_VERSION_S:
@ -62,7 +62,7 @@
* *
* Since: 2017.4 * Since: 2017.4
*/ */
#define OSTREE_VERSION_S "2017.12" #define OSTREE_VERSION_S "2017.13"
#define OSTREE_ENCODE_VERSION(year,release) \ #define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release)) ((year) << 16 | (release))

View File

@ -40,6 +40,7 @@
#include <ostree-repo-finder-avahi.h> #include <ostree-repo-finder-avahi.h>
#include <ostree-repo-finder-config.h> #include <ostree-repo-finder-config.h>
#include <ostree-repo-finder-mount.h> #include <ostree-repo-finder-mount.h>
#include <ostree-repo-finder-override.h>
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
#include <ostree-autocleanups.h> #include <ostree-autocleanups.h>

View File

@ -22,25 +22,10 @@
#include "ot-checksum-instream.h" #include "ot-checksum-instream.h"
#include "ot-checksum-utils.h" #include "ot-checksum-utils.h"
#if defined(HAVE_OPENSSL)
#include <openssl/evp.h>
#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#endif
G_DEFINE_TYPE (OtChecksumInstream, ot_checksum_instream, G_TYPE_FILTER_INPUT_STREAM) G_DEFINE_TYPE (OtChecksumInstream, ot_checksum_instream, G_TYPE_FILTER_INPUT_STREAM)
struct _OtChecksumInstreamPrivate { struct _OtChecksumInstreamPrivate {
#if defined(HAVE_OPENSSL) OtChecksum checksum;
EVP_MD_CTX *checksum;
#elif defined(HAVE_GNUTLS)
gnutls_digest_algorithm_t checksum_type;
gnutls_hash_hd_t checksum;
#else
GChecksumType checksum_type;
GChecksum *checksum;
#endif
}; };
static gssize ot_checksum_instream_read (GInputStream *stream, static gssize ot_checksum_instream_read (GInputStream *stream,
@ -54,13 +39,7 @@ ot_checksum_instream_finalize (GObject *object)
{ {
OtChecksumInstream *self = (OtChecksumInstream*)object; OtChecksumInstream *self = (OtChecksumInstream*)object;
#if defined(HAVE_OPENSSL) ot_checksum_clear (&self->priv->checksum);
EVP_MD_CTX_destroy (self->priv->checksum);
#elif defined(HAVE_GNUTLS)
gnutls_hash_deinit (self->priv->checksum, NULL);
#else
g_checksum_free (self->priv->checksum);
#endif
G_OBJECT_CLASS (ot_checksum_instream_parent_class)->finalize (object); G_OBJECT_CLASS (ot_checksum_instream_parent_class)->finalize (object);
} }
@ -83,33 +62,6 @@ ot_checksum_instream_init (OtChecksumInstream *self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OT_TYPE_CHECKSUM_INSTREAM, OtChecksumInstreamPrivate); self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OT_TYPE_CHECKSUM_INSTREAM, OtChecksumInstreamPrivate);
} }
#if defined(HAVE_OPENSSL)
static const EVP_MD *
gchecksum_type_to_openssl (GChecksumType checksum_type)
{
switch (checksum_type)
{
case G_CHECKSUM_SHA256:
return EVP_sha256 ();
default:
/* If there's something else, fill in here */
g_assert_not_reached ();
}
}
#elif defined(HAVE_GNUTLS)
static gnutls_digest_algorithm_t
gchecksum_type_to_gnutls (GChecksumType checksum_type)
{
switch (checksum_type)
{
case G_CHECKSUM_SHA256:
return GNUTLS_DIG_SHA256;
default:
g_assert_not_reached ();
}
}
#endif
OtChecksumInstream * OtChecksumInstream *
ot_checksum_instream_new (GInputStream *base, ot_checksum_instream_new (GInputStream *base,
GChecksumType checksum_type) GChecksumType checksum_type)
@ -124,18 +76,7 @@ ot_checksum_instream_new (GInputStream *base,
/* For now */ /* For now */
g_assert (checksum_type == G_CHECKSUM_SHA256); g_assert (checksum_type == G_CHECKSUM_SHA256);
ot_checksum_init (&stream->priv->checksum);
#if defined(HAVE_OPENSSL)
stream->priv->checksum = EVP_MD_CTX_create ();
g_assert (stream->priv->checksum);
g_assert (EVP_DigestInit_ex (stream->priv->checksum, gchecksum_type_to_openssl (checksum_type), NULL));
#elif defined(HAVE_GNUTLS)
stream->priv->checksum_type = gchecksum_type_to_gnutls (checksum_type);
g_assert (!gnutls_hash_init (&stream->priv->checksum, stream->priv->checksum_type));
#else
stream->priv->checksum = g_checksum_new (checksum_type);
stream->priv->checksum_type = checksum_type;
#endif
return (OtChecksumInstream*) (stream); return (OtChecksumInstream*) (stream);
} }
@ -157,78 +98,15 @@ ot_checksum_instream_read (GInputStream *stream,
cancellable, cancellable,
error); error);
if (res > 0) if (res > 0)
{ ot_checksum_update (&self->priv->checksum, buffer, res);
#if defined(HAVE_OPENSSL)
g_assert (EVP_DigestUpdate (self->priv->checksum, buffer, res));
#elif defined(HAVE_GNUTLS)
g_assert (!gnutls_hash (self->priv->checksum, buffer, res));
#else
g_checksum_update (self->priv->checksum, buffer, res);
#endif
}
return res; return res;
} }
void
ot_checksum_instream_get_digest (OtChecksumInstream *stream,
guint8 *buffer,
gsize *digest_len)
{
#if defined(HAVE_OPENSSL)
unsigned len;
EVP_DigestFinal_ex (stream->priv->checksum, buffer, &len);
if (digest_len)
*digest_len = len;
#elif defined(HAVE_GNUTLS)
gnutls_hash_output (stream->priv->checksum, buffer);
if (digest_len)
*digest_len = gnutls_hash_get_len (stream->priv->checksum_type);
#else
g_checksum_get_digest (stream->priv->checksum, buffer, digest_len);
#endif
}
guint8*
ot_checksum_instream_dup_digest (OtChecksumInstream *stream,
gsize *ret_len)
{
#if defined(HAVE_OPENSSL)
guint len;
guchar *ret = g_malloc0 (EVP_MAX_MD_SIZE);
g_assert (EVP_DigestFinal_ex (stream->priv->checksum, ret, &len));
#elif defined(HAVE_GNUTLS)
guint len = gnutls_hash_get_len (stream->priv->checksum_type);
guchar *ret = g_malloc0 (len);
gnutls_hash_output (stream->priv->checksum, ret);
#else
gsize len = g_checksum_type_get_length (stream->priv->checksum_type);
guchar *ret = g_malloc (len);
g_checksum_get_digest (stream->priv->checksum, ret, &len);
#endif
if (ret_len)
*ret_len = len;
return ret;
}
char * char *
ot_checksum_instream_get_string (OtChecksumInstream *stream) ot_checksum_instream_get_string (OtChecksumInstream *stream)
{ {
#if defined(HAVE_OPENSSL) char buf[_OSTREE_SHA256_STRING_LEN+1];
unsigned len; ot_checksum_get_hexdigest (&stream->priv->checksum, buf, sizeof(buf));
guint8 csum[EVP_MAX_MD_SIZE]; return g_strndup (buf, sizeof(buf));
g_assert (EVP_DigestFinal_ex (stream->priv->checksum, csum, &len));
char *buf = g_malloc (len * 2 + 1);
ot_bin2hex (buf, (guint8*)csum, len);
return buf;
#elif defined(HAVE_GNUTLS)
gsize len;
guint8 *csum = ot_checksum_instream_dup_digest(stream, &len);
char *buf = g_malloc0 (len * 2 + 1);
ot_bin2hex (buf, csum, len);
g_free (csum);
return buf;
#else
return g_strdup (g_checksum_get_string (stream->priv->checksum));
#endif
} }

View File

@ -52,12 +52,6 @@ GType ot_checksum_instream_get_type (void) G_GNUC_CONST;
OtChecksumInstream * ot_checksum_instream_new (GInputStream *stream, GChecksumType checksum); OtChecksumInstream * ot_checksum_instream_new (GInputStream *stream, GChecksumType checksum);
void ot_checksum_instream_get_digest (OtChecksumInstream *stream,
guint8 *buffer,
gsize *digest_len);
guint8* ot_checksum_instream_dup_digest (OtChecksumInstream *stream,
gsize *ret_len);
char * ot_checksum_instream_get_string (OtChecksumInstream *stream); char * ot_checksum_instream_get_string (OtChecksumInstream *stream);
G_END_DECLS G_END_DECLS

View File

@ -22,10 +22,15 @@
#include "config.h" #include "config.h"
#include "otutil.h" #include "otutil.h"
#if defined(HAVE_OPENSSL)
#include <openssl/evp.h>
#elif defined(HAVE_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#endif
#include <string.h> #include <string.h>
void void
ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len) ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len)
{ {
@ -41,6 +46,120 @@ ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len)
out_buf[j] = '\0'; out_buf[j] = '\0';
} }
/* I like to think of this as AbstractChecksumProxyFactoryBean. In homage to
* https://news.ycombinator.com/item?id=4549544
* aka http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.html
*/
typedef struct {
gboolean initialized;
#if defined(HAVE_OPENSSL)
EVP_MD_CTX *checksum;
#elif defined(HAVE_GNUTLS)
gnutls_hash_hd_t checksum;
#else
GChecksum *checksum;
#endif
guint digest_len;
} OtRealChecksum;
G_STATIC_ASSERT (sizeof (OtChecksum) >= sizeof (OtRealChecksum));
void
ot_checksum_init (OtChecksum *checksum)
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
g_return_if_fail (!real->initialized);
#if defined(HAVE_OPENSSL)
real->checksum = EVP_MD_CTX_create ();
g_assert (real->checksum);
g_assert (EVP_DigestInit_ex (real->checksum, EVP_sha256 (), NULL));
real->digest_len = EVP_MD_CTX_size (real->checksum);
#elif defined(HAVE_GNUTLS)
g_assert (!gnutls_hash_init (&real->checksum, GNUTLS_DIG_SHA256));
real->digest_len = gnutls_hash_get_len (GNUTLS_DIG_SHA256);
#else
real->checksum = g_checksum_new (G_CHECKSUM_SHA256);
real->digest_len = g_checksum_type_get_length (G_CHECKSUM_SHA256);
#endif
g_assert_cmpint (real->digest_len, ==, _OSTREE_SHA256_DIGEST_LEN);
real->initialized = TRUE;
}
void
ot_checksum_update (OtChecksum *checksum,
const guint8 *buf,
size_t len)
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
g_return_if_fail (real->initialized);
#if defined(HAVE_OPENSSL)
g_assert (EVP_DigestUpdate (real->checksum, buf, len));
#elif defined(HAVE_GNUTLS)
g_assert (!gnutls_hash (real->checksum, buf, len));
#else
g_checksum_update (real->checksum, buf, len);
#endif
}
static void
ot_checksum_get_digest_internal (OtRealChecksum *real,
guint8 *buf,
size_t buflen)
{
g_return_if_fail (real->initialized);
g_assert_cmpint (buflen, ==, _OSTREE_SHA256_DIGEST_LEN);
#if defined(HAVE_OPENSSL)
guint digest_len = buflen;
g_assert (EVP_DigestFinal_ex (real->checksum, buf, &digest_len));
g_assert_cmpint (digest_len, ==, buflen);
#elif defined(HAVE_GNUTLS)
gnutls_hash_output (real->checksum, buf);
#else
gsize digest_len = buflen;
g_checksum_get_digest (real->checksum, buf, &digest_len);
g_assert_cmpint (digest_len, ==, buflen);
#endif
}
void
ot_checksum_get_digest (OtChecksum *checksum,
guint8 *buf,
size_t buflen)
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
ot_checksum_get_digest_internal (real, buf, buflen);
real->initialized = FALSE;
}
void
ot_checksum_get_hexdigest (OtChecksum *checksum,
char *buf,
size_t buflen)
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
const guint digest_len = real->digest_len;
guint8 digest_buf[digest_len];
ot_checksum_get_digest (checksum, digest_buf, digest_len);
ot_bin2hex (buf, (guint8*)digest_buf, digest_len);
real->initialized = FALSE;
}
void
ot_checksum_clear (OtChecksum *checksum)
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
if (!real->initialized)
return;
#if defined(HAVE_OPENSSL)
EVP_MD_CTX_destroy (real->checksum);
#elif defined(HAVE_GNUTLS)
gnutls_hash_deinit (real->checksum, NULL);
#else
g_checksum_free (real->checksum);
#endif
real->initialized = FALSE;
}
guchar * guchar *
ot_csum_from_gchecksum (GChecksum *checksum) ot_csum_from_gchecksum (GChecksum *checksum)
{ {
@ -57,7 +176,7 @@ ot_gio_write_update_checksum (GOutputStream *out,
gconstpointer data, gconstpointer data,
gsize len, gsize len,
gsize *out_bytes_written, gsize *out_bytes_written,
GChecksum *checksum, OtChecksum *checksum,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
@ -73,14 +192,14 @@ ot_gio_write_update_checksum (GOutputStream *out,
} }
if (checksum) if (checksum)
g_checksum_update (checksum, data, len); ot_checksum_update (checksum, data, len);
return TRUE; return TRUE;
} }
gboolean gboolean
ot_gio_splice_update_checksum (GOutputStream *out, ot_gio_splice_update_checksum (GOutputStream *out,
GInputStream *in, GInputStream *in,
GChecksum *checksum, OtChecksum *checksum,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
@ -92,7 +211,7 @@ ot_gio_splice_update_checksum (GOutputStream *out,
char buf[4096]; char buf[4096];
do do
{ {
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) if (!g_input_stream_read_all (in, buf, sizeof (buf), &bytes_read, cancellable, error))
return FALSE; return FALSE;
if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum, if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum,
cancellable, error)) cancellable, error))
@ -119,27 +238,20 @@ ot_gio_splice_get_checksum (GOutputStream *out,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); g_auto(OtChecksum) checksum = { 0, };
ot_checksum_init (&checksum);
if (!ot_gio_splice_update_checksum (out, in, checksum, cancellable, error)) if (!ot_gio_splice_update_checksum (out, in, &checksum, cancellable, error))
return FALSE; return FALSE;
g_autofree guchar *ret_csum = ot_csum_from_gchecksum (checksum); guint8 digest[_OSTREE_SHA256_DIGEST_LEN];
ot_checksum_get_digest (&checksum, digest, sizeof (digest));
g_autofree guchar *ret_csum = g_malloc (sizeof (digest));
memcpy (ret_csum, digest, sizeof (digest));
ot_transfer_out_value (out_csum, &ret_csum); ot_transfer_out_value (out_csum, &ret_csum);
return TRUE; return TRUE;
} }
gboolean
ot_gio_checksum_stream (GInputStream *in,
guchar **out_csum,
GCancellable *cancellable,
GError **error)
{
if (!out_csum)
return TRUE;
return ot_gio_splice_get_checksum (NULL, in, out_csum, cancellable, error);
}
char * char *
ot_checksum_file_at (int dfd, ot_checksum_file_at (int dfd,
const char *path, const char *path,
@ -151,9 +263,12 @@ ot_checksum_file_at (int dfd,
if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error)) if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error))
return FALSE; return FALSE;
g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type); g_auto(OtChecksum) checksum = { 0, };
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) ot_checksum_init (&checksum);
if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE; return FALSE;
return g_strdup (g_checksum_get_string (checksum)); char hexdigest[_OSTREE_SHA256_STRING_LEN+1];
ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest));
return g_strdup (hexdigest);
} }

View File

@ -21,7 +21,7 @@
#pragma once #pragma once
#include <gio/gio.h> #include "libglnx.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -29,11 +29,50 @@ void ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len);
guchar *ot_csum_from_gchecksum (GChecksum *checksum); guchar *ot_csum_from_gchecksum (GChecksum *checksum);
struct OtChecksum {
gboolean initialized;
guint uints[2];
gpointer data[2];
};
typedef struct OtChecksum OtChecksum;
/* Same as OSTREE_SHA256_DIGEST_LEN, but this header can't depend on that */
#define _OSTREE_SHA256_DIGEST_LEN (32)
#if defined(OSTREE_SHA256_DIGEST_LEN) && _OSTREE_SHA256_DIGEST_LEN != OSTREE_SHA256_DIGEST_LEN
#error Mismatched OSTREE_SHA256_DIGEST_LEN
#endif
/* See above */
#define _OSTREE_SHA256_STRING_LEN (64)
#if defined(OSTREE_SHA256_STRING_LEN) && _OSTREE_SHA256_STRING_LEN != OSTREE_SHA256_STRING_LEN
#error Mismatched OSTREE_SHA256_STRING_LEN
#endif
void ot_checksum_init (OtChecksum *checksum);
void ot_checksum_update (OtChecksum *checksum,
const guint8 *buf,
size_t len);
static inline void
ot_checksum_update_bytes (OtChecksum *checksum,
GBytes *buf)
{
gsize len;
const guint8 *bufdata = g_bytes_get_data (buf, &len);
ot_checksum_update (checksum, bufdata, len);
}
void ot_checksum_get_digest (OtChecksum *checksum,
guint8 *buf,
size_t buflen);
void ot_checksum_get_hexdigest (OtChecksum *checksum,
char *buf,
size_t buflen);
void ot_checksum_clear (OtChecksum *checksum);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtChecksum, ot_checksum_clear)
gboolean ot_gio_write_update_checksum (GOutputStream *out, gboolean ot_gio_write_update_checksum (GOutputStream *out,
gconstpointer data, gconstpointer data,
gsize len, gsize len,
gsize *out_bytes_written, gsize *out_bytes_written,
GChecksum *checksum, OtChecksum *checksum,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
@ -45,12 +84,7 @@ gboolean ot_gio_splice_get_checksum (GOutputStream *out,
gboolean ot_gio_splice_update_checksum (GOutputStream *out, gboolean ot_gio_splice_update_checksum (GOutputStream *out,
GInputStream *in, GInputStream *in,
GChecksum *checksum, OtChecksum *checksum,
GCancellable *cancellable,
GError **error);
gboolean ot_gio_checksum_stream (GInputStream *in,
guchar **out_csum,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);

View File

@ -22,6 +22,7 @@
#include "ot-fs-utils.h" #include "ot-fs-utils.h"
#include "libglnx.h" #include "libglnx.h"
#include <sys/xattr.h> #include <sys/xattr.h>
#include <sys/mman.h>
#include <gio/gunixinputstream.h> #include <gio/gunixinputstream.h>
#include <gio/gunixoutputstream.h> #include <gio/gunixoutputstream.h>
@ -35,6 +36,9 @@ ot_fdrel_to_gfile (int dfd, const char *path)
return g_file_new_for_path (abspath); return g_file_new_for_path (abspath);
} }
/* Wraps readlinkat(), and sets the `symlink-target` property
* of @target_info.
*/
gboolean gboolean
ot_readlinkat_gfile_info (int dfd, ot_readlinkat_gfile_info (int dfd,
const char *path, const char *path,
@ -53,7 +57,6 @@ ot_readlinkat_gfile_info (int dfd,
return TRUE; return TRUE;
} }
/** /**
* ot_openat_read_stream: * ot_openat_read_stream:
* @dfd: Directory file descriptor * @dfd: Directory file descriptor
@ -76,16 +79,10 @@ ot_openat_read_stream (int dfd,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
int fd = -1; glnx_autofd int fd = -1;
int flags = O_RDONLY | O_NOCTTY | O_CLOEXEC; if (!glnx_openat_rdonly (dfd, path, follow, &fd, error))
return FALSE;
if (!follow) *out_istream = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE);
flags |= O_NOFOLLOW;
if (TEMP_FAILURE_RETRY (fd = openat (dfd, path, flags, 0)) < 0)
return glnx_throw_errno_prefix (error, "openat(%s)", path);
*out_istream = g_unix_input_stream_new (fd, TRUE);
return TRUE; return TRUE;
} }
@ -130,7 +127,7 @@ ot_dfd_iter_init_allow_noent (int dfd,
gboolean *out_exists, gboolean *out_exists,
GError **error) GError **error)
{ {
glnx_fd_close int fd = glnx_opendirat_with_errno (dfd, path, TRUE); glnx_autofd int fd = glnx_opendirat_with_errno (dfd, path, TRUE);
if (fd < 0) if (fd < 0)
{ {
if (errno != ENOENT) if (errno != ENOENT)
@ -144,22 +141,57 @@ ot_dfd_iter_init_allow_noent (int dfd,
return TRUE; return TRUE;
} }
typedef struct {
gpointer addr;
gsize len;
} MapData;
static void
map_data_destroy (gpointer data)
{
MapData *mdata = data;
(void) munmap (mdata->addr, mdata->len);
g_free (mdata);
}
/* Return a newly-allocated GBytes that refers to the contents of the file
* starting at offset @start. If the file is large enough, mmap() may be used.
*/
GBytes * GBytes *
ot_file_mapat_bytes (int dfd, ot_fd_readall_or_mmap (int fd,
const char *path, goffset start,
GError **error) GError **error)
{ {
glnx_fd_close int fd = openat (dfd, path, O_RDONLY | O_CLOEXEC); struct stat stbuf;
g_autoptr(GMappedFile) mfile = NULL; if (!glnx_fstat (fd, &stbuf, error))
if (fd < 0)
return glnx_null_throw_errno_prefix (error, "openat(%s)", path);
mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
if (!mfile)
return FALSE; return FALSE;
return g_mapped_file_get_bytes (mfile); /* http://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access */
if (start > stbuf.st_size)
return g_bytes_new_static (NULL, 0);
const gsize len = stbuf.st_size - start;
if (len > 16*1024)
{
/* The reason we don't use g_mapped_file_new_from_fd() here
* is it doesn't support passing an offset, which is actually
* used by the static delta code.
*/
gpointer map = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, start);
if (map == (void*)-1)
return glnx_null_throw_errno_prefix (error, "mmap");
MapData *mdata = g_new (MapData, 1);
mdata->addr = map;
mdata->len = len;
return g_bytes_new_with_free_func (map, len, map_data_destroy, mdata);
}
/* Fall through to plain read into a malloc buffer */
if (lseek (fd, start, SEEK_SET) < 0)
return glnx_null_throw_errno_prefix (error, "lseek");
/* Not cancellable since this should be small */
return glnx_fd_readall_bytes (fd, NULL, error);
} }
/* Given an input stream, splice it to an anonymous file (O_TMPFILE). /* Given an input stream, splice it to an anonymous file (O_TMPFILE).

View File

@ -85,8 +85,7 @@ ot_map_anonymous_tmpfile_from_content (GInputStream *instream,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
GBytes *ot_file_mapat_bytes (int dfd, GBytes *ot_fd_readall_or_mmap (int fd, goffset offset,
const char *path,
GError **error); GError **error);
G_END_DECLS G_END_DECLS

View File

@ -34,22 +34,21 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
/* Ensure that a pathname component @name does not contain the special Unix
* entries `.` or `..`, and does not contain `/`.
*/
gboolean gboolean
ot_util_filename_validate (const char *name, ot_util_filename_validate (const char *name,
GError **error) GError **error)
{ {
if (strcmp (name, ".") == 0) if (strcmp (name, ".") == 0)
{
return glnx_throw (error, "Invalid self-referential filename '.'"); return glnx_throw (error, "Invalid self-referential filename '.'");
}
if (strcmp (name, "..") == 0) if (strcmp (name, "..") == 0)
{
return glnx_throw (error, "Invalid path uplink filename '..'"); return glnx_throw (error, "Invalid path uplink filename '..'");
}
if (strchr (name, '/') != NULL) if (strchr (name, '/') != NULL)
{
return glnx_throw (error, "Invalid / in filename %s", name); return glnx_throw (error, "Invalid / in filename %s", name);
} if (!g_utf8_validate (name, -1, NULL))
return glnx_throw (error, "Invalid UTF-8 in filename %s", name);
return TRUE; return TRUE;
} }
@ -58,8 +57,8 @@ ot_split_string_ptrarray (const char *str,
char c) char c)
{ {
GPtrArray *ret = g_ptr_array_new_with_free_func (g_free); GPtrArray *ret = g_ptr_array_new_with_free_func (g_free);
const char *p;
const char *p;
do { do {
p = strchr (str, '/'); p = strchr (str, '/');
if (!p) if (!p)
@ -77,40 +76,29 @@ ot_split_string_ptrarray (const char *str,
return ret; return ret;
} }
/* Given a pathname @path, split it into individual entries in @out_components,
* validating that it does not have backreferences (`..`) etc.
*/
gboolean gboolean
ot_util_path_split_validate (const char *path, ot_util_path_split_validate (const char *path,
GPtrArray **out_components, GPtrArray **out_components,
GError **error) GError **error)
{ {
gboolean ret = FALSE;
int i;
g_autoptr(GPtrArray) ret_components = NULL;
if (strlen (path) > PATH_MAX) if (strlen (path) > PATH_MAX)
{ return glnx_throw (error, "Path '%s' is too long", path);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Path '%s' is too long", path);
goto out;
}
ret_components = ot_split_string_ptrarray (path, '/'); g_autoptr(GPtrArray) ret_components = ot_split_string_ptrarray (path, '/');
/* Canonicalize by removing '.' and '', throw an error on .. */ /* Canonicalize by removing '.' and '', throw an error on .. */
for (i = ret_components->len-1; i >= 0; i--) for (int i = ret_components->len-1; i >= 0; i--)
{ {
const char *name = ret_components->pdata[i]; const char *name = ret_components->pdata[i];
if (strcmp (name, "..") == 0) if (strcmp (name, "..") == 0)
{ return glnx_throw (error, "Invalid uplink '..' in path %s", path);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid uplink '..' in path %s", path);
goto out;
}
if (strcmp (name, ".") == 0 || name[0] == '\0') if (strcmp (name, ".") == 0 || name[0] == '\0')
g_ptr_array_remove_index (ret_components, i); g_ptr_array_remove_index (ret_components, i);
} }
ret = TRUE;
ot_transfer_out_value(out_components, &ret_components); ot_transfer_out_value(out_components, &ret_components);
out: return TRUE;
return ret;
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2017 Alexander Larsson <alexl@redhat.com>.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Alexander Larsson <alexl@redhat.com>.
*/
#pragma once
#include <gio/gio.h>
#include "libglnx.h"
G_BEGIN_DECLS
typedef struct _OtVariantBuilder OtVariantBuilder;
OtVariantBuilder *ot_variant_builder_new (const GVariantType *type,
int fd);
void ot_variant_builder_unref (OtVariantBuilder *builder);
OtVariantBuilder *ot_variant_builder_ref (OtVariantBuilder *builder);
gboolean ot_variant_builder_end (OtVariantBuilder *builder,
GError **error);
gboolean ot_variant_builder_open (OtVariantBuilder *builder,
const GVariantType *type,
GError **error);
gboolean ot_variant_builder_close (OtVariantBuilder *builder,
GError **error);
gboolean ot_variant_builder_add_from_fd (OtVariantBuilder *builder,
const GVariantType *type,
int fd,
guint64 size,
GError **error);
gboolean ot_variant_builder_add_value (OtVariantBuilder *builder,
GVariant *value,
GError **error);
gboolean ot_variant_builder_add (OtVariantBuilder *builder,
GError **error,
const gchar *format_string,
...);
void ot_variant_builder_add_parsed (OtVariantBuilder *builder,
const gchar *format,
...);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OtVariantBuilder, ot_variant_builder_unref)
G_END_DECLS

View File

@ -25,10 +25,10 @@
#include <gio/gfiledescriptorbased.h> #include <gio/gfiledescriptorbased.h>
#include <string.h> #include <string.h>
#include <sys/mman.h>
#include "otutil.h" #include "otutil.h"
/* Create a new GVariant empty GVariant of type a{sv} */
GVariant * GVariant *
ot_gvariant_new_empty_string_dict (void) ot_gvariant_new_empty_string_dict (void)
{ {
@ -37,167 +37,66 @@ ot_gvariant_new_empty_string_dict (void)
return g_variant_builder_end (&builder); return g_variant_builder_end (&builder);
} }
/* Create a new GVariant of type ay from the raw @data pointer */
GVariant * GVariant *
ot_gvariant_new_bytearray (const guchar *data, ot_gvariant_new_bytearray (const guchar *data,
gsize len) gsize len)
{ {
gpointer data_copy; gpointer data_copy = g_memdup (data, len);
GVariant *ret; GVariant *ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
data_copy = g_memdup (data, len);
ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
len, FALSE, g_free, data_copy); len, FALSE, g_free, data_copy);
return ret; return ret;
} }
/* Convert a GBytes into a GVariant of type ay (byte array) */
GVariant * GVariant *
ot_gvariant_new_ay_bytes (GBytes *bytes) ot_gvariant_new_ay_bytes (GBytes *bytes)
{ {
gsize size; gsize size;
gconstpointer data; gconstpointer data = g_bytes_get_data (bytes, &size);
data = g_bytes_get_data (bytes, &size);
g_bytes_ref (bytes); g_bytes_ref (bytes);
return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size, return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size,
TRUE, (GDestroyNotify)g_bytes_unref, bytes); TRUE, (GDestroyNotify)g_bytes_unref, bytes);
} }
GHashTable * /* Create a GVariant in @out_variant that is backed by
ot_util_variant_asv_to_hash_table (GVariant *variant) * the data from @fd, starting at @start. If the data is
{ * large enough, mmap() may be used. @trusted is used
GHashTable *ret; * by the GVariant core; see g_variant_new_from_data().
GVariantIter *viter; */
char *key;
GVariant *value;
ret = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
viter = g_variant_iter_new (variant);
while (g_variant_iter_next (viter, "{s@v}", &key, &value))
g_hash_table_replace (ret, key, g_variant_ref_sink (value));
g_variant_iter_free (viter);
return ret;
}
GVariant *
ot_util_variant_take_ref (GVariant *variant)
{
return g_variant_take_ref (variant);
}
gboolean gboolean
ot_util_variant_map_at (int dfd, ot_variant_read_fd (int fd,
const char *path,
const GVariantType *type,
OtVariantMapFlags flags,
GVariant **out_variant,
GError **error)
{
glnx_fd_close int fd = -1;
const gboolean trusted = (flags & OT_VARIANT_MAP_TRUSTED) > 0;
fd = openat (dfd, path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
{
if (errno == ENOENT && (flags & OT_VARIANT_MAP_ALLOW_NOENT) > 0)
{
*out_variant = NULL;
return TRUE;
}
else
{
glnx_set_error_from_errno (error);
g_prefix_error (error, "Opening %s: ", path);
return FALSE;
}
}
return ot_util_variant_map_fd (fd, 0, type, trusted, out_variant, error);
}
typedef struct {
gpointer addr;
gsize len;
} VariantMapData;
static void
variant_map_data_destroy (gpointer data)
{
VariantMapData *mdata = data;
(void) munmap (mdata->addr, mdata->len);
g_free (mdata);
}
gboolean
ot_util_variant_map_fd (int fd,
goffset start, goffset start,
const GVariantType *type, const GVariantType *type,
gboolean trusted, gboolean trusted,
GVariant **out_variant, GVariant **out_variant,
GError **error) GError **error)
{ {
gboolean ret = FALSE; g_autoptr(GBytes) bytes = ot_fd_readall_or_mmap (fd, start, error);
gpointer map; if (!bytes)
struct stat stbuf; return FALSE;
VariantMapData *mdata = NULL;
gsize len;
if (fstat (fd, &stbuf) != 0) *out_variant = g_variant_ref_sink (g_variant_new_from_bytes (type, bytes, trusted));
{ return TRUE;
glnx_set_error_from_errno (error);
goto out;
}
len = stbuf.st_size - start;
map = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, start);
if (!map)
{
glnx_set_error_from_errno (error);
goto out;
}
mdata = g_new (VariantMapData, 1);
mdata->addr = map;
mdata->len = len;
ret = TRUE;
*out_variant = g_variant_ref_sink (g_variant_new_from_data (type, map, len, trusted,
variant_map_data_destroy, mdata));
out:
return ret;
}
GInputStream *
ot_variant_read (GVariant *variant)
{
GMemoryInputStream *ret = NULL;
ret = (GMemoryInputStream*)g_memory_input_stream_new_from_data (g_variant_get_data (variant),
g_variant_get_size (variant),
NULL);
g_object_set_data_full ((GObject*)ret, "ot-variant-data",
g_variant_ref (variant), (GDestroyNotify) g_variant_unref);
return (GInputStream*)ret;
} }
/* GVariants are immutable; this function allows generating an open builder
* for a new variant, inherting the data from @variant.
*/
GVariantBuilder * GVariantBuilder *
ot_util_variant_builder_from_variant (GVariant *variant, ot_util_variant_builder_from_variant (GVariant *variant,
const GVariantType *type) const GVariantType *type)
{ {
GVariantBuilder *builder = NULL; GVariantBuilder *builder = g_variant_builder_new (type);
builder = g_variant_builder_new (type);
if (variant != NULL) if (variant != NULL)
{ {
gint i, n; const int n = g_variant_n_children (variant);
for (int i = 0; i < n; i++)
n = g_variant_n_children (variant);
for (i = 0; i < n; i++)
{ {
GVariant *child = g_variant_get_child_value (variant, i); g_autoptr(GVariant) child = g_variant_get_child_value (variant, i);
g_variant_builder_add_value (builder, child); g_variant_builder_add_value (builder, child);
g_variant_unref (child);
} }
} }
@ -221,28 +120,23 @@ ot_variant_bsearch_str (GVariant *array,
const char *str, const char *str,
int *out_pos) int *out_pos)
{ {
gsize imax, imin; const gsize n = g_variant_n_children (array);
gsize imid = -1;
gsize n;
n = g_variant_n_children (array);
if (n == 0) if (n == 0)
return FALSE; return FALSE;
imax = n - 1; gsize imax = n - 1;
imin = 0; gsize imin = 0;
gsize imid = -1;
while (imax >= imin) while (imax >= imin)
{ {
g_autoptr(GVariant) child = NULL;
const char *cur; const char *cur;
int cmp;
imid = (imin + imax) / 2; imid = (imin + imax) / 2;
child = g_variant_get_child_value (array, imid); g_autoptr(GVariant) child = g_variant_get_child_value (array, imid);
g_variant_get_child (child, 0, "&s", &cur, NULL); g_variant_get_child (child, 0, "&s", &cur, NULL);
cmp = strcmp (cur, str); int cmp = strcmp (cur, str);
if (cmp < 0) if (cmp < 0)
imin = imid + 1; imin = imid + 1;
else if (cmp > 0) else if (cmp > 0)

View File

@ -32,31 +32,13 @@ GVariant *ot_gvariant_new_ay_bytes (GBytes *bytes);
GVariant *ot_gvariant_new_empty_string_dict (void); GVariant *ot_gvariant_new_empty_string_dict (void);
GHashTable *ot_util_variant_asv_to_hash_table (GVariant *variant); gboolean ot_variant_read_fd (int fd,
GVariant * ot_util_variant_take_ref (GVariant *variant);
typedef enum {
OT_VARIANT_MAP_TRUSTED = (1 << 0),
OT_VARIANT_MAP_ALLOW_NOENT = (1 << 1)
} OtVariantMapFlags;
gboolean ot_util_variant_map_at (int dfd,
const char *path,
const GVariantType *type,
OtVariantMapFlags flags,
GVariant **out_variant,
GError **error);
gboolean ot_util_variant_map_fd (int fd,
goffset offset, goffset offset,
const GVariantType *type, const GVariantType *type,
gboolean trusted, gboolean trusted,
GVariant **out_variant, GVariant **out_variant,
GError **error); GError **error);
GInputStream *ot_variant_read (GVariant *variant);
GVariantBuilder *ot_util_variant_builder_from_variant (GVariant *variant, GVariantBuilder *ot_util_variant_builder_from_variant (GVariant *variant,
const GVariantType *type); const GVariantType *type);

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Colin Walters <walters@verbum.org>
*/
#include "config.h"
#include "otutil.h"
#include <string.h>
void
ot_ptrarray_add_many (GPtrArray *a, ...)
{
va_list args;
void *p;
va_start (args, a);
while ((p = va_arg (args, void *)) != NULL)
g_ptr_array_add (a, p);
va_end (args);
}

View File

@ -48,8 +48,7 @@
#include <ot-opt-utils.h> #include <ot-opt-utils.h>
#include <ot-unix-utils.h> #include <ot-unix-utils.h>
#include <ot-variant-utils.h> #include <ot-variant-utils.h>
#include <ot-variant-builder.h>
#include <ot-checksum-utils.h> #include <ot-checksum-utils.h>
#include <ot-gpg-utils.h> #include <ot-gpg-utils.h>
#include <ot-checksum-instream.h> #include <ot-checksum-instream.h>
void ot_ptrarray_add_many (GPtrArray *a, ...) G_GNUC_NULL_TERMINATED;

View File

@ -32,37 +32,94 @@
#include "ot-builtins.h" #include "ot-builtins.h"
static OstreeCommand commands[] = { static OstreeCommand commands[] = {
{ "admin", ostree_builtin_admin }, /* Note: all admin related commands have
{ "cat", ostree_builtin_cat }, * no_repo as their command flag, but each
{ "checkout", ostree_builtin_checkout }, * admin command may have their own
{ "checksum", ostree_builtin_checksum }, * admin flag
{ "commit", ostree_builtin_commit }, */
{ "config", ostree_builtin_config }, { "admin", OSTREE_BUILTIN_FLAG_NO_REPO,
{ "diff", ostree_builtin_diff }, ostree_builtin_admin,
{ "export", ostree_builtin_export }, "Commands for managing a host system booted with ostree" },
{ "cat", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_cat,
"Concatenate contents of files"},
{ "checkout", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_checkout,
"Check out a commit into a filesystem tree" },
{ "checksum", OSTREE_BUILTIN_FLAG_NO_REPO,
ostree_builtin_checksum,
"Checksum a file or directory" },
{ "commit", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_commit,
"Commit a new revision" },
{ "config", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_config,
"Change repo configuration settings" },
{ "diff", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_diff,
"Compare directory TARGETDIR against revision REV"},
{ "export", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_export,
"Stream COMMIT to stdout in tar format" },
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API #ifdef OSTREE_ENABLE_EXPERIMENTAL_API
{ "find-remotes", ostree_builtin_find_remotes }, { "find-remotes", OSTREE_BUILTIN_FLAG_NONE,
{ "create-usb", ostree_builtin_create_usb }, ostree_builtin_find_remotes,
"Find remotes to serve the given refs" },
{ "create-usb", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_create_usb,
"Copy the refs to a USB stick" },
#endif #endif
{ "fsck", ostree_builtin_fsck }, { "fsck", OSTREE_BUILTIN_FLAG_NONE,
{ "gpg-sign", ostree_builtin_gpg_sign }, ostree_builtin_fsck,
{ "init", ostree_builtin_init }, "Check the repository for consistency" },
{ "log", ostree_builtin_log }, { "gpg-sign", OSTREE_BUILTIN_FLAG_NONE,
{ "ls", ostree_builtin_ls }, ostree_builtin_gpg_sign,
{ "prune", ostree_builtin_prune }, "Sign a commit" },
{ "pull-local", ostree_builtin_pull_local }, { "init", OSTREE_BUILTIN_FLAG_NO_CHECK,
#ifdef HAVE_LIBSOUP ostree_builtin_init,
{ "pull", ostree_builtin_pull }, "Initialize a new empty repository" },
{ "log", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_log,
"Show log starting at commit or ref" },
{ "ls", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_ls,
"List file paths" },
{ "prune", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_prune,
"Search for unreachable objects" },
{ "pull-local", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_pull_local,
"Copy data from SRC_REPO" },
#ifdef HAVE_LIBCURL_OR_LIBSOUP
{ "pull", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_pull,
"Download data from remote repository" },
#endif #endif
{ "refs", ostree_builtin_refs }, { "refs", OSTREE_BUILTIN_FLAG_NONE,
{ "remote", ostree_builtin_remote }, ostree_builtin_refs,
{ "reset", ostree_builtin_reset }, "List refs" },
{ "rev-parse", ostree_builtin_rev_parse }, { "remote", OSTREE_BUILTIN_FLAG_NO_REPO,
{ "show", ostree_builtin_show }, ostree_builtin_remote,
{ "static-delta", ostree_builtin_static_delta }, "Remote commands that may involve internet access" },
{ "summary", ostree_builtin_summary }, { "reset", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_reset,
"Reset a REF to a previous COMMIT" },
{ "rev-parse", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_rev_parse,
"Output the target of a rev" },
{ "show", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_show,
"Output a metadata object" },
{ "static-delta", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_static_delta,
"Static delta related commands" },
{ "summary", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_summary,
"Manage summary metadata" },
#if defined(HAVE_LIBSOUP) && defined(BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE) #if defined(HAVE_LIBSOUP) && defined(BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE)
{ "trivial-httpd", ostree_builtin_trivial_httpd }, { "trivial-httpd", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_trivial_httpd,
NULL },
#endif #endif
{ NULL } { NULL }
}; };

View File

@ -353,7 +353,7 @@ do_get (OtTrivialHttpd *self,
if (msg->method == SOUP_METHOD_GET) if (msg->method == SOUP_METHOD_GET)
{ {
glnx_fd_close int fd = -1; glnx_autofd int fd = -1;
g_autoptr(GMappedFile) mapping = NULL; g_autoptr(GMappedFile) mapping = NULL;
gsize buffer_length, file_size; gsize buffer_length, file_size;
SoupRange *ranges; SoupRange *ranges;

View File

@ -38,17 +38,17 @@ static GOptionEntry options[] = {
}; };
gboolean gboolean
ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GError **error) ot_admin_builtin_cleanup (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{ {
g_autoptr(GOptionContext) context = NULL; g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(OstreeSysroot) sysroot = NULL;
gboolean ret = FALSE; gboolean ret = FALSE;
context = g_option_context_new ("Delete untagged deployments and repository objects"); context = g_option_context_new ("");
if (!ostree_admin_option_context_parse (context, options, &argc, &argv, if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error)) invocation, &sysroot, cancellable, error))
goto out; goto out;
if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) if (!ostree_sysroot_cleanup (sysroot, cancellable, error))

View File

@ -60,17 +60,17 @@ static GOptionEntry options[] = {
}; };
gboolean gboolean
ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error) ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{ {
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; g_autoptr(OstreeKernelArgs) kargs = NULL;
g_autoptr(GOptionContext) context = g_autoptr(GOptionContext) context =
g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); g_option_context_new ("REFSPEC");
g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(OstreeSysroot) sysroot = NULL;
if (!ostree_admin_option_context_parse (context, options, &argc, &argv, if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error)) invocation, &sysroot, cancellable, error))
return FALSE; return FALSE;
if (argc < 2) if (argc < 2)

View File

@ -41,7 +41,7 @@ static GOptionEntry options[] = {
}; };
gboolean gboolean
ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error) ot_admin_builtin_diff (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{ {
g_autoptr(GOptionContext) context = NULL; g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(OstreeSysroot) sysroot = NULL;
@ -54,13 +54,13 @@ ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError
g_autoptr(GFile) orig_etc_path = NULL; g_autoptr(GFile) orig_etc_path = NULL;
g_autoptr(GFile) new_etc_path = NULL; g_autoptr(GFile) new_etc_path = NULL;
context = g_option_context_new ("Diff current /etc configuration versus default"); context = g_option_context_new ("");
g_option_context_add_main_entries (context, options, NULL); g_option_context_add_main_entries (context, options, NULL);
if (!ostree_admin_option_context_parse (context, options, &argc, &argv, if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED,
&sysroot, cancellable, error)) invocation, &sysroot, cancellable, error))
goto out; goto out;
if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,

View File

@ -38,15 +38,15 @@ static GOptionEntry options[] = {
}; };
gboolean gboolean
ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error) ot_admin_builtin_init_fs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{ {
g_autoptr(GOptionContext) context = g_option_context_new ("PATH - Initialize a root filesystem"); g_autoptr(GOptionContext) context = g_option_context_new ("PATH");
if (!ostree_admin_option_context_parse (context, options, &argc, &argv, if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER |
OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED |
OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT,
NULL, cancellable, error)) invocation, NULL, cancellable, error))
return FALSE; return FALSE;
if (argc < 2) if (argc < 2)
@ -57,7 +57,7 @@ ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GErr
const char *sysroot_path = argv[1]; const char *sysroot_path = argv[1];
glnx_fd_close int root_dfd = -1; glnx_autofd int root_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error)) if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error))
return FALSE; return FALSE;

Some files were not shown because too many files have changed in this diff Show More