Remove warnings about conflicts with the stable version.
[platform/upstream/glib.git] / gfileutils.c
index 1176852..86b33bc 100644 (file)
  *   Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
+
 #include "glib.h"
 
 #include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <stdlib.h>
 
+#ifdef G_OS_WIN32
+#include <io.h>
+#ifndef F_OK
+#define        F_OK 0
+#define        X_OK 1
+#define        W_OK 2
+#define        R_OK 4
+#endif /* !F_OK */
+
+#ifndef S_ISREG
+#define S_ISREG(mode) ((mode)&_S_IFREG)
+#endif
 
-#define _(x) x
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode)&_S_IFDIR)
+#endif
+
+#endif /* G_OS_WIN32 */
+
+#ifndef S_ISLNK
+#define S_ISLNK(x) 0
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include "glibintl.h"
 
 /**
  * g_file_test:
@@ -85,10 +117,25 @@ g_file_error_quark (void)
   return q;
 }
 
+/**
+ * g_file_error_from_errno:
+ * @err_no: an "errno" value
+ * 
+ * Gets a #GFileError constant based on the passed-in errno.
+ * For example, if you pass in EEXIST this function returns
+ * #G_FILE_ERROR_EXIST. Unlike errno values, you can portably
+ * assume that all #GFileError values will exist.
+ *
+ * Normally a #GFileError value goes into a #GError returned
+ * from a function that manipulates files. So you would use
+ * g_file_error_from_errno() when constructing a #GError.
+ * 
+ * Return value: #GFileError corresponding to the given errno
+ **/
 GFileError
-g_file_error_from_errno (gint en)
+g_file_error_from_errno (gint err_no)
 {
-  switch (en)
+  switch (err_no)
     {
 #ifdef EEXIST
     case EEXIST:
@@ -279,6 +326,8 @@ get_contents_stdio (const gchar *filename,
   return TRUE;  
 }
 
+#ifndef G_OS_WIN32
+
 static gboolean
 get_contents_regfile (const gchar *filename,
                       struct stat *stat_buf,
@@ -344,7 +393,8 @@ get_contents_posix (const gchar *filename,
   struct stat stat_buf;
   gint fd;
   
-  fd = open (filename, O_RDONLY);
+  /* O_BINARY useful on Cygwin */
+  fd = open (filename, O_RDONLY|O_BINARY);
 
   if (fd < 0)
     {
@@ -401,7 +451,8 @@ get_contents_posix (const gchar *filename,
     }
 }
 
-#ifdef G_OS_WIN32
+#else  /* G_OS_WIN32 */
+
 static gboolean
 get_contents_win32 (const gchar *filename,
                     gchar      **contents,
@@ -426,6 +477,7 @@ get_contents_win32 (const gchar *filename,
   
   return get_contents_stdio (filename, f, contents, length, error);
 }
+
 #endif
 
 /**
@@ -468,3 +520,179 @@ g_file_get_contents (const gchar *filename,
 #endif
 }
 
+/*
+ * mkstemp() implementation is from the GNU C library.
+ * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
+ */
+/**
+ * g_mkstemp:
+ * @tmpl: template filename
+ *
+ * Open a temporary file. See "man mkstemp" on most UNIX-like systems.
+ * This is a portability wrapper, which simply calls mkstemp() on systems
+ * that have it, and implements it in GLib otherwise.
+ *
+ * The parameter is a string that should match the rules for mktemp, i.e.
+ * end in "XXXXXX". The X string will be modified to form the name
+ * of a file that didn't exist.
+ *
+ * Return value: A file handle (as from open()) to the file
+ * opened for reading and writing. The file is opened in binary mode
+ * on platforms where there is a difference. The file handle should be
+ * closed with close(). In case of errors, -1 is returned.
+ */
+int
+g_mkstemp (char *tmpl)
+{
+#ifdef HAVE_MKSTEMP
+  return mkstemp (tmpl);
+#else
+  int len;
+  char *XXXXXX;
+  int count, fd;
+  static const char letters[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  static const int NLETTERS = sizeof (letters) - 1;
+  glong value;
+  GTimeVal tv;
+  static int counter = 0;
+
+  len = strlen (tmpl);
+  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+    return -1;
+
+  /* This is where the Xs start.  */
+  XXXXXX = &tmpl[len - 6];
+
+  /* Get some more or less random data.  */
+  g_get_current_time (&tv);
+  value = (tv.tv_usec ^ tv.tv_sec) + counter++;
+
+  for (count = 0; count < 100; value += 7777, ++count)
+    {
+      glong v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[1] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[2] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[3] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[4] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[5] = letters[v % NLETTERS];
+
+      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+
+      if (fd >= 0)
+       return fd;
+      else if (errno != EEXIST)
+       /* Any other error will apply also to other names we might
+        *  try, and there are 2^32 or so of them, so give up now.
+        */
+       return -1;
+    }
+
+  /* We got out of the loop because we ran out of combinations to try.  */
+  return -1;
+#endif
+}
+
+/**
+ * g_file_open_tmp:
+ * @tmpl: Template for file name, as in g_mkstemp, basename only
+ * @name_used: location to store actual name used
+ * @error: return location for a #GError
+ *
+ * Opens a file for writing in the preferred directory for temporary
+ * files (as returned by g_get_tmp_dir()). 
+ *
+ * @tmpl should be a string ending with six 'X' characters, as the
+ * parameter to g_mkstemp() (or mkstemp()). However, unlike these
+ * functions, the template should only be a basename, no directory
+ * components are allowed. If template is NULL, a default template is
+ * used.
+ *
+ * Note that in contrast to g_mkstemp() (and mkstemp()) @tmpl is not
+ * modified, and might thus be a read-only literal string.
+ *
+ * The actual name used is returned in @name_used if non-NULL. This
+ * string should be freed with g_free when not needed any longer.
+ *
+ * Return value: A file handle (as from open()) to the file
+ * opened for reading and writing. The file is opened in binary mode
+ * on platforms where there is a difference. The file handle should be
+ * closed with close(). In case of errors, -1 is returned and
+ * @error will be set.
+ **/
+int
+g_file_open_tmp (const char *tmpl,
+                char      **name_used,
+                GError    **error)
+{
+  int retval;
+  const char *tmpdir;
+  char *sep;
+  char *fulltemplate;
+
+  if (tmpl == NULL)
+    tmpl = ".XXXXXX";
+
+  if (strchr (tmpl, G_DIR_SEPARATOR)
+#ifdef G_OS_WIN32
+      || strchr (tmpl, '/')
+#endif
+                                   )
+    {
+      g_set_error (error,
+                  G_FILE_ERROR,
+                  G_FILE_ERROR_FAILED,
+                  _("Template '%s' illegal, should not contain a '%s'"),
+                  tmpl, G_DIR_SEPARATOR_S);
+
+      return -1;
+    }
+  
+  if (strlen (tmpl) < 6 ||
+      strcmp (tmpl + strlen (tmpl) - 6, "XXXXXX") != 0)
+    {
+      g_set_error (error,
+                  G_FILE_ERROR,
+                  G_FILE_ERROR_FAILED,
+                  _("Template '%s' doesn't end with XXXXXX"),
+                  tmpl);
+      return -1;
+    }
+
+  tmpdir = g_get_tmp_dir ();
+
+  if (tmpdir [strlen (tmpdir) - 1] == G_DIR_SEPARATOR)
+    sep = "";
+  else
+    sep = G_DIR_SEPARATOR_S;
+
+  fulltemplate = g_strconcat (tmpdir, sep, tmpl, NULL);
+
+  retval = g_mkstemp (fulltemplate);
+
+  if (retval == -1)
+    {
+      g_set_error (error,
+                  G_FILE_ERROR,
+                  g_file_error_from_errno (errno),
+                  _("Failed to create file '%s': %s"),
+                  fulltemplate, strerror (errno));
+      g_free (fulltemplate);
+      return -1;
+    }
+
+  if (name_used)
+    *name_used = fulltemplate;
+  else
+    g_free (fulltemplate);
+
+  return retval;
+}