diff options
author | Nick Ing-Simmons <nik@tiuk.ti.com> | 2002-04-27 10:12:00 +0000 |
---|---|---|
committer | Nick Ing-Simmons <nik@tiuk.ti.com> | 2002-04-27 10:12:00 +0000 |
commit | d9dac8cda3a8128f09ab4445f683196e1392e4fa (patch) | |
tree | 51c295cc2653c2439a295fbdb0e771cd3de5bc9b /ext/PerlIO | |
parent | 5f228b1d3feafe3247efca23709f3c7bd5daf91b (diff) | |
download | perl-d9dac8cda3a8128f09ab4445f683196e1392e4fa.tar.gz |
Fix fd leak on Via(bogus).
Finish implementing PerlIOVia_open().
Export more guts of PerlIO_* so Via_open() can work.
Fix various PerlIO_allocate() features exposed by above.
p4raw-id: //depot/perlio@16207
Diffstat (limited to 'ext/PerlIO')
-rw-r--r-- | ext/PerlIO/Via/Via.xs | 59 | ||||
-rw-r--r-- | ext/PerlIO/t/via.t | 22 |
2 files changed, 76 insertions, 5 deletions
diff --git a/ext/PerlIO/Via/Via.xs b/ext/PerlIO/Via/Via.xs index af5f5ea00f..494ddf9118 100644 --- a/ext/PerlIO/Via/Via.xs +++ b/ext/PerlIO/Via/Via.xs @@ -55,6 +55,14 @@ PerlIOVia_fetchmethod(pTHX_ PerlIOVia *s,char *method,CV **save) } } +/* + * Try and call method, possibly via cached lookup. + * If method does not exist return Nullsv (caller may fallback to another approach + * If method does exist call it with flags passing variable number of args + * Last arg is a "filehandle" to layer below (if present) + * Returns scalar returned by method (if any) otherwise sv_undef + */ + SV * PerlIOVia_method(pTHX_ PerlIO *f,char *method,CV **save,int flags,...) { @@ -88,6 +96,10 @@ PerlIOVia_method(pTHX_ PerlIO *f,char *method,CV **save,int flags,...) IoOFP(s->io) = PerlIONext(f); XPUSHs(s->fh); } + else + { + PerlIO_debug("No next\n"); + } PUTBACK; count = call_sv((SV *)cv,flags); if (count) @@ -117,6 +129,7 @@ PerlIOVia_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) { if (ckWARN(WARN_LAYER)) Perl_warner(aTHX_ packWARN(WARN_LAYER), "No package specified"); + errno = EINVAL; code = -1; } else @@ -163,7 +176,9 @@ PerlIOVia_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) } PerlIO * -PerlIOVia_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, const char *mode, int fd, int imode, int perm, PerlIO *f, int narg, SV **args) +PerlIOVia_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, + const char *mode, int fd, int imode, int perm, + PerlIO *f, int narg, SV **args) { if (!f) { @@ -171,6 +186,7 @@ PerlIOVia_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, const char } else { + /* Reopen */ if (!PerlIO_push(aTHX_ f,self,mode,PerlIOArg)) return NULL; } @@ -206,7 +222,44 @@ PerlIOVia_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, const char } } else - return NULL; + { + /* Required open method not present */ + PerlIO_funcs *tab = NULL; + IV m = n-1; + while (m >= 0) { + PerlIO_funcs *t = PerlIO_layer_fetch(aTHX_ layers, m, NULL); + if (t && t->Open) { + tab = t; + break; + } + n--; + } + if (tab) { + if ((*tab->Open) (aTHX_ tab, layers, m, mode, fd, imode, perm, + PerlIONext(f), narg, args)) { + PerlIO_debug("Opened with %s => %p->%p\n",tab->name,PerlIONext(f),*PerlIONext(f)); + if (m + 1 < n) { + /* + * More layers above the one that we used to open - + * apply them now + */ + if (PerlIO_apply_layera(aTHX_ PerlIONext(f), mode, layers, m+1, n) != 0) { + /* If pushing layers fails close the file */ + PerlIO_close(f); + f = NULL; + } + } + return f; + } + else { + /* Sub-layer open failed */ + } + } + else { + /* Nothing to do the open */ + } + return NULL; + } } return f; } @@ -494,7 +547,7 @@ PerlIO_funcs PerlIO_object = { PERLIO_K_BUFFERED|PERLIO_K_DESTRUCT, PerlIOVia_pushed, PerlIOVia_popped, - NULL, /* PerlIOVia_open, */ + PerlIOVia_open, /* NULL, */ PerlIOVia_getarg, PerlIOVia_fileno, PerlIOVia_dup, diff --git a/ext/PerlIO/t/via.t b/ext/PerlIO/t/via.t index 89a1e13236..43ea3c5a95 100644 --- a/ext/PerlIO/t/via.t +++ b/ext/PerlIO/t/via.t @@ -14,7 +14,7 @@ BEGIN { my $tmp = "via$$"; -use Test::More tests => 11; +use Test::More tests => 13; my $fh; my $a = join("", map { chr } 0..255) x 10; @@ -38,14 +38,32 @@ is($a, $b, 'compare original data with filtered version'); local $SIG{__WARN__} = sub { $warnings = join '', @_ }; use warnings 'layer'; + + # Find fd number we should be using + my $fd = open($fh,">$tmp") && fileno($fh); + print $fh "Hello\n"; + close($fh); + ok( ! open($fh,">Via(Unknown::Module)", $tmp), 'open Via Unknown::Module will fail'); like( $warnings, qr/^Cannot find package 'Unknown::Module'/, 'warn about unknown package' ); + # Now open normally again to see if we get right fileno + my $fd2 = open($fh,"<$tmp") && fileno($fh); + is($fd2,$fd,"Wrong fd number after failed open"); + + my $data = <$fh>; + + is($data,"Hello\n","File clobbered by failed open"); + + close($fh); + + + $warnings = ''; no warnings 'layer'; ok( ! open($fh,">Via(Unknown::Module)", $tmp), 'open Via Unknown::Module will fail'); is( $warnings, "", "don't warn about unknown package" ); -} +} END { 1 while unlink $tmp; |