[libgsystem] fileutil: Add new API to open a temporary file in a particular directory



commit 3dee2f23ac34d1d5ce2ed8cbad14cb0596d2b57f
Author: Colin Walters <walters verbum org>
Date:   Tue Aug 6 23:49:11 2013 +0200

    fileutil: Add new API to open a temporary file in a particular directory
    
    This is useful for ostree to write to repo/tmp.

 gsystem-file-utils.c |   70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gsystem-file-utils.h |    7 +++++
 2 files changed, 77 insertions(+), 0 deletions(-)
---
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index 5510948..c25b309 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -35,6 +35,7 @@
 #include <gio/gunixoutputstream.h>
 #include <glib-unix.h>
 #include <limits.h>
+#include <dirent.h>
 
 static int
 close_nointr (int fd)
@@ -428,6 +429,75 @@ gsystem_fileutil_gen_tmp_name (const char *prefix,
   return g_string_free (str, FALSE);
 }
 
+/**
+ * gs_file_open_in_tmpdir:
+ * @tmpdir: Directory to place temporary file
+ * @mode: Default mode (will be affected by umask)
+ * @out_file: (out) (transfer full): Newly created file path
+ * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
+ * @cancellable:
+ * @error:
+ *
+ * Like g_file_open_tmp(), except the file will be created in the
+ * provided @tmpdir, and allows specification of the Unix @mode, which
+ * means private files may be created.  Return values will be stored
+ * in @out_file, and optionally @out_stream.
+ */
+gboolean
+gs_file_open_in_tmpdir (GFile             *tmpdir,
+                        int                mode,
+                        GFile            **out_file,
+                        GOutputStream    **out_stream,
+                        GCancellable      *cancellable,
+                        GError           **error)
+{
+  gboolean ret = FALSE;
+  const int max_attempts = 128;
+  guint i;
+  DIR *d;
+  int dfd;
+  char *tmp_name = NULL;
+  int fd;
+
+  d = opendir (gs_file_get_path_cached (tmpdir));
+  if (!d)
+    {
+      _set_error_from_errno (error);
+      goto out;
+    }
+  dfd = dirfd (d);
+  
+  /* 128 attempts seems reasonable... */
+  for (i = 0; i < max_attempts; i++)
+    {
+      g_free (tmp_name);
+      tmp_name = gsystem_fileutil_gen_tmp_name (NULL, NULL);
+
+      do
+        fd = openat (dfd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode);
+      while (fd == -1 && errno == EINTR);
+      if (fd < 0 && errno != EEXIST)
+        {
+          _set_error_from_errno (error);
+          goto out;
+        }
+      break;
+    }
+  if (i == max_attempts)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Exhausted attempts to open temporary file");
+      goto out;
+    }
+
+  ret = TRUE;
+  *out_file = g_file_get_child (tmpdir, tmp_name);
+  if (out_stream)
+    *out_stream = g_unix_output_stream_new (fd, TRUE);
+ out:
+  return ret;
+}
+
 static gboolean
 linkcopy_internal_attempt (GFile          *src,
                           GFile          *dest,
diff --git a/gsystem-file-utils.h b/gsystem-file-utils.h
index d8cd73d..0d9994d 100644
--- a/gsystem-file-utils.h
+++ b/gsystem-file-utils.h
@@ -55,6 +55,13 @@ gboolean gs_file_sync_data (GFile          *file,
 char * gsystem_fileutil_gen_tmp_name (const char *prefix,
                                       const char *suffix);
 
+gboolean gs_file_open_in_tmpdir (GFile             *tmpdir,
+                                 int                mode,
+                                 GFile            **out_file,
+                                 GOutputStream    **out_stream,
+                                 GCancellable      *cancellable,
+                                 GError           **error);
+
 gboolean gs_file_create (GFile          *file,
                          int             mode,
                          GOutputStream **out_stream,


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