This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Test if the probed availability of v?snprintf () is
[perl5.git] / doio.c
diff --git a/doio.c b/doio.c
index 7010238..f9a07fb 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1,7 +1,7 @@
 /*    doio.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 #include <signal.h>
 
 bool
-Perl_do_open(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
-            int rawmode, int rawperm, PerlIO *supplied_fp)
-{
-    return do_openn(gv, name, len, as_raw, rawmode, rawperm,
-                   supplied_fp, (SV **) NULL, 0);
-}
-
-bool
-Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
-             int rawmode, int rawperm, PerlIO *supplied_fp, SV *svs,
-             I32 num_svs)
-{
-    (void)num_svs;
-    return do_openn(gv, name, len, as_raw, rawmode, rawperm,
-                   supplied_fp, &svs, 1);
-}
-
-bool
-Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
+Perl_do_openn(pTHX_ GV *gv, register const char *oname, I32 len, int as_raw,
              int rawmode, int rawperm, PerlIO *supplied_fp, SV **svp,
              I32 num_svs)
 {
     dVAR;
-    register IO *io = GvIOn(gv);
+    register IO * const io = GvIOn(gv);
     PerlIO *saveifp = Nullfp;
     PerlIO *saveofp = Nullfp;
     int savefd = -1;
@@ -194,7 +176,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
 
         IoTYPE(io) = PerlIO_intmode2str(rawmode, &mode[ix], &writing);
 
-       namesv = sv_2mortal(newSVpvn(name,strlen(name)));
+       namesv = sv_2mortal(newSVpv(oname,0));
        num_svs = 1;
        svp = &namesv;
         type = Nullch;
@@ -202,13 +184,13 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
     }
     else {
        /* Regular (non-sys) open */
-       char *oname = name;
+       char *name;
        STRLEN olen = len;
        char *tend;
        int dodup = 0;
        PerlIO *that_fp = NULL;
 
-       type = savepvn(name, len);
+       type = savepvn(oname, len);
        tend = type+len;
        SAVEFREEPV(type);
 
@@ -220,7 +202,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
        if (num_svs) {
            /* New style explicit name, type is just mode and layer info */
 #ifdef USE_STDIO
-           if (SvROK(*svp) && !strchr(name,'&')) {
+           if (SvROK(*svp) && !strchr(oname,'&')) {
                if (ckWARN(WARN_IO))
                    Perl_warner(aTHX_ packWARN(WARN_IO),
                            "Can't open a reference");
@@ -354,7 +336,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                        }
                        else {
                            GV *thatgv;
-                           thatgv = gv_fetchpv(type,FALSE,SVt_PVIO);
+                           thatgv = gv_fetchpv(type,0,SVt_PVIO);
                            thatio = GvIO(thatgv);
                        }
                        if (!thatio) {
@@ -372,7 +354,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
 #ifdef USE_SFIO
                            /* sfio fails to clear error on next
                               sfwrite, contrary to documentation.
-                              -- Nick Clark */
+                              -- Nicholas Clark */
                            if (PerlIO_seek(that_fp, 0, SEEK_CUR) == -1)
                                PerlIO_clearerr(that_fp);
 #endif
@@ -408,7 +390,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                        else
                            was_fdopen = TRUE;
                        if (!(fp = PerlIO_openn(aTHX_ type,mode,fd,0,0,NULL,num_svs,svp))) {
-                           if (dodup)
+                           if (dodup && fd >= 0)
                                PerlLIO_close(fd);
                        }
                    }
@@ -426,7 +408,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                }
                else  {
                    if (!num_svs) {
-                       namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                       namesv = sv_2mortal(newSVpvn(type,tend - type));
                        num_svs = 1;
                        svp = &namesv;
                        type = Nullch;
@@ -464,7 +446,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            }
            else {
                if (!num_svs) {
-                   namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                   namesv = sv_2mortal(newSVpvn(type,tend - type));
                    num_svs = 1;
                    svp = &namesv;
                    type = Nullch;
@@ -556,7 +538,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            }
            else {
                if (!num_svs) {
-                   namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                   namesv = sv_2mortal(newSVpvn(type,tend - type));
                    num_svs = 1;
                    svp = &namesv;
                    type = Nullch;
@@ -566,7 +548,10 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
        }
     }
     if (!fp) {
-       if (ckWARN(WARN_NEWLINE) && IoTYPE(io) == IoTYPE_RDONLY && strchr(name, '\n'))
+       if (IoTYPE(io) == IoTYPE_RDONLY && ckWARN(WARN_NEWLINE)
+           && strchr(oname, '\n')
+           
+       )
            Perl_warner(aTHX_ packWARN(WARN_NEWLINE), PL_warn_nl, "open");
        goto say_false;
     }
@@ -701,7 +686,7 @@ Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
     }
 #if defined(HAS_FCNTL) && defined(F_SETFD)
     if (fd >= 0) {
-       int save_errno = errno;
+       const int save_errno = errno;
        fcntl(fd,F_SETFD,fd > PL_maxsysfd); /* can change errno */
        errno = save_errno;
     }
@@ -744,7 +729,7 @@ Perl_nextargv(pTHX_ register GV *gv)
 #endif
     Uid_t fileuid;
     Gid_t filegid;
-    IO *io = GvIOp(gv);
+    IO * const io = GvIOp(gv);
 
     if (!PL_argvoutgv)
        PL_argvoutgv = gv_fetchpv("ARGVOUT",TRUE,SVt_PVIO);
@@ -773,7 +758,7 @@ Perl_nextargv(pTHX_ register GV *gv)
        STRLEN oldlen;
        sv = av_shift(GvAV(gv));
        SAVEFREESV(sv);
-       sv_setsv(GvSV(gv),sv);
+       sv_setsv(GvSVn(gv),sv);
        SvSETMAGIC(GvSV(gv));
        PL_oldname = SvPVx(GvSV(gv), oldlen);
        if (do_open(gv,PL_oldname,oldlen,PL_inplace!=0,O_RDONLY,0,Nullfp)) {
@@ -799,9 +784,9 @@ Perl_nextargv(pTHX_ register GV *gv)
                    continue;
                }
                if (*PL_inplace) {
-                   char *star = strchr(PL_inplace, '*');
+                   const char *star = strchr(PL_inplace, '*');
                    if (star) {
-                       char *begin = PL_inplace;
+                       const char *begin = PL_inplace;
                        sv_setpvn(sv, "", 0);
                        do {
                            sv_catpvn(sv, begin, star - begin);
@@ -952,52 +937,6 @@ Perl_nextargv(pTHX_ register GV *gv)
     return Nullfp;
 }
 
-#ifdef HAS_PIPE
-void
-Perl_do_pipe(pTHX_ SV *sv, GV *rgv, GV *wgv)
-{
-    register IO *rstio;
-    register IO *wstio;
-    int fd[2];
-
-    if (!rgv)
-       goto badexit;
-    if (!wgv)
-       goto badexit;
-
-    rstio = GvIOn(rgv);
-    wstio = GvIOn(wgv);
-
-    if (IoIFP(rstio))
-       do_close(rgv,FALSE);
-    if (IoIFP(wstio))
-       do_close(wgv,FALSE);
-
-    if (PerlProc_pipe(fd) < 0)
-       goto badexit;
-    IoIFP(rstio) = PerlIO_fdopen(fd[0], "r"PIPE_OPEN_MODE);
-    IoOFP(wstio) = PerlIO_fdopen(fd[1], "w"PIPE_OPEN_MODE);
-    IoOFP(rstio) = IoIFP(rstio);
-    IoIFP(wstio) = IoOFP(wstio);
-    IoTYPE(rstio) = IoTYPE_RDONLY;
-    IoTYPE(wstio) = IoTYPE_WRONLY;
-    if (!IoIFP(rstio) || !IoOFP(wstio)) {
-       if (IoIFP(rstio)) PerlIO_close(IoIFP(rstio));
-       else PerlLIO_close(fd[0]);
-       if (IoOFP(wstio)) PerlIO_close(IoOFP(wstio));
-       else PerlLIO_close(fd[1]);
-       goto badexit;
-    }
-
-    sv_setsv(sv,&PL_sv_yes);
-    return;
-
-badexit:
-    sv_setsv(sv,&PL_sv_undef);
-    return;
-}
-#endif
-
 /* explicit renamed to avoid C++ conflict    -- kja */
 bool
 Perl_do_close(pTHX_ GV *gv, bool not_implicit)
@@ -1040,7 +979,7 @@ Perl_io_close(pTHX_ IO *io, bool not_implicit)
        if (IoTYPE(io) == IoTYPE_PIPE) {
            const int status = PerlProc_pclose(IoIFP(io));
            if (not_implicit) {
-               STATUS_NATIVE_SET(status);
+               STATUS_NATIVE_CHILD_SET(status);
                retval = (STATUS_UNIX == 0);
            }
            else {
@@ -1051,12 +990,12 @@ Perl_io_close(pTHX_ IO *io, bool not_implicit)
            retval = TRUE;
        else {
            if (IoOFP(io) && IoOFP(io) != IoIFP(io)) {          /* a socket */
-               bool prev_err = PerlIO_error(IoOFP(io));
+               const bool prev_err = PerlIO_error(IoOFP(io));
                retval = (PerlIO_close(IoOFP(io)) != EOF && !prev_err);
                PerlIO_close(IoIFP(io));        /* clear stdio, fd already closed */
            }
            else {
-               bool prev_err = PerlIO_error(IoIFP(io));
+               const bool prev_err = PerlIO_error(IoIFP(io));
                retval = (PerlIO_close(IoIFP(io)) != EOF && !prev_err);
            }
        }
@@ -1072,32 +1011,30 @@ Perl_io_close(pTHX_ IO *io, bool not_implicit)
 bool
 Perl_do_eof(pTHX_ GV *gv)
 {
-    register IO *io;
-    int ch;
-
-    io = GvIO(gv);
+    register IO * const io = GvIO(gv);
 
     if (!io)
        return TRUE;
-    else if (ckWARN(WARN_IO) && (IoTYPE(io) == IoTYPE_WRONLY))
+    else if ((IoTYPE(io) == IoTYPE_WRONLY) && ckWARN(WARN_IO))
        report_evil_fh(gv, io, OP_phoney_OUTPUT_ONLY);
 
     while (IoIFP(io)) {
-        int saverrno;
-
         if (PerlIO_has_cntptr(IoIFP(io))) {    /* (the code works without this) */
            if (PerlIO_get_cnt(IoIFP(io)) > 0)  /* cheat a little, since */
                return FALSE;                   /* this is the most usual case */
         }
 
-       saverrno = errno; /* getc and ungetc can stomp on errno */
-       ch = PerlIO_getc(IoIFP(io));
-       if (ch != EOF) {
-           (void)PerlIO_ungetc(IoIFP(io),ch);
+       {
+            /* getc and ungetc can stomp on errno */
+           const int saverrno = errno;
+           const int ch = PerlIO_getc(IoIFP(io));
+           if (ch != EOF) {
+               (void)PerlIO_ungetc(IoIFP(io),ch);
+               errno = saverrno;
+               return FALSE;
+           }
            errno = saverrno;
-           return FALSE;
        }
-       errno = saverrno;
 
         if (PerlIO_has_cntptr(IoIFP(io)) && PerlIO_canset_cnt(IoIFP(io))) {
            if (PerlIO_get_cnt(IoIFP(io)) < -1)
@@ -1116,7 +1053,7 @@ Perl_do_eof(pTHX_ GV *gv)
 Off_t
 Perl_do_tell(pTHX_ GV *gv)
 {
-    register IO *io = 0;
+    register IO *io = NULL;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io))) {
@@ -1135,7 +1072,7 @@ Perl_do_tell(pTHX_ GV *gv)
 bool
 Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
 {
-    register IO *io = 0;
+    register IO *io = NULL;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io))) {
@@ -1154,7 +1091,7 @@ Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
 Off_t
 Perl_do_sysseek(pTHX_ GV *gv, Off_t pos, int whence)
 {
-    register IO *io = 0;
+    register IO *io = NULL;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io)))
@@ -1221,20 +1158,6 @@ fail_discipline:
     return mode;
 }
 
-int
-Perl_do_binmode(pTHX_ PerlIO *fp, int iotype, int mode)
-{
- /* The old body of this is now in non-LAYER part of perlio.c
-  * This is a stub for any XS code which might have been calling it.
-  */
- const char *name = ":raw";
-#ifdef PERLIO_USING_CRLF
- if (!(mode & O_BINARY))
-     name = ":crlf";
-#endif
- return PerlIO_binmode(aTHX_ fp, iotype, mode, name);
-}
-
 #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE)
 I32
 my_chsize(int fd, Off_t length)
@@ -1305,8 +1228,7 @@ Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
        return TRUE;
     case SVt_IV:
        if (SvIOK(sv)) {
-           if (SvGMAGICAL(sv))
-               mg_get(sv);
+           SvGETMAGIC(sv);
            if (SvIsUV(sv))
                PerlIO_printf(fp, "%"UVuf, (UV)SvUVX(sv));
            else
@@ -1373,7 +1295,7 @@ Perl_my_stat(pTHX)
        return PL_laststatval;
     }
     else {
-       SV* sv = POPs;
+       SV* const sv = POPs;
        const char *s;
        STRLEN len;
        PUTBACK;
@@ -1398,11 +1320,11 @@ Perl_my_stat(pTHX)
     }
 }
 
-static const char no_prev_lstat[] = "The stat preceding -l _ wasn't an lstat";
 
 I32
 Perl_my_lstat(pTHX)
 {
+    static const char no_prev_lstat[] = "The stat preceding -l _ wasn't an lstat";
     dSP;
     SV *sv;
     if (PL_op->op_flags & OPf_REF) {
@@ -1418,8 +1340,8 @@ Perl_my_lstat(pTHX)
            return (PL_laststatval = -1);
        }
     }
-    else if (ckWARN(WARN_IO) && PL_laststype != OP_LSTAT
-           && (PL_op->op_private & OPpFT_STACKED))
+    else if (PL_laststype != OP_LSTAT
+           && (PL_op->op_private & OPpFT_STACKED) && ckWARN(WARN_IO))
        Perl_croak(aTHX_ no_prev_lstat);
 
     PL_laststype = OP_LSTAT;
@@ -1439,28 +1361,20 @@ Perl_my_lstat(pTHX)
     return PL_laststatval;
 }
 
-#ifndef OS2
-bool
-Perl_do_aexec(pTHX_ SV *really, register SV **mark, register SV **sp)
-{
-    return do_aexec5(really, mark, sp, 0, 0);
-}
-#endif
-
 bool
 Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
               int fd, int do_report)
 {
     dVAR;
-#if defined(MACOS_TRADITIONAL) || defined(SYMBIAN)
+#if defined(MACOS_TRADITIONAL) || defined(__SYMBIAN32__)
     Perl_croak(aTHX_ "exec? I'm not *that* kind of operating system");
 #else
-    register char **a;
-    const char *tmps = Nullch;
-
     if (sp > mark) {
-       New(401,PL_Argv, sp - mark + 1, char*);
+       char **a;
+       const char *tmps = Nullch;
+       Newx(PL_Argv, sp - mark + 1, char*);
        a = PL_Argv;
+
        while (++mark <= sp) {
            if (*mark)
                *a++ = (char*)SvPV_nolen_const(*mark);
@@ -1483,7 +1397,7 @@ Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
            Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't exec \"%s\": %s",
                (really ? tmps : PL_Argv[0]), Strerror(errno));
        if (do_report) {
-           int e = errno;
+           const int e = errno;
 
            PerlLIO_write(fd, (void*)&e, sizeof(int));
            PerlLIO_close(fd);
@@ -1497,30 +1411,27 @@ Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
 void
 Perl_do_execfree(pTHX)
 {
-    if (PL_Argv) {
-       Safefree(PL_Argv);
-       PL_Argv = Null(char **);
-    }
-    if (PL_Cmd) {
-       Safefree(PL_Cmd);
-       PL_Cmd = Nullch;
-    }
+    Safefree(PL_Argv);
+    PL_Argv = Null(char **);
+    Safefree(PL_Cmd);
+    PL_Cmd = Nullch;
 }
 
-#if !defined(OS2) && !defined(WIN32) && !defined(DJGPP) && !defined(EPOC) && !defined(SYMBIAN) && !defined(MACOS_TRADITIONAL)
-
-bool
-Perl_do_exec(pTHX_ char *cmd)
-{
-    return do_exec3(cmd,0,0);
-}
+#ifdef PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION
 
 bool
-Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
+Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
 {
     dVAR;
     register char **a;
     register char *s;
+    char *cmd;
+
+    /* Make a copy so we can change it */
+    const int cmdlen = strlen(incmd);
+    Newx(cmd, cmdlen+1, char);
+    strncpy(cmd, incmd, cmdlen);
+    cmd[cmdlen] = 0;
 
     while (*cmd && isSPACE(*cmd))
        cmd++;
@@ -1549,7 +1460,7 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
          if (*s == ' ')
              s++;
          if (*s++ == '\'') {
-             char *ncmd = s;
+             char * const ncmd = s;
 
              while (*s)
                  s++;
@@ -1561,6 +1472,7 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
                  PerlProc_execl(PL_cshname,"csh", flags, ncmd, (char*)0);
                  PERL_FPU_POST_EXEC
                  *s = '\'';
+                 Safefree(cmd);
                  return FALSE;
              }
          }
@@ -1605,11 +1517,12 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
            PERL_FPU_PRE_EXEC
            PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char*)0);
            PERL_FPU_POST_EXEC
+           Safefree(cmd);
            return FALSE;
        }
     }
 
-    New(402,PL_Argv, (s - cmd) / 2 + 2, char*);
+    Newx(PL_Argv, (s - cmd) / 2 + 2, char*);
     PL_Cmd = savepvn(cmd, s-cmd);
     a = PL_Argv;
     for (s = PL_Cmd; *s;) {
@@ -1634,13 +1547,14 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
                Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't exec \"%s\": %s",
                    PL_Argv[0], Strerror(errno));
            if (do_report) {
-               int e = errno;
+               const int e = errno;
                PerlLIO_write(fd, (void*)&e, sizeof(int));
                PerlLIO_close(fd);
            }
        }
     }
     do_execfree();
+    Safefree(cmd);
     return FALSE;
 }
 
@@ -1651,9 +1565,22 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
 {
     register I32 val;
     register I32 tot = 0;
-    const char *what;
+    const char *const what = PL_op_name[type];
     const char *s;
-    SV **oldmark = mark;
+    SV ** const oldmark = mark;
+
+    /* Doing this ahead of the switch statement preserves the old behaviour,
+       where attempting to use kill as a taint test test would fail on
+       platforms where kill was not defined.  */
+#ifndef HAS_KILL
+    if (type == OP_KILL)
+       Perl_die(aTHX_ PL_no_func, what);
+#endif
+#ifndef HAS_CHOWN
+    if (type == OP_CHOWN)
+       Perl_die(aTHX_ PL_no_func, what);
+#endif
+
 
 #define APPLY_TAINT_PROPER() \
     STMT_START {                                                       \
@@ -1672,23 +1599,44 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
     }
     switch (type) {
     case OP_CHMOD:
-       what = "chmod";
        APPLY_TAINT_PROPER();
        if (++mark <= sp) {
            val = SvIVx(*mark);
            APPLY_TAINT_PROPER();
            tot = sp - mark;
            while (++mark <= sp) {
-               const char *name = SvPV_nolen_const(*mark);
-               APPLY_TAINT_PROPER();
-               if (PerlLIO_chmod(name, val))
-                   tot--;
+                GV* gv;
+                if (SvTYPE(*mark) == SVt_PVGV) {
+                    gv = (GV*)*mark;
+               do_fchmod:
+                   if (GvIO(gv) && IoIFP(GvIOp(gv))) {
+#ifdef HAS_FCHMOD
+                       APPLY_TAINT_PROPER();
+                       if (fchmod(PerlIO_fileno(IoIFP(GvIOn(gv))), val))
+                           tot--;
+#else
+                       Perl_die(aTHX_ PL_no_func, "fchmod");
+#endif
+                   }
+                   else {
+                       tot--;
+                   }
+               }
+               else if (SvROK(*mark) && SvTYPE(SvRV(*mark)) == SVt_PVGV) {
+                   gv = (GV*)SvRV(*mark);
+                   goto do_fchmod;
+               }
+               else {
+                   const char *name = SvPV_nolen_const(*mark);
+                   APPLY_TAINT_PROPER();
+                   if (PerlLIO_chmod(name, val))
+                       tot--;
+               }
            }
        }
        break;
 #ifdef HAS_CHOWN
     case OP_CHOWN:
-       what = "chown";
        APPLY_TAINT_PROPER();
        if (sp - mark > 2) {
             register I32 val2;
@@ -1697,10 +1645,33 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
            APPLY_TAINT_PROPER();
            tot = sp - mark;
            while (++mark <= sp) {
-               const char *name = SvPV_nolen_const(*mark);
-               APPLY_TAINT_PROPER();
-               if (PerlLIO_chown(name, val, val2))
-                   tot--;
+                GV* gv;
+                if (SvTYPE(*mark) == SVt_PVGV) {
+                    gv = (GV*)*mark;
+               do_fchown:
+                   if (GvIO(gv) && IoIFP(GvIOp(gv))) {
+#ifdef HAS_FCHOWN
+                       APPLY_TAINT_PROPER();
+                       if (fchown(PerlIO_fileno(IoIFP(GvIOn(gv))), val, val2))
+                           tot--;
+#else
+                       Perl_die(aTHX_ PL_no_func, "fchown");
+#endif
+                   }
+                   else {
+                       tot--;
+                   }
+               }
+               else if (SvROK(*mark) && SvTYPE(SvRV(*mark)) == SVt_PVGV) {
+                   gv = (GV*)SvRV(*mark);
+                   goto do_fchown;
+               }
+               else {
+                   const char *name = SvPV_nolen_const(*mark);
+                   APPLY_TAINT_PROPER();
+                   if (PerlLIO_chown(name, val, val2))
+                       tot--;
+               }
            }
        }
        break;
@@ -1713,7 +1684,6 @@ nothing in the core.
 */
 #ifdef HAS_KILL
     case OP_KILL:
-       what = "kill";
        APPLY_TAINT_PROPER();
        if (mark == sp)
            break;
@@ -1762,7 +1732,7 @@ nothing in the core.
        if (val < 0) {
            val = -val;
            while (++mark <= sp) {
-               I32 proc = SvIVx(*mark);
+               const I32 proc = SvIVx(*mark);
                APPLY_TAINT_PROPER();
 #ifdef HAS_KILLPG
                if (PerlProc_killpg(proc,val))  /* BSD */
@@ -1774,7 +1744,7 @@ nothing in the core.
        }
        else {
            while (++mark <= sp) {
-               I32 proc = SvIVx(*mark);
+               const I32 proc = SvIVx(*mark);
                APPLY_TAINT_PROPER();
                if (PerlProc_kill(proc, val))
                    tot--;
@@ -1783,7 +1753,6 @@ nothing in the core.
        break;
 #endif
     case OP_UNLINK:
-       what = "unlink";
        APPLY_TAINT_PROPER();
        tot = sp - mark;
        while (++mark <= sp) {
@@ -1803,12 +1772,14 @@ nothing in the core.
            }
        }
        break;
-#ifdef HAS_UTIME
+#if defined(HAS_UTIME) || defined(HAS_FUTIMES)
     case OP_UTIME:
-       what = "utime";
        APPLY_TAINT_PROPER();
        if (sp - mark > 2) {
-#if defined(I_UTIME) || defined(VMS)
+#if defined(HAS_FUTIMES)
+           struct timeval utbuf[2];
+           void *utbufp = utbuf;
+#elif defined(I_UTIME) || defined(VMS)
            struct utimbuf utbuf;
            struct utimbuf *utbufp = &utbuf;
 #else
@@ -1819,8 +1790,8 @@ nothing in the core.
            void *utbufp = &utbuf;
 #endif
 
-           SV* accessed = *++mark;
-           SV* modified = *++mark;
+          SV* const accessed = *++mark;
+          SV* const modified = *++mark;
 
            /* Be like C, and if both times are undefined, let the C
             * library figure out what to do.  This usually means
@@ -1830,7 +1801,12 @@ nothing in the core.
                 utbufp = NULL;
            else {
                 Zero(&utbuf, sizeof utbuf, char);
-#ifdef BIG_TIME
+#ifdef HAS_FUTIMES
+               utbuf[0].tv_sec = (long)SvIVx(accessed);  /* time accessed */
+               utbuf[0].tv_usec = 0;
+               utbuf[1].tv_sec = (long)SvIVx(modified);  /* time modified */
+               utbuf[1].tv_usec = 0;
+#elif defined(BIG_TIME)
                 utbuf.actime = (Time_t)SvNVx(accessed);  /* time accessed */
                 utbuf.modtime = (Time_t)SvNVx(modified); /* time modified */
 #else
@@ -1841,10 +1817,38 @@ nothing in the core.
            APPLY_TAINT_PROPER();
            tot = sp - mark;
            while (++mark <= sp) {
-               const char *name = SvPV_nolen_const(*mark);
-               APPLY_TAINT_PROPER();
-               if (PerlLIO_utime(name, utbufp))
-                   tot--;
+                GV* gv;
+                if (SvTYPE(*mark) == SVt_PVGV) {
+                    gv = (GV*)*mark;
+               do_futimes:
+                   if (GvIO(gv) && IoIFP(GvIOp(gv))) {
+#ifdef HAS_FUTIMES
+                       APPLY_TAINT_PROPER();
+                       if (futimes(PerlIO_fileno(IoIFP(GvIOn(gv))), utbufp))
+                           tot--;
+#else
+                       Perl_die(aTHX_ PL_no_func, "futimes");
+#endif
+                   }
+                   else {
+                       tot--;
+                   }
+               }
+               else if (SvROK(*mark) && SvTYPE(SvRV(*mark)) == SVt_PVGV) {
+                   gv = (GV*)SvRV(*mark);
+                   goto do_futimes;
+               }
+               else {
+                   const char * const name = SvPV_nolen_const(*mark);
+                   APPLY_TAINT_PROPER();
+#ifdef HAS_FUTIMES
+                   if (utimes(name, utbufp))
+#else
+                   if (PerlLIO_utime(name, utbufp))
+#endif
+                       tot--;
+               }
+
            }
        }
        else
@@ -1860,9 +1864,10 @@ nothing in the core.
 /* Do the permissions allow some operation?  Assumes statcache already set. */
 #ifndef VMS /* VMS' cando is in vms.c */
 bool
-Perl_cando(pTHX_ Mode_t mode, Uid_t effective, register const Stat_t *statbufp)
-/* Note: we use "effective" both for uids and gids.
- * Here we are betting on Uid_t being equal or wider than Gid_t.  */
+Perl_cando(pTHX_ Mode_t mode, bool effective, register const Stat_t *statbufp)
+/* effective is a flag, true for EUID, or for checking if the effective gid
+ *  is in the list of groups returned from getgroups().
+ */
 {
 #ifdef DOSISH
     /* [Comments and code from Len Reed]
@@ -1914,7 +1919,7 @@ Perl_cando(pTHX_ Mode_t mode, Uid_t effective, register const Stat_t *statbufp)
 #endif /* ! VMS */
 
 bool
-Perl_ingroup(pTHX_ Gid_t testgid, Uid_t effective)
+Perl_ingroup(pTHX_ Gid_t testgid, bool effective)
 {
 #ifdef MACOS_TRADITIONAL
     /* This is simply not correct for AppleShare, but fix it yerself. */
@@ -1923,17 +1928,22 @@ Perl_ingroup(pTHX_ Gid_t testgid, Uid_t effective)
     if (testgid == (effective ? PL_egid : PL_gid))
        return TRUE;
 #ifdef HAS_GETGROUPS
-#ifndef NGROUPS
-#define NGROUPS 32
-#endif
     {
-       Groups_t gary[NGROUPS];
+       Groups_t *gary = NULL;
        I32 anum;
+        bool rc = FALSE;
 
-       anum = getgroups(NGROUPS,gary);
+       anum = getgroups(0, gary);
+        Newx(gary, anum, Groups_t);
+        anum = getgroups(anum, gary);
        while (--anum >= 0)
-           if (gary[anum] == testgid)
-               return TRUE;
+           if (gary[anum] == testgid) {
+                rc = TRUE;
+                break;
+            }
+
+        Safefree(gary);
+        return rc;
     }
 #endif
     return FALSE;
@@ -1945,7 +1955,7 @@ Perl_ingroup(pTHX_ Gid_t testgid, Uid_t effective)
 I32
 Perl_do_ipcget(pTHX_ I32 optype, SV **mark, SV **sp)
 {
-    key_t key = (key_t)SvNVx(*++mark);
+    const key_t key = (key_t)SvNVx(*++mark);
     const I32 n = (optype == OP_MSGGET) ? 0 : SvIVx(*++mark);
     const I32 flags = SvIVx(*++mark);
     (void)sp;
@@ -1976,19 +1986,16 @@ Perl_do_ipcget(pTHX_ I32 optype, SV **mark, SV **sp)
 I32
 Perl_do_ipcctl(pTHX_ I32 optype, SV **mark, SV **sp)
 {
-    SV *astr;
     char *a;
-    STRLEN infosize;
-    I32 getinfo;
     I32 ret = -1;
     const I32 id  = SvIVx(*++mark);
     const I32 n   = (optype == OP_SEMCTL) ? SvIVx(*++mark) : 0;
     const I32 cmd = SvIVx(*++mark);
-    (void)sp;
+    SV * const astr = *++mark;
+    STRLEN infosize = 0;
+    I32 getinfo = (cmd == IPC_STAT);
 
-    astr = *++mark;
-    infosize = 0;
-    getinfo = (cmd == IPC_STAT);
+    PERL_UNUSED_ARG(sp);
 
     switch (optype)
     {
@@ -2056,7 +2063,7 @@ Perl_do_ipcctl(pTHX_ I32 optype, SV **mark, SV **sp)
     }
     else
     {
-       IV i = SvIV(astr);
+       const IV i = SvIV(astr);
        a = INT2PTR(char *,i);          /* ouch */
     }
     SETERRNO(0,0);
@@ -2102,17 +2109,16 @@ I32
 Perl_do_msgsnd(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_MSG
-    SV *mstr;
-    const char *mbuf;
-    I32 msize, flags;
     STRLEN len;
     const I32 id = SvIVx(*++mark);
-    (void)sp;
+    SV * const mstr = *++mark;
+    const I32 flags = SvIVx(*++mark);
+    const char * const mbuf = SvPV_const(mstr, len);
+    const I32 msize = len - sizeof(long);
 
-    mstr = *++mark;
-    flags = SvIVx(*++mark);
-    mbuf = SvPV_const(mstr, len);
-    if ((msize = len - sizeof(long)) < 0)
+    PERL_UNUSED_ARG(sp);
+
+    if (msize < 0)
        Perl_croak(aTHX_ "Arg too short for msgsnd");
     SETERRNO(0,0);
     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
@@ -2125,14 +2131,13 @@ I32
 Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_MSG
-    SV *mstr;
     char *mbuf;
     long mtype;
     I32 msize, flags, ret;
     const I32 id = SvIVx(*++mark);
-    (void)sp;
+    SV * const mstr = *++mark;
+    PERL_UNUSED_ARG(sp);
 
-    mstr = *++mark;
     /* suppress warning when reading into undef var --jhi */
     if (! SvOK(mstr))
        sv_setpvn(mstr, "", 0);
@@ -2162,14 +2167,12 @@ I32
 Perl_do_semop(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_SEM
-    SV *opstr;
-    const char *opbuf;
     STRLEN opsize;
     const I32 id = SvIVx(*++mark);
-    (void)sp;
+    SV * const opstr = *++mark;
+    const char * const opbuf = SvPV_const(opstr, opsize);
+    PERL_UNUSED_ARG(sp);
 
-    opstr = *++mark;
-    opbuf = SvPV_const(opstr, opsize);
     if (opsize < 3 * SHORTSIZE
        || (opsize % (3 * SHORTSIZE))) {
        SETERRNO(EINVAL,LIB_INVARG);
@@ -2180,12 +2183,12 @@ Perl_do_semop(pTHX_ SV **mark, SV **sp)
     {
         const int nsops  = opsize / (3 * sizeof (short));
         int i      = nsops;
-        short *ops = (short *) opbuf;
+        short * const ops = (short *) opbuf;
         short *o   = ops;
         struct sembuf *temps, *t;
         I32 result;
 
-        New (0, temps, nsops, struct sembuf);
+        Newx (temps, nsops, struct sembuf);
         t = temps;
         while (i--) {
             t->sem_num = *o++;
@@ -2215,16 +2218,14 @@ I32
 Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
 {
 #ifdef HAS_SHM
-    SV *mstr;
     char *shm;
-    I32 mpos, msize;
     struct shmid_ds shmds;
     const I32 id = SvIVx(*++mark);
-    (void)sp;
+    SV * const mstr = *++mark;
+    const I32 mpos = SvIVx(*++mark);
+    const I32 msize = SvIVx(*++mark);
+    PERL_UNUSED_ARG(sp);
 
-    mstr = *++mark;
-    mpos = SvIVx(*++mark);
-    msize = SvIVx(*++mark);
     SETERRNO(0,0);
     if (shmctl(id, IPC_STAT, &shmds) == -1)
        return -1;
@@ -2288,7 +2289,7 @@ PerlIO *
 Perl_start_glob (pTHX_ SV *tmpglob, IO *io)
 {
     dVAR;
-    SV *tmpcmd = NEWSV(55, 0);
+    SV * const tmpcmd = NEWSV(55, 0);
     PerlIO *fp;
     ENTER;
     SAVEFREESV(tmpcmd);
@@ -2301,7 +2302,8 @@ Perl_start_glob (pTHX_ SV *tmpglob, IO *io)
 #include <rmsdef.h>
        char rslt[NAM$C_MAXRSS+1+sizeof(unsigned short int)] = {'\0','\0'};
        char vmsspec[NAM$C_MAXRSS+1];
-       char *rstr = rslt + sizeof(unsigned short int), *begin, *end, *cp;
+       char * const rstr = rslt + sizeof(unsigned short int);
+       char *begin, *end, *cp;
        $DESCRIPTOR(dfltdsc,"SYS$DISK:[]*.*;");
        PerlIO *tmpfp;
        STRLEN i;