Skip to content

Commit

Permalink
Throw specific exceptions depending on the errno in IO.
Browse files Browse the repository at this point in the history
Merges #3
  • Loading branch information
moufmouf authored and Girgias committed Mar 4, 2021
1 parent d3a8b91 commit 782f5ea
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 2 deletions.
2 changes: 1 addition & 1 deletion ext/standard/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ PHP_FUNCTION(chroot)

ret = chroot(str);
if (ret != 0) {
php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (errno %d)", strerror(errno), errno);
handle_io_error(errno, str);
RETURN_FALSE;
}

Expand Down
27 changes: 27 additions & 0 deletions ext/standard/io_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
PHPAPI zend_class_entry *zend_ce_filesystem;
PHPAPI zend_class_entry *zend_ce_network;
PHPAPI zend_class_entry *zend_ce_filesystem_error;
PHPAPI zend_class_entry *zend_ce_file_not_found;
PHPAPI zend_class_entry *zend_ce_not_directory;
PHPAPI zend_class_entry *zend_ce_insufficient_permissions;
PHPAPI zend_class_entry *zend_ce_temporary_failure;

Expand All @@ -42,6 +44,14 @@ PHP_MINIT_FUNCTION(io_exceptions) {
zend_ce_filesystem_error = zend_register_internal_class_ex(&ce, zend_ce_exception);
zend_class_implements(zend_ce_filesystem_error, 1, zend_ce_filesystem);

INIT_CLASS_ENTRY(ce, "FileNotFound", class_FileNotFound_methods);
zend_ce_file_not_found = zend_register_internal_class_ex(&ce, zend_ce_exception);
zend_class_implements(zend_ce_file_not_found, 1, zend_ce_filesystem);

INIT_CLASS_ENTRY(ce, "NotDirectory", class_FileNotFound_methods);
zend_ce_not_directory = zend_register_internal_class_ex(&ce, zend_ce_exception);
zend_class_implements(zend_ce_not_directory, 1, zend_ce_filesystem);

INIT_CLASS_ENTRY(ce, "InsufficientPermissions", class_InsufficientPermissions_methods);
zend_ce_insufficient_permissions = zend_register_internal_class_ex(&ce, zend_ce_exception);
zend_class_implements(zend_ce_insufficient_permissions, 1, zend_ce_filesystem);
Expand All @@ -52,3 +62,20 @@ PHP_MINIT_FUNCTION(io_exceptions) {

return SUCCESS;
}

PHPAPI void handle_io_error(int error, const char *path) {
if (path == NULL) {
path = "[unknown]";
}
switch (error) {
case ENOENT:
php_exception_or_warning_docref(NULL, zend_ce_file_not_found, "File not found: \"%s\"", path);
break;
case ENOTDIR:
php_exception_or_warning_docref(NULL, zend_ce_not_directory, "\"%s\" is not a directory", path);
break;
default:
php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (path: \"%s\", errno %d)", strerror(errno), path, errno);
break;
}
}
4 changes: 4 additions & 0 deletions ext/standard/io_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ BEGIN_EXTERN_C()
extern PHPAPI zend_class_entry *zend_ce_filesystem;
extern PHPAPI zend_class_entry *zend_ce_network;
extern PHPAPI zend_class_entry *zend_ce_filesystem_error;
extern PHPAPI zend_class_entry *zend_ce_file_not_found;
extern PHPAPI zend_class_entry *zend_ce_not_directory;
extern PHPAPI zend_class_entry *zend_ce_insufficient_permissions;
extern PHPAPI zend_class_entry *zend_ce_temporary_failure;

END_EXTERN_C()

PHPAPI void handle_io_error(int error, const char *path);

#endif /* PHP_IO_EXCEPTION */
4 changes: 4 additions & 0 deletions ext/standard/io_exceptions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ interface Network extends IO {}
/* Should use more specialized ones instead but for PoC will use this instead */
class FileSystemError extends Exception implements FileSystem {}

class FileNotFound extends Exception implements FileSystem {}

class NotDirectory extends Exception implements FileSystem {}

class InsufficientPermissions extends Exception implements FileSystem {}

class TemporaryFailure extends Exception implements Network {}
12 changes: 11 additions & 1 deletion ext/standard/io_exceptions_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 68880a94d8393c0d367cee9e9c18c8ac6d16d9f2 */
* Stub hash: c4ecc9d6fb58a424dc63d5c5a039843b89273142 */



Expand All @@ -19,6 +19,16 @@ static const zend_function_entry class_FileSystemError_methods[] = {
};


static const zend_function_entry class_FileNotFound_methods[] = {
ZEND_FE_END
};


static const zend_function_entry class_NotDirectory_methods[] = {
ZEND_FE_END
};


static const zend_function_entry class_InsufficientPermissions_methods[] = {
ZEND_FE_END
};
Expand Down
33 changes: 33 additions & 0 deletions ext/standard/tests/dir/chroot_throw_on_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Test chroot() function error conditions with throw on error declare enabled - Non-existent directory
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) == 'WIN') {
die('skip.. Not valid for Windows');
}

if (!function_exists('chroot')) {
die('skip.. chroot() not defined in this build');
}
?>
--FILE--
<?php

declare(throw_on_error=1);

echo "*** Testing chroot() : error conditions ***\n";
$directory = __DIR__ . '/idonotexist';

echo "\n-- Pass chroot() an absolute path that does not exist --\n";
try {
chroot($directory);
} catch (\FileNotFound $e) {
echo $e->getMessage() . \PHP_EOL;
}

?>
--EXPECTF--
*** Testing chroot() : error conditions ***

-- Pass chroot() an absolute path that does not exist --
File not found: "%sidonotexist"
33 changes: 33 additions & 0 deletions ext/standard/tests/dir/chroot_throw_on_error_file_in_path.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Test chroot() function error conditions with throw on error declare enabled - Non-existent directory
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) == 'WIN') {
die('skip.. Not valid for Windows');
}

if (!function_exists('chroot')) {
die('skip.. chroot() not defined in this build');
}
?>
--FILE--
<?php

declare(throw_on_error=1);

echo "*** Testing chroot() : error conditions ***\n";
$directory = __FILE__;

echo "\n-- Pass chroot() a non directory --\n";
try {
chroot($directory);
} catch (\NotDirectory $e) {
echo $e->getMessage() . \PHP_EOL;
}

?>
--EXPECTF--
*** Testing chroot() : error conditions ***

-- Pass chroot() a non directory --
"%schroot_throw_on_error_file_in_path.php" is not a directory

0 comments on commit 782f5ea

Please sign in to comment.