📄 doio.c
字号:
/* $RCSfile: doio.c,v $$Revision: 4.0.1.6 $$Date: 92/06/11 21:08:16 $ * * Copyright (c) 1991, Larry Wall * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * * $Log: doio.c,v $ * Revision 4.0.1.6 92/06/11 21:08:16 lwall * patch34: some systems don't declare h_errno extern in header files * * Revision 4.0.1.5 92/06/08 13:00:21 lwall * patch20: some machines don't define ENOTSOCK in errno.h * patch20: new warnings for failed use of stat operators on filenames with \n * patch20: wait failed when STDOUT or STDERR reopened to a pipe * patch20: end of file latch not reset on reopen of STDIN * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround * patch20: fixed memory leak on system() for vfork() machines * patch20: get*by* routines now return something useful in a scalar context * patch20: h_errno now accessible via $? * * Revision 4.0.1.4 91/11/05 16:51:43 lwall * patch11: prepared for ctype implementations that don't define isascii() * patch11: perl mistook some streams for sockets because they return mode 0 too * patch11: reopening STDIN, STDOUT and STDERR failed on some machines * patch11: certain perl errors should set EBADF so that $! looks better * patch11: truncate on a closed filehandle could dump * patch11: stats of _ forgot whether prior stat was actually lstat * patch11: -T returned true on NFS directory * * Revision 4.0.1.3 91/06/10 01:21:19 lwall * patch10: read didn't work from character special files open for writing * patch10: close-on-exec wrongly set on system file descriptors * * Revision 4.0.1.2 91/06/07 10:53:39 lwall * patch4: new copyright notice * patch4: system fd's are now treated specially * patch4: added $^F variable to specify maximum system fd, default 2 * patch4: character special files now opened with bidirectional stdio buffers * patch4: taintchecks could improperly modify parent in vfork() * patch4: many, many itty-bitty portability fixes * * Revision 4.0.1.1 91/04/11 17:41:06 lwall * patch1: hopefully straightened out some of the Xenix mess * * Revision 4.0 91/03/20 01:07:06 lwall * 4.0 baseline. * */#include "EXTERN.h"#include "perl.h"#ifdef HAS_SOCKET#include <sys/socket.h>#include <netdb.h>#ifndef ENOTSOCK#include <net/errno.h>#endif#endif#ifdef HAS_SELECT#ifdef I_SYS_SELECT#ifndef I_SYS_TIME#include <sys/select.h>#endif#endif#endif#ifdef HOST_NOT_FOUNDextern int h_errno;#endif#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)#include <sys/ipc.h>#ifdef HAS_MSG#include <sys/msg.h>#endif#ifdef HAS_SEM#include <sys/sem.h>#endif#ifdef HAS_SHM#include <sys/shm.h>#endif#endif#ifdef I_PWD#include <pwd.h>#endif#ifdef I_GRP#include <grp.h>#endif#ifdef I_UTIME#include <utime.h>#endif#ifdef I_FCNTL#include <fcntl.h>#endif#ifdef I_SYS_FILE#include <sys/file.h>#endifint laststatval = -1;int laststype = O_STAT;static char* warn_nl = "Unsuccessful %s on filename containing newline";booldo_open(stab,name,len)STAB *stab;register char *name;int len;{ FILE *fp; register STIO *stio = stab_io(stab); char *myname = savestr(name); int result; int fd; int writing = 0; char mode[3]; /* stdio file mode ("r\0" or "r+\0") */ FILE *saveifp = Nullfp; FILE *saveofp = Nullfp; char savetype = ' '; mode[0] = mode[1] = mode[2] = '\0'; name = myname; forkprocess = 1; /* assume true if no fork */ while (len && isSPACE(name[len-1])) name[--len] = '\0'; if (!stio) stio = stab_io(stab) = stio_new(); else if (stio->ifp) { fd = fileno(stio->ifp); if (stio->type == '-') result = 0; else if (fd <= maxsysfd) { saveifp = stio->ifp; saveofp = stio->ofp; savetype = stio->type; result = 0; } else if (stio->type == '|') result = mypclose(stio->ifp); else if (stio->ifp != stio->ofp) { if (stio->ofp) { result = fclose(stio->ofp); fclose(stio->ifp); /* clear stdio, fd already closed */ } else result = fclose(stio->ifp); } else result = fclose(stio->ifp); if (result == EOF && fd > maxsysfd) fprintf(stderr,"Warning: unable to close filehandle %s properly.\n", stab_ename(stab)); stio->ofp = stio->ifp = Nullfp; } if (*name == '+' && len > 1 && name[len-1] != '|') { /* scary */ mode[1] = *name++; mode[2] = '\0'; --len; writing = 1; } else { mode[1] = '\0'; } stio->type = *name; if (*name == '|') { /*SUPPRESS 530*/ for (name++; isSPACE(*name); name++) ;#ifdef TAINT taintenv(); taintproper("Insecure dependency in piped open");#endif fp = mypopen(name,"w"); writing = 1; } else if (*name == '>') {#ifdef TAINT taintproper("Insecure dependency in open");#endif name++; if (*name == '>') { mode[0] = stio->type = 'a'; name++; } else mode[0] = 'w'; writing = 1; if (*name == '&') { duplicity: name++; while (isSPACE(*name)) name++; if (isDIGIT(*name)) fd = atoi(name); else { stab = stabent(name,FALSE); if (!stab || !stab_io(stab)) {#ifdef EINVAL errno = EINVAL;#endif goto say_false; } if (stab_io(stab) && stab_io(stab)->ifp) { fd = fileno(stab_io(stab)->ifp); if (stab_io(stab)->type == 's') stio->type = 's'; } else fd = -1; } if (!(fp = fdopen(fd = dup(fd),mode))) { close(fd); } } else { while (isSPACE(*name)) name++; if (strEQ(name,"-")) { fp = stdout; stio->type = '-'; } else { fp = fopen(name,mode); } } } else { if (*name == '<') { mode[0] = 'r'; name++; while (isSPACE(*name)) name++; if (*name == '&') goto duplicity; if (strEQ(name,"-")) { fp = stdin; stio->type = '-'; } else fp = fopen(name,mode); } else if (name[len-1] == '|') {#ifdef TAINT taintenv(); taintproper("Insecure dependency in piped open");#endif name[--len] = '\0'; while (len && isSPACE(name[len-1])) name[--len] = '\0'; /*SUPPRESS 530*/ for (; isSPACE(*name); name++) ; fp = mypopen(name,"r"); stio->type = '|'; } else { stio->type = '<'; /*SUPPRESS 530*/ for (; isSPACE(*name); name++) ; if (strEQ(name,"-")) { fp = stdin; stio->type = '-'; } else fp = fopen(name,"r"); } } if (!fp) { if (dowarn && stio->type == '<' && index(name, '\n')) warn(warn_nl, "open"); Safefree(myname); goto say_false; } Safefree(myname); if (stio->type && stio->type != '|' && stio->type != '-') { if (fstat(fileno(fp),&statbuf) < 0) { (void)fclose(fp); goto say_false; } if (S_ISSOCK(statbuf.st_mode)) stio->type = 's'; /* in case a socket was passed in to us */#ifdef HAS_SOCKET else if (#ifdef S_IFMT !(statbuf.st_mode & S_IFMT)#else !statbuf.st_mode#endif ) { int buflen = sizeof tokenbuf; if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0 || errno != ENOTSOCK) stio->type = 's'; /* some OS's return 0 on fstat()ed socket */ /* but some return 0 for streams too, sigh */ }#endif } if (saveifp) { /* must use old fp? */ fd = fileno(saveifp); if (saveofp) { fflush(saveofp); /* emulate fclose() */ if (saveofp != saveifp) { /* was a socket? */ fclose(saveofp); if (fd > 2) Safefree(saveofp); } } if (fd != fileno(fp)) { int pid; STR *str; dup2(fileno(fp), fd); str = afetch(fdpid,fileno(fp),TRUE); pid = str->str_u.str_useful; str->str_u.str_useful = 0; str = afetch(fdpid,fd,TRUE); str->str_u.str_useful = pid; fclose(fp); } fp = saveifp; clearerr(fp); }#if defined(HAS_FCNTL) && defined(F_SETFD) fd = fileno(fp); fcntl(fd,F_SETFD,fd > maxsysfd);#endif stio->ifp = fp; if (writing) { if (stio->type == 's' || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) { if (!(stio->ofp = fdopen(fileno(fp),"w"))) { fclose(fp); stio->ifp = Nullfp; goto say_false; } } else stio->ofp = fp; } return TRUE;say_false: stio->ifp = saveifp; stio->ofp = saveofp; stio->type = savetype; return FALSE;}FILE *nextargv(stab)register STAB *stab;{ register STR *str;#ifndef FLEXFILENAMES int filedev; int fileino;#endif int fileuid; int filegid; static int filemode = 0; static int lastfd; static char *oldname; if (!argvoutstab) argvoutstab = stabent("ARGVOUT",TRUE); if (filemode & (S_ISUID|S_ISGID)) { fflush(stab_io(argvoutstab)->ifp); /* chmod must follow last write */#ifdef HAS_FCHMOD (void)fchmod(lastfd,filemode);#else (void)chmod(oldname,filemode);#endif } filemode = 0; while (alen(stab_xarray(stab)) >= 0) { str = ashift(stab_xarray(stab)); str_sset(stab_val(stab),str); STABSET(stab_val(stab)); oldname = str_get(stab_val(stab)); if (do_open(stab,oldname,stab_val(stab)->str_cur)) { if (inplace) {#ifdef TAINT taintproper("Insecure dependency in inplace open");#endif if (strEQ(oldname,"-")) { str_free(str); defoutstab = stabent("STDOUT",TRUE); return stab_io(stab)->ifp; }#ifndef FLEXFILENAMES filedev = statbuf.st_dev; fileino = statbuf.st_ino;#endif filemode = statbuf.st_mode; fileuid = statbuf.st_uid; filegid = statbuf.st_gid; if (!S_ISREG(filemode)) { warn("Can't do inplace edit: %s is not a regular file", oldname ); do_close(stab,FALSE); str_free(str); continue; } if (*inplace) {#ifdef SUFFIX add_suffix(str,inplace);#else str_cat(str,inplace);#endif#ifndef FLEXFILENAMES if (stat(str->str_ptr,&statbuf) >= 0 && statbuf.st_dev == filedev && statbuf.st_ino == fileino ) { warn("Can't do inplace edit: %s > 14 characters", str->str_ptr ); do_close(stab,FALSE); str_free(str); continue; }#endif#ifdef HAS_RENAME#ifndef DOSISH if (rename(oldname,str->str_ptr) < 0) { warn("Can't rename %s to %s: %s, skipping file", oldname, str->str_ptr, strerror(errno) ); do_close(stab,FALSE); str_free(str); continue; }#else do_close(stab,FALSE); (void)unlink(str->str_ptr); (void)rename(oldname,str->str_ptr); do_open(stab,str->str_ptr,stab_val(stab)->str_cur);#endif /* MSDOS */#else (void)UNLINK(str->str_ptr); if (link(oldname,str->str_ptr) < 0) { warn("Can't rename %s to %s: %s, skipping file", oldname, str->str_ptr, strerror(errno) ); do_close(stab,FALSE); str_free(str); continue; } (void)UNLINK(oldname);#endif } else {#ifndef DOSISH if (UNLINK(oldname) < 0) { warn("Can't rename %s to %s: %s, skipping file", oldname, str->str_ptr, strerror(errno) ); do_close(stab,FALSE); str_free(str); continue; }#else fatal("Can't do inplace edit without backup");#endif } str_nset(str,">",1); str_cat(str,oldname); errno = 0; /* in case sprintf set errno */ if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) { warn("Can't do inplace edit on %s: %s", oldname, strerror(errno) ); do_close(stab,FALSE); str_free(str); continue; } defoutstab = argvoutstab; lastfd = fileno(stab_io(argvoutstab)->ifp); (void)fstat(lastfd,&statbuf);#ifdef HAS_FCHMOD (void)fchmod(lastfd,filemode);#else (void)chmod(oldname,filemode);#endif if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {#ifdef HAS_FCHOWN (void)fchown(lastfd,fileuid,filegid);#else#ifdef HAS_CHOWN (void)chown(oldname,fileuid,filegid);#endif#endif } } str_free(str); return stab_io(stab)->ifp; } else fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno)); str_free(str); } if (inplace) { (void)do_close(argvoutstab,FALSE); defoutstab = stabent("STDOUT",TRUE); } return Nullfp;}#ifdef HAS_PIPEvoiddo_pipe(str, rstab, wstab)STR *str;STAB *rstab;STAB *wstab;{ register STIO *rstio; register STIO *wstio; int fd[2]; if (!rstab) goto badexit; if (!wstab) goto badexit; rstio = stab_io(rstab); wstio = stab_io(wstab); if (!rstio) rstio = stab_io(rstab) = stio_new(); else if (rstio->ifp) do_close(rstab,FALSE); if (!wstio) wstio = stab_io(wstab) = stio_new(); else if (wstio->ifp) do_close(wstab,FALSE); if (pipe(fd) < 0) goto badexit; rstio->ifp = fdopen(fd[0], "r"); wstio->ofp = fdopen(fd[1], "w"); wstio->ifp = wstio->ofp; rstio->type = '<'; wstio->type = '>'; if (!rstio->ifp || !wstio->ofp) { if (rstio->ifp) fclose(rstio->ifp); else close(fd[0]); if (wstio->ofp) fclose(wstio->ofp); else close(fd[1]); goto badexit; } str_sset(str,&str_yes); return;badexit: str_sset(str,&str_undef); return;}#endifbooldo_close(stab,explicit)STAB *stab;bool explicit;{ bool retval = FALSE; register STIO *stio; int status; if (!stab) stab = argvstab; if (!stab) { errno = EBADF; return FALSE; } stio = stab_io(stab); if (!stio) { /* never opened */ if (dowarn && explicit) warn("Close on unopened file <%s>",stab_ename(stab)); return FALSE; } if (stio->ifp) { if (stio->type == '|') { status = mypclose(stio->ifp); retval = (status == 0); statusvalue = (unsigned short)status & 0xffff; } else if (stio->type == '-') retval = TRUE; else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -