This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
38d96942 missed a side-effect in PerlIO_open flags parsing.
[perl5.git] / perlio.c
index 60b6a59..90622c1 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -117,8 +117,6 @@ extern off_t ftello(FILE *);
 #define NATIVE_0xd  CR_NATIVE
 #define NATIVE_0xa  LF_NATIVE
 
-#ifndef USE_SFIO
-
 EXTERN_C int perlsio_binmode(FILE *fp, int iotype, int mode);
 
 int
@@ -157,7 +155,6 @@ perlsio_binmode(FILE *fp, int iotype, int mode)
 #  endif
 #endif
 }
-#endif /* sfio */
 
 #ifndef O_ACCMODE
 #define O_ACCMODE 3             /* Assume traditional implementation */
@@ -202,8 +199,12 @@ PerlIO_intmode2str(int rawmode, char *mode, int *writing)
            mode[ix++] = '+';
        }
     }
+#if O_BINARY != 0
+    /* Unless O_BINARY is different from zero, bit-and:ing
+     * with it won't do much good. */
     if (rawmode & O_BINARY)
        mode[ix++] = 'b';
+# endif
     mode[ix] = '\0';
     return ptype;
 }
@@ -234,14 +235,7 @@ PerlIO_destruct(pTHX)
 int
 PerlIO_binmode(pTHX_ PerlIO *fp, int iotype, int mode, const char *names)
 {
-#ifdef USE_SFIO
-    PERL_UNUSED_ARG(iotype);
-    PERL_UNUSED_ARG(mode);
-    PERL_UNUSED_ARG(names);
-    return 1;
-#else
     return perlsio_binmode(fp, iotype, mode);
-#endif
 }
 
 PerlIO *
@@ -320,6 +314,7 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
     return NULL;
 }
 
+XS(XS_PerlIO__Layer__find); /* prototype to pass -Wmissing-prototypes */
 XS(XS_PerlIO__Layer__find)
 {
     dXSARGS;
@@ -366,67 +361,6 @@ PerlIO_tmpfile(void)
 
 #else                           /* PERLIO_IS_STDIO */
 
-#ifdef USE_SFIO
-
-#undef HAS_FSETPOS
-#undef HAS_FGETPOS
-
-/*
- * This section is just to make sure these functions get pulled in from
- * libsfio.a
- */
-
-#undef PerlIO_tmpfile
-PerlIO *
-PerlIO_tmpfile(void)
-{
-    return sftmp(0);
-}
-
-void
-PerlIO_init(pTHX)
-{
-    PERL_UNUSED_CONTEXT;
-    /*
-     * Force this file to be included in perl binary. Which allows this
-     * file to force inclusion of other functions that may be required by
-     * loadable extensions e.g. for FileHandle::tmpfile
-     */
-
-    /*
-     * Hack sfio does its own 'autoflush' on stdout in common cases. Flush
-     * results in a lot of lseek()s to regular files and lot of small
-     * writes to pipes.
-     */
-    sfset(sfstdout, SF_SHARE, 0);
-}
-
-/* This is not the reverse of PerlIO_exportFILE(), PerlIO_releaseFILE() is. */
-PerlIO *
-PerlIO_importFILE(FILE *stdio, const char *mode)
-{
-    const int fd = fileno(stdio);
-    if (!mode || !*mode) {
-       mode = "r+";
-    }
-    return PerlIO_fdopen(fd, mode);
-}
-
-FILE *
-PerlIO_findFILE(PerlIO *pio)
-{
-    const int fd = PerlIO_fileno(pio);
-    FILE * const f = fdopen(fd, "r+");
-    PerlIO_flush(pio);
-    if (!f && errno == EINVAL)
-       f = fdopen(fd, "w");
-    if (!f && errno == EINVAL)
-       f = fdopen(fd, "r");
-    return f;
-}
-
-
-#else                           /* USE_SFIO */
 /*======================================================================================*/
 /*
  * Implement all the PerlIO interface ourselves.
@@ -463,7 +397,7 @@ PerlIO_debug(const char *fmt, ...)
        char buffer[1024];
        const STRLEN len1 = my_snprintf(buffer, sizeof(buffer), "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
        const STRLEN len2 = my_vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
-       (void)PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2);
+       PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2));
 #else
        const char *s = CopFILE(PL_curcop);
        STRLEN len;
@@ -472,7 +406,7 @@ PerlIO_debug(const char *fmt, ...)
        Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap);
 
        s = SvPV_const(sv, len);
-       (void)PerlLIO_write(PL_perlio_debug_fd, s, len);
+       PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, s, len));
        SvREFCNT_dec(sv);
 #endif
     }
@@ -886,6 +820,7 @@ MGVTBL perlio_vtab = {
     perlio_mg_free
 };
 
+XS(XS_io_MODIFY_SCALAR_ATTRIBUTES); /* prototype to pass -Wmissing-prototypes */
 XS(XS_io_MODIFY_SCALAR_ATTRIBUTES)
 {
     dXSARGS;
@@ -926,6 +861,7 @@ PerlIO_tab_sv(pTHX_ PerlIO_funcs *tab)
     return sv;
 }
 
+XS(XS_PerlIO__Layer__NoWarnings); /* prototype to pass -Wmissing-prototypes */
 XS(XS_PerlIO__Layer__NoWarnings)
 {
     /* This is used as a %SIG{__WARN__} handler to suppress warnings
@@ -939,6 +875,7 @@ XS(XS_PerlIO__Layer__NoWarnings)
     XSRETURN(0);
 }
 
+XS(XS_PerlIO__Layer__find); /* prototype to pass -Wmissing-prototypes */
 XS(XS_PerlIO__Layer__find)
 {
     dVAR;
@@ -2289,6 +2226,7 @@ PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags)
        PerlIO_funcs * const self = PerlIOBase(o)->tab;
        SV *arg = NULL;
        char buf[8];
+       assert(self);
        PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n",
                     self ? self->name : "(Null)",
                     (void*)f, (void*)o, (void*)param);
@@ -2593,24 +2531,41 @@ PerlIOUnix_oflags(const char *mode)
            oflags |= O_WRONLY;
        break;
     }
-    if (*mode == 'b') {
-       oflags |= O_BINARY;
+
+    /* XXX TODO: PerlIO_open() test that exercises 'rb' and 'rt'. */
+
+    /* Unless O_BINARY is different from O_TEXT, first bit-or:ing one
+     * of them in, and then bit-and-masking the other them away, won't
+     * have much of an effect. */
+    switch (*mode) {
+    case 'b':
+#if O_TEXT != O_BINARY
+        oflags |= O_BINARY;
        oflags &= ~O_TEXT;
-       mode++;
-    }
-    else if (*mode == 't') {
+#endif
+        mode++;
+        break;
+    case 't':
+#if O_TEXT != O_BINARY
        oflags |= O_TEXT;
        oflags &= ~O_BINARY;
-       mode++;
-    }
-    else {
-#ifdef PERLIO_USING_CRLF
+#endif
+        mode++;
+        break;
+    default:
+#  if O_BINARY != 0
+        /* bit-or:ing with zero O_BINARY would be useless. */
        /*
         * If neither "t" nor "b" was specified, open the file
         * in O_BINARY mode.
+         *
+         * Note that if something else than the zero byte was seen
+         * here (e.g. bogus mode "rx"), just few lines later we will
+         * set the errno and invalidate the flags.
         */
        oflags |= O_BINARY;
-#endif
+#  endif
+        break;
     }
     if (*mode || oflags == -1) {
        SETERRNO(EINVAL, LIB_INVARG);
@@ -2725,6 +2680,7 @@ PerlIOUnix_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
        }
        if (!PerlIOValid(f)) {
            if (!(f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) {
+               PerlLIO_close(fd);
                return NULL;
            }
        }
@@ -2760,6 +2716,7 @@ PerlIOUnix_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags)
            PerlIOUnix_setfd(aTHX_ f, fd, os->oflags);
            return f;
        }
+        PerlLIO_close(fd);
     }
     return NULL;
 }
@@ -2969,6 +2926,7 @@ PerlIOStdio_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab
                PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
                /* We never call down so do any pending stuff now */
                PerlIO_flush(PerlIONext(f));
+                return PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
            }
            else {
                return -1;
@@ -2986,6 +2944,10 @@ PerlIO_importFILE(FILE *stdio, const char *mode)
     PerlIO *f = NULL;
     if (stdio) {
        PerlIOStdio *s;
+        int fd0 = fileno(stdio);
+        if (fd0 < 0) {
+            return NULL;
+        }
        if (!mode || !*mode) {
            /* We need to probe to see how we can open the stream
               so start with read/write and then try write and read
@@ -2994,8 +2956,12 @@ PerlIO_importFILE(FILE *stdio, const char *mode)
               Note that the errno value set by a failing fdopen
               varies between stdio implementations.
             */
-           const int fd = PerlLIO_dup(fileno(stdio));
-           FILE *f2 = PerlSIO_fdopen(fd, (mode = "r+"));
+            const int fd = PerlLIO_dup(fd0);
+           FILE *f2;
+            if (fd < 0) {
+                return f;
+            }
+           f2 = PerlSIO_fdopen(fd, (mode = "r+"));
            if (!f2) {
                f2 = PerlSIO_fdopen(fd, (mode = "w"));
            }
@@ -3009,7 +2975,7 @@ PerlIO_importFILE(FILE *stdio, const char *mode)
            }
            fclose(f2);
        }
-       if ((f = PerlIO_push(aTHX_(f = PerlIO_allocate(aTHX)), PERLIO_FUNCS_CAST(&PerlIO_stdio), mode, NULL))) {
+       if ((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)), PERLIO_FUNCS_CAST(&PerlIO_stdio), mode, NULL))) {
            s = PerlIOSelf(f, PerlIOStdio);
            s->stdio = stdio;
            PerlIOUnix_refcnt_inc(fileno(stdio));
@@ -3032,8 +2998,8 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
        if (!IS_SAFE_PATHNAME(path, len, "open"))
             return NULL;
        PerlIOUnix_refcnt_dec(fileno(s->stdio));
-       stdio = PerlSIO_freopen(path, (mode = PerlIOStdio_mode(mode, tmode)),
-                           s->stdio);
+       stdio = PerlSIO_freopen(path, PerlIOStdio_mode(mode, tmode),
+                                s->stdio);
        if (!s->stdio)
            return NULL;
        s->stdio = stdio;
@@ -3113,6 +3079,7 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers,
                }
                return f;
            }
+            PerlLIO_close(fd);
        }
     }
     return NULL;
@@ -3414,8 +3381,8 @@ PerlIOStdio_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
            }
            if ((STDCHAR*)PerlSIO_get_ptr(s) != --eptr || ((*eptr & 0xFF) != ch)) {
                /* Did not change pointer as expected */
-               fgetc(s);  /* get char back again */
-               break;
+               if (fgetc(s) != EOF)  /* get char back again */
+                    break;
            }
            /* It worked ! */
            count--;
@@ -3731,6 +3698,10 @@ PerlIO_exportFILE(PerlIO * f, const char *mode)
     FILE *stdio = NULL;
     if (PerlIOValid(f)) {
        char buf[8];
+        int fd = PerlIO_fileno(f);
+        if (fd < 0) {
+            return NULL;
+        }
        PerlIO_flush(f);
        if (!mode || !*mode) {
            mode = PerlIO_modestr(f, buf);
@@ -4973,6 +4944,7 @@ PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap)
     va_list apc;
     Perl_va_copy(ap, apc);
     sv = vnewSVpvf(fmt, &apc);
+    va_end(apc);
 #else
     sv = vnewSVpvf(fmt, &ap);
 #endif
@@ -5025,6 +4997,7 @@ PerlIO_tmpfile(void)
      char tempname[] = "/tmp/PerlIO_XXXXXX";
      const char * const tmpdir = TAINTING_get ? NULL : PerlEnv_getenv("TMPDIR");
      SV * sv = NULL;
+     int old_umask = umask(0600);
      /*
       * I have no idea how portable mkstemp() is ... NI-S
       */
@@ -5035,10 +5008,18 @@ PerlIO_tmpfile(void)
         fd = mkstemp(SvPVX(sv));
      }
      if (fd < 0) {
+        SvREFCNT_dec(sv);
         sv = NULL;
         /* else we try /tmp */
         fd = mkstemp(tempname);
      }
+     if (fd < 0) {
+         /* Try cwd */
+         sv = newSVpvs(".");
+         sv_catpv(sv, tempname + 4);
+         fd = mkstemp(SvPVX(sv));
+     }
+     umask(old_umask);
      if (fd >= 0) {
          f = PerlIO_fdopen(fd, "w+");
          if (f)
@@ -5060,7 +5041,6 @@ PerlIO_tmpfile(void)
 #undef HAS_FSETPOS
 #undef HAS_FGETPOS
 
-#endif                          /* USE_SFIO */
 #endif                          /* PERLIO_IS_STDIO */
 
 /*======================================================================================*/
@@ -5163,7 +5143,7 @@ PerlIO_getpos(PerlIO *f, SV *pos)
 }
 #endif
 
-#if (defined(PERLIO_IS_STDIO) || !defined(USE_SFIO)) && !defined(HAS_VPRINTF)
+#if !defined(HAS_VPRINTF)
 
 int
 vprintf(char *pat, char *args)