#define dSYS dNOOP
#endif
-#define VOIDUSED 1
-#ifdef PERL_MICRO
-# include "uconfig.h"
-#else
-# ifndef USE_CROSS_COMPILE
-# include "config.h"
-# else
-# include "xconfig.h"
-# endif
-#endif
-
#define PERLIO_NOT_STDIO 0
-#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
-/*
- * #define PerlIO FILE
- */
-#endif
/*
* This file provides those parts of PerlIO abstraction
* which are not #defined in perlio.h.
#include "XSUB.h"
-#ifdef __Lynx__
-/* Missing proto on LynxOS */
-int mkstemp(char*);
-#endif
-
#ifdef VMS
#include <rms.h>
#endif
extern off_t ftello(FILE *);
#endif
-#ifndef USE_SFIO
+#define NATIVE_0xd CR_NATIVE
+#define NATIVE_0xa LF_NATIVE
EXTERN_C int perlsio_binmode(FILE *fp, int iotype, int mode);
# endif
#endif
}
-#endif /* sfio */
#ifndef O_ACCMODE
#define O_ACCMODE 3 /* Assume traditional implementation */
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;
}
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 *
{
#if defined(PERL_MICRO) || defined(__SYMBIAN32__)
return NULL;
-#else
-#ifdef PERL_IMPLICIT_SYS
+#elif defined(PERL_IMPLICIT_SYS)
return PerlSIO_fdupopen(f);
#else
-#ifdef WIN32
+# ifdef WIN32
return win32_fdupopen(f);
-#else
+# else
if (f) {
- const int fd = PerlLIO_dup(PerlIO_fileno(f));
+ const int fd = PerlLIO_dup_cloexec(PerlIO_fileno(f));
if (fd >= 0) {
char mode[8];
-#ifdef DJGPP
+# ifdef DJGPP
const int omode = djgpp_get_stream_mode(f);
-#else
+# else
const int omode = fcntl(fd, F_GETFL);
-#endif
+# endif
PerlIO_intmode2str(omode,mode,NULL);
/* the r+ is a hack */
return PerlIO_fdopen(fd, mode);
else {
SETERRNO(EBADF, SS_IVCHAN);
}
-#endif
+# endif
return NULL;
#endif
-#endif
}
if (*args == &PL_sv_undef)
return PerlIO_tmpfile();
else {
- const char *name = SvPV_nolen_const(*args);
+ STRLEN len;
+ const char *name = SvPV_const(*args, len);
+ if (!IS_SAFE_PATHNAME(name, len, "open"))
+ return NULL;
+
if (*mode == IoTYPE_NUMERIC) {
- fd = PerlLIO_open3(name, imode, perm);
+ fd = PerlLIO_open3_cloexec(name, imode, perm);
if (fd >= 0)
return PerlIO_fdopen(fd, mode + 1);
}
return NULL;
}
+XS(XS_PerlIO__Layer__find); /* prototype to pass -Wmissing-prototypes */
XS(XS_PerlIO__Layer__find)
{
dXSARGS;
#endif
-#ifdef PERLIO_IS_STDIO
-
-void
-PerlIO_init(pTHX)
-{
- PERL_UNUSED_CONTEXT;
- /*
- * Does nothing (yet) except force this file to be included in perl
- * binary. That allows this file to force inclusion of other functions
- * that may be required by loadable extensions e.g. for
- * FileHandle::tmpfile
- */
-}
-
-#undef PerlIO_tmpfile
-PerlIO *
-PerlIO_tmpfile(void)
-{
- return tmpfile();
-}
-
-#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.
{
va_list ap;
dSYS;
+
+ if (!DEBUG_i_TEST)
+ return;
+
va_start(ap, fmt);
+
if (!PL_perlio_debug_fd) {
if (!TAINTING_get &&
PerlProc_getuid() == PerlProc_geteuid() &&
PerlProc_getgid() == PerlProc_getegid()) {
const char * const s = PerlEnv_getenv("PERLIO_DEBUG");
if (s && *s)
- PL_perlio_debug_fd
- = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ PL_perlio_debug_fd = PerlLIO_open3_cloexec(s,
+ O_WRONLY | O_CREAT | O_APPEND, 0666);
else
- PL_perlio_debug_fd = -1;
+ PL_perlio_debug_fd = PerlLIO_dup_cloexec(2); /* stderr */
} else {
- /* tainting or set*id, so ignore the environment, and ensure we
- skip these tests next time through. */
- PL_perlio_debug_fd = -1;
+ /* tainting or set*id, so ignore the environment and send the
+ debug output to stderr, like other -D switches. */
+ PL_perlio_debug_fd = PerlLIO_dup_cloexec(2); /* stderr */
}
}
if (PL_perlio_debug_fd > 0) {
/* Use fixed buffer as sv_catpvf etc. needs SVs */
char buffer[1024];
const STRLEN len1 = my_snprintf(buffer, sizeof(buffer), "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
+# ifdef USE_QUADMATH
+# ifdef HAS_VSNPRINTF
+ /* my_vsnprintf() isn't available with quadmath, but the native vsnprintf()
+ should be, otherwise the system isn't likely to support quadmath.
+ Nothing should be calling PerlIO_debug() with floating point anyway.
+ */
+ const STRLEN len2 = vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
+# else
+ STATIC_ASSERT_STMT(0);
+# endif
+# else
const STRLEN len2 = my_vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
- PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2);
+# endif
+ PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2));
#else
const char *s = CopFILE(PL_curcop);
STRLEN len;
Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap);
s = SvPV_const(sv, len);
- PerlLIO_write(PL_perlio_debug_fd, s, len);
+ PERL_UNUSED_RESULT(PerlLIO_write(PL_perlio_debug_fd, s, len));
SvREFCNT_dec(sv);
#endif
}
{
PerlIOl *head, *p;
int seen = 0;
+#ifndef PERL_IMPLICIT_SYS
+ PERL_UNUSED_CONTEXT;
+#endif
if (!PerlIOValid(f))
return;
p = head = PerlIOBase(f)->head;
PerlIO *
PerlIO_allocate(pTHX)
{
- dVAR;
/*
* Find a free slot in the table, allocating new table as necessary
*/
last = (PerlIOl **) (f);
for (i = 1; i < PERLIO_TABLE_SIZE; i++) {
if (!((++f)->next)) {
- f->flags = 0; /* lockcnt */
- f->tab = NULL;
- f->head = f;
- return (PerlIO *)f;
+ goto good_exit;
}
}
}
return NULL;
}
*last = (PerlIOl*) f++;
+
+ good_exit:
f->flags = 0; /* lockcnt */
f->tab = NULL;
f->head = f;
{
if (PerlIOValid(f)) {
const PerlIO_funcs * const tab = PerlIOBase(f)->tab;
- PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param);
+ DEBUG_i( PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param) );
if (tab && tab->Dup)
return (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
else {
void
PerlIO_list_push(pTHX_ PerlIO_list_t *list, PerlIO_funcs *funcs, SV *arg)
{
- dVAR;
PerlIO_pair_t *p;
PERL_UNUSED_CONTEXT;
if (list->cur >= list->len) {
- list->len += 8;
+ const IV new_len = list->len + 8;
if (list->array)
- Renew(list->array, list->len, PerlIO_pair_t);
+ Renew(list->array, new_len, PerlIO_pair_t);
else
- Newx(list->array, list->len, PerlIO_pair_t);
+ Newx(list->array, new_len, PerlIO_pair_t);
+ list->len = new_len;
}
p = &(list->array[list->cur++]);
p->funcs = funcs;
list = PerlIO_list_alloc(aTHX);
for (i=0; i < proto->cur; i++) {
SV *arg = proto->array[i].arg;
-#ifdef sv_dup
+#ifdef USE_ITHREADS
if (arg && param)
arg = sv_dup(arg, param);
#else
PL_known_layers = PerlIO_clone_list(aTHX_ proto->Iknown_layers, param);
PL_def_layerlist = PerlIO_clone_list(aTHX_ proto->Idef_layerlist, param);
PerlIO_init_table(aTHX);
- PerlIO_debug("Clone %p from %p\n",(void*)aTHX,(void*)proto);
+ DEBUG_i( PerlIO_debug("Clone %p from %p\n",(void*)aTHX,(void*)proto) );
while ((f = *table)) {
int i;
table = (PerlIOl **) (f++);
void
PerlIO_destruct(pTHX)
{
- dVAR;
PerlIOl **table = &PL_perlio;
PerlIOl *f;
#ifdef USE_ITHREADS
- PerlIO_debug("Destruct %p\n",(void*)aTHX);
+ DEBUG_i( PerlIO_debug("Destruct %p\n",(void*)aTHX) );
#endif
while ((f = *table)) {
int i;
const PerlIOl *l;
while ((l = *x)) {
if (l->tab && l->tab->kind & PERLIO_K_DESTRUCT) {
- PerlIO_debug("Destruct popping %s\n", l->tab->name);
+ DEBUG_i( PerlIO_debug("Destruct popping %s\n", l->tab->name) );
PerlIO_flush(x);
PerlIO_pop(aTHX_ x);
}
const PerlIOl *l = *f;
VERIFY_HEAD(f);
if (l) {
- PerlIO_debug("PerlIO_pop f=%p %s\n", (void*)f,
- l->tab ? l->tab->name : "(Null)");
+ DEBUG_i( PerlIO_debug("PerlIO_pop f=%p %s\n", (void*)f,
+ l->tab ? l->tab->name : "(Null)") );
if (l->tab && l->tab->Popped) {
/*
* If popped returns non-zero do not free its layer structure
AV *
PerlIO_get_layers(pTHX_ PerlIO *f)
{
- dVAR;
AV * const av = newAV();
if (PerlIOValid(f)) {
PerlIO_funcs *
PerlIO_find_layer(pTHX_ const char *name, STRLEN len, int load)
{
- dVAR;
+
IV i;
if ((SSize_t) len <= 0)
len = strlen(name);
for (i = 0; i < PL_known_layers->cur; i++) {
PerlIO_funcs * const f = PL_known_layers->array[i].funcs;
- if (memEQ(f->name, name, len) && f->name[len] == 0) {
- PerlIO_debug("%.*s => %p\n", (int) len, name, (void*)f);
+ const STRLEN this_len = strlen(f->name);
+ if (this_len == len && memEQ(f->name, name, len)) {
+ DEBUG_i( PerlIO_debug("%.*s => %p\n", (int) len, name, (void*)f) );
return f;
}
}
return PerlIO_find_layer(aTHX_ name, len, 0);
}
}
- PerlIO_debug("Cannot find %.*s\n", (int) len, name);
+ DEBUG_i( PerlIO_debug("Cannot find %.*s\n", (int) len, name) );
return NULL;
}
perlio_mg_free
};
+XS(XS_io_MODIFY_SCALAR_ATTRIBUTES); /* prototype to pass -Wmissing-prototypes */
XS(XS_io_MODIFY_SCALAR_ATTRIBUTES)
{
dXSARGS;
XSRETURN(count);
}
-#endif /* USE_ATTIBUTES_FOR_PERLIO */
+#endif /* USE_ATTRIBUTES_FOR_PERLIO */
SV *
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
during loading of layers.
*/
- dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
- if (items)
- PerlIO_debug("warning:%s\n",SvPV_nolen_const(ST(0)));
+ PERL_UNUSED_VAR(items);
+ DEBUG_i(
+ if (items)
+ PerlIO_debug("warning:%s\n",SvPV_nolen_const(ST(0))) );
XSRETURN(0);
}
+XS(XS_PerlIO__Layer__find); /* prototype to pass -Wmissing-prototypes */
XS(XS_PerlIO__Layer__find)
{
- dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 2)
Perl_croak(aTHX_ "Usage class->find(name[,load])");
else {
STRLEN len;
const char * const name = SvPV_const(ST(1), len);
- const bool load = (items > 2) ? SvTRUE(ST(2)) : 0;
+ const bool load = (items > 2) ? SvTRUE_NN(ST(2)) : 0;
PerlIO_funcs * const layer = PerlIO_find_layer(aTHX_ name, len, load);
ST(0) =
(layer) ? sv_2mortal(PerlIO_tab_sv(aTHX_ layer)) :
void
PerlIO_define_layer(pTHX_ PerlIO_funcs *tab)
{
- dVAR;
if (!PL_known_layers)
PL_known_layers = PerlIO_list_alloc(aTHX);
PerlIO_list_push(aTHX_ PL_known_layers, tab, NULL);
- PerlIO_debug("define %s %p\n", tab->name, (void*)tab);
+ DEBUG_i( PerlIO_debug("define %s %p\n", tab->name, (void*)tab) );
}
int
PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names)
{
- dVAR;
if (names) {
const char *s = names;
while (*s) {
}
do {
e++;
- } while (isALNUM(*e));
+ } while (isWORDCHAR(*e));
llen = e - s;
if (*e == '(') {
int nesting = 1;
if (*e++) {
break;
}
- /*
- * Drop through
- */
+ /* Fall through */
case '\0':
e--;
Perl_ck_warner(aTHX_ packWARN(WARN_LAYER),
void
PerlIO_default_buffer(pTHX_ PerlIO_list_t *av)
{
- dVAR;
PERLIO_FUNCS_DECL(*tab) = &PerlIO_perlio;
#ifdef PERLIO_USING_CRLF
tab = &PerlIO_crlf;
if (PerlIO_stdio.Set_ptrcnt)
tab = &PerlIO_stdio;
#endif
- PerlIO_debug("Pushing %s\n", tab->name);
- PerlIO_list_push(aTHX_ av, PerlIO_find_layer(aTHX_ tab->name, 0, 0),
- &PL_sv_undef);
+ DEBUG_i( PerlIO_debug("Pushing %s\n", tab->name) );
+ PerlIO_list_push(aTHX_ av, (PerlIO_funcs *)tab, &PL_sv_undef);
}
SV *
PerlIO_layer_fetch(pTHX_ PerlIO_list_t *av, IV n, PerlIO_funcs *def)
{
if (n >= 0 && n < av->cur) {
- PerlIO_debug("Layer %" IVdf " is %s\n", n,
- av->array[n].funcs->name);
+ DEBUG_i( PerlIO_debug("Layer %" IVdf " is %s\n", n,
+ av->array[n].funcs->name) );
return av->array[n].funcs;
}
if (!def)
PerlIO_list_t *
PerlIO_default_layers(pTHX)
{
- dVAR;
if (!PL_def_layerlist) {
const char * const s = TAINTING_get ? NULL : PerlEnv_getenv("PERLIO");
PERLIO_FUNCS_DECL(*osLayer) = &PerlIO_unix;
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_utf8));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_remove));
PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_byte));
- PerlIO_list_push(aTHX_ PL_def_layerlist,
- PerlIO_find_layer(aTHX_ osLayer->name, 0, 0),
- &PL_sv_undef);
+ PerlIO_list_push(aTHX_ PL_def_layerlist, (PerlIO_funcs *)osLayer,
+ &PL_sv_undef);
if (s) {
PerlIO_parse_layers(aTHX_ PL_def_layerlist, s);
}
PerlIO_funcs *
PerlIO_default_layer(pTHX_ I32 n)
{
- dVAR;
PerlIO_list_t * const av = PerlIO_default_layers(aTHX);
if (n < 0)
n += av->cur;
void
PerlIO_stdstreams(pTHX)
{
- dVAR;
if (!PL_perlio) {
PerlIO_init_table(aTHX);
PerlIO_fdopen(0, "Ir" PERLIO_STDTEXT);
VERIFY_HEAD(f);
if (tab->fsize != sizeof(PerlIO_funcs)) {
Perl_croak( aTHX_
- "%s (%"UVuf") does not match %s (%"UVuf")",
+ "%s (%" UVuf ") does not match %s (%" UVuf ")",
"PerlIO layer function table size", (UV)tab->fsize,
"size expected by this perl", (UV)sizeof(PerlIO_funcs) );
}
PerlIOl *l;
if (tab->size < sizeof(PerlIOl)) {
Perl_croak( aTHX_
- "%s (%"UVuf") smaller than %s (%"UVuf")",
+ "%s (%" UVuf ") smaller than %s (%" UVuf ")",
"PerlIO layer instance size", (UV)tab->size,
"size expected by this perl", (UV)sizeof(PerlIOl) );
}
l->tab = (PerlIO_funcs*) tab;
l->head = ((PerlIOl*)f)->head;
*f = l;
- PerlIO_debug("PerlIO_push f=%p %s %s %p\n",
- (void*)f, tab->name,
- (mode) ? mode : "(Null)", (void*)arg);
+ DEBUG_i( PerlIO_debug("PerlIO_push f=%p %s %s %p\n",
+ (void*)f, tab->name,
+ (mode) ? mode : "(Null)", (void*)arg) );
if (*l->tab->Pushed &&
(*l->tab->Pushed)
(aTHX_ f, mode, arg, (PerlIO_funcs*) tab) != 0) {
}
else if (f) {
/* Pseudo-layer where push does its own stack adjust */
- PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name,
- (mode) ? mode : "(Null)", (void*)arg);
+ DEBUG_i( PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name,
+ (mode) ? mode : "(Null)", (void*)arg) );
if (tab->Pushed &&
(*tab->Pushed) (aTHX_ f, mode, arg, (PerlIO_funcs*) tab) != 0) {
return NULL;
}
}
if (PerlIOValid(f)) {
- PerlIO_debug(":raw f=%p :%s\n", (void*)f,
- PerlIOBase(f)->tab ? PerlIOBase(f)->tab->name : "(Null)");
+ DEBUG_i( PerlIO_debug(":raw f=%p :%s\n", (void*)f,
+ PerlIOBase(f)->tab ? PerlIOBase(f)->tab->name : "(Null)") );
return 0;
}
}
int
PerlIO_binmode(pTHX_ PerlIO *f, int iotype, int mode, const char *names)
{
- PerlIO_debug("PerlIO_binmode f=%p %s %c %x %s\n", (void*)f,
- (PerlIOBase(f) && PerlIOBase(f)->tab) ?
- PerlIOBase(f)->tab->name : "(Null)",
- iotype, mode, (names) ? names : "(Null)");
+ PERL_UNUSED_ARG(iotype);
+ PERL_UNUSED_ARG(mode);
+
+ DEBUG_i(
+ PerlIO_debug("PerlIO_binmode f=%p %s %c %x %s\n", (void*)f,
+ (PerlIOBase(f) && PerlIOBase(f)->tab) ?
+ PerlIOBase(f)->tab->name : "(Null)",
+ iotype, mode, (names) ? names : "(Null)") );
if (names) {
/* Do not flush etc. if (e.g.) switching encodings.
(for example :unix which is never going to call them)
it can do the flush when it is pushed.
*/
- return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE;
+ return cBOOL(PerlIO_apply_layers(aTHX_ f, NULL, names) == 0);
}
else {
/* Fake 5.6 legacy of using this call to turn ON O_TEXT */
/* Legacy binmode is now _defined_ as being equivalent to pushing :raw
So code that used to be here is now in PerlIORaw_pushed().
*/
- return PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_raw), NULL, NULL) ? TRUE : FALSE;
+ return cBOOL(PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_raw), NULL, NULL));
}
}
int
Perl_PerlIO_fileno(pTHX_ PerlIO *f)
{
- dVAR;
- Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f));
+ Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f));
}
static PerlIO_funcs *
PerlIO_layer_from_ref(pTHX_ SV *sv)
{
- dVAR;
/*
* For any scalar type load the handler which is bundled with perl
*/
PerlIO_resolve_layers(pTHX_ const char *layers,
const char *mode, int narg, SV **args)
{
- dVAR;
PerlIO_list_t *def = PerlIO_default_layers(aTHX);
int incdef = 1;
if (!PL_perlio)
* If it is a reference but not an object see if we have a handler
* for it
*/
- if (SvROK(arg) && !sv_isobject(arg)) {
+ if (SvROK(arg) && !SvOBJECT(SvRV(arg))) {
PerlIO_funcs * const handler = PerlIO_layer_from_ref(aTHX_ SvRV(arg));
if (handler) {
def = PerlIO_list_alloc(aTHX);
PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
int imode, int perm, PerlIO *f, int narg, SV **args)
{
- dVAR;
if (!f && narg == 1 && *args == &PL_sv_undef) {
if ((f = PerlIO_tmpfile())) {
if (!layers || !*layers)
if (narg > 1 && !(tab->kind & PERLIO_K_MULTIARG)) {
Perl_croak(aTHX_ "More than one argument to open(,':%s')",tab->name);
}
- PerlIO_debug("openn(%s,'%s','%s',%d,%x,%o,%p,%d,%p)\n",
- tab->name, layers ? layers : "(Null)", mode, fd,
- imode, perm, (void*)f, narg, (void*)args);
+ DEBUG_i( PerlIO_debug("openn(%s,'%s','%s',%d,%x,%o,%p,%d,%p)\n",
+ tab->name, layers ? layers : "(Null)", mode, fd,
+ imode, perm, (void*)f, narg, (void*)args) );
if (tab->Open)
f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm,
f, narg, args);
int
Perl_PerlIO_flush(pTHX_ PerlIO *f)
{
- dVAR;
if (f) {
if (*f) {
const PerlIO_funcs *tab = PerlIOBase(f)->tab;
return 0; /* If no Flush defined, silently succeed. */
}
else {
- PerlIO_debug("Cannot flush f=%p\n", (void*)f);
+ DEBUG_i( PerlIO_debug("Cannot flush f=%p\n", (void*)f) );
SETERRNO(EBADF, SS_IVCHAN);
return -1;
}
void
PerlIOBase_flush_linebuf(pTHX)
{
- dVAR;
PerlIOl **table = &PL_perlio;
PerlIOl *f;
while ((f = *table)) {
Perl_PerlIO_or_fail(f, Get_base, NULL, (aTHX_ f));
}
-int
+SSize_t
Perl_PerlIO_get_bufsiz(pTHX_ PerlIO *f)
{
+ /* Note that Get_bufsiz returns a Size_t */
Perl_PerlIO_or_fail(f, Get_bufsiz, -1, (aTHX_ f));
}
Perl_PerlIO_or_fail(f, Get_ptr, NULL, (aTHX_ f));
}
-int
+SSize_t
Perl_PerlIO_get_cnt(pTHX_ PerlIO *f)
{
Perl_PerlIO_or_fail(f, Get_cnt, -1, (aTHX_ f));
}
void
-Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, int cnt)
+Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, SSize_t cnt)
{
Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, NULL, cnt));
}
void
-Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, int cnt)
+Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, ptr, cnt));
}
SETERRNO(EINVAL, LIB_INVARG);
return -1;
}
+#ifdef EBCDIC
+ {
+ /* The mode variable contains one positional parameter followed by
+ * optional keyword parameters. The positional parameters must be
+ * passed as lowercase characters. The keyword parameters can be
+ * passed in mixed case. They must be separated by commas. Only one
+ * instance of a keyword can be specified. */
+ int comma = 0;
+ while (*mode) {
+ switch (*mode++) {
+ case '+':
+ if(!comma)
+ l->flags |= PERLIO_F_CANREAD | PERLIO_F_CANWRITE;
+ break;
+ case 'b':
+ if(!comma)
+ l->flags &= ~PERLIO_F_CRLF;
+ break;
+ case 't':
+ if(!comma)
+ l->flags |= PERLIO_F_CRLF;
+ break;
+ case ',':
+ comma = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+#else
while (*mode) {
switch (*mode++) {
case '+':
return -1;
}
}
+#endif
}
else {
if (l->next) {
}
}
#if 0
+ DEBUG_i(
PerlIO_debug("PerlIOBase_pushed f=%p %s %s fl=%08" UVxf " (%s)\n",
(void*)f, PerlIOBase(f)->tab->name, (omode) ? omode : "(Null)",
l->flags, PerlIO_modestr(f, temp));
+ );
#endif
return 0;
}
if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
SETERRNO(EBADF, SS_IVCHAN);
+ PerlIO_save_errno(f);
return 0;
}
while (count > 0) {
SSize_t avail = PerlIO_get_cnt(f);
SSize_t take = 0;
if (avail > 0)
- take = ((SSize_t)count < avail) ? (SSize_t)count : avail;
+ take = (((SSize_t) count >= 0) && ((SSize_t)count < avail)) ? (SSize_t)count : avail;
if (take > 0) {
STDCHAR *ptr = PerlIO_get_ptr(f);
Copy(ptr, buf, take, STDCHAR);
{
if (!arg)
return NULL;
-#ifdef sv_dup
+#ifdef USE_ITHREADS
if (param) {
arg = sv_dup(arg, param);
SvREFCNT_inc_simple_void_NN(arg);
PerlIO_funcs * const self = PerlIOBase(o)->tab;
SV *arg = NULL;
char buf[8];
- PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n",
- self ? self->name : "(Null)",
- (void*)f, (void*)o, (void*)param);
- if (self && self->Getarg)
- arg = (*self->Getarg)(aTHX_ o, param, flags);
+ assert(self);
+ DEBUG_i(PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n",
+ self->name,
+ (void*)f, (void*)o, (void*)param) );
+ if (self->Getarg)
+ arg = (*self->Getarg)(aTHX_ o, param, flags);
f = PerlIO_push(aTHX_ f, self, PerlIO_modestr(o,buf), arg);
- if (PerlIOBase(o)->flags & PERLIO_F_UTF8)
+ if (f && PerlIOBase(o)->flags & PERLIO_F_UTF8)
PerlIOBase(f)->flags |= PERLIO_F_UTF8;
SvREFCNT_dec(arg);
}
/* Must be called with PL_perlio_mutex locked. */
static void
-S_more_refcounted_fds(pTHX_ const int new_fd) {
+S_more_refcounted_fds(pTHX_ const int new_fd)
+ PERL_TSA_REQUIRES(PL_perlio_mutex)
+{
dVAR;
const int old_max = PL_perlio_fd_refcnt_size;
const int new_max = 16 + (new_fd & ~15);
int *new_array;
- PerlIO_debug("More fds - old=%d, need %d, new=%d\n",
- old_max, new_fd, new_max);
+#ifndef PERL_IMPLICIT_SYS
+ PERL_UNUSED_CONTEXT;
+#endif
+
+ DEBUG_i( PerlIO_debug("More fds - old=%d, need %d, new=%d\n",
+ old_max, new_fd, new_max) );
if (new_fd < old_max) {
return;
new_array = (int*) realloc(PL_perlio_fd_refcnt, new_max * sizeof(int));
if (!new_array) {
-#ifdef USE_ITHREADS
MUTEX_UNLOCK(&PL_perlio_mutex);
-#endif
croak_no_mem();
}
PL_perlio_fd_refcnt_size = new_max;
PL_perlio_fd_refcnt = new_array;
- PerlIO_debug("Zeroing %p, %d\n",
- (void*)(new_array + old_max),
- new_max - old_max);
+ DEBUG_i( PerlIO_debug("Zeroing %p, %d\n",
+ (void*)(new_array + old_max),
+ new_max - old_max) );
Zero(new_array + old_max, new_max - old_max, int);
}
if (fd >= 0) {
dVAR;
-#ifdef USE_ITHREADS
MUTEX_LOCK(&PL_perlio_mutex);
-#endif
if (fd >= PL_perlio_fd_refcnt_size)
S_more_refcounted_fds(aTHX_ fd);
Perl_croak(aTHX_ "refcnt_inc: fd %d: %d <= 0\n",
fd, PL_perlio_fd_refcnt[fd]);
}
- PerlIO_debug("refcnt_inc: fd %d refcnt=%d\n",
- fd, PL_perlio_fd_refcnt[fd]);
+ DEBUG_i( PerlIO_debug("refcnt_inc: fd %d refcnt=%d\n",
+ fd, PL_perlio_fd_refcnt[fd]) );
-#ifdef USE_ITHREADS
MUTEX_UNLOCK(&PL_perlio_mutex);
-#endif
} else {
/* diag_listed_as: refcnt_inc: fd %d%s */
Perl_croak(aTHX_ "refcnt_inc: fd %d < 0\n", fd);
{
int cnt = 0;
if (fd >= 0) {
+#ifdef DEBUGGING
+ dTHX;
+#else
dVAR;
-#ifdef USE_ITHREADS
- MUTEX_LOCK(&PL_perlio_mutex);
#endif
+ MUTEX_LOCK(&PL_perlio_mutex);
if (fd >= PL_perlio_fd_refcnt_size) {
/* diag_listed_as: refcnt_dec: fd %d%s */
Perl_croak_nocontext("refcnt_dec: fd %d >= refcnt_size %d\n",
fd, PL_perlio_fd_refcnt[fd]);
}
cnt = --PL_perlio_fd_refcnt[fd];
- PerlIO_debug("refcnt_dec: fd %d refcnt=%d\n", fd, cnt);
-#ifdef USE_ITHREADS
+ DEBUG_i( PerlIO_debug("refcnt_dec: fd %d refcnt=%d\n", fd, cnt) );
MUTEX_UNLOCK(&PL_perlio_mutex);
-#endif
} else {
/* diag_listed_as: refcnt_dec: fd %d%s */
Perl_croak_nocontext("refcnt_dec: fd %d < 0\n", fd);
int cnt = 0;
if (fd >= 0) {
dVAR;
-#ifdef USE_ITHREADS
MUTEX_LOCK(&PL_perlio_mutex);
-#endif
if (fd >= PL_perlio_fd_refcnt_size) {
/* diag_listed_as: refcnt: fd %d%s */
Perl_croak(aTHX_ "refcnt: fd %d >= refcnt_size %d\n",
fd, PL_perlio_fd_refcnt[fd]);
}
cnt = PL_perlio_fd_refcnt[fd];
-#ifdef USE_ITHREADS
MUTEX_UNLOCK(&PL_perlio_mutex);
-#endif
} else {
/* diag_listed_as: refcnt: fd %d%s */
Perl_croak(aTHX_ "refcnt: fd %d < 0\n", fd);
void
PerlIO_cleanup(pTHX)
{
- dVAR;
int i;
#ifdef USE_ITHREADS
- PerlIO_debug("Cleanup layers for %p\n",(void*)aTHX);
+ DEBUG_i( PerlIO_debug("Cleanup layers for %p\n",(void*)aTHX) );
#else
- PerlIO_debug("Cleanup layers\n");
+ DEBUG_i( PerlIO_debug("Cleanup layers\n") );
#endif
/* Raise STDIN..STDERR refcount so we don't close them */
static void
S_lockcnt_dec(pTHX_ const void* f)
{
+#ifndef PERL_IMPLICIT_SYS
+ PERL_UNUSED_CONTEXT;
+#endif
PerlIO_lockcnt((PerlIO*)f)--;
}
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++;
+#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
+ break;
}
- /*
- * Always open in binary mode
- */
- oflags |= O_BINARY;
if (*mode || oflags == -1) {
SETERRNO(EINVAL, LIB_INVARG);
oflags = -1;
Stat_t st;
if (PerlLIO_fstat(fd, &st) == 0) {
if (!S_ISREG(st.st_mode)) {
- PerlIO_debug("%d is not regular file\n",fd);
+ DEBUG_i( PerlIO_debug("%d is not regular file\n",fd) );
PerlIOBase(f)->flags |= PERLIO_F_NOTREG;
}
else {
- PerlIO_debug("%d _is_ a regular file\n",fd);
+ DEBUG_i( PerlIO_debug("%d _is_ a regular file\n",fd) );
}
}
#endif
IV n, const char *mode, int fd, int imode,
int perm, PerlIO *f, int narg, SV **args)
{
+ bool known_cloexec = 0;
if (PerlIOValid(f)) {
if (PerlIOBase(f)->tab && PerlIOBase(f)->flags & PERLIO_F_OPEN)
(*PerlIOBase(f)->tab->Close)(aTHX_ f);
#endif
}
if (imode != -1) {
- const char *path = SvPV_nolen_const(*args);
- fd = PerlLIO_open3(path, imode, perm);
+ STRLEN len;
+ const char *path = SvPV_const(*args, len);
+ if (!IS_SAFE_PATHNAME(path, len, "open"))
+ return NULL;
+ fd = PerlLIO_open3_cloexec(path, imode, perm);
+ known_cloexec = 1;
}
}
if (fd >= 0) {
+ if (known_cloexec)
+ setfd_inhexec_for_sysfd(fd);
+ else
+ setfd_cloexec_or_inhexec_by_sysfdness(fd);
if (*mode == IoTYPE_IMPLICIT)
mode++;
if (!f) {
}
if (!PerlIOValid(f)) {
if (!(f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) {
+ PerlLIO_close(fd);
return NULL;
}
}
const PerlIOUnix * const os = PerlIOSelf(o, PerlIOUnix);
int fd = os->fd;
if (flags & PERLIO_DUP_FD) {
- fd = PerlLIO_dup(fd);
+ fd = PerlLIO_dup_cloexec(fd);
+ if (fd >= 0)
+ setfd_inhexec_for_sysfd(fd);
}
if (fd >= 0) {
f = PerlIOBase_dup(aTHX_ f, o, param, flags);
PerlIOUnix_setfd(aTHX_ f, fd, os->oflags);
return f;
}
+ PerlLIO_close(fd);
}
return NULL;
}
SSize_t
PerlIOUnix_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
{
- dVAR;
int fd;
if (PerlIO_lockcnt(f)) /* in use: abort ungracefully */
return -1;
if (len < 0) {
if (errno != EAGAIN) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ PerlIO_save_errno(f);
}
}
else if (len == 0 && count != 0) {
if (PL_sig_pending && S_perlio_async_run(aTHX_ f))
return -1;
}
- /*NOTREACHED*/
+ NOT_REACHED; /*NOTREACHED*/
}
SSize_t
PerlIOUnix_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- dVAR;
int fd;
if (PerlIO_lockcnt(f)) /* in use: abort ungracefully */
return -1;
if (len < 0) {
if (errno != EAGAIN) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ PerlIO_save_errno(f);
}
}
return len;
if (PL_sig_pending && S_perlio_async_run(aTHX_ f))
return -1;
}
- /*NOTREACHED*/
+ NOT_REACHED; /*NOTREACHED*/
}
Off_t
IV
PerlIOUnix_close(pTHX_ PerlIO *f)
{
- dVAR;
const int fd = PerlIOSelf(f, PerlIOUnix)->fd;
int code = 0;
if (PerlIOBase(f)->flags & PERLIO_F_OPEN) {
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;
{
dTHX;
PerlIO *f = NULL;
+#ifdef EBCDIC
+ int rc;
+ char filename[FILENAME_MAX];
+ fldata_t fileinfo;
+#endif
if (stdio) {
PerlIOStdio *s;
+ int fd0 = fileno(stdio);
+ if (fd0 < 0) {
+#ifdef EBCDIC
+ rc = fldata(stdio,filename,&fileinfo);
+ if(rc != 0){
+ return NULL;
+ }
+ if(fileinfo.__dsorgHFS){
+ return NULL;
+ }
+ /*This MVS dataset , OK!*/
+#else
+ return NULL;
+#endif
+ }
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
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_cloexec(fd0);
+ FILE *f2;
+ if (fd < 0) {
+ return f;
+ }
+ f2 = PerlSIO_fdopen(fd, (mode = "r+"));
if (!f2) {
f2 = PerlSIO_fdopen(fd, (mode = "w"));
}
}
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));
+ fd0 = fileno(stdio);
+ if(fd0 != -1){
+ PerlIOUnix_refcnt_inc(fd0);
+ setfd_cloexec_or_inhexec_by_sysfdness(fd0);
+ }
+#ifdef EBCDIC
+ else{
+ rc = fldata(stdio,filename,&fileinfo);
+ if(rc != 0){
+ PerlIOUnix_refcnt_inc(fd0);
+ }
+ if(fileinfo.__dsorgHFS){
+ PerlIOUnix_refcnt_inc(fd0);
+ }
+ /*This MVS dataset , OK!*/
+ }
+#endif
}
}
return f;
{
char tmode[8];
if (PerlIOValid(f)) {
- const char * const path = SvPV_nolen_const(*args);
+ STRLEN len;
+ const char * const path = SvPV_const(*args, len);
PerlIOStdio * const s = PerlIOSelf(f, PerlIOStdio);
FILE *stdio;
+ 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;
- PerlIOUnix_refcnt_inc(fileno(s->stdio));
+ fd = fileno(stdio);
+ PerlIOUnix_refcnt_inc(fd);
+ setfd_cloexec_or_inhexec_by_sysfdness(fd);
return f;
}
else {
if (narg > 0) {
- const char * const path = SvPV_nolen_const(*args);
+ STRLEN len;
+ const char * const path = SvPV_const(*args, len);
+ if (!IS_SAFE_PATHNAME(path, len, "open"))
+ return NULL;
if (*mode == IoTYPE_NUMERIC) {
mode++;
- fd = PerlLIO_open3(path, imode, perm);
+ fd = PerlLIO_open3_cloexec(path, imode, perm);
}
else {
FILE *stdio;
f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg);
if (f) {
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
- PerlIOUnix_refcnt_inc(fileno(stdio));
+ fd = fileno(stdio);
+ PerlIOUnix_refcnt_inc(fd);
+ setfd_cloexec_or_inhexec_by_sysfdness(fd);
} else {
PerlSIO_fclose(stdio);
}
}
if ((f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) {
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
- PerlIOUnix_refcnt_inc(fileno(stdio));
+ fd = fileno(stdio);
+ PerlIOUnix_refcnt_inc(fd);
+ setfd_cloexec_or_inhexec_by_sysfdness(fd);
}
return f;
}
+ PerlLIO_close(fd);
}
}
return NULL;
const int fd = fileno(stdio);
char mode[8];
if (flags & PERLIO_DUP_FD) {
- const int dfd = PerlLIO_dup(fileno(stdio));
+ const int dfd = PerlLIO_dup_cloexec(fileno(stdio));
if (dfd >= 0) {
stdio = PerlSIO_fdopen(dfd, PerlIO_modestr(o,mode));
goto set_this;
set_this:
PerlIOSelf(f, PerlIOStdio)->stdio = stdio;
if(stdio) {
- PerlIOUnix_refcnt_inc(fileno(stdio));
+ int fd = fileno(stdio);
+ PerlIOUnix_refcnt_inc(fd);
+ setfd_cloexec_or_inhexec_by_sysfdness(fd);
}
}
return f;
/* XXX this could use PerlIO_canset_fileno() and
* PerlIO_set_fileno() support from Configure
*/
-# if defined(__UCLIBC__)
+# if defined(HAS_FDCLOSE)
+ return fdclose(f, NULL) == 0 ? 1 : 0;
+# elif defined(__UCLIBC__)
/* uClibc must come before glibc because it defines __GLIBC__ as well. */
f->__filedes = -1;
return 1;
*/
f->_fileno = -1;
return 1;
-# elif defined(__sun__)
+# elif defined(__sun)
PERL_UNUSED_ARG(f);
return 0;
# elif defined(__hpux)
structure at all
*/
# else
- f->_file = -1;
+ PERLIO_FILE_file(f) = -1;
# endif
return 1;
# else
return 0;
if (stdio == stdout || stdio == stderr)
return PerlIO_flush(f);
+ }
+ MUTEX_LOCK(&PL_perlio_mutex);
+ /* Right. We need a mutex here because for a brief while we
+ will have the situation that fd is actually closed. Hence if
+ a second thread were to get into this block, its dup() would
+ likely return our fd as its dupfd. (after all, it is closed)
+ Then if we get to the dup2() first, we blat the fd back
+ (messing up its temporary as a side effect) only for it to
+ then close its dupfd (== our fd) in its close(dupfd) */
+
+ /* There is, of course, a race condition, that any other thread
+ trying to input/output/whatever on this fd will be stuffed
+ for the duration of this little manoeuvrer. Perhaps we
+ should hold an IO mutex for the duration of every IO
+ operation if we know that invalidate doesn't work on this
+ platform, but that would suck, and could kill performance.
+
+ Except that correctness trumps speed.
+ Advice from klortho #11912. */
+ if (invalidate) {
/* Tricky - must fclose(stdio) to free memory but not close(fd)
Use Sarathy's trick from maint-5.6 to invalidate the
fileno slot of the FILE *
SAVE_ERRNO;
invalidate = PerlIOStdio_invalidate_fileno(aTHX_ stdio);
if (!invalidate) {
-#ifdef USE_ITHREADS
- MUTEX_LOCK(&PL_perlio_mutex);
- /* Right. We need a mutex here because for a brief while we
- will have the situation that fd is actually closed. Hence if
- a second thread were to get into this block, its dup() would
- likely return our fd as its dupfd. (after all, it is closed)
- Then if we get to the dup2() first, we blat the fd back
- (messing up its temporary as a side effect) only for it to
- then close its dupfd (== our fd) in its close(dupfd) */
-
- /* There is, of course, a race condition, that any other thread
- trying to input/output/whatever on this fd will be stuffed
- for the duration of this little manoeuvrer. Perhaps we
- should hold an IO mutex for the duration of every IO
- operation if we know that invalidate doesn't work on this
- platform, but that would suck, and could kill performance.
-
- Except that correctness trumps speed.
- Advice from klortho #11912. */
-#endif
- dupfd = PerlLIO_dup(fd);
+ dupfd = PerlLIO_dup_cloexec(fd);
#ifdef USE_ITHREADS
if (dupfd < 0) {
- MUTEX_UNLOCK(&PL_perlio_mutex);
/* Oh cXap. This isn't going to go well. Not sure if we can
recover from here, or if closing this particular FILE *
is a good idea now. */
result = close(fd);
#endif
if (dupfd >= 0) {
- PerlLIO_dup2(dupfd,fd);
+ PerlLIO_dup2_cloexec(dupfd, fd);
+ setfd_inhexec_for_sysfd(fd);
PerlLIO_close(dupfd);
-#ifdef USE_ITHREADS
- MUTEX_UNLOCK(&PL_perlio_mutex);
-#endif
}
+ MUTEX_UNLOCK(&PL_perlio_mutex);
return result;
}
}
SSize_t
PerlIOStdio_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
{
- dVAR;
FILE * s;
SSize_t got = 0;
if (PerlIO_lockcnt(f)) /* in use: abort ungracefully */
return -1;
SETERRNO(0,0); /* just in case */
}
+#ifdef __sgi
+ /* Under some circumstances IRIX stdio fgetc() and fread()
+ * set the errno to ENOENT, which makes no sense according
+ * to either IRIX or POSIX. [rt.perl.org #123977] */
+ if (errno == ENOENT) SETERRNO(0,0);
+#endif
return got;
}
}
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--;
SSize_t
PerlIOStdio_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- dVAR;
SSize_t got;
if (PerlIO_lockcnt(f)) /* in use: abort ungracefully */
return -1;
PerlIOStdio_get_base(pTHX_ PerlIO *f)
{
FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ PERL_UNUSED_CONTEXT;
return (STDCHAR*)PerlSIO_get_base(stdio);
}
PerlIOStdio_get_bufsiz(pTHX_ PerlIO *f)
{
FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ PERL_UNUSED_CONTEXT;
return PerlSIO_get_bufsiz(stdio);
}
#endif
PerlIOStdio_get_ptr(pTHX_ PerlIO *f)
{
FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ PERL_UNUSED_CONTEXT;
return (STDCHAR*)PerlSIO_get_ptr(stdio);
}
PerlIOStdio_get_cnt(pTHX_ PerlIO *f)
{
FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ PERL_UNUSED_CONTEXT;
return PerlSIO_get_cnt(stdio);
}
PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
{
FILE * const stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ PERL_UNUSED_CONTEXT;
if (ptr != NULL) {
#ifdef STDIO_PTR_LVALUE
+ /* This is a long-standing infamous mess. The root of the
+ * problem is that one cannot know the signedness of char, and
+ * more precisely the signedness of FILE._ptr. The following
+ * things have been tried, and they have all failed (across
+ * different compilers (remember that core needs to to build
+ * also with c++) and compiler options:
+ *
+ * - casting the RHS to (void*) -- works in *some* places
+ * - casting the LHS to (void*) -- totally unportable
+ *
+ * So let's try silencing the warning at least for gcc. */
+ GCC_DIAG_IGNORE_STMT(-Wpointer-sign);
PerlSIO_set_ptr(stdio, ptr); /* LHS STDCHAR* cast non-portable */
+ GCC_DIAG_RESTORE_STMT;
#ifdef STDIO_PTR_LVAL_SETS_CNT
assert(PerlSIO_get_cnt(stdio) == (cnt));
#endif
*/
#ifdef STDIO_CNT_LVALUE
PerlSIO_set_cnt(stdio, cnt);
-#else /* STDIO_CNT_LVALUE */
-#if (defined(STDIO_PTR_LVALUE) && defined(STDIO_PTR_LVAL_SETS_CNT))
+#elif (defined(STDIO_PTR_LVALUE) && defined(STDIO_PTR_LVAL_SETS_CNT))
PerlSIO_set_ptr(stdio,
PerlSIO_get_ptr(stdio) + (PerlSIO_get_cnt(stdio) -
cnt));
#else /* STDIO_PTR_LVAL_SETS_CNT */
PerlProc_abort();
-#endif /* STDIO_PTR_LVAL_SETS_CNT */
#endif /* STDIO_CNT_LVALUE */
}
}
#endif
-#if defined(VMS)
- /* An ungetc()d char is handled separately from the regular
- * buffer, so we stuff it in the buffer ourselves.
- * Should never get called as should hit code above
- */
- *(--((*stdio)->_ptr)) = (unsigned char) c;
- (*stdio)->_cnt++;
-#else
/* If buffer snoop scheme above fails fall back to
using ungetc().
*/
if (PerlSIO_ungetc(c, stdio) != c)
return EOF;
-#endif
+
return 0;
}
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);
void
PerlIO_releaseFILE(PerlIO *p, FILE *f)
{
- dVAR;
PerlIOl *l;
while ((l = *p)) {
if (l->tab == &PerlIO_stdio) {
}
else if (count < 0 || PerlIO_error(n)) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ PerlIO_save_errno(f);
code = -1;
break;
}
if (avail == 0)
PerlIOBase(f)->flags |= PERLIO_F_EOF;
else
+ {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ PerlIO_save_errno(f);
+ }
return -1;
}
b->end = b->buf + avail;
*/
b->posn -= b->bufsiz;
}
- if (avail > (SSize_t) count) {
+ if ((SSize_t) count >= 0 && avail > (SSize_t) count) {
/*
* If we have space for more than count, just move count
*/
}
while (count > 0) {
SSize_t avail = b->bufsiz - (b->ptr - b->buf);
- if ((SSize_t) count < avail)
+ if ((SSize_t) count >= 0 && (SSize_t) count < avail)
avail = count;
if (flushptr > buf && flushptr <= buf + avail)
avail = flushptr - buf;
if (!b->buf) {
if (!b->bufsiz)
b->bufsiz = PERLIOBUF_DEFAULT_BUFSIZ;
- Newxz(b->buf,b->bufsiz, STDCHAR);
+ Newx(b->buf,b->bufsiz, STDCHAR);
if (!b->buf) {
b->buf = (STDCHAR *) & b->oneword;
b->bufsiz = sizeof(b->oneword);
{
SSize_t avail = PerlIO_get_cnt(f);
SSize_t got = 0;
- if ((SSize_t)count < avail)
+ if ((SSize_t) count >= 0 && (SSize_t)count < avail)
avail = count;
if (avail > 0)
got = PerlIOBuf_read(aTHX_ f, vbuf, avail);
PerlIOBase(f)->flags |= PERLIO_F_CRLF;
code = PerlIOBuf_pushed(aTHX_ f, mode, arg, tab);
#if 0
+ DEBUG_i(
PerlIO_debug("PerlIOCrlf_pushed f=%p %s %s fl=%08" UVxf "\n",
(void*)f, PerlIOBase(f)->tab->name, (mode) ? mode : "(Null)",
PerlIOBase(f)->flags);
+ );
#endif
{
/* If the old top layer is a CRLF layer, reactivate it (if
{
PerlIOCrlf * const c = PerlIOSelf(f, PerlIOCrlf);
if (c->nl) { /* XXXX Shouldn't it be done only if b->ptr > c->nl? */
- *(c->nl) = 0xd;
+ *(c->nl) = NATIVE_0xd;
c->nl = NULL;
}
if (!(PerlIOBase(f)->flags & PERLIO_F_CRLF))
const int ch = *--buf;
if (ch == '\n') {
if (b->ptr - 2 >= b->buf) {
- *--(b->ptr) = 0xa;
- *--(b->ptr) = 0xd;
+ *--(b->ptr) = NATIVE_0xa;
+ *--(b->ptr) = NATIVE_0xd;
unread++;
count--;
}
else {
/* If b->ptr - 1 == b->buf, we are undoing reading 0xa */
- *--(b->ptr) = 0xa; /* Works even if 0xa == '\r' */
+ *--(b->ptr) = NATIVE_0xa; /* Works even if 0xa ==
+ '\r' */
unread++;
count--;
}
}
}
}
+ if (count > 0)
+ unread += PerlIOBase_unread(aTHX_ f, (const STDCHAR *) vbuf + unread, count);
return unread;
}
}
PerlIO_get_base(f);
if (PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
PerlIOCrlf * const c = PerlIOSelf(f, PerlIOCrlf);
- if ((PerlIOBase(f)->flags & PERLIO_F_CRLF) && (!c->nl || *c->nl == 0xd)) {
+ if ((PerlIOBase(f)->flags & PERLIO_F_CRLF) && (!c->nl || *c->nl == NATIVE_0xd)) {
STDCHAR *nl = (c->nl) ? c->nl : b->ptr;
scan:
- while (nl < b->end && *nl != 0xd)
+ while (nl < b->end && *nl != NATIVE_0xd)
nl++;
- if (nl < b->end && *nl == 0xd) {
+ if (nl < b->end && *nl == NATIVE_0xd) {
test:
if (nl + 1 < b->end) {
- if (nl[1] == 0xa) {
+ if (nl[1] == NATIVE_0xa) {
*nl = '\n';
c->nl = nl;
}
b->buf--; /* Point at space */
b->ptr = nl = b->buf; /* Which is what we hand
* off */
- *nl = 0xd; /* Fill in the CR */
+ *nl = NATIVE_0xd; /* Fill in the CR */
if (code == 0)
goto test; /* fill() call worked */
/*
if (!ptr) {
if (c->nl) {
ptr = c->nl + 1;
- if (ptr == b->end && *c->nl == 0xd) {
+ if (ptr == b->end && *c->nl == NATIVE_0xd) {
/* Deferred CR at end of buffer case - we lied about count */
ptr--;
}
*/
IV flags = PerlIOBase(f)->flags;
STDCHAR *chk = (c->nl) ? (c->nl+1) : b->end;
- if (ptr+cnt == c->nl && c->nl+1 == b->end && *c->nl == 0xd) {
+ if (ptr+cnt == c->nl && c->nl+1 == b->end && *c->nl == NATIVE_0xd) {
/* Deferred CR at end of buffer case - we lied about count */
chk--;
}
/*
* They have taken what we lied about
*/
- *(c->nl) = 0xd;
+ *(c->nl) = NATIVE_0xd;
c->nl = NULL;
ptr++;
}
break;
}
else {
- *(b->ptr)++ = 0xd; /* CR */
- *(b->ptr)++ = 0xa; /* LF */
+ *(b->ptr)++ = NATIVE_0xd; /* CR */
+ *(b->ptr)++ = NATIVE_0xa; /* LF */
buf++;
if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) {
PerlIO_flush(f);
{
PerlIOCrlf * const c = PerlIOSelf(f, PerlIOCrlf);
if (c->nl) {
- *(c->nl) = 0xd;
+ *(c->nl) = NATIVE_0xd;
c->nl = NULL;
}
return PerlIOBuf_flush(aTHX_ f);
PerlIO_pop(aTHX_ f);
#endif
}
- return 0;
+ return PerlIOBase_binmode(aTHX_ f);
}
PERLIO_FUNCS_DECL(PerlIO_crlf) = {
PerlIO *
Perl_PerlIO_stdin(pTHX)
{
- dVAR;
if (!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
PerlIO *
Perl_PerlIO_stdout(pTHX)
{
- dVAR;
if (!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
PerlIO *
Perl_PerlIO_stderr(pTHX)
{
- dVAR;
if (!PL_perlio) {
PerlIO_stdstreams(aTHX);
}
va_list apc;
Perl_va_copy(ap, apc);
sv = vnewSVpvf(fmt, &apc);
+ va_end(apc);
#else
sv = vnewSVpvf(fmt, &ap);
#endif
const int fd = win32_tmpfd();
if (fd >= 0)
f = PerlIO_fdopen(fd, "w+b");
-#else /* WIN32 */
-# if defined(HAS_MKSTEMP) && ! defined(VMS) && ! defined(OS2)
+#elif ! defined(VMS) && ! defined(OS2)
int fd = -1;
char tempname[] = "/tmp/PerlIO_XXXXXX";
const char * const tmpdir = TAINTING_get ? NULL : PerlEnv_getenv("TMPDIR");
SV * sv = NULL;
- /*
- * I have no idea how portable mkstemp() is ... NI-S
- */
+ int old_umask = umask(0177);
if (tmpdir && *tmpdir) {
/* if TMPDIR is set and not empty, we try that first */
sv = newSVpv(tmpdir, 0);
sv_catpv(sv, tempname + 4);
- fd = mkstemp(SvPVX(sv));
+ fd = Perl_my_mkstemp_cloexec(SvPVX(sv));
}
if (fd < 0) {
+ SvREFCNT_dec(sv);
sv = NULL;
/* else we try /tmp */
- fd = mkstemp(tempname);
+ fd = Perl_my_mkstemp_cloexec(tempname);
+ }
+ if (fd < 0) {
+ /* Try cwd */
+ sv = newSVpvs(".");
+ sv_catpv(sv, tempname + 4);
+ fd = Perl_my_mkstemp_cloexec(SvPVX(sv));
}
+ umask(old_umask);
if (fd >= 0) {
f = PerlIO_fdopen(fd, "w+");
if (f)
PerlLIO_unlink(sv ? SvPVX_const(sv) : tempname);
}
SvREFCNT_dec(sv);
-# else /* !HAS_MKSTEMP, fallback to stdio tmpfile(). */
+#else /* !HAS_MKSTEMP, fallback to stdio tmpfile(). */
FILE * const stdio = PerlSIO_tmpfile();
if (stdio)
f = PerlIO_fdopen(fileno(stdio), "w+");
-# endif /* else HAS_MKSTEMP */
#endif /* else WIN32 */
return f;
}
+void
+Perl_PerlIO_save_errno(pTHX_ PerlIO *f)
+{
+ PERL_UNUSED_CONTEXT;
+ if (!PerlIOValid(f))
+ return;
+ PerlIOBase(f)->err = errno;
+#ifdef VMS
+ PerlIOBase(f)->os_err = vaxc$errno;
+#elif defined(OS2)
+ PerlIOBase(f)->os_err = Perl_rc;
+#elif defined(WIN32)
+ PerlIOBase(f)->os_err = GetLastError();
+#endif
+}
+
+void
+Perl_PerlIO_restore_errno(pTHX_ PerlIO *f)
+{
+ PERL_UNUSED_CONTEXT;
+ if (!PerlIOValid(f))
+ return;
+ SETERRNO(PerlIOBase(f)->err, PerlIOBase(f)->os_err);
+#ifdef OS2
+ Perl_rc = PerlIOBase(f)->os_err);
+#elif defined(WIN32)
+ SetLastError(PerlIOBase(f)->os_err);
+#endif
+}
+
#undef HAS_FSETPOS
#undef HAS_FGETPOS
-#endif /* USE_SFIO */
-#endif /* PERLIO_IS_STDIO */
/*======================================================================================*/
/*
const char *
Perl_PerlIO_context_layers(pTHX_ const char *mode)
{
- dVAR;
const char *direction = NULL;
SV *layers;
/*
PerlIO_setpos(PerlIO *f, SV *pos)
{
if (SvOK(pos)) {
- STRLEN len;
- dTHX;
- const Off_t * const posn = (Off_t *) SvPV(pos, len);
- if (f && len == sizeof(Off_t))
- return PerlIO_seek(f, *posn, SEEK_SET);
+ if (f) {
+ dTHX;
+ STRLEN len;
+ const Off_t * const posn = (Off_t *) SvPV(pos, len);
+ if(len == sizeof(Off_t))
+ return PerlIO_seek(f, *posn, SEEK_SET);
+ }
}
SETERRNO(EINVAL, SS_IVCHAN);
return -1;
int
PerlIO_setpos(PerlIO *f, SV *pos)
{
- dTHX;
if (SvOK(pos)) {
- STRLEN len;
- Fpos_t * const fpos = (Fpos_t *) SvPV(pos, len);
- if (f && len == sizeof(Fpos_t)) {
+ if (f) {
+ dTHX;
+ STRLEN len;
+ Fpos_t * const fpos = (Fpos_t *) SvPV(pos, len);
+ if(len == sizeof(Fpos_t))
#if defined(USE_64_BIT_STDIO) && defined(USE_FSETPOS64)
- return fsetpos64(f, fpos);
+ return fsetpos64(f, fpos);
#else
- return fsetpos(f, fpos);
+ return fsetpos(f, fpos);
#endif
}
}
}
#endif
-#if (defined(PERLIO_IS_STDIO) || !defined(USE_SFIO)) && !defined(HAS_VPRINTF)
-
-int
-vprintf(char *pat, char *args)
-{
- _doprnt(pat, args, stdout);
- return 0; /* wrong, but perl doesn't use the return
- * value */
-}
-
-int
-vfprintf(FILE *fd, char *pat, char *args)
-{
- _doprnt(pat, args, fd);
- return 0; /* wrong, but perl doesn't use the return
- * value */
-}
-
-#endif
-
-#ifndef PerlIO_vsprintf
-int
-PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
-{
- dTHX;
- const int val = my_vsnprintf(s, n > 0 ? n : 0, fmt, ap);
- PERL_UNUSED_CONTEXT;
-
-#ifndef PERL_MY_VSNPRINTF_GUARDED
- if (val < 0 || (n > 0 ? val >= n : 0)) {
- Perl_croak(aTHX_ "panic: my_vsnprintf overflow in PerlIO_vsprintf\n");
- }
-#endif
- return val;
-}
-#endif
+/* print a failure format string message to stderr and fail exit the process
+ using only libc without depending on any perl data structures being
+ initialized.
+*/
-#ifndef PerlIO_sprintf
-int
-PerlIO_sprintf(char *s, int n, const char *fmt, ...)
+void
+Perl_noperl_die(const char* pat, ...)
{
- va_list ap;
- int result;
- va_start(ap, fmt);
- result = PerlIO_vsprintf(s, n, fmt, ap);
- va_end(ap);
- return result;
+ va_list arglist;
+ PERL_ARGS_ASSERT_NOPERL_DIE;
+ va_start(arglist, pat);
+ vfprintf(stderr, pat, arglist);
+ va_end(arglist);
+ exit(1);
}
-#endif
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
* ex: set ts=8 sts=4 sw=4 et:
*/