1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-19570: unable to fseek in /dev/zero and /dev/null

On Linux, these two character devices are exceptions in that they can be
seeked. Check their major/minor device number.

Co-authored-by: divinity76 <hans@loltek.net>
This commit is contained in:
Niels Dossche
2025-09-06 14:20:24 +02:00
parent 64c1d43b68
commit b7aeb0a69f
3 changed files with 49 additions and 0 deletions

2
NEWS
View File

@@ -64,6 +64,8 @@ PHP NEWS
causing an exception on sort). (nielsdos) causing an exception on sort). (nielsdos)
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array . Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois) while COW violation flag is still set). (alexandre-daubois)
. Fixed bug GH-19570 (unable to fseek in /dev/zero and /dev/null).
(nielsdos, divinity76)
- Streams: - Streams:
. Fixed bug GH-19248 (Use strerror_r instead of strerror in main). . Fixed bug GH-19248 (Use strerror_r instead of strerror in main).

View File

@@ -0,0 +1,22 @@
--TEST--
GH-19570 (unable to fseek in /dev/zero and /dev/null)
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== "Linux") die("skip only for Linux");
?>
--FILE--
<?php
$devices = [
// Note: could test others but they're not necessarily available
"/dev/zero",
"/dev/null",
"/dev/full",
];
foreach ($devices as $device) {
var_dump(fseek(fopen($device, "rb"), 1*1024*1024, SEEK_SET));
}
?>
--EXPECT--
int(0)
int(0)
int(0)

View File

@@ -43,6 +43,10 @@
# include <limits.h> # include <limits.h>
#endif #endif
#ifdef __linux__
# include <sys/sysmacros.h>
#endif
#define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC) #define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC)
#define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC) #define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC)
#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC) #define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC)
@@ -255,7 +259,28 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC)
static void detect_is_seekable(php_stdio_stream_data *self) { static void detect_is_seekable(php_stdio_stream_data *self) {
#if defined(S_ISFIFO) && defined(S_ISCHR) #if defined(S_ISFIFO) && defined(S_ISCHR)
if (self->fd >= 0 && do_fstat(self, 0) == 0) { if (self->fd >= 0 && do_fstat(self, 0) == 0) {
#ifdef __linux__
if (S_ISCHR(self->sb.st_mode)) {
/* Some character devices are exceptions, check their major/minor ID
* https://www.kernel.org/doc/Documentation/admin-guide/devices.txt */
if (major(self->sb.st_rdev) == 1) {
unsigned m = minor(self->sb.st_rdev);
self->is_seekable =
m == 1 || /* /dev/mem */
m == 2 || /* /dev/kmem */
m == 3 || /* /dev/null */
m == 4 || /* /dev/port (seekable, offset = I/O port) */
m == 5 || /* /dev/zero */
m == 7; /* /dev/full */
} else {
self->is_seekable = false;
}
} else {
self->is_seekable = !S_ISFIFO(self->sb.st_mode);
}
#else
self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode)); self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode));
#endif
self->is_pipe = S_ISFIFO(self->sb.st_mode); self->is_pipe = S_ISFIFO(self->sb.st_mode);
} }
#elif defined(PHP_WIN32) #elif defined(PHP_WIN32)