diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 45aec5e589..bbb420ea01 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -614,6 +614,63 @@ _create_payload_link (OstreeRepo *self, return TRUE; } +static gboolean +_lookup_payload_link (OstreeRepo *self, + const char *actual_payload_checksum, + GFileInfo *file_info, + GLnxTmpfile *tmpf, + GCancellable *cancellable, + GError **error) +{ + int dfd_searches[] = { -1, self->objects_dir_fd }; + if (self->commit_stagedir.initialized) + dfd_searches[0] = self->commit_stagedir.fd; + for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++) + { + glnx_autofd int fdf = -1; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + char loose_path_target_buf[_OSTREE_LOOSE_PATH_MAX]; + char target_checksum[OSTREE_SHA256_STRING_LEN+1]; + int dfd = dfd_searches[i]; + if (dfd == -1) + continue; + + _ostree_loose_path (loose_path_buf, actual_payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, self->mode); + + if (TEMP_FAILURE_RETRY (readlinkat (dfd, loose_path_buf, target_checksum, sizeof (target_checksum))) < 0) + { + if (errno == ENOENT) + continue; + return glnx_throw_errno (error); + } + + _ostree_loose_path (loose_path_target_buf, target_checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + if (!ot_openat_ignore_enoent (dfd, loose_path_target_buf, &fdf, error)) + return FALSE; + + if (fdf < 0) + { + /* If the link is referring to an object that doesn't exist anymore in the repository, just unlink it. */ + if (!glnx_unlinkat (dfd, loose_path_buf, 0, error)) + return FALSE; + } + else + { + if (ftruncate (tmpf->fd, 0) < 0) + return glnx_throw_errno (error); + + if (glnx_regfile_copy_bytes (fdf, tmpf->fd, -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + return TRUE; + } + } + if (self->parent_repo) + return _lookup_payload_link (self->parent_repo, actual_payload_checksum, file_info, tmpf, cancellable, error); + + return TRUE; +} + /* 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 @@ -894,52 +951,8 @@ write_content_object (OstreeRepo *self, repo_store_size_entry (self, actual_checksum, unpacked_size, stbuf.st_size); } - if (actual_payload_checksum) - { - int dfd_searches[] = { -1, self->objects_dir_fd }; - if (self->commit_stagedir.initialized) - dfd_searches[0] = self->commit_stagedir.fd; - for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++) - { - glnx_autofd int fdf = -1; - char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; - char loose_path_target_buf[_OSTREE_LOOSE_PATH_MAX]; - char target_checksum[OSTREE_SHA256_STRING_LEN+1]; - int dfd = dfd_searches[i]; - if (dfd == -1) - continue; - - _ostree_loose_path (loose_path_buf, actual_payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, self->mode); - - if (readlinkat (dfd, loose_path_buf, target_checksum, sizeof (target_checksum)) < 0) - { - if (errno == ENOENT) - continue; - return glnx_throw_errno (error); - } - - _ostree_loose_path (loose_path_target_buf, target_checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); - if (!ot_openat_ignore_enoent (dfd, loose_path_target_buf, &fdf, error)) - return FALSE; - - if (fdf < 0) - { - /* If the link is referring to an object that doesn't exist anymore in the repository, just unlink it. */ - if (!glnx_unlinkat (dfd, loose_path_buf, 0, error)) - return FALSE; - } - else - { - if (ftruncate (tmpf.fd, 0) < 0) - return glnx_throw_errno (error); - - if (glnx_regfile_copy_bytes (fdf, tmpf.fd, -1) < 0) - return glnx_throw_errno_prefix (error, "regfile copy"); - - return TRUE; - } - } - } + if (!_lookup_payload_link (self, actual_payload_checksum, file_info, &tmpf, cancellable, error)) + return FALSE; /* This path is for regular files */ if (!commit_loose_regfile_object (self, actual_checksum, &tmpf,