lib/repo: Always look in staging directory for objects
authorAlexander Larsson <alexl@redhat.com>
Thu, 8 Jun 2017 07:43:23 +0000 (09:43 +0200)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 13 Jun 2017 00:47:42 +0000 (00:47 +0000)
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:
  https://github.com/flatpak/flatpak/commit/1e5ffa926a25acb655af7889b679b140bf44870b
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

src/libostree/ostree-repo.c

index bf126a917c1a10908c1aee8c285b32b038efe1ba..1da0621760813b6bfff160c25ad4fce3773709eb 100644 (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;