In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/269a3b2e76d9e7b398d9faa62b30dc6d93dd9476?hp=ac1ba09e8362c54848dc27d3484a5882c4b28f43>
- Log ----------------------------------------------------------------- commit 269a3b2e76d9e7b398d9faa62b30dc6d93dd9476 Merge: ac1ba09e83 b416949bcc Author: Tony Cook <t...@develop-help.com> Date: Mon Sep 18 11:18:55 2017 +1000 (127663) fix some portability issues with the new in-place edit - renameat() is present but broken for absolute paths on FreeBSD 11, add a workaround. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222258 - the new implementation uses linkat() but the availability checks in doio.c and the tests didn't check for it. ----------------------------------------------------------------------- Summary of changes: doio.c | 31 ++++++++++++++++++++++++++++--- t/run/switches.t | 17 ++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/doio.c b/doio.c index 8c08455eda..7b6c43531b 100644 --- a/doio.c +++ b/doio.c @@ -863,7 +863,8 @@ S_openindirtemp(pTHX_ GV *gv, SV *orig_name, SV *temp_out_name) { } #if defined(HAS_UNLINKAT) && defined(HAS_RENAMEAT) && defined(HAS_FCHMODAT) && \ - (defined(HAS_DIRFD) || defined(HAS_DIR_DD_FD)) && !defined(NO_USE_ATFUNCTIONS) + (defined(HAS_DIRFD) || defined(HAS_DIR_DD_FD)) && !defined(NO_USE_ATFUNCTIONS) && \ + defined(HAS_LINKAT) # define ARGV_USE_ATFUNCTIONS #endif @@ -1191,6 +1192,30 @@ Perl_nextargv(pTHX_ GV *gv, bool nomagicopen) return NULL; } +#ifdef ARGV_USE_ATFUNCTIONS +# if defined(__FreeBSD__) + +/* FreeBSD 11 renameat() mis-behaves strangely with absolute paths in cases where the + * equivalent rename() succeeds + */ +static int +S_my_renameat(int olddfd, const char *oldpath, int newdfd, const char *newpath) { + /* this is intended only for use in Perl_do_close() */ + assert(olddfd == newdfd); + assert(PERL_FILE_IS_ABSOLUTE(oldpath) == PERL_FILE_IS_ABSOLUTE(newpath)); + if (PERL_FILE_IS_ABSOLUTE(oldpath)) { + return PerlLIO_rename(oldpath, newpath); + } + else { + return renameat(olddfd, oldpath, newdfd, newpath); + } +} + +# else +# define S_my_renameat(dh1, pv1, dh2, pv2) renameat((dh1), (pv1), (dh2), (pv2)) +# endif /* if defined(__FreeBSD__) */ +#endif + /* explicit renamed to avoid C++ conflict -- kja */ bool Perl_do_close(pTHX_ GV *gv, bool not_implicit) @@ -1320,7 +1345,7 @@ Perl_do_close(pTHX_ GV *gv, bool not_implicit) #ifdef HAS_RENAME if ( # ifdef ARGV_USE_ATFUNCTIONS - renameat(dfd, orig_pv, dfd, SvPVX(*back_psv)) < 0 + S_my_renameat(dfd, orig_pv, dfd, SvPVX(*back_psv)) < 0 # else PerlLIO_rename(orig_pv, SvPVX(*back_psv)) < 0 # endif @@ -1360,7 +1385,7 @@ Perl_do_close(pTHX_ GV *gv, bool not_implicit) if ( #ifdef HAS_RENAME # ifdef ARGV_USE_ATFUNCTIONS - renameat(dfd, SvPVX(*temp_psv), dfd, orig_pv) < 0 + S_my_renameat(dfd, SvPVX(*temp_psv), dfd, orig_pv) < 0 # else PerlLIO_rename(SvPVX(*temp_psv), orig_pv) < 0 # endif diff --git a/t/run/switches.t b/t/run/switches.t index 6725f8fd35..ffc8fabc0d 100644 --- a/t/run/switches.t +++ b/t/run/switches.t @@ -12,7 +12,7 @@ BEGIN { BEGIN { require "./test.pl"; require "./loc_tools.pl"; } -plan(tests => 136); +plan(tests => 137); use Config; @@ -468,6 +468,7 @@ __EOF__ skip "Not enough *at functions", 3 unless $Config{d_unlinkat} && $Config{d_renameat} && $Config{d_fchmodat} && ($Config{d_dirfd} || $Config{d_dir_dd_fd}) + && $Config{d_linkat} && $Config{ccflags} !~ /-DNO_USE_ATFUNCTIONS\b/; fresh_perl_is(<<'CODE', "ok\n", { }, @ARGV = ("inplacetmp/foo"); @@ -552,6 +553,19 @@ CODE rmdir "$work.bak" or die "Cannot remove mask backup directory: $!"; } + { + # test with absolute paths, this was failing on FreeBSD 11ish due + # to a bug in renameat() + my $abs_work = File::Spec->rel2abs($work); + fresh_perl_is(<<'CODE', "", +while (<>) { + print; +} +CODE + { stderr => 1, args => [ $abs_work ], switches => [ "-i" ] }, + "abs paths"); + } + # we now use temp files for in-place editing, make sure we didn't leave # any behind in the above test opendir my $d, "inplacetmp" or die "Cannot opendir inplacetmp: $!"; @@ -594,6 +608,7 @@ CODE skip "Testing without *at functions", 1 if $Config{d_unlinkat} && $Config{d_renameat} && $Config{d_fchmodat} && ($Config{d_dirfd} || $Config{d_dir_dd_fd}) + && $Config{d_linkat} && $Config{ccflags} !~ /-DNO_USE_ATFUNCTIONS\b/; fresh_perl_like(<<'CODE', qr/^Cannot complete in-place edit of inplacetmp\/foo: .* - line 5, <> line \d+\./, { }, @ARGV = ("inplacetmp/foo"); -- Perl5 Master Repository