f6ea51
From 3dfcac940930a8aa6779f5debea6ea6357372419 Mon Sep 17 00:00:00 2001
f6ea51
From: Daniel Dragan <bulk88@hotmail.com>
f6ea51
Date: Sun, 16 Aug 2015 04:30:23 -0400
f6ea51
Subject: [PATCH] fix do dir returning no $!
f6ea51
MIME-Version: 1.0
f6ea51
Content-Type: text/plain; charset=UTF-8
f6ea51
Content-Transfer-Encoding: 8bit
f6ea51
f6ea51
do()ing a directory was returning false/empty string in $!, which isn't
f6ea51
an error, yet documentation says $! should have the error code in it.
f6ea51
Fix this by returning EISDIR for dirs, and EINVAL for block devices.
f6ea51
[perl #125774]
f6ea51
f6ea51
Remove "errno = 0" and comment added in b2da7ead68, since now there is no
f6ea51
scenario where errno is uninitialized, since the dir and block device
f6ea51
failure branches now set errno, where previously they didn't.
f6ea51
f6ea51
Petr Písař: Ported to 5.26.1.
f6ea51
f6ea51
Signed-off-by: Petr Písař <ppisar@redhat.com>
f6ea51
---
f6ea51
 pp_ctl.c  | 25 +++++++++++++++++--------
f6ea51
 t/op/do.t | 14 +++++++++++++-
f6ea51
 2 files changed, 30 insertions(+), 9 deletions(-)
f6ea51
f6ea51
diff --git a/pp_ctl.c b/pp_ctl.c
f6ea51
index e24d7b6..f136f91 100644
f6ea51
--- a/pp_ctl.c
f6ea51
+++ b/pp_ctl.c
f6ea51
@@ -3534,15 +3534,22 @@ S_check_type_and_open(pTHX_ SV *name)
f6ea51
        errno EACCES, so only do a stat to separate a dir from a real EACCES
f6ea51
        caused by user perms */
f6ea51
 #ifndef WIN32
f6ea51
-    /* we use the value of errno later to see how stat() or open() failed.
f6ea51
-     * We don't want it set if the stat succeeded but we still failed,
f6ea51
-     * such as if the name exists, but is a directory */
f6ea51
-    errno = 0;
f6ea51
-
f6ea51
     st_rc = PerlLIO_stat(p, &st);
f6ea51
 
f6ea51
-    if (st_rc < 0 || S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) {
f6ea51
+    if (st_rc < 0)
f6ea51
 	return NULL;
f6ea51
+    else {
f6ea51
+	int eno;
f6ea51
+	if(S_ISBLK(st.st_mode)) {
f6ea51
+	    eno = EINVAL;
f6ea51
+	    goto not_file;
f6ea51
+	}
f6ea51
+	else if(S_ISDIR(st.st_mode)) {
f6ea51
+	    eno = EISDIR;
f6ea51
+	    not_file:
f6ea51
+	    errno = eno;
f6ea51
+	    return NULL;
f6ea51
+	}
f6ea51
     }
f6ea51
 #endif
f6ea51
 
f6ea51
@@ -3554,8 +3561,10 @@ S_check_type_and_open(pTHX_ SV *name)
f6ea51
 	int eno;
f6ea51
 	st_rc = PerlLIO_stat(p, &st);
f6ea51
 	if (st_rc >= 0) {
f6ea51
-	    if(S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode))
f6ea51
-		eno = 0;
f6ea51
+	    if(S_ISDIR(st.st_mode))
f6ea51
+		eno = EISDIR;
f6ea51
+	    else if(S_ISBLK(st.st_mode))
f6ea51
+		eno = EINVAL;
f6ea51
 	    else
f6ea51
 		eno = EACCES;
f6ea51
 	    errno = eno;
f6ea51
diff --git a/t/op/do.t b/t/op/do.t
f6ea51
index 78d8800..1c54f0b 100644
f6ea51
--- a/t/op/do.t
f6ea51
+++ b/t/op/do.t
f6ea51
@@ -7,6 +7,7 @@ BEGIN {
f6ea51
 }
f6ea51
 use strict;
f6ea51
 no warnings 'void';
f6ea51
+use Errno qw(ENOENT EISDIR);
f6ea51
 
f6ea51
 my $called;
f6ea51
 my $result = do{ ++$called; 'value';};
f6ea51
@@ -247,7 +248,7 @@ SKIP: {
f6ea51
     my $saved_errno = $!;
f6ea51
     ok(!$rv,          "do returns false on io errror");
f6ea51
     ok(!$saved_error, "\$\@ not set on io error");
f6ea51
-    ok($saved_errno,  "\$! set on io error");
f6ea51
+    ok($saved_errno == ENOENT, "\$! is ENOENT for nonexistent file");
f6ea51
 }
f6ea51
 
f6ea51
 # do subname should not be do "subname"
f6ea51
@@ -305,4 +306,15 @@ SKIP: {
f6ea51
 }
f6ea51
 
f6ea51
 
f6ea51
+# do file $!s must be correct
f6ea51
+{
f6ea51
+    local @INC = ('.'); #want EISDIR not ENOENT
f6ea51
+    my $rv = do 'op'; # /t/op dir
f6ea51
+    my $saved_error = $@;
f6ea51
+    my $saved_errno = $!+0;
f6ea51
+    ok(!$rv,                    "do dir returns false");
f6ea51
+    ok(!$saved_error,           "\$\@ is false on do dir");
f6ea51
+    ok($saved_errno == EISDIR,  "\$! is EISDIR on do dir");
f6ea51
+}
f6ea51
+
f6ea51
 done_testing();
f6ea51
-- 
f6ea51
2.13.6
f6ea51