lib/repo: Always look in staging directory for objects

Its often the case that we want to look at objects inside a commit,
before the objects the transaction is finished. For instance:
  https://github.com/flatpak/flatpak/pull/837
Which tries to verify the file permissions before committing the
transaction.

And:
  1e5ffa926a
Which collects the storage size of the objects so that we can
put the total download size in the commit metadata.

I tried to find all the places where we did reads from the
object directories, and in particular this fixes:

 - `ostree_repo_load_file()` for `bare` repos (`archive` was already working).
 - `ostree_repo_query_object_storage_size()`
 - Applying deltas that reference not-yet-commited objects

Closes: #916
Approved by: cgwalters
This commit is contained in:
Alexander Larsson 2017-06-08 09:43:23 +02:00 committed by Atomic Bot
parent 848b7c0201
commit 7159bed8e1

View File

@ -2501,19 +2501,33 @@ load_metadata_internal (OstreeRepo *self,
return TRUE;
}
/* Basically fstatat(), but also looks in both the committed and staging
* directories, and returns *out_dfd for where we found the object.
*/
static gboolean
query_info_for_bare_content_object (OstreeRepo *self,
const char *loose_path_buf,
GFileInfo **out_info,
GCancellable *cancellable,
GError **error)
stat_bare_content_object (OstreeRepo *self,
const char *loose_path_buf,
int *out_dfd,
GFileInfo **out_info,
GCancellable *cancellable,
GError **error)
{
struct stat stbuf;
int res;
int dirfd;
if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0)
dirfd = self->objects_dir_fd;
res = TEMP_FAILURE_RETRY (fstatat (dirfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0 && errno == ENOENT && self->commit_stagedir_fd != -1)
{
dirfd = self->commit_stagedir_fd;
res = TEMP_FAILURE_RETRY (fstatat (dirfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW));
}
if (res < 0)
{
if (errno == ENOENT)
{
*out_dfd = -1;
*out_info = NULL;
return TRUE;
}
@ -2528,13 +2542,14 @@ query_info_for_bare_content_object (OstreeRepo *self,
}
else if (S_ISLNK (stbuf.st_mode))
{
if (!ot_readlinkat_gfile_info (self->objects_dir_fd, loose_path_buf,
if (!ot_readlinkat_gfile_info (dirfd, loose_path_buf,
ret_info, cancellable, error))
return FALSE;
}
else
return glnx_throw (error, "Not a regular file or symlink: %s", loose_path_buf);
*out_dfd = dirfd;
ot_transfer_out_value (out_info, &ret_info);
return TRUE;
}
@ -2575,6 +2590,12 @@ _ostree_repo_read_bare_fd (OstreeRepo *self,
if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, out_fd, error))
return FALSE;
if (*out_fd == -1 && self->commit_stagedir_fd != -1)
{
if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, out_fd, error))
return FALSE;
}
if (*out_fd == -1)
{
if (self->parent_repo)
@ -2661,9 +2682,11 @@ ostree_repo_load_file (OstreeRepo *self,
}
else
{
if (!query_info_for_bare_content_object (self, loose_path_buf,
&ret_file_info,
cancellable, error))
int objdir_fd; /* referenced */
if (!stat_bare_content_object (self, loose_path_buf,
&objdir_fd,
&ret_file_info,
cancellable, error))
return FALSE;
if (ret_file_info)
@ -2681,7 +2704,7 @@ ostree_repo_load_file (OstreeRepo *self,
* always do an open, then query the user.ostreemeta xattr for
* more information.
*/
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@ -2735,7 +2758,7 @@ ostree_repo_load_file (OstreeRepo *self,
if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR &&
out_input)
{
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@ -2759,7 +2782,7 @@ ostree_repo_load_file (OstreeRepo *self,
{
glnx_fd_close int fd = -1;
fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
fd = openat (objdir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return glnx_throw_errno (error);
@ -2783,7 +2806,7 @@ ostree_repo_load_file (OstreeRepo *self,
{
if (self->disable_xattrs)
ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
else if (!glnx_dfd_name_get_all_xattrs (self->objects_dir_fd, loose_path_buf,
else if (!glnx_dfd_name_get_all_xattrs (objdir_fd, loose_path_buf,
&ret_xattrs,
cancellable, error))
return FALSE;
@ -3260,9 +3283,14 @@ ostree_repo_query_object_storage_size (OstreeRepo *self,
{
char loose_path[_OSTREE_LOOSE_PATH_MAX];
_ostree_loose_path (loose_path, sha256, objtype, self->mode);
int res;
struct stat stbuf;
if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0)
res = TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0 && errno == ENOENT && self->commit_stagedir_fd != -1)
res = TEMP_FAILURE_RETRY (fstatat (self->commit_stagedir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW));
if (res < 0)
return glnx_throw_errno_prefix (error, "Querying object %s.%s", sha256, ostree_object_type_to_string (objtype));
*out_size = stbuf.st_size;