d7b4489
From 7f4f4354540440c0a8a37beaccbec8bc7fc15ec7 Mon Sep 17 00:00:00 2001
d7b4489
From: Erik van Pienbroek <epienbro@fedoraproject.org>
d7b4489
Date: Mon, 27 Aug 2012 23:28:54 +0200
d7b4489
Subject: [PATCH] Use CreateFile on Win32 to make sure g_unlink always works
d7b4489
d7b4489
The functions g_open(), g_creat() and g_fopen() defer to _wopen(),
d7b4489
_wcreat() and _wfopen() respectively. This is very similar to
d7b4489
the corresponding arrangement for Linux. However, those Windows
d7b4489
functions do not support renaming a file whilst it's open. As a
d7b4489
result, g_rename() behaves differently on the Windows platform
d7b4489
compared to its Linux behaviour, where files can be renamed even
d7b4489
while there are file handles still open. Resolved this by using
d7b4489
the Win32 API function CreateFile() instead of _wopen(), _wcreat()
d7b4489
and _wfopen()
d7b4489
d7b4489
Patch initially created by John Emmas
d7b4489
---
Fabiano Fidêncio b4fa7ad
 glib/gstdio.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Fabiano Fidêncio b4fa7ad
 1 file changed, 235 insertions(+), 29 deletions(-)
d7b4489
d7b4489
diff --git a/glib/gstdio.c b/glib/gstdio.c
Fabiano Fidêncio b4fa7ad
index 653c8a3..26e8158 100644
d7b4489
--- a/glib/gstdio.c
d7b4489
+++ b/glib/gstdio.c
Fabiano Fidêncio b4fa7ad
@@ -1035,6 +1035,11 @@ g_open (const gchar *filename,
d7b4489
 	int          mode)
d7b4489
 {
d7b4489
 #ifdef G_OS_WIN32
d7b4489
+  HANDLE hFile;
d7b4489
+  DWORD  dwDesiredAccess       = 0;
d7b4489
+  DWORD  dwFlagsAndAttributes  = 0;
d7b4489
+  DWORD  dwDisposition         = OPEN_EXISTING;
d7b4489
+  DWORD  dwSharedAccess        = FILE_SHARE_READ | FILE_SHARE_DELETE;
d7b4489
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
d7b4489
   int retval;
d7b4489
   int save_errno;
Fabiano Fidêncio b4fa7ad
@@ -1045,12 +1050,114 @@ g_open (const gchar *filename,
d7b4489
       return -1;
d7b4489
     }
d7b4489
 
d7b4489
-  retval = _wopen (wfilename, flags, mode);
d7b4489
-  save_errno = errno;
d7b4489
+  /* Set up the access modes and other attributes */
d7b4489
+  if ((flags & _O_CREAT) && (mode & _S_IREAD))
d7b4489
+  {
d7b4489
+    if (! (mode & _S_IWRITE))
d7b4489
+      dwFlagsAndAttributes  = FILE_ATTRIBUTE_READONLY; /* Sets file to 'read only' after the file gets closed */
d7b4489
+  }
d7b4489
+  if ( !(flags & _O_ACCMODE))
d7b4489
+  {
d7b4489
+    /* Equates to _O_RDONLY */
d7b4489
+    if (flags & _O_TRUNC)
d7b4489
+	{
d7b4489
+	  errno = EINVAL;
d7b4489
+	  g_free (wfilename);
d7b4489
+	  return -1;
d7b4489
+	}
Fabiano Fidêncio b4fa7ad
+
d7b4489
+	dwDesiredAccess |= GENERIC_READ;
d7b4489
+	dwSharedAccess  |= FILE_SHARE_WRITE;
d7b4489
+  }
d7b4489
+  if (flags & _O_WRONLY)
d7b4489
+  {
d7b4489
+    if (flags & _O_RDWR)
d7b4489
+	{
d7b4489
+	  errno = EINVAL;
d7b4489
+	  g_free (wfilename);
d7b4489
+	  return -1;
d7b4489
+	}
e992e13
+
d7b4489
+	dwDesiredAccess |= GENERIC_WRITE;
d7b4489
+  }
d7b4489
+  if (flags & _O_RDWR)
d7b4489
+  {
d7b4489
+	dwDesiredAccess |= GENERIC_READ;
d7b4489
+	dwDesiredAccess |= GENERIC_WRITE;
d7b4489
+  }
d7b4489
+  if (flags & _O_TRUNC)
d7b4489
+  {
d7b4489
+    if (flags & _O_CREAT)
d7b4489
+	  dwDisposition = CREATE_ALWAYS;
d7b4489
+	else
d7b4489
+	  dwDisposition = TRUNCATE_EXISTING;
d7b4489
+  }
d7b4489
+  if ((flags & _O_CREAT) && !(flags & _O_TRUNC))
d7b4489
+  {
d7b4489
+    if (flags & _O_EXCL)
d7b4489
+	  dwDisposition = CREATE_NEW;
d7b4489
+	else
d7b4489
+	  dwDisposition = OPEN_ALWAYS;
d7b4489
+  }
d7b4489
+  if (flags & _O_CREAT)
d7b4489
+  {
d7b4489
+    /* Handle the other flags that can be attached to _O_CREAT */
d7b4489
+    if ((flags & _O_TEMPORARY) || (flags & _O_SHORT_LIVED))
d7b4489
+      dwFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY;
d7b4489
+
d7b4489
+    if (flags & _O_TEMPORARY)
d7b4489
+      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
d7b4489
+  }
d7b4489
+  if ((flags & _O_SEQUENTIAL) || (flags & _O_APPEND))
d7b4489
+  {
d7b4489
+    dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
d7b4489
+  }
d7b4489
+  else if (flags & _O_RANDOM)
d7b4489
+  {
d7b4489
+    dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
d7b4489
+  }
Fabiano Fidêncio b4fa7ad
 
Fabiano Fidêncio b4fa7ad
-  g_free (wfilename);
d7b4489
+  if (0 == dwFlagsAndAttributes)
d7b4489
+    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
d7b4489
+  hFile = CreateFileW(wfilename, dwDesiredAccess, dwSharedAccess, NULL, dwDisposition, dwFlagsAndAttributes, NULL);
d7b4489
+
d7b4489
+  if (INVALID_HANDLE_VALUE == hFile)
d7b4489
+  {
d7b4489
+    retval = (-1);
d7b4489
+
d7b4489
+    switch (GetLastError ())
d7b4489
+    {
d7b4489
+#define CASE(a,b) case ERROR_##a: errno = b; break
d7b4489
+      CASE (FILE_NOT_FOUND, ENOENT);
d7b4489
+      CASE (PATH_NOT_FOUND, ENOENT);
d7b4489
+      CASE (ACCESS_DENIED, EACCES);
d7b4489
+      CASE (NOT_SAME_DEVICE, EXDEV);
d7b4489
+      CASE (LOCK_VIOLATION, EACCES);
d7b4489
+      CASE (SHARING_VIOLATION, EACCES);
d7b4489
+      CASE (FILE_EXISTS, EEXIST);
d7b4489
+      CASE (ALREADY_EXISTS, EEXIST);
d7b4489
+#undef CASE
d7b4489
+      default: errno = EIO;
d7b4489
+    }
d7b4489
+  }
d7b4489
+  else
d7b4489
+    retval = _open_osfhandle((long)hFile, flags);
e992e13
 
d7b4489
+  if ((-1) != retval)
d7b4489
+  {
d7b4489
+    /* We have a valid file handle. Set its translation mode to text or binary, as appropriate */
d7b4489
+    if ((!(flags & _O_TEXT)) && (_fmode == _O_BINARY))
d7b4489
+      _setmode(retval, _O_BINARY);
d7b4489
+    else if ((flags & _O_TEXT) || (_fmode == _O_TEXT))
d7b4489
+      _setmode(retval, _O_TEXT);
d7b4489
+    else
d7b4489
+      _setmode(retval, _O_BINARY);
d7b4489
+  }
d7b4489
+
d7b4489
+  save_errno = errno;
d7b4489
+  g_free (wfilename);
d7b4489
   errno = save_errno;
d7b4489
+
d7b4489
   return retval;
d7b4489
 #else
ba6393e
   int fd;
Fabiano Fidêncio b4fa7ad
@@ -1098,6 +1205,8 @@ g_creat (const gchar *filename,
d7b4489
 	 int          mode)
d7b4489
 {
d7b4489
 #ifdef G_OS_WIN32
d7b4489
+  HANDLE hFile;
d7b4489
+  DWORD  dwFlagsAndAttributes  = FILE_ATTRIBUTE_NORMAL;
d7b4489
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
d7b4489
   int retval;
d7b4489
   int save_errno;
Fabiano Fidêncio b4fa7ad
@@ -1108,12 +1217,41 @@ g_creat (const gchar *filename,
d7b4489
       return -1;
d7b4489
     }
d7b4489
 
d7b4489
-  retval = _wcreat (wfilename, mode);
d7b4489
-  save_errno = errno;
d7b4489
+  if (mode & _S_IREAD)
d7b4489
+  {
d7b4489
+    if (! (mode & _S_IWRITE))
d7b4489
+      dwFlagsAndAttributes  = FILE_ATTRIBUTE_READONLY; /* Sets file to 'read only' after the file gets closed */
d7b4489
+  }
Fabiano Fidêncio b4fa7ad
 
Fabiano Fidêncio b4fa7ad
-  g_free (wfilename);
d7b4489
+  hFile = CreateFileW(wfilename, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_DELETE),
d7b4489
+                                  NULL, CREATE_ALWAYS, dwFlagsAndAttributes, NULL);
Fabiano Fidêncio b4fa7ad
 
d7b4489
+  if (INVALID_HANDLE_VALUE == hFile)
d7b4489
+  {
d7b4489
+    retval = (-1);
d7b4489
+
d7b4489
+    switch (GetLastError ())
d7b4489
+    {
d7b4489
+#define CASE(a,b) case ERROR_##a: errno = b; break
d7b4489
+      CASE (FILE_NOT_FOUND, ENOENT);
d7b4489
+      CASE (PATH_NOT_FOUND, ENOENT);
d7b4489
+      CASE (ACCESS_DENIED, EACCES);
d7b4489
+      CASE (NOT_SAME_DEVICE, EXDEV);
d7b4489
+      CASE (LOCK_VIOLATION, EACCES);
d7b4489
+      CASE (SHARING_VIOLATION, EACCES);
d7b4489
+      CASE (FILE_EXISTS, EEXIST);
d7b4489
+      CASE (ALREADY_EXISTS, EEXIST);
d7b4489
+#undef CASE
d7b4489
+      default: errno = EIO;
d7b4489
+    }
d7b4489
+  }
d7b4489
+  else
d7b4489
+    retval = _open_osfhandle((long)hFile, _O_RDWR);
Fabiano Fidêncio b4fa7ad
+
d7b4489
+  save_errno = errno;
Fabiano Fidêncio b4fa7ad
+  g_free (wfilename);
d7b4489
   errno = save_errno;
d7b4489
+
d7b4489
   return retval;
d7b4489
 #else
d7b4489
   return creat (filename, mode);
Fabiano Fidêncio b4fa7ad
@@ -1550,34 +1688,102 @@ g_fopen (const gchar *filename,
d7b4489
 	 const gchar *mode)
d7b4489
 {
d7b4489
 #ifdef G_OS_WIN32
d7b4489
-  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
d7b4489
-  wchar_t *wmode;
d7b4489
-  FILE *retval;
d7b4489
-  int save_errno;
Fabiano Fidêncio b4fa7ad
+  int   hFile;
Fabiano Fidêncio b4fa7ad
+  int   flags  = 0;
Fabiano Fidêncio b4fa7ad
+  gchar priv_mode[4];
Fabiano Fidêncio b4fa7ad
+  FILE *retval = NULL;
Fabiano Fidêncio b4fa7ad
 
d7b4489
-  if (wfilename == NULL)
e992e13
-    {
e992e13
-      errno = EINVAL;
e992e13
-      return NULL;
e992e13
-    }
d7b4489
+  if ((NULL == filename) || (NULL == mode))
d7b4489
+  {
d7b4489
+    errno = EINVAL;
d7b4489
+    goto out;
d7b4489
+  }
d7b4489
+  if ((strlen(mode) < 1) || (strlen(mode) > 3))
d7b4489
+  {
d7b4489
+    errno - EINVAL;
d7b4489
+    goto out;
d7b4489
+  }
Fabiano Fidêncio b4fa7ad
 
Fabiano Fidêncio b4fa7ad
-  wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
d7b4489
+  strncpy(priv_mode, mode, 3);
d7b4489
+  priv_mode[3] = '\0';
Fabiano Fidêncio b4fa7ad
 
Fabiano Fidêncio b4fa7ad
-  if (wmode == NULL)
d7b4489
+  /* Set up any flags to pass to 'g_open()' */
d7b4489
+  if (3 == strlen(priv_mode))
d7b4489
+  {
d7b4489
+    if (('c' == priv_mode[2]) || ('n' == priv_mode[2]))
d7b4489
+      priv_mode[2] = '\0';
d7b4489
+    else
Fabiano Fidêncio b4fa7ad
     {
Fabiano Fidêncio b4fa7ad
-      g_free (wfilename);
Fabiano Fidêncio b4fa7ad
-      errno = EINVAL;
Fabiano Fidêncio b4fa7ad
-      return NULL;
d7b4489
+      if (0 == strcmp(priv_mode, "a+b"))
d7b4489
+        flags = _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "a+t"))
d7b4489
+        flags = _O_RDWR | _O_CREAT | _O_APPEND | _O_TEXT;
d7b4489
+      else if (0 == strcmp(priv_mode, "r+b"))
d7b4489
+        flags = _O_RDWR | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "r+t"))
d7b4489
+        flags = _O_RDWR | _O_TEXT;
d7b4489
+      else if (0 == strcmp(priv_mode, "w+b"))
d7b4489
+        flags = _O_RDWR | _O_CREAT |_O_TRUNC | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "w+t"))
d7b4489
+        flags = _O_RDWR | _O_CREAT |_O_TRUNC | _O_TEXT;
d7b4489
+      else
d7b4489
+	  {
d7b4489
+	    errno = EINVAL;
d7b4489
+        goto out;
d7b4489
+	  }
Fabiano Fidêncio b4fa7ad
     }
Fabiano Fidêncio b4fa7ad
-
Fabiano Fidêncio b4fa7ad
-  _g_win32_fix_mode (wmode);
Fabiano Fidêncio b4fa7ad
-  retval = _wfopen (wfilename, wmode);
Fabiano Fidêncio b4fa7ad
-  save_errno = errno;
Fabiano Fidêncio b4fa7ad
-
Fabiano Fidêncio b4fa7ad
-  g_free (wfilename);
Fabiano Fidêncio b4fa7ad
-  g_free (wmode);
Fabiano Fidêncio b4fa7ad
-
Fabiano Fidêncio b4fa7ad
-  errno = save_errno;
d7b4489
+  }
d7b4489
+  if (2 == strlen(priv_mode))
d7b4489
+  {
d7b4489
+    if (('c' == priv_mode[1]) || ('n' == priv_mode[1]))
d7b4489
+      priv_mode[1] = '\0';
d7b4489
+    else
e992e13
+    {
d7b4489
+      if (0 == strcmp(priv_mode, "a+"))
d7b4489
+        flags = _O_RDWR | _O_CREAT | _O_APPEND;
d7b4489
+      else if (0 == strcmp(priv_mode, "ab"))
d7b4489
+        flags = _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "at"))
d7b4489
+        flags = _O_WRONLY | _O_CREAT | _O_APPEND | _O_TEXT;
d7b4489
+      else if (0 == strcmp(priv_mode, "rb"))
d7b4489
+        flags = _O_RDONLY | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "rt"))
d7b4489
+        flags = _O_RDONLY | _O_TEXT;
d7b4489
+      else if (0 == strcmp(priv_mode, "wb"))
d7b4489
+        flags = _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY;
d7b4489
+      else if (0 == strcmp(priv_mode, "wt"))
d7b4489
+        flags = _O_WRONLY | _O_CREAT | _O_TRUNC | _O_TEXT;
d7b4489
+      else
d7b4489
+	  {
d7b4489
+	    errno = EINVAL;
d7b4489
+        goto out;
d7b4489
+	  }
e992e13
+    }
d7b4489
+  }
d7b4489
+  if (1 == strlen(priv_mode))
d7b4489
+  {
d7b4489
+    if (0 == strcmp(priv_mode, "a"))
d7b4489
+      flags = _O_WRONLY | _O_CREAT | _O_APPEND;
d7b4489
+    else if (0 == strcmp(priv_mode, "r"))
d7b4489
+      flags = _O_RDONLY;
d7b4489
+    else if (0 == strcmp(priv_mode, "w"))
d7b4489
+      flags = _O_WRONLY | _O_CREAT | _O_TRUNC;
d7b4489
+    else if ( !((0 == strcmp(priv_mode, "c")) || (0 == strcmp(priv_mode, "n"))))
d7b4489
+	{
d7b4489
+	  errno = EINVAL;
d7b4489
+      goto out;
d7b4489
+	}
d7b4489
+  }
Fabiano Fidêncio b4fa7ad
+ 
d7b4489
+  hFile = g_open (filename, flags, (_S_IREAD | _S_IWRITE));
Fabiano Fidêncio b4fa7ad
+ 
d7b4489
+  if (INVALID_HANDLE_VALUE == (HANDLE)hFile)
d7b4489
+    /* 'errno' will have already been set by 'g_open()' */
d7b4489
+    retval = NULL;
d7b4489
+  else
d7b4489
+    retval = _fdopen(hFile, mode);
Fabiano Fidêncio b4fa7ad
+ 
d7b4489
+out:
d7b4489
   return retval;
d7b4489
 #else
d7b4489
   return fopen (filename, mode);