mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Add fsync() and fdatasync() functions
fsync is a straightforward wrapper around the same C function (implemented on Windows API as _commit() with identical signature). From the man pages: fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even if the system crashes or is rebooted. This includes writing through or flushing a disk cache if present. The call blocks until the device reports that the transfer has completed. RFC: https://wiki.php.net/rfc/fsync_function Closes GH-6650.
This commit is contained in:
parent
0c5711856f
commit
cbcfd86026
@ -283,6 +283,11 @@ PHP 8.1 UPGRADE NOTES
|
||||
. Added array_is_list(array $array), which will return true if the array keys are 0 .. count($array)-1 in that order.
|
||||
RFC: https://wiki.php.net/rfc/is_list
|
||||
|
||||
- Standard:
|
||||
. Added fsync() and fdatasync(), which instruct the operating system to
|
||||
flush its buffers to physical storage.
|
||||
RFC: https://wiki.php.net/rfc/fsync_function
|
||||
|
||||
========================================
|
||||
7. New Classes and Interfaces
|
||||
========================================
|
||||
|
@ -825,6 +825,12 @@ function ftell($stream): int|false {}
|
||||
/** @param resource $stream */
|
||||
function fflush($stream): bool {}
|
||||
|
||||
/** @param resource $stream */
|
||||
function fsync($stream): bool {}
|
||||
|
||||
/** @param resource $stream */
|
||||
function fdatasync($stream): bool {}
|
||||
|
||||
/** @param resource $stream */
|
||||
function fwrite($stream, string $data, ?int $length = null): int|false {}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 469c5fbccef35aa6bd3893589495071d2250078f */
|
||||
* Stub hash: 2d92e992837a61a052eea6d0257837aaccc54be6 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
@ -1270,6 +1270,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_fflush arginfo_rewind
|
||||
|
||||
#define arginfo_fsync arginfo_rewind
|
||||
|
||||
#define arginfo_fdatasync arginfo_rewind
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_fwrite, 0, 2, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_INFO(0, stream)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
@ -2562,6 +2566,8 @@ ZEND_FUNCTION(fstat);
|
||||
ZEND_FUNCTION(fseek);
|
||||
ZEND_FUNCTION(ftell);
|
||||
ZEND_FUNCTION(fflush);
|
||||
ZEND_FUNCTION(fsync);
|
||||
ZEND_FUNCTION(fdatasync);
|
||||
ZEND_FUNCTION(fwrite);
|
||||
ZEND_FUNCTION(mkdir);
|
||||
ZEND_FUNCTION(rename);
|
||||
@ -3198,6 +3204,8 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(fseek, arginfo_fseek)
|
||||
ZEND_FE(ftell, arginfo_ftell)
|
||||
ZEND_FE(fflush, arginfo_fflush)
|
||||
ZEND_FE(fsync, arginfo_fsync)
|
||||
ZEND_FE(fdatasync, arginfo_fdatasync)
|
||||
ZEND_FE(fwrite, arginfo_fwrite)
|
||||
ZEND_FALIAS(fputs, fwrite, arginfo_fputs)
|
||||
ZEND_FE(mkdir, arginfo_mkdir)
|
||||
|
@ -1464,6 +1464,44 @@ PHP_FUNCTION(unlink)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_FUNCTION(fsync)
|
||||
{
|
||||
zval *res;
|
||||
php_stream *stream;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_RESOURCE(res)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
PHP_STREAM_TO_ZVAL(stream, res);
|
||||
|
||||
if (!php_stream_sync_supported(stream)) {
|
||||
php_error_docref(NULL, E_WARNING, "Can't fsync this stream!");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_BOOL(php_stream_sync(stream, /* data_only */ 0) == 0);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(fdatasync)
|
||||
{
|
||||
zval *res;
|
||||
php_stream *stream;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_RESOURCE(res)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
PHP_STREAM_TO_ZVAL(stream, res);
|
||||
|
||||
if (!php_stream_sync_supported(stream)) {
|
||||
php_error_docref(NULL, E_WARNING, "Can't fsync this stream!");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_BOOL(php_stream_sync(stream, /* data_only */ 1) == 0);
|
||||
}
|
||||
|
||||
/* {{{ Truncate file to 'size' length */
|
||||
PHP_FUNCTION(ftruncate)
|
||||
{
|
||||
|
73
ext/standard/tests/file/fdatasync.phpt
Normal file
73
ext/standard/tests/file/fdatasync.phpt
Normal file
@ -0,0 +1,73 @@
|
||||
--TEST--
|
||||
Test fdatasync() function: basic functionality
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "*** Testing fdatasync(): writing to a file and reading the contents ***\n";
|
||||
$data = <<<EOD
|
||||
first line of string
|
||||
second line of string
|
||||
third line of string
|
||||
EOD;
|
||||
|
||||
$file_path = __DIR__;
|
||||
$filename = "$file_path/fdatasync_basic.tmp";
|
||||
|
||||
// opening a file
|
||||
$file_handle = fopen($filename, "w");
|
||||
if($file_handle == false)
|
||||
exit("Error:failed to open file $filename");
|
||||
|
||||
if(PHP_OS_FAMILY == 'Windows') {
|
||||
$data = str_replace("\r",'', $data);
|
||||
}
|
||||
|
||||
// writing data to the file
|
||||
var_dump( fwrite($file_handle, $data) );
|
||||
var_dump( fdatasync($file_handle) );
|
||||
var_dump( readfile($filename) );
|
||||
|
||||
echo "\n*** Testing fdatasync(): for return type ***\n";
|
||||
$return_value = fdatasync($file_handle);
|
||||
var_dump( is_bool($return_value) );
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Testing fdatasync(): attempting to sync stdin ***\n";
|
||||
$file_handle = fopen("php://stdin", "w");
|
||||
var_dump(fdatasync($file_handle));
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Testing fdatasync(): for non-file stream ***\n";
|
||||
$file_handle = fopen("php://memory", "w");
|
||||
$return_value = fdatasync($file_handle);
|
||||
var_dump( ($return_value) );
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Done ***";
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$file_path = __DIR__;
|
||||
$filename = "$file_path/fdatasync_basic.tmp";
|
||||
unlink($filename);
|
||||
?>
|
||||
--EXPECTF--
|
||||
*** Testing fdatasync(): writing to a file and reading the contents ***
|
||||
int(63)
|
||||
bool(true)
|
||||
first line of string
|
||||
second line of string
|
||||
third line of stringint(63)
|
||||
|
||||
*** Testing fdatasync(): for return type ***
|
||||
bool(true)
|
||||
|
||||
*** Testing fdatasync(): attempting to sync stdin ***
|
||||
bool(false)
|
||||
|
||||
*** Testing fdatasync(): for non-file stream ***
|
||||
|
||||
Warning: fdatasync(): Can't fsync this stream! in %s on line %d
|
||||
bool(false)
|
||||
|
||||
*** Done ***
|
73
ext/standard/tests/file/fsync.phpt
Normal file
73
ext/standard/tests/file/fsync.phpt
Normal file
@ -0,0 +1,73 @@
|
||||
--TEST--
|
||||
Test fsync() function: basic functionality
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "*** Testing fsync(): writing to a file and reading the contents ***\n";
|
||||
$data = <<<EOD
|
||||
first line of string
|
||||
second line of string
|
||||
third line of string
|
||||
EOD;
|
||||
|
||||
$file_path = __DIR__;
|
||||
$filename = "$file_path/fsync_basic.tmp";
|
||||
|
||||
// opening a file
|
||||
$file_handle = fopen($filename, "w");
|
||||
if($file_handle == false)
|
||||
exit("Error:failed to open file $filename");
|
||||
|
||||
if(PHP_OS_FAMILY == 'Windows') {
|
||||
$data = str_replace("\r",'', $data);
|
||||
}
|
||||
|
||||
// writing data to the file
|
||||
var_dump( fwrite($file_handle, $data) );
|
||||
var_dump( fsync($file_handle) );
|
||||
var_dump( readfile($filename) );
|
||||
|
||||
echo "\n*** Testing fsync(): for return type ***\n";
|
||||
$return_value = fsync($file_handle);
|
||||
var_dump( is_bool($return_value) );
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Testing fsync(): attempting to sync stdin ***\n";
|
||||
$file_handle = fopen("php://stdin", "w");
|
||||
var_dump(fsync($file_handle));
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Testing fsync(): for non-file stream ***\n";
|
||||
$file_handle = fopen("php://memory", "w");
|
||||
$return_value = fsync($file_handle);
|
||||
var_dump( ($return_value) );
|
||||
fclose($file_handle);
|
||||
|
||||
echo "\n*** Done ***";
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$file_path = __DIR__;
|
||||
$filename = "$file_path/fsync_basic.tmp";
|
||||
unlink($filename);
|
||||
?>
|
||||
--EXPECTF--
|
||||
*** Testing fsync(): writing to a file and reading the contents ***
|
||||
int(63)
|
||||
bool(true)
|
||||
first line of string
|
||||
second line of string
|
||||
third line of stringint(63)
|
||||
|
||||
*** Testing fsync(): for return type ***
|
||||
bool(true)
|
||||
|
||||
*** Testing fsync(): attempting to sync stdin ***
|
||||
bool(false)
|
||||
|
||||
*** Testing fsync(): for non-file stream ***
|
||||
|
||||
Warning: fsync(): Can't fsync this stream! in %s on line %d
|
||||
bool(false)
|
||||
|
||||
*** Done ***
|
@ -334,6 +334,9 @@ PHPAPI int _php_stream_putc(php_stream *stream, int c);
|
||||
PHPAPI int _php_stream_flush(php_stream *stream, int closing);
|
||||
#define php_stream_flush(stream) _php_stream_flush((stream), 0)
|
||||
|
||||
PHPAPI int _php_stream_sync(php_stream *stream, bool data_only);
|
||||
#define php_stream_sync(stream, d) _php_stream_sync((stream), (d))
|
||||
|
||||
PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len);
|
||||
#define php_stream_gets(stream, buf, maxlen) _php_stream_get_line((stream), (buf), (maxlen), NULL)
|
||||
|
||||
@ -442,6 +445,15 @@ END_EXTERN_C()
|
||||
/* Enable/disable blocking reads on anonymous pipes on Windows. */
|
||||
#define PHP_STREAM_OPTION_PIPE_BLOCKING 13
|
||||
|
||||
/* Stream can support fsync operation */
|
||||
#define PHP_STREAM_OPTION_SYNC_API 14
|
||||
#define PHP_STREAM_SYNC_SUPPORTED 0
|
||||
#define PHP_STREAM_SYNC_FSYNC 1
|
||||
#define PHP_STREAM_SYNC_FDSYNC 2
|
||||
|
||||
#define php_stream_sync_supported(stream) (_php_stream_set_option((stream), PHP_STREAM_OPTION_SYNC_API, PHP_STREAM_SYNC_SUPPORTED, NULL) == PHP_STREAM_OPTION_RETURN_OK ? 1 : 0)
|
||||
|
||||
|
||||
#define PHP_STREAM_OPTION_RETURN_OK 0 /* option set OK */
|
||||
#define PHP_STREAM_OPTION_RETURN_ERR -1 /* problem setting option */
|
||||
#define PHP_STREAM_OPTION_RETURN_NOTIMPL -2 /* underlying stream does not implement; streams can handle it instead */
|
||||
|
@ -54,6 +54,8 @@ extern int php_get_gid_by_name(const char *name, gid_t *gid);
|
||||
|
||||
#if defined(PHP_WIN32)
|
||||
# define PLAIN_WRAP_BUF_SIZE(st) (((st) > UINT_MAX) ? UINT_MAX : (unsigned int)(st))
|
||||
#define fsync _commit
|
||||
#define fdatasync fsync
|
||||
#else
|
||||
# define PLAIN_WRAP_BUF_SIZE(st) (st)
|
||||
#endif
|
||||
@ -537,6 +539,28 @@ static int php_stdiop_flush(php_stream *stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int php_stdiop_sync(php_stream *stream, bool dataonly)
|
||||
{
|
||||
php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
|
||||
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS) == FAILURE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (php_stdiop_flush(stream) == 0) {
|
||||
PHP_STDIOP_GET_FD(fd, data);
|
||||
if (dataonly) {
|
||||
return fdatasync(fd);
|
||||
} else {
|
||||
return fsync(fd);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int php_stdiop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
|
||||
{
|
||||
php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
|
||||
@ -885,6 +909,16 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
|
||||
#endif
|
||||
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
|
||||
|
||||
case PHP_STREAM_OPTION_SYNC_API:
|
||||
switch (value) {
|
||||
case PHP_STREAM_SYNC_SUPPORTED:
|
||||
return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
|
||||
case PHP_STREAM_SYNC_FSYNC:
|
||||
return php_stdiop_sync(stream, 0) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
|
||||
case PHP_STREAM_SYNC_FDSYNC:
|
||||
return php_stdiop_sync(stream, 1) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
|
||||
}
|
||||
|
||||
case PHP_STREAM_OPTION_TRUNCATE_API:
|
||||
switch (value) {
|
||||
case PHP_STREAM_TRUNCATE_SUPPORTED:
|
||||
|
@ -1406,6 +1406,15 @@ PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, voi
|
||||
return ret;
|
||||
}
|
||||
|
||||
PHPAPI int _php_stream_sync(php_stream *stream, bool data_only)
|
||||
{
|
||||
int op = PHP_STREAM_SYNC_FSYNC;
|
||||
if (data_only) {
|
||||
op = PHP_STREAM_SYNC_FDSYNC;
|
||||
}
|
||||
return php_stream_set_option(stream, PHP_STREAM_OPTION_SYNC_API, op, NULL);
|
||||
}
|
||||
|
||||
PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize)
|
||||
{
|
||||
return php_stream_set_option(stream, PHP_STREAM_OPTION_TRUNCATE_API, PHP_STREAM_TRUNCATE_SET_SIZE, &newsize);
|
||||
|
Loading…
Reference in New Issue
Block a user