[ostree] core: Further unify API to create files



commit d1950da1a04f7f501bc9a3432f8732d681b858e5
Author: Colin Walters <walters verbum org>
Date:   Fri Dec 2 11:22:32 2011 -0500

    core: Further unify API to create files
    
    We now have just one place which writes to the filesystem.  Wrap a
    temporary file allocation API on top of that.

 src/libostree/ostree-core.c  |  210 +++++++++++++++++++++++++++++++++++++++--
 src/libostree/ostree-core.h  |   21 ++++
 src/libostree/ostree-repo.c  |   12 +--
 src/libotutil/ot-gio-utils.c |  129 --------------------------
 src/libotutil/ot-gio-utils.h |   18 ----
 5 files changed, 224 insertions(+), 166 deletions(-)
---
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index da84fec..8e6b854 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -881,6 +881,7 @@ ostree_create_file_from_input (GFile            *dest_file,
                                GFileInfo        *finfo,
                                GVariant         *xattrs,
                                GInputStream     *input,
+                               OstreeObjectType objtype,
                                GChecksum       **out_checksum,
                                GCancellable     *cancellable,
                                GError          **error)
@@ -891,14 +892,22 @@ ostree_create_file_from_input (GFile            *dest_file,
   guint32 uid, gid, mode;
   GChecksum *ret_checksum = NULL;
 
-  uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
-  gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
-  mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return FALSE;
+
+  if (finfo != NULL)
+    {
+      mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
+    }
+  else
+    {
+      mode = S_IFREG | 0666;
+    }
   dest_path = ot_gfile_get_path_cached (dest_file);
 
   if (S_ISREG (mode))
     {
-      out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
+      out = g_file_create (dest_file, 0, cancellable, error);
       if (!out)
         goto out;
 
@@ -913,6 +922,7 @@ ostree_create_file_from_input (GFile            *dest_file,
   else if (S_ISLNK (mode))
     {
       const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
+      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
       if (ret_checksum)
         g_checksum_update (ret_checksum, (guint8*)target, strlen (target));
       if (symlink (target, dest_path) < 0)
@@ -924,6 +934,7 @@ ostree_create_file_from_input (GFile            *dest_file,
   else if (S_ISCHR (mode) || S_ISBLK (mode))
     {
       guint32 dev = g_file_info_get_attribute_uint32 (finfo, "unix::rdev");
+      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
       if (ret_checksum)
         g_checksum_update (ret_checksum, (guint8*)&dev, 4);
       if (mknod (dest_path, mode, dev) < 0)
@@ -934,6 +945,7 @@ ostree_create_file_from_input (GFile            *dest_file,
     }
   else if (S_ISFIFO (mode))
     {
+      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
       if (mkfifo (dest_path, mode) < 0)
         {
           ot_util_set_error_from_errno (error, errno);
@@ -947,10 +959,21 @@ ostree_create_file_from_input (GFile            *dest_file,
       goto out;
     }
 
-  if (lchown (dest_path, uid, gid) < 0)
+  if (finfo != NULL)
     {
-      ot_util_set_error_from_errno (error, errno);
-      goto out;
+      uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
+      gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
+      
+      if (lchown (dest_path, uid, gid) < 0)
+        {
+          ot_util_set_error_from_errno (error, errno);
+          goto out;
+        }
+    }
+  else
+    {
+      uid = geteuid ();
+      gid = getegid ();
     }
 
   if (!S_ISLNK (mode))
@@ -962,13 +985,18 @@ ostree_create_file_from_input (GFile            *dest_file,
         }
     }
 
-  if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
-    goto out;
+  if (xattrs != NULL)
+    {
+      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
+      if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
+        goto out;
+    }
 
-  if (ret_checksum)
+  if (ret_checksum && objtype == OSTREE_OBJECT_TYPE_FILE)
     {
       ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
-      g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
+      if (xattrs)
+        g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
     }
 
   ret = TRUE;
@@ -985,6 +1013,165 @@ ostree_create_file_from_input (GFile            *dest_file,
   return ret;
 }
 
+static GString *
+create_tmp_string (const char *dirpath,
+                   const char *prefix,
+                   const char *suffix)
+{
+  GString *tmp_name = NULL;
+
+  if (!prefix)
+    prefix = "tmp-";
+  if (!suffix)
+    suffix = ".tmp";
+
+  tmp_name = g_string_new (dirpath);
+  g_string_append_c (tmp_name, '/');
+  g_string_append (tmp_name, prefix);
+  g_string_append (tmp_name, "XXXXXX");
+  g_string_append (tmp_name, suffix);
+
+  return tmp_name;
+}
+
+static char *
+subst_xxxxxx (GRand      *rand,
+              const char *string)
+{
+  static const char table[] = "ABCEDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789";
+  char *ret = g_strdup (string);
+  guint8 *xxxxxx = (guint8*)strstr (ret, "XXXXXX");
+
+  g_assert (xxxxxx != NULL);
+
+  while (*xxxxxx == 'X')
+    {
+      int offset = g_random_int_range (0, sizeof (table));
+      *xxxxxx = (guint8)table[offset];
+      xxxxxx++;
+    }
+
+  return ret;
+}
+
+gboolean
+ostree_create_temp_file_from_input (GFile            *dir,
+                                    const char       *prefix,
+                                    const char       *suffix,
+                                    GFileInfo        *finfo,
+                                    GVariant         *xattrs,
+                                    GInputStream     *input,
+                                    OstreeObjectType objtype,
+                                    GFile           **out_file,
+                                    GChecksum       **out_checksum,
+                                    GCancellable     *cancellable,
+                                    GError          **error)
+{
+  gboolean ret = FALSE;
+  GChecksum *ret_checksum = NULL;
+  GRand *rand = NULL;
+  GString *tmp_name = NULL;
+  char *possible_name = NULL;
+  GFile *possible_file = NULL;
+  GError *temp_error = NULL;
+  int i = 0;
+
+  rand = g_rand_new ();
+  
+  tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
+                                prefix, suffix);
+  
+  /* 128 attempts seems reasonable... */
+  for (i = 0; i < 128; i++)
+    {
+      g_free (possible_name);
+      possible_name = subst_xxxxxx (rand, tmp_name->str);
+      g_clear_object (&possible_file);
+      possible_file = ot_gfile_new_for_path (possible_name);
+      
+      if (!ostree_create_file_from_input (possible_file, finfo, xattrs, input,
+                                          objtype,
+                                          out_checksum ? &ret_checksum : NULL,
+                                          cancellable, &temp_error))
+        {
+          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+            {
+              g_clear_error (&temp_error);
+              continue;
+            }
+          else
+            {
+              g_propagate_error (error, temp_error);
+              goto out;
+            }
+        }
+      else
+        {
+          break;
+        }
+    }
+  if (i == 128)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Exhausted 128 attempts to create a temporary file");
+      goto out;
+    }
+
+  ret = TRUE;
+  if (out_checksum)
+    {
+      *out_checksum = ret_checksum;
+      ret_checksum = NULL;
+    }
+  if (out_file)
+    {
+      *out_file = possible_file;
+      possible_file = NULL;
+    }
+ out:
+  if (rand)
+    g_rand_free (rand);
+  if (tmp_name)
+    g_string_free (tmp_name, TRUE);
+  g_free (possible_name);
+  g_clear_object (&possible_file);
+  ot_clear_checksum (&ret_checksum);
+  return ret;
+}
+
+gboolean
+ostree_create_temp_regular_file (GFile            *dir,
+                                 const char       *prefix,
+                                 const char       *suffix,
+                                 GFile           **out_file,
+                                 GOutputStream   **out_stream,
+                                 GCancellable     *cancellable,
+                                 GError          **error)
+{
+  gboolean ret = FALSE;
+  GFile *ret_file = NULL;
+  GOutputStream *ret_stream = NULL;
+
+  if (!ostree_create_temp_file_from_input (dir, prefix, suffix, NULL, NULL, NULL,
+                                           OSTREE_OBJECT_TYPE_FILE, &ret_file,
+                                           NULL, cancellable, error))
+    goto out;
+  
+  ret_stream = (GOutputStream*)g_file_append_to (ret_file, 0, cancellable, error);
+  if (ret_stream == NULL)
+    goto out;
+  
+  ret = TRUE;
+  *out_file = ret_file;
+  ret_file = NULL;
+  *out_stream = ret_stream;
+  ret_stream = NULL;
+ out:
+  g_clear_object (&ret_file);
+  g_clear_object (&ret_stream);
+  return ret;
+}
+
 static gboolean
 unpack_file (GFile        *file,
              GFile        *dest_file,    
@@ -1003,6 +1190,7 @@ unpack_file (GFile        *file,
     goto out;
 
   if (!ostree_create_file_from_input (dest_file, finfo, xattrs, in,
+                                      OSTREE_OBJECT_TYPE_FILE,
                                       out_checksum ? &ret_checksum : NULL,
                                       cancellable, error))
     goto out;
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 64bfca7..454889f 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -166,10 +166,31 @@ gboolean ostree_create_file_from_input (GFile          *file,
                                         GFileInfo      *finfo,
                                         GVariant       *xattrs,
                                         GInputStream   *input,
+                                        OstreeObjectType objtype,
                                         GChecksum     **out_checksum,
                                         GCancellable   *cancellable,
                                         GError        **error);
 
+gboolean ostree_create_temp_file_from_input (GFile            *dir,
+                                             const char       *prefix,
+                                             const char       *suffix,
+                                             GFileInfo        *finfo,
+                                             GVariant         *xattrs,
+                                             GInputStream     *input,
+                                             OstreeObjectType objtype,
+                                             GFile           **out_file,
+                                             GChecksum       **out_checksum,
+                                             GCancellable     *cancellable,
+                                             GError          **error);
+
+gboolean ostree_create_temp_regular_file (GFile            *dir,
+                                          const char       *prefix,
+                                          const char       *suffix,
+                                          GFile           **out_file,
+                                          GOutputStream   **out_stream,
+                                          GCancellable     *cancellable,
+                                          GError          **error);
+
 gboolean ostree_parse_packed_file (GFile            *file,
                                    GFileInfo       **out_file_info,
                                    GVariant        **out_xattrs,
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index e4a6c92..0beef27 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -592,14 +592,10 @@ stage_and_checksum (OstreeRepo       *self,
       break;
     }
 
-  if (!ot_gfile_create_tmp (priv->tmp_dir, prefix, NULL, 0666,
-                            &tmp_f, &stream, cancellable, error))
-    goto out;
-
-  if (!ot_gio_splice_and_checksum (stream, input, &ret_checksum, cancellable, error))
-    goto out;
-
-  if (!g_output_stream_close ((GOutputStream*)stream, NULL, error))
+  if (!ostree_create_temp_file_from_input (priv->tmp_dir, prefix, NULL, NULL,
+                                           NULL, input, OSTREE_OBJECT_TYPE_META,
+                                           &tmp_f, &ret_checksum,
+                                           cancellable, error))
     goto out;
 
   ret_tmpname = g_file_get_child (priv->tmp_dir, g_checksum_get_string (ret_checksum));
diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c
index 0e8f4c2..ed730e7 100644
--- a/src/libotutil/ot-gio-utils.c
+++ b/src/libotutil/ot-gio-utils.c
@@ -196,135 +196,6 @@ ot_gio_splice_and_checksum (GOutputStream  *out,
   return ret;
 }
 
-static GString *
-create_tmp_string (const char *dirpath,
-                   const char *prefix,
-                   const char *suffix)
-{
-  GString *tmp_name = NULL;
-
-  if (!prefix)
-    prefix = "tmp-";
-  if (!suffix)
-    suffix = ".tmp";
-
-  tmp_name = g_string_new (dirpath);
-  g_string_append_c (tmp_name, '/');
-  g_string_append (tmp_name, prefix);
-  g_string_append (tmp_name, "XXXXXX");
-  g_string_append (tmp_name, suffix);
-
-  return tmp_name;
-}
-
-gboolean
-ot_gfile_create_tmp (GFile       *dir,
-                     const char  *prefix,
-                     const char  *suffix,
-                     int          mode,
-                     GFile      **out_file,
-                     GOutputStream **out_stream,
-                     GCancellable *cancellable,
-                     GError       **error)
-{
-  gboolean ret = FALSE;
-  GString *tmp_name = NULL;
-  int tmpfd = -1;
-  GFile *ret_file = NULL;
-  GOutputStream *ret_stream = NULL;
-
-  if (g_cancellable_set_error_if_cancelled (cancellable, error))
-    return FALSE;
-
-  tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir), prefix, suffix);
-  
-  tmpfd = g_mkstemp_full (tmp_name->str, O_WRONLY | O_BINARY, mode);
-  if (tmpfd == -1)
-    {
-      ot_util_set_error_from_errno (error, errno);
-      goto out;
-    }
-
-  ret_file = ot_gfile_new_for_path (tmp_name->str);
-  ret_stream = g_unix_output_stream_new (tmpfd, TRUE);
-  
-  ret = TRUE;
-  if (out_file)
-    {
-      *out_file = ret_file;
-      ret_file = NULL;
-    }
-  if (out_stream)
-    {
-      *out_stream = ret_stream;
-      ret_stream = NULL;
-    }
- out:
-  g_clear_object (&ret_file);
-  g_clear_object (&ret_stream);
-  g_string_free (tmp_name, TRUE);
-  return ret;
-}
-
-static char *
-subst_xxxxxx (GRand      *rand,
-              const char *string)
-{
-  char *ret = g_strdup (string);
-  guint8 *xxxxxx = (guint8*)strstr (ret, "XXXXXX");
-
-  g_assert (xxxxxx != NULL);
-
-  while (*xxxxxx == 'X')
-    {
-      *xxxxxx = (guint8)g_random_int_range (0, 255);
-      xxxxxx++;
-    }
-
-  return ret;
-}
-
-gboolean
-ot_gfile_create_tmp_symlink (const char  *target,
-                             GFile       *dir,
-                             const char  *prefix,
-                             const char  *suffix,
-                             GFile      **out_file,
-                             GCancellable *cancellable,
-                             GError       **error)
-{
-  gboolean ret = FALSE;
-  GRand *rand = NULL;
-  GString *tmp_name = NULL;
-  char *possible_name = NULL;
-
-  rand = g_rand_new ();
-  
-  tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
-                                prefix, suffix);
-  
-  while (TRUE)
-    {
-      g_free (possible_name);
-      possible_name = subst_xxxxxx (rand, tmp_name->str);
-      if (symlink (target, possible_name) < 0)
-        {
-          if (errno == EEXIST)
-            continue;
-          ot_util_set_error_from_errno (error, errno);
-          goto out;
-        }
-    }
-
-  *out_file = ot_gfile_new_for_path (possible_name);
- out:
-  g_string_free (tmp_name, TRUE);
-  g_free (possible_name);
-  if (rand)
-    g_rand_free (rand);
-  return ret;
-}
-
 gboolean
 ot_gfile_merge_dirs (GFile    *destination,
                      GFile    *src,
diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h
index de131df..a8cc080 100644
--- a/src/libotutil/ot-gio-utils.h
+++ b/src/libotutil/ot-gio-utils.h
@@ -51,24 +51,6 @@ gboolean ot_gio_splice_and_checksum (GOutputStream  *out,
                                      GCancellable   *cancellable,
                                      GError        **error);
 
-
-gboolean ot_gfile_create_tmp (GFile       *dir,
-                              const char  *prefix,
-                              const char  *suffix,
-                              int          mode,
-                              GFile      **out_file,
-                              GOutputStream **out_stream,
-                              GCancellable *cancellable,
-                              GError       **error);
-
-gboolean ot_gfile_create_tmp_symlink (const char  *target,
-                                      GFile       *dir,
-                                      const char  *prefix,
-                                      const char  *suffix,
-                                      GFile      **out_file,
-                                      GCancellable *cancellable,
-                                      GError       **error);
-
 gboolean ot_gfile_merge_dirs (GFile    *destination,
                               GFile    *src,
                               GCancellable *cancellable,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]