78f1eb
From 74b421cc877e412c4eda06757396a1e19fc756ba Mon Sep 17 00:00:00 2001
78f1eb
From: Tony Cook <tony@develop-help.com>
78f1eb
Date: Mon, 15 Jul 2019 11:53:23 +1000
78f1eb
Subject: [PATCH 3/3] (perl #134221) support O_APPEND for open ..., undef on
78f1eb
 VMS
78f1eb
MIME-Version: 1.0
78f1eb
Content-Type: text/plain; charset=UTF-8
78f1eb
Content-Transfer-Encoding: 8bit
78f1eb
78f1eb
VMS doesn't allow you to delete an open file like POSIXish systems
78f1eb
do, but you can mark a file to be deleted once it's closed, but
78f1eb
only when you open it.
78f1eb
78f1eb
Since VMS doesn't (yet) have mkostemp() we can add our own flag to
78f1eb
our mkostemp() emulation to pass the necessary magic to open() call
78f1eb
to delete the file on close.
78f1eb
78f1eb
Signed-off-by: Petr Písař <ppisar@redhat.com>
78f1eb
---
78f1eb
 perlio.c | 10 ++++++----
78f1eb
 util.c   | 15 ++++++++++++++-
78f1eb
 util.h   | 11 +++++++++++
78f1eb
 3 files changed, 31 insertions(+), 5 deletions(-)
78f1eb
78f1eb
diff --git a/perlio.c b/perlio.c
78f1eb
index 81ebc156ad..805959f840 100644
78f1eb
--- a/perlio.c
78f1eb
+++ b/perlio.c
78f1eb
@@ -5062,7 +5062,7 @@ PerlIO_tmpfile_flags(int imode)
78f1eb
      const int fd = win32_tmpfd_mode(imode);
78f1eb
      if (fd >= 0)
78f1eb
 	  f = PerlIO_fdopen(fd, "w+b");
78f1eb
-#elif ! defined(VMS) && ! defined(OS2)
78f1eb
+#elif ! defined(OS2)
78f1eb
      int fd = -1;
78f1eb
      char tempname[] = "/tmp/PerlIO_XXXXXX";
78f1eb
      const char * const tmpdir = TAINTING_get ? NULL : PerlEnv_getenv("TMPDIR");
78f1eb
@@ -5073,19 +5073,19 @@ PerlIO_tmpfile_flags(int imode)
78f1eb
 	 /* if TMPDIR is set and not empty, we try that first */
78f1eb
 	 sv = newSVpv(tmpdir, 0);
78f1eb
 	 sv_catpv(sv, tempname + 4);
78f1eb
-	 fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode);
78f1eb
+	 fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode | O_VMS_DELETEONCLOSE);
78f1eb
      }
78f1eb
      if (fd < 0) {
78f1eb
 	 SvREFCNT_dec(sv);
78f1eb
 	 sv = NULL;
78f1eb
 	 /* else we try /tmp */
78f1eb
-	 fd = Perl_my_mkostemp_cloexec(tempname, imode);
78f1eb
+	 fd = Perl_my_mkostemp_cloexec(tempname, imode | O_VMS_DELETEONCLOSE);
78f1eb
      }
78f1eb
      if (fd < 0) {
78f1eb
          /* Try cwd */
78f1eb
          sv = newSVpvs(".");
78f1eb
          sv_catpv(sv, tempname + 4);
78f1eb
-         fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode);
78f1eb
+         fd = Perl_my_mkostemp_cloexec(SvPVX(sv), imode | O_VMS_DELETEONCLOSE);
78f1eb
      }
78f1eb
      umask(old_umask);
78f1eb
      if (fd >= 0) {
78f1eb
@@ -5096,7 +5096,9 @@ PerlIO_tmpfile_flags(int imode)
78f1eb
          f = PerlIO_fdopen(fd, mode);
78f1eb
 	  if (f)
78f1eb
 	       PerlIOBase(f)->flags |= PERLIO_F_TEMP;
78f1eb
+#   ifndef VMS
78f1eb
 	  PerlLIO_unlink(sv ? SvPVX_const(sv) : tempname);
78f1eb
+#   endif
78f1eb
      }
78f1eb
      SvREFCNT_dec(sv);
78f1eb
 #else	/* !HAS_MKSTEMP, fallback to stdio tmpfile(). */
78f1eb
diff --git a/util.c b/util.c
78f1eb
index e6863f6dfe..165d13a39e 100644
78f1eb
--- a/util.c
78f1eb
+++ b/util.c
78f1eb
@@ -5712,6 +5712,11 @@ S_my_mkostemp(char *templte, int flags) {
78f1eb
     STRLEN len = strlen(templte);
78f1eb
     int fd;
78f1eb
     int attempts = 0;
78f1eb
+#ifdef VMS
78f1eb
+    int delete_on_close = flags & O_VMS_DELETEONCLOSE;
78f1eb
+
78f1eb
+    flags &= ~O_VMS_DELETEONCLOSE;
78f1eb
+#endif
78f1eb
 
78f1eb
     if (len < 6 ||
78f1eb
         templte[len-1] != 'X' || templte[len-2] != 'X' || templte[len-3] != 'X' ||
78f1eb
@@ -5725,7 +5730,15 @@ S_my_mkostemp(char *templte, int flags) {
78f1eb
         for (i = 1; i <= 6; ++i) {
78f1eb
             templte[len-i] = TEMP_FILE_CH[(int)(Perl_internal_drand48() * TEMP_FILE_CH_COUNT)];
78f1eb
         }
78f1eb
-        fd = PerlLIO_open3(templte, O_RDWR | O_CREAT | O_EXCL | flags, 0600);
78f1eb
+#ifdef VMS
78f1eb
+        if (delete_on_close) {
78f1eb
+            fd = open(templte, O_RDWR | O_CREAT | O_EXCL | flags, 0600, "fop=dlt");
78f1eb
+        }
78f1eb
+        else
78f1eb
+#endif
78f1eb
+        {
78f1eb
+            fd = PerlLIO_open3(templte, O_RDWR | O_CREAT | O_EXCL | flags, 0600);
78f1eb
+        }
78f1eb
     } while (fd == -1 && errno == EEXIST && ++attempts <= 100);
78f1eb
 
78f1eb
     return fd;
78f1eb
diff --git a/util.h b/util.h
78f1eb
index d8fa3e8396..d9df7b39c6 100644
78f1eb
--- a/util.h
78f1eb
+++ b/util.h
78f1eb
@@ -248,6 +248,17 @@ means arg not present, 1 is empty string/null byte */
78f1eb
 int mkstemp(char*);
78f1eb
 #endif
78f1eb
 
78f1eb
+#ifdef PERL_CORE
78f1eb
+#   if defined(VMS)
78f1eb
+/* only useful for calls to our mkostemp() emulation */
78f1eb
+#       define O_VMS_DELETEONCLOSE 0x40000000
78f1eb
+#       ifdef HAS_MKOSTEMP
78f1eb
+#           error 134221 will need a new solution for VMS
78f1eb
+#       endif
78f1eb
+#   else
78f1eb
+#       define O_VMS_DELETEONCLOSE 0
78f1eb
+#   endif
78f1eb
+#endif
78f1eb
 #if defined(HAS_MKOSTEMP) && defined(PERL_CORE)
78f1eb
 #   define Perl_my_mkostemp(templte, flags) mkostemp(templte, flags)
78f1eb
 #endif
78f1eb
-- 
78f1eb
2.20.1
78f1eb