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-config.h \
src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL)
endif

View File

@ -156,6 +156,7 @@ libostree_experimental_headers = \
src/libostree/ostree-repo-finder-avahi.h \
src/libostree/ostree-repo-finder-config.h \
src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL)
if !ENABLE_EXPERIMENTAL_API
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-config.c \
src/libostree/ostree-repo-finder-mount.c \
src/libostree/ostree-repo-finder-override.c \
$(NULL)
if USE_AVAHI

View File

@ -34,11 +34,12 @@ libotutil_la_SOURCES = \
src/libotutil/ot-unix-utils.h \
src/libotutil/ot-variant-utils.c \
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.h \
src/libotutil/ot-gpg-utils.c \
src/libotutil/ot-gpg-utils.h \
src/libotutil/otutil.c \
src/libotutil/otutil.h \
src/libotutil/ot-tool-util.c \
src/libotutil/ot-tool-util.h \

View File

@ -69,6 +69,8 @@ _installed_or_uninstalled_test_scripts = \
tests/test-parent.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-mirror-summary.sh \
@ -159,10 +161,13 @@ endif
dist_installed_test_data = tests/archive-test.sh \
tests/pull-test.sh \
tests/pull-test2.sh \
tests/admin-test.sh \
tests/basic-test.sh \
tests/pre-endian-deltas-repo-big.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 \
$(NULL)

View File

@ -90,13 +90,24 @@ endif # end ENABLE_RUST
libglnx_srcpath := $(srcdir)/libglnx
libglnx_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(libglnx_srcpath)"
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
EXTRA_DIST += libglnx/Makefile-libglnx.am
noinst_LTLIBRARIES += libglnx.la
libbsdiff_srcpath := $(srcdir)/bsdiff
libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)"
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
EXTRA_DIST += bsdiff/Makefile-bsdiff.am
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-config.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_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-config.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@@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-config.h \
src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
src/libostree/ostree-bloom.c \
src/libostree/ostree-bloom-private.h \
src/libostree/ostree-repo-finder.c \
src/libostree/ostree-repo-finder-avahi.c \
src/libostree/ostree-repo-finder-config.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-private.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-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-override.lo \
@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_1)
@ -875,9 +880,9 @@ am_libotutil_la_OBJECTS = \
src/libotutil/libotutil_la-ot-opt-utils.lo \
src/libotutil/libotutil_la-ot-unix-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-gpg-utils.lo \
src/libotutil/libotutil_la-otutil.lo \
src/libotutil/libotutil_la-ot-tool-util.lo $(am__objects_1)
libotutil_la_OBJECTS = $(am_libotutil_la_OBJECTS)
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)
am__EXEEXT_14 = test-libglnx-xattrs$(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)
@ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_16 = $(am__EXEEXT_8) \
@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) \
$(test_libglnx_macros_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(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)
test_libglnx_xattrs_OBJECTS = $(am_test_libglnx_xattrs_OBJECTS)
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_trivial_httpd_SOURCES) $(rofiles_fuse_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_test_bloom_SOURCES) tests/test-bsdiff.c \
$(tests_test_checksum_SOURCES) \
@ -1408,7 +1421,8 @@ DIST_SOURCES = $(libbsdiff_la_SOURCES) \
$(am__ostree_trivial_httpd_SOURCES_DIST) \
$(am__rofiles_fuse_SOURCES_DIST) \
$(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_test_bloom_SOURCES) tests/test-bsdiff.c \
$(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-config.h \
src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
src/libostree/ostree-version.h
HEADERS = $(libostreeinclude_HEADERS)
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-libarchive.sh tests/test-parent.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-mirror-summary.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_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic
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_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
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_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
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_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)"
libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS)
@ -2213,11 +2233,12 @@ libotutil_la_SOURCES = \
src/libotutil/ot-unix-utils.h \
src/libotutil/ot-variant-utils.c \
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.h \
src/libotutil/ot-gpg-utils.c \
src/libotutil/ot-gpg-utils.h \
src/libotutil/otutil.c \
src/libotutil/otutil.h \
src/libotutil/ot-tool-util.c \
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-config.h \
src/libostree/ostree-repo-finder-mount.h \
src/libostree/ostree-repo-finder-override.h \
$(NULL)
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-help.sh tests/test-libarchive.sh \
tests/test-parent.sh tests/test-pull-bare.sh \
tests/test-pull-bareuser.sh tests/test-pull-commit-only.sh \
tests/test-pull-depth.sh tests/test-pull-mirror-summary.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-mirror-summary.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-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
dist_installed_test_data = tests/archive-test.sh \
tests/pull-test.sh \
tests/pull-test2.sh \
tests/admin-test.sh \
tests/basic-test.sh \
tests/pre-endian-deltas-repo-big.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 \
$(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/$(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/$(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/$(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/$(am__dirstamp) \
src/libotutil/$(DEPDIR)/$(am__dirstamp)
src/libotutil/libotutil_la-ot-gpg-utils.lo: \
src/libotutil/$(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/$(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)
@rm -f test-libglnx-macros$(EXEEXT)
$(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/$(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_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_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@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@
@ -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-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-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-libarchive.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-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-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-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-ot-admin-builtin-cleanup.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@
@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
@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
@ -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@
@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
@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
@ -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@
@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
@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
@ -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@
@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
@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
@ -7333,6 +7394,20 @@ tests/test-pull-bareuser.sh.log: tests/test-pull-bareuser.sh
--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-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
@p='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 \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$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:
@p='$<'; \
$(am__set_b); \
@ -8292,6 +8374,16 @@ all-local: $(ALL_LOCAL_RULES)
@ENABLE_RUST_TRUE@ cargo vendor -q && \
@ENABLE_RUST_TRUE@ mkdir .cargo && \
@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@ 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
# 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 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
@ -112,7 +115,7 @@ dnl
#include <stdlib.h>
int
main ()
main (void)
{
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-config.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)
subdir = apidoc

View File

@ -14,7 +14,7 @@
<div class="titlepage">
<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>
<hr>
</div>

View File

@ -307,6 +307,14 @@
</tr>
<tr>
<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>
</td>
<td class="function_name">
@ -1786,6 +1794,69 @@ ostree_checksum_file (<em class="parameter"><code><span class="type">GFile</span
</div>
<hr>
<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>
<pre class="programlisting"><span class="returnvalue">void</span>
ostree_checksum_file_async (<em class="parameter"><code><span class="type">GFile</span> *f</code></em>,

View File

@ -769,6 +769,14 @@
</tr>
<tr>
<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>
</td>
<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>
</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="function_name"><a class="link" href="ostree-OstreeRepo.html#OstreeRepoCheckoutMode" title="enum OstreeRepoCheckoutMode">OstreeRepoCheckoutMode</a></td>
</tr>
@ -2187,6 +2199,8 @@ respectively.</p>
is
set to <em class="parameter"><code>NULL</code></em>
. 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>
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">
@ -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>,
<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>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>
<hr>
<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">guchar</span> **out_csum</code></em>,
<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>
<hr>
<div class="refsect2">
@ -4768,6 +4846,7 @@ should avoid further mutation of the cache.</p>
</tbody>
</table></div>
</div>
<p class="since">Since: 2017.13</p>
</div>
<hr>
<div class="refsect2">
@ -5322,6 +5401,44 @@ data will be deleted.</p>
</div>
<hr>
<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>
<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>,
@ -5468,7 +5585,7 @@ cache.</p>
<a name="ostree-repo-checkout-at"></a><h3>ostree_repo_checkout_at ()</h3>
<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>,
<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>const <span class="type">char</span> *destination_path</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 class="enum_member_annotations"> </td>
</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>
</table></div>
</div>
</div>
<hr>
<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>
<div class="refsect3">
<a name="OstreeRepoCheckoutMode.members"></a><h4>Members</h4>
@ -7678,7 +7834,7 @@ in bytes, counting only content objects.</p></td>
<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_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 class="enum_member_annotations"> </td>
</tr>

View File

@ -365,6 +365,11 @@ perform locking externally.</p>
<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> *
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">
<a name="ostree-sysroot-new.parameters"></a><h4>Parameters</h4>
<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>
<tbody><tr>
<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>
</tr></tbody>
</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">GError</span> **error</code></em>);</pre>
<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">
<a name="ostree-sysroot-get-repo.parameters"></a><h4>Parameters</h4>
<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_description"><p> Repository in sysroot <em class="parameter"><code>self</code></em>
. </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>
<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>
</table></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>
<hr>
<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_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_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_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"/>
@ -157,7 +158,7 @@
<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_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_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"/>
@ -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_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_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_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"/>
@ -218,6 +220,7 @@
<keyword type="enum" name="enum OstreeRepoCommitFilterResult" link="ostree-OstreeRepo.html#OstreeRepoCommitFilterResult"/>
<keyword type="typedef" name="OstreeRepoCommitModifier" link="ostree-OstreeRepo.html#OstreeRepoCommitModifier"/>
<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 OstreeRepoCheckoutOverwriteMode" link="ostree-OstreeRepo.html#OstreeRepoCheckoutOverwriteMode"/>
<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_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_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_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"/>

View File

@ -214,6 +214,10 @@
</dt>
<dd></dd>
<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>
</dt>
<dd></dd>
@ -598,6 +602,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
</dt>
<dd></dd>
<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>
</dt>
<dd></dd>
@ -690,6 +698,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
</dt>
<dd></dd>
<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>
</dt>
<dd></dd>

View File

@ -76,6 +76,15 @@ ostree_repo_finder_mount_new
ostree_repo_finder_mount_get_type
</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>
<FILE>ostree-misc-experimental</FILE>
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_checksum_file_from_input
ostree_checksum_file
ostree_checksum_file_at
ostree_checksum_file_async
ostree_checksum_file_async_finish
ostree_create_directory_metadata
@ -370,6 +371,8 @@ ostree_repo_write_commit
ostree_repo_write_commit_with_time
ostree_repo_read_commit_detached_metadata
ostree_repo_write_commit_detached_metadata
OstreeRepoCheckoutAtOptions
ostree_repo_checkout_at_options_set_devino
OstreeRepoCheckoutMode
OstreeRepoCheckoutOverwriteMode
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_get_type
ostree_repo_finder_mount_get_type
ostree_repo_finder_override_get_type
ostree_repo_finder_result_get_type
ostree_repo_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
git submodule update --init
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,$(libbsdiff_srcpath),bsdiff,g' < bsdiff/Makefile-bsdiff.am >bsdiff/Makefile-bsdiff.am.inc

View File

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

View File

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

View File

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

32
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# 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>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libostree'
PACKAGE_TARNAME='libostree'
PACKAGE_VERSION='2017.12'
PACKAGE_STRING='libostree 2017.12'
PACKAGE_VERSION='2017.13'
PACKAGE_STRING='libostree 2017.13'
PACKAGE_BUGREPORT='walters@verbum.org'
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.
# This message is too long to be a string in the A/UX 3.1 sh.
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]...
@ -1610,7 +1610,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of libostree 2017.12:";;
short | recursive ) echo "Configuration of libostree 2017.13:";;
esac
cat <<\_ACEOF
@ -1851,7 +1851,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
libostree configure 2017.12
libostree configure 2017.13
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2266,7 +2266,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
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
$ $0 $@
@ -3134,7 +3134,7 @@ fi
# Define the identity of the package.
PACKAGE='libostree'
VERSION='2017.12'
VERSION='2017.13'
# Some tools Automake needs.
@ -5868,9 +5868,9 @@ test -n "$YACC" || YACC="yacc"
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 :
@ -13731,7 +13731,7 @@ fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_RENAMEAT2 $ac_have_decl
_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 <unistd.h>
#include <sys/mount.h>
@ -13741,14 +13741,14 @@ ac_fn_c_check_decl "$LINENO" "" "ac_cv_have_decl_" "
#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
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_ $ac_have_decl
#define HAVE_DECL_MEMFD_CREATE $ac_have_decl
_ACEOF
@ -14155,7 +14155,7 @@ else
#include <stdlib.h>
int
main ()
main (void)
{
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
# values after options handling.
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
CONFIG_FILES = $CONFIG_FILES
@ -18234,7 +18234,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
libostree config.status 2017.12
libostree config.status 2017.13
configured by $0, generated by GNU Autoconf 2.69,
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 another post-release commit to bump the version, and set is_release_build=no.
m4_define([year_version], [2017])
m4_define([release_version], [12])
m4_define([release_version], [13])
m4_define([package_version], [year_version.release_version])
AC_INIT([libostree], [package_version], [walters@verbum.org])
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_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)
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_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags)
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`
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`.

View File

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

View File

@ -141,7 +141,14 @@ glnx_renameat2_exchange (int olddirfd, const char *oldpath,
#endif
/* 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 */
if (renameat (olddirfd, oldpath, olddirfd, old_tmp_name) < 0)
@ -168,11 +175,7 @@ glnx_tmpfile_clear (GLnxTmpfile *tmpf)
return;
if (!tmpf->initialized)
return;
if (tmpf->fd != -1)
{
if (close (tmpf->fd) < 0)
g_assert (errno != EBADF);
}
glnx_close_fd (&tmpf->fd);
/* If ->path is set, we're likely aborting due to an error. Clean it up */
if (tmpf->path)
{
@ -188,9 +191,8 @@ open_tmpfile_core (int dfd, const char *subpath,
GLnxTmpfile *out_tmpf,
GError **error)
{
/* Picked this to match mkstemp() */
const guint mode = 0600;
glnx_fd_close int fd = -1;
int count;
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
* in full. */
#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)))
return glnx_throw_errno_prefix (error, "open(O_TMPFILE)");
if (fd != -1)
@ -217,17 +220,18 @@ open_tmpfile_core (int dfd, const char *subpath,
out_tmpf->path = NULL;
return TRUE;
}
}
/* Fallthrough */
#endif
{ g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL);
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);
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 (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,
"Exhausted %u attempts to create temporary file", count);
"Exhausted %u attempts to create temporary file", count_max);
return FALSE;
}
@ -356,9 +360,9 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf,
char *dnbuf = strdupa (target);
const char *dn = dirname (dnbuf);
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++)
{
glnx_gen_temp_name (tmpname_buf);
@ -569,7 +573,7 @@ glnx_file_get_contents_utf8_at (int 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))
return NULL;
@ -599,17 +603,13 @@ glnx_readlinkat_malloc (int dfd,
GCancellable *cancellable,
GError **error)
{
size_t l = 100;
dfd = glnx_dirfd_canonicalize (dfd);
size_t l = 100;
for (;;)
{
g_autofree char *c = NULL;
ssize_t n;
c = g_malloc (l);
n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1));
g_autofree char *c = g_malloc (l);
ssize_t n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1));
if (n < 0)
return glnx_null_throw_errno_prefix (error, "readlinkat");
@ -679,18 +679,15 @@ copy_symlink_at (int src_dfd,
int
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);
errno = 0;
const uint8_t *p = buf;
while (nbytes > 0)
{
ssize_t k;
k = write(fd, p, nbytes);
ssize_t k = write(fd, p, nbytes);
if (k < 0)
{
if (errno == EINTR)
@ -926,7 +923,7 @@ glnx_file_copy_at (int src_dfd,
/* 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))
return FALSE;

View File

@ -299,7 +299,7 @@ glnx_fstatat (int dfd,
* glnx_fstatat_allow_noent:
* @dfd: Directory FD to stat beneath
* @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()
* @error: Return location for a #GError, or %NULL
*
@ -318,15 +318,12 @@ glnx_fstatat_allow_noent (int dfd,
int flags,
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)
{
int errsv = errno;
(void) glnx_throw_errno_prefix (error, "fstatat(%s)", path);
errno = errsv;
return FALSE;
}
return glnx_throw_errno_prefix (error, "fstatat(%s)", path);
/* Note we preserve errno as ENOENT */
}
else
errno = 0;

View File

@ -42,14 +42,30 @@ glnx_local_obj_unref (void *v)
}
#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref)))
static inline void
glnx_cleanup_close_fdp (int *fdp)
static inline int
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);
fd = *fdp;
int fd = glnx_steal_fd (fdp);
if (fd >= 0)
{
errsv = errno;
@ -62,16 +78,14 @@ glnx_cleanup_close_fdp (int *fdp)
/**
* 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.
*/
#define glnx_fd_close __attribute__((cleanup(glnx_cleanup_close_fdp)))
static inline int
glnx_steal_fd (int *fdp)
{
int fd = *fdp;
*fdp = -1;
return fd;
}
#define glnx_autofd __attribute__((cleanup(glnx_close_fd)))
G_END_DECLS

View File

@ -61,7 +61,7 @@
*/
gboolean
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;
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)
break;
(void) close(fd);
fd = -1;
glnx_close_fd (&fd);
}
/* 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;
}
if (f->fd != -1)
(void) close (f->fd);
f->fd = -1;
glnx_close_fd (&f->fd);
f->operation = 0;
f->initialized = FALSE;
}

View File

@ -18,7 +18,18 @@
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
# ifndef __NR_renameat2
@ -26,6 +37,8 @@
# define __NR_renameat2 316
# elif defined __arm__
# define __NR_renameat2 382
# elif defined __aarch64__
# define __NR_renameat2 276
# elif defined _MIPS_SIM
# if _MIPS_SIM == _MIPS_SIM_ABI32
# define __NR_renameat2 4351
@ -38,6 +51,12 @@
# endif
# elif defined __i386__
# 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
# warning "__NR_renameat2 unknown for your architecture"
# endif
@ -53,6 +72,45 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha
}
#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:
commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca
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/>.
***/
/* 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 <fcntl.h>
@ -29,22 +39,30 @@
#include <uchar.h>
#include <unistd.h>
#if defined(__i386__) || defined(__x86_64__)
/* The precise definition of __O_TMPFILE is arch specific, so let's
* just define this on x86 where we know the value. */
/* The precise definition of __O_TMPFILE is arch specific; use the
* values defined by the kernel (note: some are hexa, some are octal,
* duplicated as-is from the kernel definitions):
* - alpha, parisc, sparc: each has a specific value;
* - others: they use the "generic" value.
*/
#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
#endif
#endif
/* a horrid kludge trying to make sure that this will fail on old kernels */
#ifndef O_TMPFILE
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#endif
#endif
#ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0)
#endif
@ -52,4 +70,26 @@
#define RENAME_EXCHANGE (1 << 1)
#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"

View File

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

View File

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

View File

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

View File

@ -32,8 +32,8 @@ static gboolean
renameat_test_setup (int *out_srcfd, int *out_destfd,
GError **error)
{
glnx_fd_close int srcfd = -1;
glnx_fd_close int destfd = -1;
glnx_autofd int srcfd = -1;
glnx_autofd int destfd = -1;
(void) glnx_shutil_rm_rf_at (AT_FDCWD, "srcdir", NULL, NULL);
if (mkdir ("srcdir", 0755) < 0)
@ -62,8 +62,8 @@ static void
test_renameat2_noreplace (void)
{
_GLNX_TEST_DECLARE_ERROR(local_error, error);
glnx_fd_close int srcfd = -1;
glnx_fd_close int destfd = -1;
glnx_autofd int srcfd = -1;
glnx_autofd int destfd = -1;
struct stat stbuf;
if (!renameat_test_setup (&srcfd, &destfd, error))
@ -92,8 +92,8 @@ test_renameat2_exchange (void)
{
_GLNX_TEST_DECLARE_ERROR(local_error, error);
glnx_fd_close int srcfd = -1;
glnx_fd_close int destfd = -1;
glnx_autofd int srcfd = -1;
glnx_autofd int destfd = -1;
if (!renameat_test_setup (&srcfd, &destfd, error))
return;
@ -161,13 +161,22 @@ test_fstatat (void)
return;
g_assert_cmpint (errno, ==, ENOENT);
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
test_filecopy (void)
{
_GLNX_TEST_DECLARE_ERROR(local_error, error);
g_auto(GLnxTmpfile) tmpf = { 0, };
const char foo[] = "foo";
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 ();
g_autofree char *randname = g_strdup_printf ("file%u", randname_v);
glnx_fd_close int fd = -1;
glnx_autofd int fd = -1;
again:
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)
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))
return FALSE;
@ -157,7 +157,7 @@ do_read_run (GLnxDirFdIterator *dfd_iter,
if (!dent)
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))
return FALSE;

View File

@ -61,6 +61,19 @@ Boston, MA 02111-1307, USA.
</para>
</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>
<title>Example</title>
<para><command>$ ostree checksum file1</command></para>

View File

@ -167,6 +167,17 @@ Boston, MA 02111-1307, USA.
</para></listitem>
</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>
<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. */
LIBOSTREE_2017.13 {
} LIBOSTREE_2017.12;
LIBOSTREE_2017.14 {
} LIBOSTREE_2017.13;
/* 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

View File

@ -82,3 +82,10 @@ LIBOSTREE_2017.12_EXPERIMENTAL {
global:
ostree_repo_resolve_collection_ref;
} 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;
} 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
* 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 (OstreeRepoFinderConfig, 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_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, ostree_repo_finder_result_freev, NULL)
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */

View File

@ -76,7 +76,7 @@
struct _OstreeBloom
{
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 */
union
{
@ -117,6 +117,7 @@ ostree_bloom_new (gsize n_bytes,
g_autoptr(OstreeBloom) bloom = 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 (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 (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 (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 */
{ 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))
return FALSE;

View File

@ -25,12 +25,13 @@
#include <string.h>
static const char syslinux_config_path[] = "boot/syslinux/syslinux.cfg";
struct _OstreeBootloaderSyslinux
{
GObject parent_instance;
OstreeSysroot *sysroot;
GFile *config_path;
};
typedef GObjectClass OstreeBootloaderSyslinuxClass;
@ -46,8 +47,11 @@ _ostree_bootloader_syslinux_query (OstreeBootloader *bootloader,
GError **error)
{
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;
}
@ -107,12 +111,12 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
{
OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader);
g_autoptr(GFile) new_config_path =
ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", bootversion);
g_autofree char *new_config_path =
g_strdup_printf ("boot/loader.%d/syslinux.cfg", bootversion);
/* This should follow the symbolic link to the current bootversion. */
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);
if (!config_contents)
return FALSE;
@ -206,11 +210,9 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
return FALSE;
g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines);
g_autoptr(GBytes) new_config_contents_bytes =
g_bytes_new_static (new_config_contents,
strlen (new_config_contents));
if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path,
(guint8*)new_config_contents, strlen (new_config_contents),
GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
return FALSE;
@ -223,7 +225,6 @@ _ostree_bootloader_syslinux_finalize (GObject *object)
OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (object);
g_clear_object (&self->sysroot);
g_clear_object (&self->config_path);
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);
self->sysroot = g_object_ref (sysroot);
self->config_path = g_file_resolve_relative_path (self->sysroot->path, "boot/syslinux/syslinux.cfg");
return self;
}

View File

@ -29,12 +29,13 @@
#include <string.h>
static const char uboot_config_path[] = "boot/loader/uEnv.txt";
struct _OstreeBootloaderUboot
{
GObject parent_instance;
OstreeSysroot *sysroot;
GFile *config_path;
};
typedef GObjectClass OstreeBootloaderUbootClass;
@ -50,8 +51,11 @@ _ostree_bootloader_uboot_query (OstreeBootloader *bootloader,
GError **error)
{
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;
}
@ -69,8 +73,8 @@ append_system_uenv (OstreeBootloaderUboot *self,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int uenv_fd = -1;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
glnx_autofd int uenv_fd = -1;
g_autoptr(OstreeKernelArgs) kargs = NULL;
const char *uenv_path = NULL;
const char *ostree_arg = NULL;
@ -156,36 +160,26 @@ _ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader,
GError **error)
{
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. */
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);
if (!config_contents)
return FALSE;
new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/uEnv.txt",
bootversion);
new_lines = g_ptr_array_new_with_free_func (g_free);
g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free);
if (!create_config_from_boot_loader_entries (self, bootversion, new_lines,
cancellable, error))
return FALSE;
new_config_contents = _ostree_sysroot_join_lines (new_lines);
{
g_autoptr(GBytes) new_config_contents_bytes =
g_bytes_new_static (new_config_contents,
strlen (new_config_contents));
if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes,
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);
if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path,
(guint8*)new_config_contents, strlen (new_config_contents),
GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
return FALSE;
}
return TRUE;
}
@ -196,7 +190,6 @@ _ostree_bootloader_uboot_finalize (GObject *object)
OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (object);
g_clear_object (&self->sysroot);
g_clear_object (&self->config_path);
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);
self->sysroot = g_object_ref (sysroot);
self->config_path = g_file_resolve_relative_path (self->sysroot->path, "boot/loader/uEnv.txt");
return self;
}

View File

@ -20,6 +20,7 @@
#pragma once
#include "ostree-core.h"
#include "otutil.h"
#include <sys/stat.h>
G_BEGIN_DECLS
@ -67,20 +68,12 @@ G_BEGIN_DECLS
#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 *_ostree_zlib_file_header_new (GFileInfo *file_info,
GBytes *_ostree_zlib_file_header_new (GFileInfo *file_info,
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
_ostree_make_temporary_symlink_at (int tmp_dirfd,
const char *target,
@ -90,6 +83,7 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
GFileInfo * _ostree_stbuf_to_gfileinfo (const struct stat *stbuf);
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);
static inline void
@ -134,6 +128,11 @@ static inline char * _ostree_get_commitpartial_path (const char *checksum)
return g_strconcat ("state/", checksum, ".commitpartial", NULL);
}
gboolean
_ostree_validate_ref_fragment (const char *fragment,
GError **error);
gboolean
_ostree_validate_bareuseronly_mode (guint32 mode,
const char *checksum,
@ -147,6 +146,12 @@ _ostree_validate_bareuseronly_mode_finfo (GFileInfo *finfo,
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
_ostree_parse_delta_name (const char *delta_name,
char **out_from,
@ -218,6 +223,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderConfig, g_object_unref)
#include "ostree-repo-finder-mount.h"
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
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_ONLY == 3);
static GBytes *variant_to_lenprefixed_buffer (GVariant *variant);
#define ALIGN_VALUE(this, boundary) \
(( ((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);
}
#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_REMOTE_NAME_REGEXP OSTREE_REF_FRAGMENT_REGEXP
@ -194,6 +199,26 @@ ostree_parse_refspec (const char *refspec,
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:
* @rev: A revision string
@ -283,192 +308,103 @@ ostree_validate_collection_id (const char *collection_id, GError **error)
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,
GVariant *xattrs)
{
guint32 uid;
guint32 gid;
guint32 mode;
guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
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;
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)
symlink_target = g_file_info_get_symlink_target (file_info);
else
symlink_target = "";
g_autoptr(GVariant) tmp_xattrs = NULL;
if (xattrs == NULL)
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,
symlink_target, xattrs ? xattrs : tmp_xattrs);
g_variant_ref_sink (ret);
return ret;
symlink_target, xattrs ?: tmp_xattrs);
return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret));
}
/*
* ostree_zlib_file_header_new:
* @file_info: a #GFileInfo
* @xattrs: (allow-none): Optional extended attribute array
*
* Returns: (transfer full): A new #GVariant containing file header for an archive repository
/* Like _ostree_file_header_new(), but used for the compressed format in archive
* repositories. This format hence lives on disk; normally the uncompressed
* stream format doesn't. Instead for "bare" repositories, the file data is
* stored directly, or for the special case of bare-user repositories, as a
* user.ostreemeta xattr.
*/
GVariant *
GBytes *
_ostree_zlib_file_header_new (GFileInfo *file_info,
GVariant *xattrs)
{
guint64 size;
guint32 uid;
guint32 gid;
guint32 mode;
guint64 size = g_file_info_get_size (file_info);
guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid");
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;
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)
symlink_target = g_file_info_get_symlink_target (file_info);
else
symlink_target = "";
g_autoptr(GVariant) tmp_xattrs = NULL;
if (xattrs == NULL)
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),
GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0,
symlink_target, xattrs ? xattrs : tmp_xattrs);
g_variant_ref_sink (ret);
return ret;
symlink_target, xattrs ?: tmp_xattrs);
return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret));
}
static gboolean
write_padding (GOutputStream *output,
guint alignment,
gsize offset,
gsize *out_bytes_written,
GChecksum *checksum,
GCancellable *cancellable,
GError **error)
/* Serialize a variant to a buffer prefixed with its length. The variant will
* have an 8-byte alignment so it can be safely used with `mmap()`.
*/
static GBytes *
variant_to_lenprefixed_buffer (GVariant *variant)
{
guint bits;
guint padding_len;
guchar padding_nuls[8] = {0, 0, 0, 0, 0, 0, 0, 0};
/* This string is really a binary memory buffer */
g_autoptr(GString) buf = g_string_new (NULL);
/* 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)
bits = ((offset) & 7);
bits = alignment_offset & 7; /* mod 8 */
else
bits = ((offset) & 3);
bits = alignment_offset & 3; /* mod 4 */
const guint padding_len = alignment - bits;
if (bits > 0)
{
padding_len = alignment - bits;
if (!ot_gio_write_update_checksum (output, (guchar*)padding_nuls, padding_len,
out_bytes_written, checksum,
cancellable, error))
return FALSE;
}
g_string_append_len (buf, (char*)padding_nuls, padding_len);
return TRUE;
}
/*
* _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;
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));
}
/*
@ -476,54 +412,38 @@ write_file_header_update_checksum (GOutputStream *out,
* @file_header: A file header
* @input: File raw content stream
* @out_input: (out): Serialized object stream
* @out_header_size: (out): Length of the header
* @cancellable: Cancellable
* @error: Error
*
* Combines @file_header and @input into a single stream.
*/
static gboolean
header_and_input_to_stream (GVariant *file_header,
header_and_input_to_stream (GBytes *file_header,
GInputStream *input,
GInputStream **out_input,
guint64 *out_header_size,
GCancellable *cancellable,
GError **error)
{
gpointer header_data;
gsize header_size;
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;
/* Our result stream chain */
g_autoptr(GPtrArray) streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
header_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
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);
/* Append the header to the chain */
g_autoptr(GInputStream) header_in_stream = g_memory_input_stream_new_from_bytes (file_header);
g_ptr_array_add (streams, g_object_ref (header_in_stream));
/* And if we have an input stream, append that */
if (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);
if (out_header_size)
*out_header_size = header_size;
return TRUE;
}
/* Convert file metadata + file content into an archive-format stream. */
gboolean
_ostree_raw_file_to_archive_stream (GInputStream *input,
GFileInfo *file_info,
@ -533,21 +453,17 @@ _ostree_raw_file_to_archive_stream (GInputStream *input,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GVariant) file_header = NULL;
g_autoptr(GInputStream) zlib_input = NULL;
file_header = _ostree_zlib_file_header_new (file_info, xattrs);
if (input != NULL)
{
g_autoptr(GConverter) zlib_compressor = NULL;
zlib_compressor = G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, compression_level));
g_autoptr(GConverter) 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);
}
g_autoptr(GBytes) file_header = _ostree_zlib_file_header_new (file_info, xattrs);
return header_and_input_to_stream (file_header,
zlib_input,
out_input,
NULL,
cancellable,
error);
}
@ -640,19 +556,15 @@ ostree_raw_file_to_content_stream (GInputStream *input,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GVariant) file_header = NULL;
guint64 header_size;
file_header = _ostree_file_header_new (file_info, xattrs);
g_autoptr(GBytes) file_header = _ostree_file_header_new (file_info, xattrs);
if (!header_and_input_to_stream (file_header,
input,
out_input,
&header_size,
cancellable,
error))
return FALSE;
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;
}
@ -781,7 +693,7 @@ ostree_content_file_parse_at (gboolean compressed,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int fd = -1;
glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (parent_dfd, path, TRUE, &fd, error))
return FALSE;
@ -859,37 +771,35 @@ ostree_checksum_file_from_input (GFileInfo *file_info,
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 (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE;
}
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_checksum_update (checksum, g_variant_get_data (dirmeta),
ot_checksum_update (&checksum, g_variant_get_data (dirmeta),
g_variant_get_size (dirmeta));
}
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);
if (!write_file_header_update_checksum (NULL, file_header, checksum,
cancellable, error))
return FALSE;
ot_checksum_update_bytes (&checksum, file_header);
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;
}
}
*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;
}
@ -945,6 +855,81 @@ ostree_checksum_file (GFile *f,
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 {
GFile *f;
OstreeObjectType objtype;
@ -1042,6 +1027,22 @@ ostree_checksum_file_async_finish (GFile *f,
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:
* @dir_info: a #GFileInfo containing directory information
@ -1614,10 +1615,31 @@ _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b)
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 *
_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_uid = uid;
stbuf.st_gid = gid;

View File

@ -21,6 +21,7 @@
#pragma once
#include <sys/stat.h>
#include <gio/gio.h>
#include <ostree-types.h>
@ -227,6 +228,23 @@ typedef enum {
* Since: 2017.7
*/
#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:
*
@ -420,6 +438,26 @@ gboolean ostree_checksum_file (GFile *f,
GCancellable *cancellable,
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
void ostree_checksum_file_async (GFile *f,
OstreeObjectType objtype,

View File

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

View File

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

View File

@ -25,14 +25,23 @@
G_BEGIN_DECLS
/* FIXME - delete this and replace by having fetchers simply
* return O_TMPFILE fds, not file paths.
*/
static inline char *
ostree_fetcher_generate_url_tmpname (const char *url)
static inline gboolean
_ostree_fetcher_tmpf_from_flags (OstreeFetcherRequestFlags flags,
int dfd,
GLnxTmpfile *tmpf,
GError **error)
{
return g_compute_checksum_for_string (G_CHECKSUM_SHA256,
url, strlen (url));
if ((flags & OSTREE_FETCHER_REQUEST_LINKABLE) > 0)
{
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,

View File

@ -55,7 +55,8 @@ typedef enum {
typedef enum {
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;
void
@ -124,7 +125,7 @@ void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
GAsyncResult *result,
char **out_filename,
GLnxTmpfile *out_tmpf,
GError **error);
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++)
{
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;
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_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));
}
@ -280,8 +283,11 @@ _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
*/
void
_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));
}
@ -289,6 +295,8 @@ void
_ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self,
const char *path)
{
g_debug ("Adding GPG key ASCII file %s to verifier", path);
if (!self->key_ascii_files)
self->key_ascii_files = g_ptr_array_new_with_free_func (g_free);
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))
return FALSE;
g_debug ("Adding GPG keyring dir %s to verifier", path);
while (TRUE)
{
struct dirent *dent;
@ -345,7 +355,7 @@ _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self,
if (g_str_equal (name, "secring.gpg"))
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))
return FALSE;

View File

@ -65,7 +65,8 @@ gboolean _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *s
GError **error);
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,
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
* 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))
return FALSE;

View File

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

View File

@ -19,15 +19,15 @@
#pragma once
#include <gio/gio.h>
#include "libglnx.h"
G_BEGIN_DECLS
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);
void _ostree_kernel_args_free (OstreeKernelArgs *kargs);
void _ostree_kernel_args_cleanup (void *loc);
void _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs,
char *key);
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");
case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES:
{
/* Unioning? Let's unlink and try again */
(void) unlinkat (destination_dfd, destination_name, 0);
/* For unioning, we further bifurcate a bit; for the "process whiteouts"
* 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)
return glnx_throw_errno_prefix (error, "symlinkat");
}
@ -309,6 +325,16 @@ create_file_copy_from_input_at (OstreeRepo *repo,
/* Handled above */
break;
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;
break;
case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES:
@ -374,6 +400,7 @@ hardlink_add_tmp_name (OstreeRepo *self,
static gboolean
checkout_file_hardlink (OstreeRepo *self,
const char *checksum,
OstreeRepoCheckoutAtOptions *options,
const char *loose_path,
int destination_dfd,
@ -436,10 +463,28 @@ checkout_file_hardlink (OstreeRepo *self,
if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf,
AT_SYMLINK_NOFOLLOW, error))
return FALSE;
const gboolean is_identical =
gboolean is_identical =
(src_stbuf.st_dev == dest_stbuf.st_dev &&
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)
ret_result = HARDLINK_RESULT_SKIP_EXISTED;
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 */
if (!hardlink_add_tmp_name (self, srcfd, loose_path, tmpname, cancellable, error))
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))
return FALSE;
ret_result = HARDLINK_RESULT_LINKED;
@ -563,6 +616,7 @@ checkout_one_file_at (OstreeRepo *repo,
the cache, which is in "bare" form */
_ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE);
if (!checkout_file_hardlink (current_repo,
checksum,
options,
loose_path_buf,
destination_dfd, destination_name,
@ -652,7 +706,7 @@ checkout_one_file_at (OstreeRepo *repo,
}
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,
FALSE, &hardlink_res,
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,
&destination_dfd, error))
return FALSE;
@ -947,7 +1001,7 @@ checkout_tree_at (OstreeRepo *self,
* exists.
*/
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 (mkdirat (destination_parent_fd, destination_name, 0700) < 0
@ -1156,6 +1210,24 @@ ostree_repo_checkout_at (OstreeRepo *self,
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
devino_hash (gconstpointer a)
{

View File

@ -38,6 +38,22 @@
#include "ostree-checksum-input-stream.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
_ostree_repo_ensure_loose_objdir_at (int dfd,
const char *loose_path,
@ -60,6 +76,7 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
return TRUE;
}
/* This GVariant is the header for content objects (regfiles and symlinks) */
static GVariant *
create_file_metadata (guint32 uid,
guint32 gid,
@ -82,6 +99,7 @@ create_file_metadata (guint32 uid,
return ret_metadata;
}
/* bare-user repositories store file metadata as a user xattr */
gboolean
_ostree_write_bareuser_metadata (int fd,
guint32 uid,
@ -137,12 +155,7 @@ _ostree_repo_commit_tmpf_final (OstreeRepo *self,
char tmpbuf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (tmpbuf, checksum, objtype, self->mode);
int dest_dfd;
if (self->in_transaction)
dest_dfd = self->commit_stagedir.fd;
else
dest_dfd = self->objects_dir_fd;
int dest_dfd = commit_dest_dfd (self);
if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf,
cancellable, error))
return FALSE;
@ -158,8 +171,8 @@ _ostree_repo_commit_tmpf_final (OstreeRepo *self,
/* Given a dfd+path combination (may be regular file or symlink),
* rename it into place.
*/
gboolean
_ostree_repo_commit_path_final (OstreeRepo *self,
static gboolean
commit_path_final (OstreeRepo *self,
const char *checksum,
OstreeObjectType objtype,
OtCleanupUnlinkat *tmp_path,
@ -170,12 +183,7 @@ _ostree_repo_commit_path_final (OstreeRepo *self,
char tmpbuf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (tmpbuf, checksum, objtype, self->mode);
int dest_dfd;
if (self->in_transaction)
dest_dfd = self->commit_stagedir.fd;
else
dest_dfd = self->objects_dir_fd;
int dest_dfd = commit_dest_dfd (self);
if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf,
cancellable, error))
return FALSE;
@ -295,6 +303,7 @@ commit_loose_regfile_object (OstreeRepo *self,
return TRUE;
}
/* This is used by OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES */
typedef struct
{
goffset unpacked;
@ -395,35 +404,26 @@ add_size_index_to_metadata (OstreeRepo *self,
return g_variant_ref_sink (g_variant_builder_end (builder));
}
/* Combines a check for whether or not we already have the object with
* allocating a tempfile if we don't. Used by the static delta code.
/* Create a tmpfile for writing a bare file. Currently just used
* by the static delta code, but will likely later be extended
* to be used also by the dfd_iter commit path.
*/
gboolean
_ostree_repo_open_content_bare (OstreeRepo *self,
const char *checksum,
guint64 content_len,
GLnxTmpfile *out_tmpf,
gboolean *out_have_object,
GCancellable *cancellable,
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,
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
_ostree_repo_commit_trusted_content_bare (OstreeRepo *self,
const char *checksum,
@ -446,6 +446,10 @@ _ostree_repo_commit_trusted_content_bare (OstreeRepo *self,
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
create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
guint64 length,
@ -498,7 +502,12 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
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
write_content_object (OstreeRepo *self,
const char *expected_checksum,
@ -611,7 +620,6 @@ write_content_object (OstreeRepo *self,
}
else
{
g_autoptr(GVariant) file_meta = NULL;
g_autoptr(GConverter) zlib_compressor = NULL;
g_autoptr(GOutputStream) compressed_out_stream = NULL;
g_autoptr(GOutputStream) temp_out = NULL;
@ -626,11 +634,15 @@ write_content_object (OstreeRepo *self,
return 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))
return FALSE;
}
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
{
@ -660,10 +672,12 @@ write_content_object (OstreeRepo *self,
else
{
actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input);
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0)
return glnx_throw (error, "Corrupted %s object %s (actual checksum is %s)",
ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE),
expected_checksum, actual_checksum);
if (expected_checksum)
{
if (!_ostree_compare_object_checksum (OSTREE_OBJECT_TYPE_FILE, expected_checksum, actual_checksum,
error))
return FALSE;
}
}
g_assert (actual_checksum != NULL); /* Pacify static analysis */
@ -723,9 +737,8 @@ write_content_object (OstreeRepo *self,
g_assert_not_reached ();
}
if (!_ostree_repo_commit_path_final (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE,
&tmp_unlinker,
cancellable, error))
if (!commit_path_final (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE,
&tmp_unlinker, cancellable, error))
return FALSE;
}
else
@ -766,6 +779,114 @@ write_content_object (OstreeRepo *self,
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
write_metadata_object (OstreeRepo *self,
OstreeObjectType objtype,
@ -790,14 +911,19 @@ write_metadata_object (OstreeRepo *self,
* *original* sha256 to say what commit was being killed.
*/
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)
{
actual_checksum = g_strdup (expected_checksum);
memcpy (actual_checksum, expected_checksum, sizeof (actual_checksum));
}
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;
if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj,
cancellable, error))
@ -817,10 +943,11 @@ write_metadata_object (OstreeRepo *self,
return TRUE;
}
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0)
return glnx_throw (error, "Corrupted %s object %s (actual checksum is %s)",
ostree_object_type_to_string (objtype),
expected_checksum, actual_checksum);
if (expected_checksum)
{
if (!_ostree_compare_object_checksum (objtype, expected_checksum, actual_checksum, error))
return FALSE;
}
}
/* Ok, checksum is known, let's get the data */
@ -888,6 +1015,9 @@ write_metadata_object (OstreeRepo *self,
return TRUE;
}
/* Look in a single subdirectory of objects/, building up the
* (device,inode) checksum map.
*/
static gboolean
scan_one_loose_devino (OstreeRepo *self,
int object_dir_fd,
@ -969,6 +1099,7 @@ scan_one_loose_devino (OstreeRepo *self,
return TRUE;
}
/* Used by ostree_repo_scan_hardlinks(); see that function for more information. */
static gboolean
scan_loose_devino (OstreeRepo *self,
GHashTable *devino_cache,
@ -995,6 +1126,8 @@ scan_loose_devino (OstreeRepo *self,
return TRUE;
}
/* Loook up a (device,inode) pair in our cache, and see if it maps to a known
* checksum. */
static const char *
devino_cache_lookup (OstreeRepo *self,
OstreeRepoCommitModifier *modifier,
@ -1122,6 +1255,12 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
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
rename_pending_loose_objects (OstreeRepo *self,
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
we want has reached the disk. In particular, we want this before we
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;
@ -1217,6 +1356,12 @@ rename_pending_loose_objects (OstreeRepo *self,
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
cleanup_tmpdir (OstreeRepo *self,
GCancellable *cancellable,
@ -1560,6 +1705,17 @@ ostree_repo_commit_transaction (OstreeRepo *self,
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
ostree_repo_abort_transaction (OstreeRepo *self,
GCancellable *cancellable,
@ -1814,6 +1970,15 @@ ostree_repo_write_metadata_async (OstreeRepo *self,
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
ostree_repo_write_metadata_finish (OstreeRepo *self,
GAsyncResult *result,
@ -1835,6 +2000,9 @@ ostree_repo_write_metadata_finish (OstreeRepo *self,
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
_ostree_repo_write_directory_meta (OstreeRepo *self,
GFileInfo *file_info,
@ -1843,13 +2011,11 @@ _ostree_repo_write_directory_meta (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GVariant) dirmeta = NULL;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
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,
dirmeta, out_csum, cancellable, error);
}
@ -2152,26 +2318,29 @@ ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
char buf[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode);
g_autoptr(GVariant) ret_metadata = NULL;
if (self->commit_stagedir.initialized &&
!ot_util_variant_map_at (self->commit_stagedir.fd, buf,
G_VARIANT_TYPE ("a{sv}"),
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
return glnx_prefix_error (error, "Unable to read existing detached metadata");
if (self->commit_stagedir.initialized)
{
glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, buf, &fd, error))
return FALSE;
if (fd != -1)
return ot_variant_read_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), TRUE,
out_metadata, error);
}
if (ret_metadata == NULL &&
!ot_util_variant_map_at (self->objects_dir_fd, buf,
G_VARIANT_TYPE ("a{sv}"),
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
return glnx_prefix_error (error, "Unable to read existing detached metadata");
glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (self->objects_dir_fd, buf, &fd, error))
return FALSE;
if (fd != -1)
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,
checksum,
out_metadata,
cancellable,
error);
ot_transfer_out_value (out_metadata, &ret_metadata);
checksum, out_metadata,
cancellable, error);
/* Nothing found */
*out_metadata = NULL;
return TRUE;
}
@ -2230,6 +2399,9 @@ ostree_repo_write_commit_detached_metadata (OstreeRepo *self,
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 *
create_tree_variant_from_hashes (GHashTable *file_checksums,
GHashTable *dir_contents_checksums,
@ -2341,6 +2513,7 @@ _ostree_repo_commit_modifier_apply (OstreeRepo *self,
return result;
}
/* Convert @path into a string */
static char *
ptrarray_path_join (GPtrArray *path)
{
@ -2370,6 +2543,7 @@ get_final_xattrs (OstreeRepo *self,
GFile *path,
int dfd,
const char *dfd_subpath,
GVariant *source_xattrs,
GVariant **out_xattrs,
gboolean *out_modified,
GCancellable *cancellable,
@ -2385,7 +2559,9 @@ get_final_xattrs (OstreeRepo *self,
g_autoptr(GVariant) original_xattrs = NULL;
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,
cancellable, error))
@ -2494,6 +2670,11 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
GCancellable *cancellable,
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
* 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 +
@ -2503,6 +2684,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
OstreeRepoFile *repo_dir,
GFileEnumerator *dir_enum,
GLnxDirFdIterator *dfd_iter,
WriteDirContentFlags writeflags,
GFileInfo *child_info,
OstreeMutableTree *mtree,
OstreeRepoCommitModifier *modifier,
@ -2512,24 +2694,62 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
{
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);
g_ptr_array_add (path, (char*)name);
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;
OstreeRepoCommitFilterResult filter_result =
_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);
/* 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)
{
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 */
return TRUE;
}
GFileType file_type = g_file_info_get_file_type (child_info);
switch (file_type)
{
case G_FILE_TYPE_DIRECTORY:
@ -2568,6 +2788,12 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
modifier, path,
cancellable, error))
return FALSE;
if (delete_after_commit)
{
if (!glnx_unlinkat (dfd_iter->fd, name, AT_REMOVEDIR, error))
return FALSE;
}
}
}
else if (repo_dir)
@ -2581,67 +2807,139 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
}
else
{
guint64 file_obj_length;
g_autoptr(GInputStream) file_input = NULL;
g_autoptr(GInputStream) file_object_input = NULL;
g_autofree guchar *child_file_csum = NULL;
g_autofree char *tmp_checksum = NULL;
glnx_autofd int file_input_fd = -1;
/* Open the file now, since it's better for reading xattrs
* rather than using the /proc/self/fd links.
*
* 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;
gboolean xattrs_were_modified;
if (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
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)
if (dir_enum != NULL)
{
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 (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
-1, name, source_xattrs, &xattrs, &xattrs_were_modified,
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,
error))
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
{
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);
if (!file_input)
return FALSE;
}
else
{
if (!ot_openat_read_stream (dfd_iter->fd, name, FALSE,
&file_input, cancellable, error))
return FALSE;
/* We already opened the fd above */
file_input = g_unix_input_stream_new (file_input_fd, FALSE);
}
}
g_autoptr(GInputStream) file_object_input = NULL;
guint64 file_obj_length;
if (!ostree_raw_file_to_content_stream (file_input,
modified_info, xattrs,
&file_object_input, &file_obj_length,
cancellable, error))
return FALSE;
g_autofree guchar *child_file_csum = NULL;
if (!ostree_repo_write_content (self, NULL, file_object_input, file_obj_length,
&child_file_csum, cancellable, error))
return FALSE;
g_free (tmp_checksum);
tmp_checksum = ostree_checksum_from_bytes (child_file_csum);
char tmp_checksum[OSTREE_SHA256_STRING_LEN+1];
ostree_checksum_inplace_from_bytes (child_file_csum, tmp_checksum);
if (!ostree_mutable_tree_replace_file (mtree, name, tmp_checksum,
error))
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);
@ -2701,7 +2999,7 @@ write_directory_to_mtree_internal (OstreeRepo *self,
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{
if (!get_final_xattrs (self, modifier, relpath, child_info, dir, -1, NULL,
&xattrs, NULL, cancellable, error))
NULL, &xattrs, NULL, cancellable, error))
return FALSE;
g_autofree guchar *child_file_csum = NULL;
@ -2736,6 +3034,7 @@ write_directory_to_mtree_internal (OstreeRepo *self,
break;
if (!write_directory_content_to_mtree_internal (self, repo_dir, dir_enum, NULL,
WRITE_DIR_CONTENT_FLAGS_NONE,
child_info,
mtree, modifier, path,
cancellable, error))
@ -2786,7 +3085,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{
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;
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;
}
/* 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)
{
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,
child_info,
flags, child_info,
mtree, modifier, path,
cancellable, error))
return FALSE;
@ -2922,6 +3226,19 @@ ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
cancellable, error))
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;
}
@ -3118,6 +3435,8 @@ ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier
*
* This function will add a reference to @cache without copying - you
* should avoid further mutation of the cache.
*
* Since: 2017.13
*/
void
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 (errno == EEXIST)
return TRUE;
did_hardlink = TRUE;
else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
{
/* 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
* 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,
FALSE, &src_fd, error))
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_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 *) &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) additional_metadata_v = NULL;
GVariantIter ref_map;
g_autoptr(GVariantIter) ref_map = NULL;
g_auto(GVariantDict) additional_metadata = OT_VARIANT_BUILDER_INITIALIZER;
const gchar *collection_id;
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);
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);
/* 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))
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;
}
g_clear_pointer (&ref_map, (GDestroyNotify) g_variant_iter_free);
/* 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))
{
@ -496,7 +498,7 @@ fill_refs_and_checksums_from_summary (GVariant *summary,
{
if (!ostree_validate_collection_id (collection_id, error))
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;
}
}

View File

@ -23,6 +23,7 @@
#include "config.h"
#include <gio/gio.h>
#include <gio/gunixmounts.h>
#include <glib.h>
#include <glib-object.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",
path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
return glnx_throw (error, "Repository is on a different file system from the mount");
}
/* 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",
path, mount_name);
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
return glnx_throw (error, "Repository is the same as the one we are resolving");
}
/* 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_autoptr(GFile) mount_root = 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;
glnx_fd_close int repos_dfd = -1;
glnx_autofd int repos_dfd = -1;
gsize i;
g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */
GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */
@ -357,6 +356,23 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
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
* repositories for individual refs are on the same device (to avoid the
* 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,
GError **error);
gboolean
_ostree_repo_commit_path_final (OstreeRepo *self,
const char *checksum,
OstreeObjectType objtype,
OtCleanupUnlinkat *tmp_path,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_open_content_bare (OstreeRepo *self,
const char *checksum,
guint64 content_len,
GLnxTmpfile *out_tmpf,
gboolean *out_have_object,
GCancellable *cancellable,
GError **error);

View File

@ -105,11 +105,12 @@ typedef struct {
GVariant *summary;
GHashTable *summary_deltas_checksums;
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;
GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */
GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */
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_content; /* Maps checksum to itself */
GHashTable *requested_fallback_content; /* Maps checksum to itself */
@ -142,6 +143,7 @@ typedef struct {
guint64 start_time;
gboolean is_mirror;
gboolean trusted_http_direct;
gboolean is_commit_only;
OstreeRepoImportFlags importflags;
@ -191,6 +193,13 @@ typedef struct {
OstreeCollectionRef *requested_ref; /* (nullable) */
} 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_deltapart (OtPullData *pull_data,
FetchStaticDeltaData *fetch);
@ -209,8 +218,8 @@ static void queue_scan_one_metadata_object_c (OtPullData *pull_da
guint recursion_depth,
const OstreeCollectionRef *ref);
static gboolean scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
static gboolean scan_one_metadata_object (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
@ -218,6 +227,14 @@ static gboolean scan_one_metadata_object_c (OtPullData *pull_dat
GCancellable *cancellable,
GError **error);
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
update_progress (gpointer user_data)
@ -450,6 +467,11 @@ scan_object_queue_data_free (ScanObjectQueueData *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
idle_worker (gpointer user_data)
{
@ -464,14 +486,11 @@ idle_worker (gpointer user_data)
return G_SOURCE_REMOVE;
}
scan_one_metadata_object_c (pull_data,
scan_data->csum,
scan_data->objtype,
scan_data->path,
scan_data->recursion_depth,
scan_data->requested_ref,
pull_data->cancellable,
&error);
char checksum[OSTREE_SHA256_STRING_LEN+1];
ostree_checksum_inplace_from_bytes (scan_data->csum, checksum);
scan_one_metadata_object (pull_data, checksum, scan_data->objtype,
scan_data->path, scan_data->recursion_depth,
scan_data->requested_ref, pull_data->cancellable, &error);
check_outstanding_requests_handle_error (pull_data, &error);
scan_object_queue_data_free (scan_data);
@ -544,7 +563,7 @@ write_commitpartial_for (OtPullData *pull_data,
GError **error)
{
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 (errno != EEXIST)
@ -844,7 +863,7 @@ fetch_ref_contents (OtPullData *pull_data,
{
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
if (!ostree_repo_resolve_collection_ref (pull_data->remote_repo_local,
ref, TRUE /* ignore enoent */,
ref, FALSE,
OSTREE_REPO_RESOLVE_REV_EXT_NONE,
&ret_contents, cancellable, error))
return FALSE;
@ -855,7 +874,7 @@ fetch_ref_contents (OtPullData *pull_data,
else if (pull_data->remote_repo_local != NULL)
{
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,
&ret_contents, error))
return FALSE;
@ -874,14 +893,13 @@ fetch_ref_contents (OtPullData *pull_data,
filename, &ret_contents,
cancellable, error))
return FALSE;
g_strchomp (ret_contents);
}
/* Validate and return. */
if (ret_contents != NULL)
g_strchomp (ret_contents);
g_assert (ret_contents);
if (ret_contents == NULL ||
!ostree_validate_checksum_string (ret_contents, error))
if (!ostree_validate_checksum_string (ret_contents, error))
return glnx_prefix_error (error, "Fetching checksum for ref (%s, %s)",
ref->collection_id ? ref->collection_id : "(empty)",
ref->ref_name);
@ -987,13 +1005,8 @@ content_fetch_on_write_complete (GObject *object,
checksum_obj = ostree_object_to_string (checksum, objtype);
g_debug ("write of %s complete", checksum_obj);
if (strcmp (checksum, expected_checksum) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted content object; checksum expected='%s' actual='%s'",
expected_checksum, checksum);
if (!_ostree_compare_object_checksum (objtype, expected_checksum, checksum, error))
goto out;
}
pull_data->n_fetched_content++;
/* Was this a delta fallback? */
@ -1017,17 +1030,18 @@ content_fetch_on_complete (GObject *object,
GError **error = &local_error;
GCancellable *cancellable = NULL;
guint64 length;
g_auto(GLnxTmpfile) tmpf = { 0, };
g_autoptr(GInputStream) tmpf_input = NULL;
g_autoptr(GFileInfo) file_info = NULL;
g_autoptr(GVariant) xattrs = NULL;
g_autoptr(GInputStream) file_in = NULL;
g_autoptr(GInputStream) object_input = NULL;
g_auto(OtCleanupUnlinkat) tmp_unlinker = { _ostree_fetcher_get_dfd (fetcher), NULL };
const char *checksum;
g_autofree char *checksum_obj = NULL;
OstreeObjectType objtype;
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;
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
@ -1039,48 +1053,31 @@ content_fetch_on_complete (GObject *object,
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.
/* See comments where we set this variable; this is implementing
* the --trusted-http/OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP flags.
*/
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;
if (mirroring_into_archive && import_trusted)
if (pull_data->trusted_http_direct)
{
gboolean have_object;
if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum,
&have_object,
cancellable, error))
g_assert (!verifying_bareuseronly);
if (!_ostree_repo_commit_tmpf_final (pull_data->repo, checksum, objtype,
&tmpf, cancellable, error))
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++;
}
else
{
struct stat stbuf;
if (!glnx_fstat (tmpf.fd, &stbuf, error))
goto out;
/* 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 (!ostree_content_file_parse_at (TRUE, _ostree_fetcher_get_dfd (fetcher),
tmp_unlinker.path, FALSE,
if (!ostree_content_stream_parse (TRUE, tmpf_input, stbuf.st_size, FALSE,
&file_in, &file_info, &xattrs,
cancellable, error))
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 (!_ostree_validate_bareuseronly_mode_finfo (file_info, checksum, error))
@ -1160,13 +1157,12 @@ meta_fetch_on_complete (GObject *object,
FetchObjectData *fetch_data = user_data;
OtPullData *pull_data = fetch_data->pull_data;
g_autoptr(GVariant) metadata = NULL;
g_auto(OtCleanupUnlinkat) tmp_unlinker = { _ostree_fetcher_get_dfd (fetcher), NULL };
g_auto(GLnxTmpfile) tmpf = { 0, };
const char *checksum;
g_autofree char *checksum_obj = NULL;
OstreeObjectType objtype;
g_autoptr(GError) local_error = NULL;
GError **error = &local_error;
glnx_fd_close int fd = -1;
gboolean free_fetch_data = TRUE;
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,
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))
{
@ -1185,7 +1181,7 @@ meta_fetch_on_complete (GObject *object,
/* Now that we've at least tried to fetch it, we can proceed to
* 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)
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)
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 (!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))
goto out;
@ -1235,7 +1223,7 @@ meta_fetch_on_complete (GObject *object,
pull_data->cancellable, error))
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)
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
{
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))
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)
{
/* 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))
goto out;
}
@ -1313,27 +1328,20 @@ static_deltapart_fetch_on_complete (GObject *object,
OstreeFetcher *fetcher = (OstreeFetcher *)object;
FetchStaticDeltaData *fetch_data = user_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(GVariant) part = NULL;
g_autoptr(GError) local_error = NULL;
GError **error = &local_error;
glnx_fd_close int fd = -1;
gboolean free_fetch_data = TRUE;
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;
if (!glnx_openat_rdonly (_ostree_fetcher_get_dfd (fetcher), temp_path, TRUE, &fd, error))
goto out;
/* 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);
/* Transfer ownership of the fd */
in = g_unix_input_stream_new (glnx_steal_fd (&tmpf.fd), TRUE);
/* TODO - make async */
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))
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;
}
@ -1390,24 +1406,15 @@ gpg_verify_unwritten_commit (OtPullData *pull_data,
{
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);
if (!detached_metadata)
{
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
"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);
g_autoptr(OstreeGpgVerifyResult) 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))
return FALSE;
}
@ -1431,6 +1438,10 @@ static char *
get_real_remote_repo_collection_id (OstreeRepo *repo,
const gchar *remote_name)
{
/* remote_name == NULL can happen for pull-local */
if (!remote_name)
return NULL;
g_autofree gchar *remote_collection_id = NULL;
if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL,
&remote_collection_id, NULL) ||
@ -1586,7 +1597,11 @@ scan_commit_object (OtPullData *pull_data,
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;
@ -1753,9 +1768,13 @@ queue_scan_one_metadata_object_c (OtPullData *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
scan_one_metadata_object_c (OtPullData *pull_data,
const guchar *csum,
scan_one_metadata_object (OtPullData *pull_data,
const char *checksum,
OstreeObjectType objtype,
const char *path,
guint recursion_depth,
@ -1763,8 +1782,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
GCancellable *cancellable,
GError **error)
{
g_autofree char *tmp_checksum = ostree_checksum_from_bytes (csum);
g_autoptr(GVariant) object = ostree_object_name_serialize (tmp_checksum, objtype);
g_autoptr(GVariant) object = ostree_object_name_serialize (checksum, objtype);
/* It may happen that we've already looked at this object (think shared
* 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;
/* Determine if we already have the object */
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))
return FALSE;
@ -1784,19 +1802,19 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
/* 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;
}
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))
return FALSE;
/* The import API will fetch both the commit and detached metadata, so
* add it to the hash to avoid re-fetching it below.
*/
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++;
is_stored = 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];
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))
return FALSE;
if (!localcache_repo_has_obj)
@ -1817,16 +1835,16 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
/* 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;
}
if (!_ostree_repo_import_object (pull_data->repo, refd_repo,
objtype, tmp_checksum, pull_data->importflags,
objtype, checksum, pull_data->importflags,
cancellable, error))
return FALSE;
/* See comment above */
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_requested = TRUE;
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));
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)
{
/* Even though we already have the commit, we always try to (re)fetch the
* detached metadata before scanning it, in case new signatures appear.
* https://github.com/projectatomic/rpm-ostree/issues/630 */
if (!g_hash_table_contains (pull_data->fetched_detached_metadata, tmp_checksum))
enqueue_one_object_request (pull_data, tmp_checksum, objtype, path, TRUE, TRUE, ref);
if (!g_hash_table_contains (pull_data->fetched_detached_metadata, checksum))
enqueue_one_object_request (pull_data, checksum, objtype, path, TRUE, TRUE, ref);
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))
return FALSE;
@ -1862,7 +1880,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
}
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))
return FALSE;
@ -1975,6 +1993,8 @@ start_fetch (OtPullData *pull_data,
else
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,
obj_subpath, flags, expected_max_size,
is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY
@ -2441,34 +2461,28 @@ on_superblock_fetched (GObject *src,
}
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_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_bytes_get_size (delta_superblock_data),
NULL);
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);
g_auto(OtChecksum) hasher = { 0, };
ot_checksum_init (&hasher);
ot_checksum_update_bytes (&hasher, delta_superblock_data);
ot_checksum_get_digest (&hasher, actual_summary_digest, sizeof (actual_summary_digest));
/* At this point we've GPG verified the data, so in theory
* could trust that they provided the right data, but let's
* 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,
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
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);
goto out;
@ -2520,7 +2534,7 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
return TRUE;
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))
return FALSE;
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)
{
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;
@ -3031,7 +3045,7 @@ initiate_delta_request (OtPullData *pull_data,
_ostree_fetcher_request_to_membuf (pull_data->fetcher,
pull_data->content_mirrorlist,
delta_name, 0,
delta_name, OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT,
OSTREE_MAX_METADATA_SIZE,
0, pull_data->cancellable,
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,
(GDestroyNotify)NULL,
(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,
(GDestroyNotify)g_variant_unref, NULL);
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,
(GDestroyNotify)g_free, NULL);
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);
/* 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()) */
if (g_str_equal (first_scheme, "file"))
* means that we're not using mirrorlists (see also fetch_mirrorlist())
* 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_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)
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
{
@ -3593,6 +3618,18 @@ ostree_repo_pull_with_options (OstreeRepo *self,
*/
if (flags & OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP)
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. */
@ -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))
{
if (!ostree_validate_rev (ref_name, error))
goto out;
g_hash_table_insert (requested_refs_to_fetch,
ostree_collection_ref_new (collection_id, ref_name),
(*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->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->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_fallback_content, (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)
{
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))
return FALSE;
@ -158,7 +158,7 @@ find_ref_in_remotes (OstreeRepo *self,
while (TRUE)
{
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))
return FALSE;
@ -234,7 +234,7 @@ resolve_refspec (OstreeRepo *self,
{
__attribute__((unused)) GCancellable *cancellable = 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);
@ -560,6 +560,14 @@ enumerate_refs_recurse (OstreeRepo *repo,
if (dent == NULL)
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);
if (dent->d_type == DT_DIR)
@ -637,7 +645,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
{
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 ("");
if (!cut_prefix)
g_string_printf (base_path, "%s/", ref_prefix);
@ -652,7 +660,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
}
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))
return FALSE;
@ -667,7 +675,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
{
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
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))
return FALSE;
@ -687,7 +695,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
while (TRUE)
{
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))
return FALSE;
@ -992,7 +1000,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
GCancellable *cancellable,
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 (!(rev != NULL && alias != NULL), FALSE);
@ -1016,7 +1024,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
}
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. */
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
{
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,
&refs_remotes_dfd, error))
@ -1212,7 +1220,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
if (main_collection_id != NULL &&
(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))
return FALSE;
@ -1237,7 +1245,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
while (refs_dir_exists)
{
struct dirent *dent;
glnx_fd_close int subdir_fd = -1;
glnx_autofd int subdir_fd = -1;
const gchar *current_collection_id;
g_autofree gchar *remote_collection_id = NULL;

View File

@ -37,7 +37,14 @@
#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 {
guint64 compressed_size;
guint64 uncompressed_size;
GPtrArray *objects;
GString *payload;
@ -46,6 +53,8 @@ typedef struct {
GPtrArray *modes;
GHashTable *xattr_set; /* GVariant(ayay) -> offset */
GPtrArray *xattrs;
GLnxTmpfile part_tmpf;
GVariant *header;
} OstreeStaticDeltaPartBuilder;
typedef struct {
@ -60,13 +69,47 @@ typedef struct {
guint n_bsdiff;
guint n_fallback;
gboolean swap_endian;
int parts_dfd;
DeltaOpts delta_opts;
} OstreeStaticDeltaBuilder;
typedef enum {
DELTAOPT_FLAG_NONE = (1 << 0),
DELTAOPT_FLAG_DISABLE_BSDIFF = (1 << 1),
DELTAOPT_FLAG_VERBOSE = (1 << 2)
} DeltaOpts;
/* Get an input stream for a GVariant */
static GInputStream *
variant_to_inputstream (GVariant *variant)
{
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
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_hash_table_unref (part_builder->xattr_set);
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);
}
@ -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;
}
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 *
allocate_part (OstreeStaticDeltaBuilder *builder)
allocate_part (OstreeStaticDeltaBuilder *builder, GError **error)
{
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->payload = g_string_new (NULL);
part->operations = g_string_new (NULL);
@ -221,31 +380,6 @@ write_unique_variant_chunk (OstreeStaticDeltaPartBuilder *current_part,
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
splice_stream_to_payload (OstreeStaticDeltaPartBuilder *current_part,
GInputStream *istream,
@ -338,7 +472,10 @@ process_one_object (OstreeRepo *repo,
if (current_part->objects->len > 0 &&
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;
@ -514,8 +651,8 @@ try_content_rollsum (OstreeRepo *repo,
if (opts & DELTAOPT_FLAG_VERBOSE)
{
g_printerr ("rollsum for %s; crcs=%u bufs=%u total=%u matchsize=%llu\n",
to, matches->crcmatches,
g_printerr ("rollsum for %s -> %s; crcs=%u bufs=%u total=%u matchsize=%llu\n",
from, to, matches->crcmatches,
matches->bufmatches,
matches->total, (unsigned long long)matches->match_size);
}
@ -577,7 +714,10 @@ process_one_rollsum (OstreeRepo *repo,
if (current_part->objects->len > 0 &&
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;
@ -692,7 +832,10 @@ process_one_bsdiff (OstreeRepo *repo,
if (current_part->objects->len > 0 &&
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;
@ -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, 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_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));
}
current_part = allocate_part (builder);
current_part = allocate_part (builder, error);
if (current_part == NULL)
return FALSE;
/* Pack the metadata first */
g_hash_table_iter_init (&hashiter, new_reachable_metadata);
@ -1000,12 +1159,20 @@ generate_delta_lowlatency (OstreeRepo *repo,
/* 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);
while (g_hash_table_iter_next (&hashiter, &key, &value))
{
const char *checksum = key;
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,
checksum, bsdiff,
cancellable, error))
@ -1013,6 +1180,7 @@ generate_delta_lowlatency (OstreeRepo *repo,
builder->n_bsdiff++;
}
}
/* Scan for large objects, so we can fall back to plain HTTP-based
* fetch.
@ -1080,6 +1248,9 @@ generate_delta_lowlatency (OstreeRepo *repo,
return FALSE;
}
if (!finish_part (builder, error))
return FALSE;
return TRUE;
}
@ -1186,24 +1357,24 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
guint min_fallback_size;
guint max_bsdiff_size;
guint max_chunk_size;
g_auto(GVariantBuilder) metadata_builder = OT_VARIANT_BUILDER_INITIALIZER;
DeltaOpts delta_opts = DELTAOPT_FLAG_NONE;
guint64 total_compressed_size = 0;
guint64 total_uncompressed_size = 0;
g_autoptr(GVariantBuilder) part_headers = NULL;
g_autoptr(GPtrArray) part_temp_paths = NULL;
g_autoptr(GVariant) delta_descriptor = NULL;
g_autoptr(GVariant) to_commit = NULL;
const char *opt_filename;
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) detached = NULL;
gboolean inline_parts;
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.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))
min_fallback_size = 4;
@ -1245,45 +1416,6 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
&to_commit, error))
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)
{
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));
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];
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;
builder.parts_dfd = tmp_dfd;
builder.delta_opts = delta_opts;
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]);
}
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,
/* Ignore optimization flags */
if (!generate_delta_lowlatency (self, from, to, delta_opts, &builder,
cancellable, error))
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)
{
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));
}
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);
/* 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);
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))
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,
cancellable, error))
goto out;
@ -1466,9 +1560,14 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
if (detached)
{
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 */
{
GDateTime *now = g_date_time_new_now_utc ();
@ -1477,17 +1576,26 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
/* floating */ GVariant *to_csum_v =
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
"@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")",
g_variant_builder_end (&metadata_builder),
GUINT64_TO_BE (g_date_time_to_unix (now)),
from_csum_v,
to_csum_v,
to_commit,
ot_gvariant_new_bytearray ((guchar*)"", 0),
part_headers,
fallback_headers));
if (!ot_variant_builder_add (descriptor_builder, error, "t",
GUINT64_TO_BE (g_date_time_to_unix (now))) ||
!ot_variant_builder_add_value (descriptor_builder,
from_csum_v, error) ||
!ot_variant_builder_add_value (descriptor_builder,
to_csum_v, error) ||
!ot_variant_builder_add_value (descriptor_builder,
to_commit, error) ||
!ot_variant_builder_add_value (descriptor_builder,
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);
}
@ -1503,10 +1611,14 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff);
}
if (!glnx_file_replace_contents_at (descriptor_dfd, descriptor_name,
g_variant_get_data (delta_descriptor),
g_variant_get_size (delta_descriptor),
0, cancellable, error))
if (fchmod (descriptor_tmpf.fd, 0644) < 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
descriptor_dfd, descriptor_name, error))
goto out;
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);
/* 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 (errno != ENOTDIR)
@ -241,12 +241,12 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
else
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)
return glnx_throw_errno_prefix (error, "openat(%s)", basename);
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))
return FALSE;
@ -377,7 +377,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
else
{
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)
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);
/* 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))
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",
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)
return glnx_throw_errno_prefix (error, "openat(%s)", part_path);
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);
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,
OT_VARIANT_MAP_TRUSTED, &delta_superblock, error))
TRUE, &delta_superblock, error))
return FALSE;
g_print ("Delta: %s\n", delta_id);

View File

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

View File

@ -488,18 +488,13 @@ ostree_repo_finalize (GObject *object)
g_free (self->stagedir_prefix);
g_clear_object (&self->repodir_fdrel);
g_clear_object (&self->repodir);
if (self->repo_dir_fd != -1)
(void) close (self->repo_dir_fd);
glnx_close_fd (&self->repo_dir_fd);
glnx_tmpdir_unset (&self->commit_stagedir);
glnx_release_lock_file (&self->commit_stagedir_lock);
if (self->tmp_dir_fd != -1)
(void) close (self->tmp_dir_fd);
if (self->cache_dir_fd != -1)
(void) close (self->cache_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);
glnx_close_fd (&self->tmp_dir_fd);
glnx_close_fd (&self->cache_dir_fd);
glnx_close_fd (&self->objects_dir_fd);
glnx_close_fd (&self->uncompressed_objects_dir_fd);
g_clear_object (&self->sysroot_dir);
g_weak_ref_clear (&self->sysroot);
g_free (self->remotes_config_dir);
@ -734,7 +729,7 @@ ostree_repo_open_at (int dfd,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int repo_dfd = -1;
glnx_autofd int repo_dfd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
return NULL;
@ -1463,7 +1458,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
gpgme_import_status_t import_status;
g_autofree char *source_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;
struct stat stbuf;
gpgme_error_t gpg_error;
@ -1596,7 +1591,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
}
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
* 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
* 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()
* with #OSTREE_SUMMARY_GVARIANT_FORMAT as the format string.
*
@ -1812,7 +1810,7 @@ repo_create_at_internal (int dfd,
return FALSE;
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))
return FALSE;
@ -1828,7 +1826,7 @@ repo_create_at_internal (int dfd,
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))
return FALSE;
@ -1919,7 +1917,7 @@ ostree_repo_create (OstreeRepo *self,
g_variant_builder_add (builder, "{s@v}", "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,
g_variant_builder_end (builder),
&repo_dir_fd,
@ -1963,7 +1961,7 @@ ostree_repo_create_at (int dfd,
GCancellable *cancellable,
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,
cancellable, error))
return NULL;
@ -2528,14 +2526,12 @@ ostree_repo_set_cache_dir (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
int fd;
glnx_autofd int fd = -1;
if (!glnx_opendirat (dfd, path, TRUE, &fd, error))
return FALSE;
if (self->cache_dir_fd != -1)
close (self->cache_dir_fd);
self->cache_dir_fd = fd;
glnx_close_fd (&self->cache_dir_fd);
self->cache_dir_fd = glnx_steal_fd (&fd);
return TRUE;
}
@ -2807,16 +2803,17 @@ load_metadata_internal (OstreeRepo *self,
GVariant **out_variant,
GInputStream **out_stream,
guint64 *out_size,
OstreeRepoCommitState *out_state,
GCancellable *cancellable,
GError **error)
{
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
struct stat stbuf;
glnx_fd_close int fd = -1;
glnx_autofd int fd = -1;
g_autoptr(GInputStream) ret_stream = NULL;
g_autoptr(GVariant) ret_variant = NULL;
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
* times.
@ -2853,36 +2850,14 @@ load_metadata_internal (OstreeRepo *self,
if (fd != -1)
{
struct stat stbuf;
if (!glnx_fstat (fd, &stbuf, error))
return FALSE;
if (out_variant)
{
/* http://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access */
if (stbuf.st_size > 16*1024)
{
GMappedFile *mfile;
mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
if (!mfile)
if (!ot_variant_read_fd (fd, 0, ostree_metadata_variant_type (objtype), TRUE,
&ret_variant, error))
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 */
if (is_dirmeta_cachable)
@ -2904,11 +2879,24 @@ load_metadata_internal (OstreeRepo *self,
if (out_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)
{
if (!ostree_repo_load_variant (self->parent_repo, objtype, sha256, &ret_variant, error))
return FALSE;
/* Directly recurse to simplify out parameters */
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)
{
@ -2952,7 +2940,7 @@ repo_load_file_archive (OstreeRepo *self,
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
_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,
error))
return FALSE;
@ -3008,7 +2996,7 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
}
struct stat stbuf;
glnx_fd_close int fd = -1;
glnx_autofd int fd = -1;
g_autofree char *ret_symlink = NULL;
g_autoptr(GVariant) ret_xattrs = NULL;
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);
}
/* 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)
@ -3158,7 +3146,7 @@ ostree_repo_load_file (OstreeRepo *self,
cancellable, error);
else
{
glnx_fd_close int fd = -1;
glnx_autofd int fd = -1;
struct stat stbuf;
g_autofree char *symlink_target = 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 (!load_metadata_internal (self, objtype, checksum, TRUE, NULL,
&ret_input, &size,
&ret_input, &size, NULL,
cancellable, error))
return FALSE;
}
@ -3516,7 +3504,7 @@ ostree_repo_load_variant_if_exists (OstreeRepo *self,
GError **error)
{
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)
{
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,
GError **error)
{
if (out_variant)
{
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;
return load_metadata_internal (self, OSTREE_OBJECT_TYPE_COMMIT, checksum, TRUE,
out_variant, NULL, NULL, out_state, NULL, error);
}
/**
@ -4119,7 +4084,9 @@ ostree_repo_sign_commit (OstreeRepo *self,
* pass the homedir so that the signing key can be imported, allowing
* subkey signatures to be recognised. */
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
=_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata,
NULL, verify_keydir, NULL,
@ -4202,15 +4169,24 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
GCancellable *cancellable,
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)
return FALSE;
/* Note that fd is reused below */
glnx_close_fd (&fd);
g_autoptr(GVariant) existing_signatures = NULL;
if (!ot_util_variant_map_at (self->repo_dir_fd, "summary.sig",
G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING),
OT_VARIANT_MAP_ALLOW_NOENT, &existing_signatures, error))
if (!ot_openat_ignore_enoent (self->repo_dir_fd, "summary.sig", &fd, error))
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;
for (guint i = 0; key_id[i]; i++)
@ -4250,7 +4226,7 @@ find_keyring (OstreeRepo *self,
GCancellable *cancellable,
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))
return FALSE;
@ -4328,7 +4304,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
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;
}
@ -4759,23 +4735,21 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
return FALSE;
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))
return FALSE;
g_autoptr(GInputStream) in_stream = g_unix_input_stream_new (superblock_file_fd, FALSE);
if (!in_stream)
g_autoptr(GBytes) superblock_content = ot_fd_readall_or_mmap (superblock_file_fd, 0, error);
if (!superblock_content)
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;
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));
g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (digest, sizeof (digest)));
}
if (delta_names->len > 0)
@ -4960,7 +4934,6 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd,
while (!ret_tmpdir.initialized)
{
struct dirent *dent;
glnx_fd_close int existing_tmpdir_fd = -1;
g_autoptr(GError) local_error = NULL;
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)
continue;
glnx_fd_close int target_dfd = -1;
glnx_autofd int target_dfd = -1;
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, FALSE,
&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_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_CONSUME: Delete added files/directories after commit; Since: 2017.13
*/
typedef enum {
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_CANONICAL_PERMISSIONS = (1 << 2),
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED = (1 << 3),
OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME = (1 << 4),
} OstreeRepoCommitModifierFlags;
/**
@ -846,7 +848,7 @@ typedef enum {
/**
* OstreeRepoCheckoutOverwriteMode:
* @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_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
void ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
void ostree_repo_checkout_at_options_set_devino (OstreeRepoCheckoutAtOptions *opts, OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
gboolean ostree_repo_checkout_at (OstreeRepo *self,
OstreeRepoCheckoutAtOptions *options,

View File

@ -203,7 +203,7 @@ get_policy_checksum (char **out_csum,
g_autofree char *best_policy = NULL;
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))
return FALSE;

View File

@ -282,7 +282,7 @@ cleanup_old_deployments (OstreeSysroot *self,
if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
{
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,
&deployment_fd, error))

View File

@ -118,6 +118,7 @@ hardlink_or_copy_at (int src_dfd,
return TRUE;
}
/* Copy ownership, mode, and xattrs from source directory to destination */
static gboolean
dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
const char *src_name,
@ -163,7 +164,7 @@ copy_dir_recurse (int src_parent_dfd,
GError **error)
{
g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, };
glnx_fd_close int dest_dfd = -1;
glnx_autofd int dest_dfd = -1;
struct dirent *dent;
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;
}
/* If a chain of directories is added, this function will ensure
* they're created.
*/
static gboolean
ensure_directory_from_template (int orig_etc_fd,
int modified_etc_fd,
@ -222,8 +226,8 @@ ensure_directory_from_template (int orig_etc_fd,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int src_dfd = -1;
glnx_fd_close int target_dfd = -1;
glnx_autofd int src_dfd = -1;
glnx_autofd int target_dfd = -1;
g_assert (path != NULL);
g_assert (*path != '/' && *path != '\0');
@ -274,12 +278,9 @@ ensure_directory_from_template (int orig_etc_fd,
return TRUE;
}
/**
* copy_modified_config_file:
*
* 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.
/* Copy (relative) @path from @modified_etc_fd to @new_etc_fd, overwriting any
* existing file there. The @path may refer to a regular file, a symbolic link,
* or a directory. Directories will be copied recursively.
*/
static gboolean
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))
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)
{
g_autofree char *parent = g_path_get_dirname (path);
@ -392,7 +393,7 @@ merge_configuration_from (OstreeSysroot *sysroot,
GCancellable *cancellable,
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;
g_assert (merge_deployment != NULL && new_deployment != NULL);
@ -442,13 +443,13 @@ merge_configuration_from (OstreeSysroot *sysroot,
_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))
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))
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))
return FALSE;
@ -490,11 +491,9 @@ merge_configuration_from (OstreeSysroot *sysroot,
return TRUE;
}
/**
* checkout_deployment_tree:
*
* Look up @revision in the repository, and check it out in
/* Look up @revision in the repository, and check it out in
* /ostree/deploy/OS/deploy/${treecsum}.${deployserial}.
* A dfd for the result is returned in @out_deployment_dfd.
*/
static gboolean
checkout_deployment_tree (OstreeSysroot *sysroot,
@ -509,7 +508,7 @@ checkout_deployment_tree (OstreeSysroot *sysroot,
const char *csum = ostree_deployment_get_csum (deployment);
g_autofree char *checkout_target_name = NULL;
g_autofree char *osdeploy_path = NULL;
glnx_fd_close int osdeploy_dfd = -1;
glnx_autofd int osdeploy_dfd = -1;
int ret_fd;
osdeploy_path = g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL);
@ -676,6 +675,9 @@ selinux_relabel_dir (OstreeSysroot *sysroot,
return ret;
}
/* Handles SELinux labeling for /var; this is slated to be deleted. See
* https://github.com/ostreedev/ostree/pull/872
*/
static gboolean
selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
OstreeSePolicy *sepolicy,
@ -730,6 +732,11 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
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
merge_configuration (OstreeSysroot *sysroot,
OstreeRepo *repo,
@ -820,6 +827,7 @@ merge_configuration (OstreeSysroot *sysroot,
return TRUE;
}
/* Write the origin file for a deployment. */
static gboolean
write_origin_file_internal (OstreeSysroot *sysroot,
OstreeDeployment *deployment,
@ -891,8 +899,7 @@ typedef struct {
static void
_ostree_kernel_layout_free (OstreeKernelLayout *layout)
{
if (layout->boot_dfd != -1)
(void) close (layout->boot_dfd);
glnx_close_fd (&layout->boot_dfd);
g_free (layout->kernel_srcpath);
g_free (layout->kernel_namever);
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 */
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256);
glnx_fd_close int fd = -1;
g_auto(OtChecksum) checksum = { 0, };
ot_checksum_init (&checksum);
glnx_autofd int fd = -1;
/* Checksum the kernel */
if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error))
return 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;
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
* 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_namever = g_strdup_printf ("initramfs-%s.img", kver);
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;
}
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);
return TRUE;
@ -1227,8 +1237,8 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
int sockpair[2];
if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0)
return glnx_throw_errno_prefix (error, "socketpair");
glnx_fd_close int sock_parent = sockpair[0];
glnx_fd_close int sock_watchdog = sockpair[1];
glnx_autofd int sock_parent = sockpair[0];
glnx_autofd int sock_watchdog = sockpair[1];
pid_t pid = fork ();
if (pid < 0)
@ -1238,7 +1248,7 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
char c = '!';
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.
* someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of
* `ostree admin upgrade`. We don't daemonize though if testing so
@ -1291,11 +1301,16 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
}
if (debug_fifreeze)
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. */
{
(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
* masked SIGTERM successfully.
*/
@ -1321,11 +1336,15 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
/* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */
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.
*/
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)
return glnx_throw_errno_prefix (error, "syncfs");
/* Write the completion, and return */
@ -1338,7 +1357,13 @@ fsfreeze_thaw_cycle (OstreeSysroot *self,
}
/* And finally thaw, then signal our completion to the watchdog */
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)");
}
if (write (sock_parent, &c, sizeof (c)) != sizeof (c))
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);
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))
return FALSE;
if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error))
@ -1391,6 +1416,12 @@ full_system_sync (OstreeSysroot *self,
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
create_new_bootlinks (OstreeSysroot *self,
int bootversion,
@ -1398,7 +1429,7 @@ create_new_bootlinks (OstreeSysroot *self,
GCancellable *cancellable,
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))
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))
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))
return FALSE;
@ -1451,6 +1482,8 @@ create_new_bootlinks (OstreeSysroot *self,
return TRUE;
}
/* Rename into place symlinks created via create_new_bootlinks().
*/
static gboolean
swap_bootlinks (OstreeSysroot *self,
int bootversion,
@ -1458,7 +1491,7 @@ swap_bootlinks (OstreeSysroot *self,
GCancellable *cancellable,
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))
return FALSE;
@ -1512,10 +1545,9 @@ parse_os_release (const char *contents,
return ret;
}
/*
* install_deployment_kernel:
*
* Write out an entry in /boot/loader/entries for @deployment.
/* Given @deployment, prepare it to be booted; basically copying its
* kernel/initramfs into /boot/ostree (if needed) and writing out an entry in
* /boot/loader/entries.
*/
static gboolean
install_deployment_kernel (OstreeSysroot *sysroot,
@ -1530,7 +1562,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (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,
&deployment_dfd, error))
return FALSE;
@ -1541,7 +1573,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
cancellable, error))
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))
return FALSE;
@ -1555,7 +1587,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error))
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))
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",
new_bootversion, osname, bootcsum,
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_arg = NULL;
g_autofree char *options_key = _ostree_kernel_args_to_string (kargs);
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))
return FALSE;
@ -1698,6 +1730,10 @@ install_deployment_kernel (OstreeSysroot *sysroot,
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
prepare_new_bootloader_link (OstreeSysroot *sysroot,
int current_bootversion,
@ -1719,6 +1755,7 @@ prepare_new_bootloader_link (OstreeSysroot *sysroot,
return TRUE;
}
/* Update the /boot/loader symlink to point to /boot/loader.$new_bootversion */
static gboolean
swap_bootloader (OstreeSysroot *sysroot,
int current_bootversion,
@ -1726,7 +1763,7 @@ swap_bootloader (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
glnx_fd_close int boot_dfd = -1;
glnx_autofd int boot_dfd = -1;
g_assert ((current_bootversion == 0 && new_bootversion == 1) ||
(current_bootversion == 1 && new_bootversion == 0));
@ -1778,6 +1815,15 @@ assign_bootserials (GPtrArray *deployments)
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
deployment_bootconfigs_equal (OstreeDeployment *a,
OstreeDeployment *b)
@ -1793,8 +1839,8 @@ deployment_bootconfigs_equal (OstreeDeployment *a,
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
const char *a_boot_options = ostree_bootconfig_parser_get (a_bootconfig, "options");
const char *b_boot_options = ostree_bootconfig_parser_get (b_bootconfig, "options");
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *a_kargs = NULL;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *b_kargs = NULL;
g_autoptr(OstreeKernelArgs) a_kargs = NULL;
g_autoptr(OstreeKernelArgs) b_kargs = NULL;
g_autofree char *a_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;
}
/* 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
is_ro_mount (const char *path)
{
@ -2207,7 +2258,7 @@ allocate_deployserial (OstreeSysroot *self,
g_autoptr(GPtrArray) tmp_current_deployments =
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))
return FALSE;
@ -2262,7 +2313,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
osname = ostree_deployment_get_osname (self->booted_deployment);
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))
return FALSE;
@ -2283,7 +2334,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
ostree_deployment_set_origin (new_deployment, origin);
/* 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,
cancellable, error))
{
@ -2349,7 +2400,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
*/
if (override_kernel_argv)
{
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
g_autoptr(OstreeKernelArgs) kargs = NULL;
g_autofree char *new_options = NULL;
kargs = _ostree_kernel_args_new ();
@ -2380,22 +2431,16 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
guint i;
g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
g_autoptr(OstreeDeployment) new_deployment = NULL;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
g_autofree char *new_options = NULL;
OstreeBootconfigParser *new_bootconfig;
g_autoptr(OstreeDeployment) new_deployment = ostree_deployment_clone (deployment);
OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (new_deployment);
new_deployment = ostree_deployment_clone (deployment);
new_bootconfig = ostree_deployment_get_bootconfig (new_deployment);
kargs = _ostree_kernel_args_new ();
g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new ();
_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);
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];
if (cur == deployment)
@ -2435,7 +2480,7 @@ ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
return FALSE;
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))
return FALSE;

View File

@ -22,6 +22,7 @@
#include "otutil.h"
#include <sys/file.h>
#include <sys/mount.h>
#include <err.h>
#include <sys/wait.h>
#include "ostree.h"
@ -201,7 +202,12 @@ ostree_sysroot_init (OstreeSysroot *self)
/**
* 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
*/
@ -291,11 +297,7 @@ _ostree_sysroot_bump_mtime (OstreeSysroot *self,
void
ostree_sysroot_unload (OstreeSysroot *self)
{
if (self->sysroot_fd != -1)
{
(void) close (self->sysroot_fd);
self->sysroot_fd = -1;
}
glnx_close_fd (&self->sysroot_fd);
}
/**
@ -633,7 +635,7 @@ parse_deployment (OstreeSysroot *self,
&treecsum, &deployserial, error))
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,
&deployment_dfd, error))
return FALSE;
@ -981,11 +983,14 @@ ostree_sysroot_get_deployment_origin_path (GFile *deployment_path)
/**
* ostree_sysroot_get_repo:
* @self: Sysroot
* @out_repo: (out): Repository in sysroot @self
* @out_repo: (out) (transfer full) (optional): Repository in sysroot @self
* @cancellable: Cancellable
* @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
ostree_sysroot_get_repo (OstreeSysroot *self,
@ -1125,7 +1130,7 @@ find_booted_deployment (OstreeSysroot *self,
if (root_stbuf.st_dev == self_stbuf.st_dev &&
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))
return FALSE;
@ -1433,7 +1438,7 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0)
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))
return FALSE;
@ -1615,7 +1620,7 @@ clone_deployment (OstreeSysroot *sysroot,
/* Copy the bootloader config options */
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
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);
/* Deploy the copy */
@ -1689,7 +1694,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return FALSE;
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))
return FALSE;
@ -1698,6 +1703,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return FALSE;
const char *ovl_options = NULL;
static const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
switch (unlocked_state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
@ -1705,7 +1711,6 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
break;
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
* directly for hotfixes. The ostree-prepare-root.c helper
* 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");
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)
exit (EXIT_FAILURE);
err (1, "fchdir");
if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0)
exit (EXIT_FAILURE);
err (1, "mount");
exit (EXIT_SUCCESS);
}
else
@ -1778,7 +1787,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0)
return glnx_throw_errno_prefix (error, "waitpid() on mount helper");
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
*/
#define OSTREE_RELEASE_VERSION (12)
#define OSTREE_RELEASE_VERSION (13)
/**
* OSTREE_VERSION
@ -52,7 +52,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2017.12)
#define OSTREE_VERSION (2017.13)
/**
* OSTREE_VERSION_S:
@ -62,7 +62,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2017.12"
#define OSTREE_VERSION_S "2017.13"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))

View File

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

View File

@ -22,25 +22,10 @@
#include "ot-checksum-instream.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)
struct _OtChecksumInstreamPrivate {
#if defined(HAVE_OPENSSL)
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
OtChecksum checksum;
};
static gssize ot_checksum_instream_read (GInputStream *stream,
@ -54,13 +39,7 @@ ot_checksum_instream_finalize (GObject *object)
{
OtChecksumInstream *self = (OtChecksumInstream*)object;
#if defined(HAVE_OPENSSL)
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
ot_checksum_clear (&self->priv->checksum);
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);
}
#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 *
ot_checksum_instream_new (GInputStream *base,
GChecksumType checksum_type)
@ -124,18 +76,7 @@ ot_checksum_instream_new (GInputStream *base,
/* For now */
g_assert (checksum_type == G_CHECKSUM_SHA256);
#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
ot_checksum_init (&stream->priv->checksum);
return (OtChecksumInstream*) (stream);
}
@ -157,78 +98,15 @@ ot_checksum_instream_read (GInputStream *stream,
cancellable,
error);
if (res > 0)
{
#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
}
ot_checksum_update (&self->priv->checksum, buffer, 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 *
ot_checksum_instream_get_string (OtChecksumInstream *stream)
{
#if defined(HAVE_OPENSSL)
unsigned len;
guint8 csum[EVP_MAX_MD_SIZE];
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
char buf[_OSTREE_SHA256_STRING_LEN+1];
ot_checksum_get_hexdigest (&stream->priv->checksum, buf, sizeof(buf));
return g_strndup (buf, sizeof(buf));
}

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);
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);
G_END_DECLS

View File

@ -22,10 +22,15 @@
#include "config.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>
void
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';
}
/* 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 *
ot_csum_from_gchecksum (GChecksum *checksum)
{
@ -57,7 +176,7 @@ ot_gio_write_update_checksum (GOutputStream *out,
gconstpointer data,
gsize len,
gsize *out_bytes_written,
GChecksum *checksum,
OtChecksum *checksum,
GCancellable *cancellable,
GError **error)
{
@ -73,14 +192,14 @@ ot_gio_write_update_checksum (GOutputStream *out,
}
if (checksum)
g_checksum_update (checksum, data, len);
ot_checksum_update (checksum, data, len);
return TRUE;
}
gboolean
ot_gio_splice_update_checksum (GOutputStream *out,
GInputStream *in,
GChecksum *checksum,
OtChecksum *checksum,
GCancellable *cancellable,
GError **error)
{
@ -119,27 +238,20 @@ ot_gio_splice_get_checksum (GOutputStream *out,
GCancellable *cancellable,
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;
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);
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 *
ot_checksum_file_at (int dfd,
const char *path,
@ -151,9 +263,12 @@ ot_checksum_file_at (int dfd,
if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error))
return FALSE;
g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type);
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
g_auto(OtChecksum) checksum = { 0, };
ot_checksum_init (&checksum);
if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
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
#include <gio/gio.h>
#include "libglnx.h"
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);
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,
gconstpointer data,
gsize len,
gsize *out_bytes_written,
GChecksum *checksum,
OtChecksum *checksum,
GCancellable *cancellable,
GError **error);
@ -45,12 +84,7 @@ gboolean ot_gio_splice_get_checksum (GOutputStream *out,
gboolean ot_gio_splice_update_checksum (GOutputStream *out,
GInputStream *in,
GChecksum *checksum,
GCancellable *cancellable,
GError **error);
gboolean ot_gio_checksum_stream (GInputStream *in,
guchar **out_csum,
OtChecksum *checksum,
GCancellable *cancellable,
GError **error);

View File

@ -22,6 +22,7 @@
#include "ot-fs-utils.h"
#include "libglnx.h"
#include <sys/xattr.h>
#include <sys/mman.h>
#include <gio/gunixinputstream.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);
}
/* Wraps readlinkat(), and sets the `symlink-target` property
* of @target_info.
*/
gboolean
ot_readlinkat_gfile_info (int dfd,
const char *path,
@ -53,7 +57,6 @@ ot_readlinkat_gfile_info (int dfd,
return TRUE;
}
/**
* ot_openat_read_stream:
* @dfd: Directory file descriptor
@ -76,16 +79,10 @@ ot_openat_read_stream (int dfd,
GCancellable *cancellable,
GError **error)
{
int fd = -1;
int flags = O_RDONLY | O_NOCTTY | O_CLOEXEC;
if (!follow)
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);
glnx_autofd int fd = -1;
if (!glnx_openat_rdonly (dfd, path, follow, &fd, error))
return FALSE;
*out_istream = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE);
return TRUE;
}
@ -130,7 +127,7 @@ ot_dfd_iter_init_allow_noent (int dfd,
gboolean *out_exists,
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 (errno != ENOENT)
@ -144,22 +141,57 @@ ot_dfd_iter_init_allow_noent (int dfd,
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 *
ot_file_mapat_bytes (int dfd,
const char *path,
ot_fd_readall_or_mmap (int fd,
goffset start,
GError **error)
{
glnx_fd_close int fd = openat (dfd, path, O_RDONLY | O_CLOEXEC);
g_autoptr(GMappedFile) mfile = NULL;
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)
struct stat stbuf;
if (!glnx_fstat (fd, &stbuf, error))
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).

View File

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

View File

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

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 <string.h>
#include <sys/mman.h>
#include "otutil.h"
/* Create a new GVariant empty GVariant of type a{sv} */
GVariant *
ot_gvariant_new_empty_string_dict (void)
{
@ -37,167 +37,66 @@ ot_gvariant_new_empty_string_dict (void)
return g_variant_builder_end (&builder);
}
/* Create a new GVariant of type ay from the raw @data pointer */
GVariant *
ot_gvariant_new_bytearray (const guchar *data,
gsize len)
{
gpointer data_copy;
GVariant *ret;
data_copy = g_memdup (data, len);
ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
gpointer data_copy = g_memdup (data, len);
GVariant *ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
len, FALSE, g_free, data_copy);
return ret;
}
/* Convert a GBytes into a GVariant of type ay (byte array) */
GVariant *
ot_gvariant_new_ay_bytes (GBytes *bytes)
{
gsize size;
gconstpointer data;
data = g_bytes_get_data (bytes, &size);
gconstpointer data = g_bytes_get_data (bytes, &size);
g_bytes_ref (bytes);
return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size,
TRUE, (GDestroyNotify)g_bytes_unref, bytes);
}
GHashTable *
ot_util_variant_asv_to_hash_table (GVariant *variant)
{
GHashTable *ret;
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);
}
/* Create a GVariant in @out_variant that is backed by
* the data from @fd, starting at @start. If the data is
* large enough, mmap() may be used. @trusted is used
* by the GVariant core; see g_variant_new_from_data().
*/
gboolean
ot_util_variant_map_at (int dfd,
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,
ot_variant_read_fd (int fd,
goffset start,
const GVariantType *type,
gboolean trusted,
GVariant **out_variant,
GError **error)
{
gboolean ret = FALSE;
gpointer map;
struct stat stbuf;
VariantMapData *mdata = NULL;
gsize len;
g_autoptr(GBytes) bytes = ot_fd_readall_or_mmap (fd, start, error);
if (!bytes)
return FALSE;
if (fstat (fd, &stbuf) != 0)
{
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;
*out_variant = g_variant_ref_sink (g_variant_new_from_bytes (type, bytes, trusted));
return TRUE;
}
/* GVariants are immutable; this function allows generating an open builder
* for a new variant, inherting the data from @variant.
*/
GVariantBuilder *
ot_util_variant_builder_from_variant (GVariant *variant,
const GVariantType *type)
{
GVariantBuilder *builder = NULL;
builder = g_variant_builder_new (type);
GVariantBuilder *builder = g_variant_builder_new (type);
if (variant != NULL)
{
gint i, n;
n = g_variant_n_children (variant);
for (i = 0; i < n; i++)
const int n = g_variant_n_children (variant);
for (int 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_unref (child);
}
}
@ -221,28 +120,23 @@ ot_variant_bsearch_str (GVariant *array,
const char *str,
int *out_pos)
{
gsize imax, imin;
gsize imid = -1;
gsize n;
n = g_variant_n_children (array);
const gsize n = g_variant_n_children (array);
if (n == 0)
return FALSE;
imax = n - 1;
imin = 0;
gsize imax = n - 1;
gsize imin = 0;
gsize imid = -1;
while (imax >= imin)
{
g_autoptr(GVariant) child = NULL;
const char *cur;
int cmp;
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);
cmp = strcmp (cur, str);
int cmp = strcmp (cur, str);
if (cmp < 0)
imin = imid + 1;
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);
GHashTable *ot_util_variant_asv_to_hash_table (GVariant *variant);
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,
gboolean ot_variant_read_fd (int fd,
goffset offset,
const GVariantType *type,
gboolean trusted,
GVariant **out_variant,
GError **error);
GInputStream *ot_variant_read (GVariant *variant);
GVariantBuilder *ot_util_variant_builder_from_variant (GVariant *variant,
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-unix-utils.h>
#include <ot-variant-utils.h>
#include <ot-variant-builder.h>
#include <ot-checksum-utils.h>
#include <ot-gpg-utils.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"
static OstreeCommand commands[] = {
{ "admin", ostree_builtin_admin },
{ "cat", ostree_builtin_cat },
{ "checkout", ostree_builtin_checkout },
{ "checksum", ostree_builtin_checksum },
{ "commit", ostree_builtin_commit },
{ "config", ostree_builtin_config },
{ "diff", ostree_builtin_diff },
{ "export", ostree_builtin_export },
/* Note: all admin related commands have
* no_repo as their command flag, but each
* admin command may have their own
* admin flag
*/
{ "admin", OSTREE_BUILTIN_FLAG_NO_REPO,
ostree_builtin_admin,
"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
{ "find-remotes", ostree_builtin_find_remotes },
{ "create-usb", ostree_builtin_create_usb },
{ "find-remotes", OSTREE_BUILTIN_FLAG_NONE,
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
{ "fsck", ostree_builtin_fsck },
{ "gpg-sign", ostree_builtin_gpg_sign },
{ "init", ostree_builtin_init },
{ "log", ostree_builtin_log },
{ "ls", ostree_builtin_ls },
{ "prune", ostree_builtin_prune },
{ "pull-local", ostree_builtin_pull_local },
#ifdef HAVE_LIBSOUP
{ "pull", ostree_builtin_pull },
{ "fsck", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_fsck,
"Check the repository for consistency" },
{ "gpg-sign", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_gpg_sign,
"Sign a commit" },
{ "init", OSTREE_BUILTIN_FLAG_NO_CHECK,
ostree_builtin_init,
"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
{ "refs", ostree_builtin_refs },
{ "remote", ostree_builtin_remote },
{ "reset", ostree_builtin_reset },
{ "rev-parse", ostree_builtin_rev_parse },
{ "show", ostree_builtin_show },
{ "static-delta", ostree_builtin_static_delta },
{ "summary", ostree_builtin_summary },
{ "refs", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_refs,
"List refs" },
{ "remote", OSTREE_BUILTIN_FLAG_NO_REPO,
ostree_builtin_remote,
"Remote commands that may involve internet access" },
{ "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)
{ "trivial-httpd", ostree_builtin_trivial_httpd },
{ "trivial-httpd", OSTREE_BUILTIN_FLAG_NONE,
ostree_builtin_trivial_httpd,
NULL },
#endif
{ NULL }
};

View File

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

View File

@ -38,17 +38,17 @@ static GOptionEntry options[] = {
};
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(OstreeSysroot) sysroot = NULL;
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,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error))
invocation, &sysroot, cancellable, error))
goto out;
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))

View File

@ -60,17 +60,17 @@ static GOptionEntry options[] = {
};
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_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment");
g_option_context_new ("REFSPEC");
g_autoptr(OstreeSysroot) sysroot = NULL;
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error))
invocation, &sysroot, cancellable, error))
return FALSE;
if (argc < 2)

View File

@ -41,7 +41,7 @@ static GOptionEntry options[] = {
};
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(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) 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);
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED,
&sysroot, cancellable, error))
invocation, &sysroot, cancellable, error))
goto out;
if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,

View File

@ -38,15 +38,15 @@ static GOptionEntry options[] = {
};
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,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER |
OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED |
OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT,
NULL, cancellable, error))
invocation, NULL, cancellable, error))
return FALSE;
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];
glnx_fd_close int root_dfd = -1;
glnx_autofd int root_dfd = -1;
if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error))
return FALSE;

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