diff mbox

Implement tmpfile with O_TMPFILE (bug 21530)

Message ID mvmbmpbotr9.fsf@suse.de
State New
Headers show

Commit Message

Andreas Schwab June 26, 2017, 11:47 a.m. UTC
If the kernel or the file system does not support O_TMPFILE fall back to
creating a temporary file based on tmpnam.

	[BZ #21530]
	* stdio-common/tmpfile.c (tmpfile) [O_TMPFILE]: Try opening an
	unnamed file first.
---
 stdio-common/tmpfile.c | 51 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 14 deletions(-)
diff mbox

Patch

diff --git a/stdio-common/tmpfile.c b/stdio-common/tmpfile.c
index e6030be0af..5505d6f571 100644
--- a/stdio-common/tmpfile.c
+++ b/stdio-common/tmpfile.c
@@ -18,6 +18,8 @@ 
 
 #include <fcntl.h>
 #include <stdio.h>
+#include <string.h>
+#include <errno.h>
 #include <unistd.h>
 
 #include <iolibio.h>
@@ -27,30 +29,51 @@ 
 #endif
 
 
-/* This returns a new stream opened on a temporary file (generated
-   by tmpnam).  The file is opened with mode "w+b" (binary read/write).
-   If we couldn't generate a unique filename or the file couldn't
-   be opened, NULL is returned.  */
+/* This returns a new stream opened on an unnamed file (if supported) or a
+   temporary file (generated by tmpnam).  The file is opened with mode
+   "w+b" (binary read/write).  If we couldn't generate a unique filename
+   or the file couldn't be opened, NULL is returned.  */
 FILE *
 tmpfile (void)
 {
-  char buf[FILENAME_MAX];
-  int fd;
+  int fd = -1;
   FILE *f;
-
-  if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0))
-    return NULL;
   int flags = 0;
 #ifdef FLAGS
   flags = FLAGS;
 #endif
-  fd = __gen_tempname (buf, 0, flags, __GT_FILE);
+
+#ifdef O_TMPFILE
+  fd = __open (P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL | flags,
+	       S_IRUSR | S_IWUSR);
+  if (fd < 0 && errno == ENOENT && strcmp (P_tmpdir, "/tmp") != 0)
+    fd = __open ("/tmp", O_RDWR | O_TMPFILE | O_EXCL | flags,
+		 S_IRUSR | S_IWUSR);
   if (fd < 0)
-    return NULL;
+    {
+      if (errno != EISDIR && errno != EOPNOTSUPP)
+	return NULL;
 
-  /* Note that this relies on the Unix semantics that
-     a file is not really removed until it is closed.  */
-  (void) __unlink (buf);
+      /* Either O_TMPFILE is unknown to the kernel, or the file system
+	 does not support it.  */
+    }
+#endif
+  if (fd < 0)
+    {
+      char buf[FILENAME_MAX];
+
+      if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0))
+	return NULL;
+      fd = __gen_tempname (buf, 0, flags, __GT_FILE);
+
+      if (fd >= 0)
+	/* Note that this relies on the Unix semantics that
+	   a file is not really removed until it is closed.  */
+	(void) __unlink (buf);
+    }
+
+  if (fd < 0)
+    return NULL;
 
   if ((f = __fdopen (fd, "w+b")) == NULL)
     __close (fd);