Skip to content

Commit 80879a6

Browse files
committed
standard: Name the missing path in rename() ENOENT warnings.
When rename() fails because a path does not exist, the warning now says whether the source is missing or the destination directory is missing, so the two cases are no longer identical. Closes GH-8597.
1 parent 0f1efaa commit 80879a6

6 files changed

Lines changed: 83 additions & 13 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ PHP NEWS
141141
sockets. (David Carlier)
142142

143143
- Standard:
144+
. rename() warnings for a missing path now say whether the source or the
145+
destination directory is missing (GH-8597). (mvanhorn)
144146
. Fixed bug #60110 (fclose(), file_put_contents(), copy() do not return false
145147
properly). (Jakub Zelenka, Ilija Tovilo)
146148
. Fixed three Windows-only proc_open() defects: an uninitialized

‎UPGRADING‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ PHP 8.7 UPGRADE NOTES
9999
rebuilding PHP with --enable-fd-setsize. On Windows, selecting on more than
100100
64 pipe or file handles no longer crashes; it fails with a warning, as that
101101
path remains bounded by WaitForMultipleObjects().
102+
. When rename() fails because a path does not exist, the warning now says
103+
whether the source path is missing or the destination directory is missing.
102104

103105
========================================
104106
6. New Functions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
GH-8597: rename() warnings name the missing source or destination directory
3+
--SKIPIF--
4+
<?php
5+
if (PHP_OS_FAMILY === 'Windows') die('skip not for Windows');
6+
?>
7+
--FILE--
8+
<?php
9+
$base = __DIR__ . '/gh8597';
10+
@mkdir($base);
11+
$src = $base . '/exists.txt';
12+
file_put_contents($src, 'x');
13+
14+
echo "missing source:\n";
15+
var_dump(rename($base . '/no-such-source.txt', $base . '/dest.txt'));
16+
17+
echo "missing destination directory:\n";
18+
var_dump(rename($src, $base . '/no-such-dir/dest.txt'));
19+
20+
echo "success:\n";
21+
var_dump(rename($src, $base . '/renamed.txt'));
22+
var_dump(file_exists($base . '/renamed.txt'));
23+
?>
24+
--CLEAN--
25+
<?php
26+
$base = __DIR__ . '/gh8597';
27+
@unlink($base . '/exists.txt');
28+
@unlink($base . '/renamed.txt');
29+
@unlink($base . '/dest.txt');
30+
@rmdir($base);
31+
?>
32+
--EXPECTF--
33+
missing source:
34+
35+
Warning: rename(): No such file or directory (source "%s/gh8597/no-such-source.txt") in %s on line %d
36+
bool(false)
37+
missing destination directory:
38+
39+
Warning: rename(): No such file or directory (destination directory "%s/gh8597/no-such-dir") in %s on line %d
40+
bool(false)
41+
success:
42+
bool(true)
43+
bool(true)

‎ext/standard/tests/file/rename_variation13.phpt‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ rmdir($file_path);
5959
-- testing '-1' --
6060
bool(true)
6161

62-
Warning: rename('-1', '%s/renameVar13/afile.tmp'): No such file or directory in %s on line %d
62+
Warning: rename('-1', '%s/renameVar13/afile.tmp'): No such file or directory (source "-1") in %s on line %d
6363
bool(false)
6464
-- testing '1' --
6565
bool(true)
6666

67-
Warning: rename('1', '%s/renameVar13/afile.tmp'): No such file or directory in %s on line %d
67+
Warning: rename('1', '%s/renameVar13/afile.tmp'): No such file or directory (source "1") in %s on line %d
6868
bool(false)
6969
-- testing '' --
7070

@@ -83,19 +83,19 @@ bool(false)
8383
-- testing ' ' --
8484
bool(true)
8585

86-
Warning: rename(' ', '%s/renameVar13/afile.tmp'): No such file or directory in %s on line %d
86+
Warning: rename(' ', '%s/renameVar13/afile.tmp'): No such file or directory (source " ") in %s on line %d
8787
bool(false)
8888
-- testing '/no/such/file/dir' --
8989

90-
Warning: rename('%s/renameVar13/afile.tmp', '/no/such/file/dir'): No such file or directory in %s on line %d
90+
Warning: rename('%s/renameVar13/afile.tmp', '/no/such/file/dir'): No such file or directory (destination directory "/no/such/file") in %s on line %d
9191
bool(false)
9292

93-
Warning: rename('/no/such/file/dir', '%s/renameVar13/afile.tmp'): No such file or directory in %s on line %d
93+
Warning: rename('/no/such/file/dir', '%s/renameVar13/afile.tmp'): No such file or directory (source "/no/such/file/dir") in %s on line %d
9494
bool(false)
9595
-- testing 'php/php' --
9696

97-
Warning: rename('%s/renameVar13/afile.tmp', 'php/php'): %s directory in %s on line %d
97+
Warning: rename('%s/renameVar13/afile.tmp', 'php/php'): No such file or directory (destination directory "php") in %s on line %d
9898
bool(false)
9999

100-
Warning: rename('php/php', '%s/renameVar13/afile.tmp'): %s directory in %s on line %d
100+
Warning: rename('php/php', '%s/renameVar13/afile.tmp'): No such file or directory (source "php/php") in %s on line %d
101101
bool(false)

‎ext/standard/tests/file/rename_variation8.phpt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ rmdir(__DIR__."/rename_basic_dir1");
4646
--EXPECTF--
4747
*** Testing rename() on non-existing file ***
4848

49-
Warning: rename(): No such file or directory in %s on line %d
49+
Warning: rename(): No such file or directory (source "%s/non_existent_file.tmp") in %s on line %d
5050
bool(false)
5151
bool(false)
5252
bool(false)
@@ -58,7 +58,7 @@ bool(true)
5858

5959
*** Testing rename() on non-existing directory ***
6060

61-
Warning: rename(): No such file or directory in %s on line %d
61+
Warning: rename(): No such file or directory (source "%s/non_existent_dir") in %s on line %d
6262
bool(false)
6363
bool(false)
6464
bool(false)

‎main/streams/plain_wrapper.c‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "ext/standard/file.h"
2020
#include "ext/standard/flock_compat.h"
2121
#include "ext/standard/php_filestat.h"
22+
#include "ext/standard/php_string.h"
2223
#include <stddef.h>
2324
#include <fcntl.h>
2425
#ifdef HAVE_SYS_WAIT_H
@@ -1397,8 +1398,9 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f
13971398
if (ret == -1) {
13981399
#ifndef PHP_WIN32
13991400
char errstr[256];
1401+
int rename_errno = errno;
14001402
# ifdef EXDEV
1401-
if (errno == EXDEV) {
1403+
if (rename_errno == EXDEV) {
14021404
zend_stat_t sb;
14031405
# if !defined(ZTS) && !defined(TSRM_WIN32)
14041406
/* not sure what to do in ZTS case, umask is not thread-safe */
@@ -1458,9 +1460,30 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f
14581460
#ifdef PHP_WIN32
14591461
php_win32_stream_wrapper_warn_error(wrapper, context, options, PHP_STREAM_EC(RenameFailed), GetLastError());
14601462
#else
1461-
php_stream_wrapper_warn(wrapper, context, options,
1462-
RenameFailed,
1463-
"%s", php_socket_strerror_s(errno, errstr, sizeof(errstr)));
1463+
if (rename_errno == ENOENT) {
1464+
zend_stat_t sb;
1465+
if (VCWD_STAT(url_from, &sb) != 0) {
1466+
php_stream_wrapper_warn(wrapper, context, options, RenameFailed,
1467+
"No such file or directory (source \"%s\")", url_from);
1468+
} else {
1469+
size_t to_len = strlen(url_to);
1470+
char *dir = estrndup(url_to, to_len);
1471+
php_dirname(dir, to_len);
1472+
if (dir[0] != '\0' && !(dir[0] == '.' && dir[1] == '\0')
1473+
&& VCWD_STAT(dir, &sb) != 0) {
1474+
php_stream_wrapper_warn(wrapper, context, options, RenameFailed,
1475+
"No such file or directory (destination directory \"%s\")", dir);
1476+
} else {
1477+
php_stream_wrapper_warn(wrapper, context, options, RenameFailed,
1478+
"%s", php_socket_strerror_s(rename_errno, errstr, sizeof(errstr)));
1479+
}
1480+
efree(dir);
1481+
}
1482+
} else {
1483+
php_stream_wrapper_warn(wrapper, context, options,
1484+
RenameFailed,
1485+
"%s", php_socket_strerror_s(rename_errno, errstr, sizeof(errstr)));
1486+
}
14641487
#endif
14651488
return 0;
14661489
}

0 commit comments

Comments
 (0)