Hello community,

here is the log from the commit of package perl-File-Path-Tiny for 
openSUSE:Factory checked in at 2018-02-09 15:47:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-File-Path-Tiny (Old)
 and      /work/SRC/openSUSE:Factory/.perl-File-Path-Tiny.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-File-Path-Tiny"

Fri Feb  9 15:47:39 2018 rev:10 rq:573990 version:0.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-File-Path-Tiny/perl-File-Path-Tiny.changes  
2016-02-17 12:19:48.000000000 +0100
+++ 
/work/SRC/openSUSE:Factory/.perl-File-Path-Tiny.new/perl-File-Path-Tiny.changes 
    2018-02-09 15:47:40.455114948 +0100
@@ -1,0 +2,13 @@
+Wed Feb  7 16:31:14 UTC 2018 - co...@suse.com
+
+- updated to 0.9
+   see /usr/share/doc/packages/perl-File-Path-Tiny/Changes
+
+  0.9  2017-12-29 16:17:42
+      - Do chdir() for security reasons by default
+      - Stop emptying/removing a path if it is changed out from underneath us
+      - rt 96843: Add SEE ALSO section
+      - prereq and unit test fixups
+      - Unit tests for symlink toggling protection
+
+-------------------------------------------------------------------

Old:
----
  File-Path-Tiny-0.8.tar.gz

New:
----
  File-Path-Tiny-0.9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-File-Path-Tiny.spec ++++++
--- /var/tmp/diff_new_pack.axmMiY/_old  2018-02-09 15:47:41.251086365 +0100
+++ /var/tmp/diff_new_pack.axmMiY/_new  2018-02-09 15:47:41.255086221 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package perl-File-Path-Tiny
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,19 +17,21 @@
 
 
 Name:           perl-File-Path-Tiny
-Version:        0.8
+Version:        0.9
 Release:        0
 %define cpan_name File-Path-Tiny
 Summary:        Recursive Versions of Mkdir() and Rmdir() Without As Much 
Overhead As Fi[cut]
 License:        Artistic-1.0 or GPL-1.0+
 Group:          Development/Libraries/Perl
 Url:            http://search.cpan.org/dist/File-Path-Tiny/
-Source0:        
http://www.cpan.org/authors/id/D/DM/DMUEY/%{cpan_name}-%{version}.tar.gz
+Source0:        
https://cpan.metacpan.org/authors/id/D/DM/DMUEY/%{cpan_name}-%{version}.tar.gz
 Source1:        cpanspec.yml
 BuildArch:      noarch
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRequires:  perl
 BuildRequires:  perl-macros
+BuildRequires:  perl(Test::Exception)
+Requires:       perl(Test::Exception)
 %{perl_requires}
 
 %description
@@ -53,14 +55,20 @@
 
 * * chdir()s
 
-It does a ton of chdir()s which could leave you somewhere you're not
+It forces a ton of chdir()s which could leave you somewhere you're not
 planning on being and requires much more overhead to do.
 
+This module provides a way to disable that if you know it is safe to do so
+in your circumstance.
+
 * * can croak not allowing you to detect and handle failure
 
 Just let me handle errors how I want. Don't make my entire app die or have
 to wrap it in an eval
 
+The exception here is the security checks can croak, which is what you
+want. See DIAGNOSTICS for more info.
+
 * * A well intentioned output system
 
 Just let me do the output how I want. (Nothing, As HTML, print to a

++++++ File-Path-Tiny-0.8.tar.gz -> File-Path-Tiny-0.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/Changes 
new/File-Path-Tiny-0.9/Changes
--- old/File-Path-Tiny-0.8/Changes      2016-01-26 21:48:41.000000000 +0100
+++ new/File-Path-Tiny-0.9/Changes      2017-12-29 23:18:10.000000000 +0100
@@ -1,5 +1,12 @@
 Revision history for File-Path-Tiny
 
+0.9  2017-12-29 16:17:42
+    - Do chdir() for security reasons by default
+    - Stop emptying/removing a path if it is changed out from underneath us
+    - rt 96843: Add SEE ALSO section
+    - prereq and unit test fixups
+    - Unit tests for symlink toggling protection
+
 0.8  2016-01-26 14:44:57
     - rt 88849: allow multiple processes to operate on the same paths (thanks 
HELENA!)
     - Add github to POD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/MANIFEST 
new/File-Path-Tiny-0.9/MANIFEST
--- old/File-Path-Tiny-0.8/MANIFEST     2013-09-27 01:44:41.000000000 +0200
+++ new/File-Path-Tiny-0.9/MANIFEST     2017-12-29 15:44:23.000000000 +0100
@@ -5,6 +5,7 @@
 lib/File/Path/Tiny.pm
 lib/File/Path/Tiny.pod
 t/00.load.t
+t/01.symtogsafe.t
 t/perlcritic.t
 t/perltidy.t
 t/pkg-changes.t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/META.json 
new/File-Path-Tiny-0.9/META.json
--- old/File-Path-Tiny-0.8/META.json    2016-01-26 21:49:47.000000000 +0100
+++ new/File-Path-Tiny-0.9/META.json    2017-12-29 23:21:26.000000000 +0100
@@ -4,7 +4,7 @@
       "Daniel Muey <http://drmuey.com/cpan_contact.pl>"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter 
version 2.150001",
+   "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter 
version 2.150001",
    "license" : [
       "perl_5"
    ],
@@ -32,10 +32,14 @@
       },
       "runtime" : {
          "requires" : {
+            "Carp" : "0",
+            "Cwd" : "0",
+            "File::Temp" : "0",
+            "Test::Exception" : "0",
             "Test::More" : "0"
          }
       }
    },
    "release_status" : "stable",
-   "version" : "0.8"
+   "version" : "0.9"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/META.yml 
new/File-Path-Tiny-0.9/META.yml
--- old/File-Path-Tiny-0.8/META.yml     2016-01-26 21:49:46.000000000 +0100
+++ new/File-Path-Tiny-0.9/META.yml     2017-12-29 23:21:26.000000000 +0100
@@ -7,7 +7,7 @@
 configure_requires:
   ExtUtils::MakeMaker: '0'
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 
2.150001'
+generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 
2.150001'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -18,5 +18,9 @@
     - t
     - inc
 requires:
+  Carp: '0'
+  Cwd: '0'
+  File::Temp: '0'
+  Test::Exception: '0'
   Test::More: '0'
-version: '0.8'
+version: '0.9'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/Makefile.PL 
new/File-Path-Tiny-0.9/Makefile.PL
--- old/File-Path-Tiny-0.8/Makefile.PL  2013-09-27 01:56:30.000000000 +0200
+++ new/File-Path-Tiny-0.9/Makefile.PL  2017-12-29 21:13:08.000000000 +0100
@@ -10,7 +10,11 @@
     PL_FILES      => {},
     LICENSE       => 'perl',
     PREREQ_PM     => {
-        'Test::More' => 0,
+        'Test::More'      => 0,    # for unit tests
+        'File::Temp'      => 0,    # for unit tests
+        'Test::Exception' => 0,    # for unit tests
+        'Cwd'             => 0,
+        'Carp'            => 0,
     },
     dist  => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
     clean => { FILES    => 'File-Path-Tiny-*' },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/README 
new/File-Path-Tiny-0.9/README
--- old/File-Path-Tiny-0.8/README       2016-01-26 21:45:59.000000000 +0100
+++ new/File-Path-Tiny-0.9/README       2017-12-29 23:18:25.000000000 +0100
@@ -1,4 +1,4 @@
-File-Path-Tiny version 0.8
+File-Path-Tiny version 0.9
 
 DOCUMENTATION
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/lib/File/Path/Tiny.pm 
new/File-Path-Tiny-0.9/lib/File/Path/Tiny.pm
--- old/File-Path-Tiny-0.8/lib/File/Path/Tiny.pm        2016-01-26 
21:45:37.000000000 +0100
+++ new/File-Path-Tiny-0.9/lib/File/Path/Tiny.pm        2017-12-29 
23:18:39.000000000 +0100
@@ -2,8 +2,10 @@
 
 use strict;
 use warnings;
+use Cwd qw(cwd chdir);
+use Carp ();
 
-$File::Path::Tiny::VERSION = 0.8;
+$File::Path::Tiny::VERSION = 0.9;
 
 sub mk {
     my ( $path, $mask ) = @_;
@@ -30,30 +32,56 @@
 }
 
 sub rm {
-    my ($path) = @_;
-    if ( -e $path && !-d $path ) { $! = 20; return; }
-    return 2 if !-d $path;
-    empty_dir($path) or return;
+    my ( $path, $fast ) = @_;
+    my ( $orig_dev, $orig_ino ) = ( lstat $path )[ 0, 1 ];
+    if ( -e _ && !-d _ ) { $! = 20; return; }
+    return 2 if !-d _;
+
+    empty_dir( $path, $fast ) or return;
+    _bail_if_changed( $path, $orig_dev, $orig_ino );
     rmdir($path) or !-e $path or return;
     return 1;
 }
 
 sub empty_dir {
-    my ($path) = @_;
-    if ( -e $path && !-d $path ) { $! = 20; return; }
+    my ( $path, $fast ) = @_;
+    my ( $orig_dev, $orig_ino ) = ( lstat $path )[ 0, 1 ];
+    if ( -e _ && !-d _ ) { $! = 20; return; }
+
+    my ( $starting_point, $starting_dev, $starting_ino );
+    if ( !$fast ) {
+        $starting_point = cwd();
+        ( $starting_dev, $starting_ino ) = ( lstat $starting_point )[ 0, 1 ];
+        chdir($path) or Carp::croak("Failed to change directory to “$path”: 
$!");
+        $path = '.';
+        _bail_if_changed( $path, $orig_dev, $orig_ino );
+    }
+
     opendir( DIR, $path ) or return;
     my @contents = grep { $_ ne '.' && $_ ne '..' } readdir(DIR);
     closedir DIR;
+    _bail_if_changed( $path, $orig_dev, $orig_ino );
+
     require File::Spec if @contents;
     for my $thing (@contents) {
         my $long = File::Spec->catdir( $path, $thing );
-        if ( !-l $long && -d $long ) {
+        if ( !-l $long && -d _ ) {
+            _bail_if_changed( $path, $orig_dev, $orig_ino );
             rm($long) or !-e $long or return;
         }
         else {
+            _bail_if_changed( $path, $orig_dev, $orig_ino );
             unlink $long or !-e $long or return;
         }
     }
+
+    _bail_if_changed( $path, $orig_dev, $orig_ino );
+
+    if ( !$fast ) {
+        chdir($starting_point) or Carp::croak("Failed to change directory to 
“$starting_point”: $!");
+        _bail_if_changed( ".", $starting_dev, $starting_ino );
+    }
+
     return 1;
 }
 
@@ -73,4 +101,23 @@
     return mk( $parent, $mode );
 }
 
+sub _bail_if_changed {
+    my ( $path, $orig_dev, $orig_ino ) = @_;
+
+    my ( $cur_dev, $cur_ino ) = ( lstat $path )[ 0, 1 ];
+
+    if ( !defined $cur_dev || !defined $cur_ino ) {
+        $cur_dev ||= "undef(path went away?)";
+        $cur_ino ||= "undef(path went away?)";
+    }
+    else {
+        $path = Cwd::abs_path($path);
+    }
+
+    if ( $orig_dev ne $cur_dev || $orig_ino ne $cur_ino ) {
+        local $Carp::CarpLevel += 1;
+        Carp::croak("directory $path changed: expected dev=$orig_dev 
ino=$orig_ino, actual dev=$cur_dev ino=$cur_ino, aborting");
+    }
+}
+
 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/lib/File/Path/Tiny.pod 
new/File-Path-Tiny-0.9/lib/File/Path/Tiny.pod
--- old/File-Path-Tiny-0.8/lib/File/Path/Tiny.pod       2016-01-26 
21:45:51.000000000 +0100
+++ new/File-Path-Tiny-0.9/lib/File/Path/Tiny.pod       2017-12-29 
23:18:46.000000000 +0100
@@ -6,7 +6,7 @@
 
 =head1 VERSION
 
-This document describes File::Path::Tiny version 0.8
+This document describes File::Path::Tiny version 0.9
 
 =head1 SYNOPSIS
 
@@ -38,12 +38,16 @@
 
 =item * chdir()s
 
-It does a ton of chdir()s which could leave you somewhere you're not planning 
on being and requires much more overhead to do.
+It forces a ton of chdir()s which could leave you somewhere you're not 
planning on being and requires much more overhead to do.
+
+This module provides a way to disable that if you know it is safe to do so in 
your circumstance.
 
 =item * can croak not allowing you to detect and handle failure
 
 Just let me handle errors how I want. Don't make my entire app die or have to 
wrap it in an eval
 
+The exception here is the security checks can croak, which is what you want. 
See L<DIAGNOSTICS> for more info.
+
 =item * A well intentioned output system
 
 Just let me do the output how I want. (Nothing, As HTML, print to a 
filehandle, etc...)
@@ -76,28 +80,50 @@
 
 Takes a single path (like L<rmdir>()) to recursively empty and remove.
 
-Returns false if it could not be emptied or removed, true otherwise. (returns 
‘2’ if it is !-d already)
+Returns false if it could not be emptied or removed, true otherwise (returns 
‘2’ if it is !-d already). Also see L<DIAGNOSTICS>.
 
 It is recursive in the sense that given “/foo/bar/baz” as the path to remove 
it will recursively empty ‘baz’ and then remove it from /foo/bar.
 
 Its parents, /, /foo, and /foo/bar are *not* touched.
 
+By default it does chdir() for security reasons. If you are sure it is safe to 
do without that for the sake of a bit of speed you can pass a second true 
argument to skip that.
+
 =head2 File::Path::Tiny::empty_dir()
 
-Takes a single path to recursively empty  but not remove.
+Takes a single path to recursively empty but not remove.
 
-Returns false when there is a problem.
+Returns false when there is a problem. Also see L<DIAGNOSTICS>.
+
+By default it does chdir() for security reasons. If you are sure it is safe to 
do without that for the sake of a bit of speed you can pass a second true 
argument to skip that.
 
 =head2 File::Path::Tiny::mk_parent()
 
 Like mk() but recursively creates the parent. e.g. given “foo/bar/baz.txt” 
creates foo/bar.
 
-=head1 DIAGNOSTICS
+=head2 From Cwd
 
-Throws no warnings or errors of its own
+It uses these internally so, for convenience, these are exposed in case you 
want to use them also.
+
+=head3 File::Path::Tiny::cwd()
+
+Comes directly from L<Cwd’s cwd()|Cwd/cwd>.
+
+=head3 File::Path::Tiny::chdir()
+
+Comes directly from L<Cwd’s chdir()|Cwd/$ENV{PWD}>.
+
+=head1 DIAGNOSTICS
 
 If the functions ever return false, $! will have been set either explicitly or 
by the L<mkdir>(), L<rmdir>(), L<unlink>(), or L<opendir>() that ultimately 
returned false.
 
+=over 4
+
+=item C<< directory %s changed: expected dev=%d ino=$d, actual dev=%d ino=%d, 
aborting >>
+
+empty_dir() and rm() throw this if any of the directories being operated on 
change during the operation.
+
+=back
+
 =head1 MISC
 
 =head2 How can I make/remove multiple paths?
@@ -175,6 +201,10 @@
 
 L<File::Spec> of course but its only loaded if needed
 
+=head1 SEE ALSO
+
+We already talked about L<File::Path> in the L</DESCRIPTION>. L<Path::Tiny> 
also offers a mkpath interface but it too has/does things that this module 
attempts to do without per the L</DESCRIPTION>. Plus its ::Tiny name is a 
misnomer, see L<Acme::Tiny> for details.
+
 =head1 INCOMPATIBILITIES
 
 None reported.
@@ -216,4 +246,4 @@
 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
\ No newline at end of file
+SUCH DAMAGES.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/t/00.load.t 
new/File-Path-Tiny-0.9/t/00.load.t
--- old/File-Path-Tiny-0.8/t/00.load.t  2013-09-27 01:56:31.000000000 +0200
+++ new/File-Path-Tiny-0.9/t/00.load.t  2017-12-29 23:19:06.000000000 +0100
@@ -1,6 +1,9 @@
-use Test::More tests => 30;
+use strict;
+use warnings;
 
-use lib '../lib';
+use Test::More tests => 30;
+use File::Temp;
+use Cwd;
 
 BEGIN {
     use_ok('File::Path::Tiny');
@@ -8,49 +11,37 @@
 
 diag("Testing File::Path::Tiny $File::Path::Tiny::VERSION");
 
-# cleanup from last time
-
-for my $path (
-    qw(
-    foo/bar/mode       foo/bar/mode2       foo/bar/mode3
-    foo/bar/mode_mkdir foo/bar/mode_mkdir2 foo/bar/dir
-    foo/bar/file       foo/bar             foo
-    zib/dib zib parent_mode parent_oct parent_str
-    )
-  ) {
-    if ( !-l $path && -d $path ) {
-        rmdir $path;
-    }
-    else {
-        unlink $path;
-    }
-}
+note "Relative paths";
+{
+    my $dir          = File::Temp->newdir;
+    my $starting_dir = cwd();
+    chdir $dir || die "Could not change into temp dir: $!";
 
-SKIP: {
-    skip 'Stale testing files exist', 5 if -d 'foo/bar';
     ok( File::Path::Tiny::mk("foo/bar"),  "make simple path - return true" );
     ok( -d "foo/bar",                     "make simple path - path recursively 
created" );
     ok( File::Path::Tiny::mk("foo") == 2, "make already existing dir" );
-    if ( open my $fh, '>', 'foo/bar/file' ) {
+
+    if ( open my $fh, '>', "foo/bar/file" ) {
         print {$fh} "test";
         close $fh;
     }
-  SKIP: {
-        skip 'test file not created', 2 if !-e 'foo/bar/file';
-        ok( !File::Path::Tiny::mk("foo/bar/file"), "make already existing non 
dir - return false" );
-        ok( $! == 20,                              "make already existing file 
- errno" );
+    else {
+        die "test file not created: $!";
     }
+    ok( !File::Path::Tiny::mk("foo/bar/file"), "make already existing non dir 
- return false" );
+    ok( $! == 20,                              "make already existing file - 
errno" );
 
     my $file = "zib/dib/kib";
     ok( File::Path::Tiny::mk_parent($file),      "mk_parent() simple path 
returns true" );
     ok( -d "zib/dib",                            "mk_parent() simple path - 
parent recursively created" );
     ok( !-e $file,                               "mk_parent() simple path - 
file not created" );
     ok( File::Path::Tiny::mk_parent($file) == 2, "mk_parent() already existing 
simple path dir" );
+
+    chdir $starting_dir || die "Could not go back into $starting_dir: $!\n";
 }
 
-SKIP: {
-    eval 'require File::Temp;';
-    skip 'Absolute path test/mk_parent requires File::Temp', 3 if $@;
+note "Absolute paths";
+{
     my $dir = File::Temp->newdir();
     my $new = "$dir/foo/bar/baz";
     ok( File::Path::Tiny::mk($new),      "make absolute path - return true" );
@@ -64,40 +55,56 @@
     ok( File::Path::Tiny::mk_parent($file) == 2, "mk_parent() already existing 
absolute path dir" );
 }
 
-mkdir 'foo/bar/dir';
+note "Modes and misc";
+{
 
-my $mk_mode = ( stat('foo/bar') )[2];
+    my $dir          = File::Temp->newdir;
+    my $starting_dir = cwd();
+    chdir $dir || die "Could not change into temp dir: $!";
+    File::Path::Tiny::mk('foo/bar/dir');
+
+    my $mk_mode = ( stat('foo/bar') )[2];
+
+    # $mk_mode       = sprintf('%04o', $mk_mode & 07777);
+    my $mkdir_mode = ( stat('foo/bar/dir') )[2];
+
+    # $mkdir_mode    = sprintf('%04o', $mkdir_mode & 07777);
+    # diag("mk: $mk_mode, mkdir: $mkdir_mode");
+    ok( $mk_mode == $mkdir_mode, 'MASK logic gets same results as mkdir()' );
+
+    File::Path::Tiny::mk( "foo/bar/mode", 0700 );
+    File::Path::Tiny::mk_parent( "parent_mode/x", 0700 );
+    mkdir 'foo/bar/mode_mkdir', 0700;
+    ok( ( stat('foo/bar/mode') )[2] == ( stat('foo/bar/mode_mkdir') )[2], 
'MASK arg OCT gets same results as mkdir()' );
+    ok( ( stat('parent_mode') )[2] ==  ( stat('foo/bar/mode_mkdir') )[2], 
'MASK arg OCT gets same results as mkdir() - mk_parent()' );
+
+    File::Path::Tiny::mk( "foo/bar/mode2", oct('0700') );
+    File::Path::Tiny::mk_parent( "parent_oct/x", oct('0700') );
+    mkdir 'foo/bar/mode_mkdir2', oct('0700');
+    ok( ( stat('foo/bar/mode2') )[2] == ( stat('foo/bar/mode_mkdir2') )[2], 
'MASK arg oct(STR) gets same results as mkdir()' );
+    ok( ( stat('parent_oct') )[2] ==    ( stat('foo/bar/mode_mkdir2') )[2], 
'MASK arg oct(STR) gets same results as mkdir() - mk_parent()' );
+
+    File::Path::Tiny::mk( "foo/bar/mode3", "0700" );
+    File::Path::Tiny::mk_parent( "parent_str/x", "0700" );
+
+    # mkdir 'foo/bar/mode_mkdir3', "0700"; # this breaks permissions so we 
compare with previous one
+    ok( ( stat('foo/bar/mode3') )[2] == ( stat('foo/bar/mode2') )[2], 'MASK 
arg STR gets detected and handled - different results as mkdir()' );
+    ok( ( stat('parent_str') )[2] ==    ( stat('foo/bar/mode2') )[2], 'MASK 
arg STR gets detected and handled - different results as mkdir() - mk_parent()' 
);
 
-# $mk_mode       = sprintf('%04o', $mk_mode & 07777);
-my $mkdir_mode = ( stat('foo/bar/dir') )[2];
+    if ( open my $fh, '>', "foo/bar/file" ) {
+        print {$fh} "test";
+        close $fh;
+    }
+    else {
+        die "test file not created: $!";
+    }
+    ok( !File::Path::Tiny::rm("foo/bar/file"), "remove existing non dir - 
return false" );
+    ok( $! == 20,                              "remove existing non dir - 
errno" );
+    undef $!;
+    ok( File::Path::Tiny::rm('foo/bar'),      "empty and remove simple path - 
return true" );
+    ok( !-d 'foo/bar',                        "remove simple path - path 
recursively removed" );
+    ok( File::Path::Tiny::rm('foo/bar') == 2, "remove already non-existing 
dir" );
+    ok( File::Path::Tiny::rm('foo'),          'remove empty dir' );
 
-# $mkdir_mode    = sprintf('%04o', $mkdir_mode & 07777);
-# diag("mk: $mk_mode, mkdir: $mkdir_mode");
-ok( $mk_mode == $mkdir_mode, 'MASK logic gets same results as mkdir()' );
-
-File::Path::Tiny::mk( "foo/bar/mode", 0700 );
-File::Path::Tiny::mk_parent( "parent_mode/x", 0700 );
-mkdir 'foo/bar/mode_mkdir', 0700;
-ok( ( stat('foo/bar/mode') )[2] == ( stat('foo/bar/mode_mkdir') )[2], 'MASK 
arg OCT gets same results as mkdir()' );
-ok( ( stat('parent_mode') )[2] ==  ( stat('foo/bar/mode_mkdir') )[2], 'MASK 
arg OCT gets same results as mkdir() - mk_parent()' );
-
-File::Path::Tiny::mk( "foo/bar/mode2", oct('0700') );
-File::Path::Tiny::mk_parent( "parent_oct/x", oct('0700') );
-mkdir 'foo/bar/mode_mkdir2', oct('0700');
-ok( ( stat('foo/bar/mode2') )[2] == ( stat('foo/bar/mode_mkdir2') )[2], 'MASK 
arg oct(STR) gets same results as mkdir()' );
-ok( ( stat('parent_oct') )[2] ==    ( stat('foo/bar/mode_mkdir2') )[2], 'MASK 
arg oct(STR) gets same results as mkdir() - mk_parent()' );
-
-File::Path::Tiny::mk( "foo/bar/mode3", "0700" );
-File::Path::Tiny::mk_parent( "parent_str/x", "0700" );
-
-# mkdir 'foo/bar/mode_mkdir3', "0700"; # this breaks permissions so we compare 
with previous one
-ok( ( stat('foo/bar/mode3') )[2] == ( stat('foo/bar/mode2') )[2], 'MASK arg 
STR gets detected and handled - different results as mkdir()' );
-ok( ( stat('parent_str') )[2] ==    ( stat('foo/bar/mode2') )[2], 'MASK arg 
STR gets detected and handled - different results as mkdir() - mk_parent()' );
-
-ok( !File::Path::Tiny::rm("foo/bar/file"), "remove existing non dir - return 
false" );
-ok( $! == 20,                              "remove existing non dir - errno" );
-undef $!;
-ok( File::Path::Tiny::rm('foo/bar'),      "empty and remove simple path - 
return true" );
-ok( !-d 'foo/bar',                        "remove simple path - path 
recursively removed" );
-ok( File::Path::Tiny::rm('foo/bar') == 2, "remove already non-existing dir" );
-ok( File::Path::Tiny::rm('foo'),          'remove empty dir' );
+    chdir $starting_dir || die "Could not go back into $starting_dir: $!\n";
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/File-Path-Tiny-0.8/t/01.symtogsafe.t 
new/File-Path-Tiny-0.9/t/01.symtogsafe.t
--- old/File-Path-Tiny-0.8/t/01.symtogsafe.t    1970-01-01 01:00:00.000000000 
+0100
+++ new/File-Path-Tiny-0.9/t/01.symtogsafe.t    2017-12-29 23:19:06.000000000 
+0100
@@ -0,0 +1,133 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use File::Path::Tiny;
+
+if ( !-x "/bin/mv" || !-x "/bin/mkdir" ) {    # dragons! patches welcome
+    plan skip_all => 'Only operate on systems w/ /bin/mv and /bin/mkdir, for 
reasons see the cource code comments';
+}
+else {
+    plan tests => 22;
+}
+
+use File::Temp;
+use Cwd;
+use File::Spec;
+
+my $orig_dir = Cwd::cwd();
+my $dir      = File::Temp->newdir();
+our $catdir_toggle = sub { };
+our @catdir_calls;
+
+chdir $dir || die "Could not chdir into temp directory: $!\n";    # so we can 
pathrm(), dragons!
+
+{
+    
##############################################################################
+    #### Wrap catdir() to control a symlink toggle in the path traversal 
loops. ##
+    
##############################################################################
+    no strict "refs";
+    no warnings "redefine", "once";
+    my $real_catdir = \&{ $File::Spec::ISA[0] . "::catdir" };
+    local *File::Spec::catdir = sub {
+        my ( $self, @args ) = @_;
+        push @catdir_calls, \@args;
+        $catdir_toggle->(@args);
+        goto &$real_catdir;
+    };
+
+    mkdir "empty_dir";
+    mkdir "empty_dir/sanity";
+    File::Path::Tiny::empty_dir("empty_dir");
+    is( @catdir_calls, 1, "sanity check: catdir was actually called in the 
empty_dir() loop" );
+
+    mkdir "rm";
+    mkdir "rm/sanity";
+    File::Path::Tiny::rm("rm");
+    is( @catdir_calls, 2, "sanity check: catdir was actually called in the 
pathrmdir() loop" );
+
+    ####################
+    #### Actual tests ##
+    ####################
+
+    for my $func (qw(empty_dir rm)) {
+        _test( $func, "cwd/foo/bar/baz", "bails when high level changes" );
+        _test( $func, "cwd/foo/bar",     "bails when mid level changes" );
+        _test( $func, "cwd/foo",         "bails when low level changes" );
+        _test( $func, "cwd",             "bails when CWD level changes" );
+        _test( $func, "",                "bails when below level changes" );
+    }
+
+    # TODO: cover readdir, chdir, and post loop failures
+}
+
+chdir $orig_dir || die "Could not chdir back to original directory: $!\n";
+
+###############
+#### helpers ##
+###############
+
+sub _test {
+    my ( $func, $toggle, $label ) = @_;
+
+    _setup_tree($func);
+
+    {
+        local @catdir_calls  = ();
+        local $catdir_toggle = sub {
+            chdir $dir || die "could not toggle dir/symlink (chdir): $!";
+
+            my $parent = "";
+            if ($toggle) {
+                $parent = $toggle;
+                $parent =~ s{[^/]+$}{};
+
+                # use system call since the perl to do this will likely use 
File::Spec
+                system("/bin/mkdir -p moved/$func/$parent") and die "could not 
toggle dir/symlink (mkdir): $?\n";
+            }
+
+            # use system call since the perl to do this will likely use 
File::Spec
+            system("/bin/mv $dir/$func/$toggle $dir/moved/$func/$toggle") and 
die "could not toggle dir/symlink (mv): $?\n";
+            symlink( "$dir/victim", "$dir/$func" . ( $toggle ? "/$toggle" : "" 
) ) or die "could not toggle dir/symlink (sym): $!\n";
+
+            chdir "$func/cwd" || die "could not toggle dir/symlink (back into 
$func/cwd): $!\n";
+        };
+
+        throws_ok { no strict "refs"; 
"File::Path::Tiny::$func"->("foo/bar/baz") }
+        qr/directory .* changed: expected dev=.* ino=.*, actual dev=.* ino=.*, 
aborting/,
+          "$func() detected symlink toggle: $label";
+
+        is( @catdir_calls, 1, "sanity check: catdir was actually called in 
$func() ($label)" );
+    }
+
+    _teardown_tree($func);
+}
+
+sub _teardown_tree {
+    my ($base) = @_;
+
+    chdir $dir || die "Could not chdir back into temp dir: $!\n";
+
+    File::Path::Tiny::rm($base);
+    File::Path::Tiny::rm("moved/");
+    File::Path::Tiny::rm("victim/");
+
+    return;
+}
+
+sub _setup_tree {
+    my ($base) = @_;
+
+    for my $dir ( "moved", "victim", "victim/cwd", $base, "$base/cwd", 
"$base/cwd/foo", "$base/cwd/foo/bar", "$base/cwd/foo/bar/baz" ) {
+        mkdir $dir || die "Could not make test tree ($dir): $!\n";
+        open my $fh, ">", "$dir/file.txt" || die "Could not make test file in 
($dir): $!\n";
+        print {$fh} "oh hai\n";
+        close($fh);
+    }
+
+    chdir "$base/cwd" || die "Could not chdir into $base/cwd: $!\n";
+
+    return;
+}


Reply via email to