FileSystem::updateConfig()   A
last analyzed

Complexity

Conditions 6
Paths 32

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
dl 0
loc 18
rs 9.0444
c 0
b 0
f 0
nc 32
nop 0
1
<?php
2
namespace PHPDaemon\FS;
3
4
use PHPDaemon\Cache\CappedStorageHits;
5
use PHPDaemon\Core\CallbackWrapper;
6
use PHPDaemon\Core\Daemon;
7
use PHPDaemon\Core\EventLoop;
8
use PHPDaemon\Traits\EventLoopContainer;
9
10
/**
11
 * FileSystem
12
 * @package PHPDaemon\FS
13
 * @author  Vasily Zorin <[email protected]>
14
 */
15
class FileSystem
16
{
17
    use \PHPDaemon\Traits\ClassWatchdog;
18
    use \PHPDaemon\Traits\StaticObjectWatchdog;
19
    use EventLoopContainer;
20
21
    /**
22
     * @var boolean Is EIO supported?
23
     */
24
    public static $supported;
25
26
    /**
27
     * @var Event Main FS event
28
     */
29
    public static $ev;
30
31
    /**
32
     * @var resource EIO file descriptor
33
     */
34
    public static $fd;
35
36
    /**
37
     * @var array Mode types
38
     */
39
    public static $modeTypes = [
40
        0140000 => 's',
41
        0120000 => 'l',
42
        0100000 => 'f',
43
        0060000 => 'b',
44
        0040000 => 'd',
45
        0020000 => 'c',
46
        0010000 => 'p',
47
    ];
48
49
    /**
50
     * @var integer TTL for bad descriptors in seconds
51
     */
52
    public static $badFDttl = 5;
53
54
    /**
55
     * @var PHPDaemon\Cache\CappedStorage File descriptor cache
56
     */
57
    public static $fdCache;
58
59
    /**
60
     * @var integer Maximum number of open files in cache
61
     */
62
    public static $fdCacheSize = 128;
63
64
    /**
65
     * @var string Required EIO version
66
     */
67
    public static $eioVer = '1.2.1';
68
69
    /**
70
     * Initialize FS driver
71
     * @return void
72
     */
73
    public static function init()
74
    {
75
        if (!Daemon::$config->eioenabled->value) {
76
            self::$supported = false;
77
            return;
78
        }
79
        if (!self::$supported = Daemon::loadModuleIfAbsent('eio', self::$eioVer)) {
80
            Daemon::log('FS: missing pecl-eio >= ' . self::$eioVer . '. Filesystem I/O performance compromised. Consider installing pecl-eio. `pecl install http://pecl.php.net/get/eio`');
81
            return;
82
        }
83
        self::$fdCache = new CappedStorageHits(self::$fdCacheSize);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \PHPDaemon\Cache\Cap...its(self::$fdCacheSize) of type object<PHPDaemon\Cache\CappedStorageHits> is incompatible with the declared type object<PHPDaemon\FS\PHPD...on\Cache\CappedStorage> of property $fdCache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
84
        eio_init();
85
    }
86
87
    public function __construct()
88
    {
89
90
    }
91
92
    /**
93
     * Initialize main FS event
94
     * @return void
95
     */
96
    public static function initEvent()
97
    {
98
        if (!self::$supported) {
99
            return;
100
        }
101
        self::updateConfig();
102
        self::$fd = eio_get_event_stream();
103
        self::$ev = EventLoop::$instance->event(self::$fd,
0 ignored issues
show
Documentation Bug introduced by
It seems like \PHPDaemon\Core\EventLoo... eio_poll(); } }) of type object<Event> is incompatible with the declared type object<PHPDaemon\FS\Event> of property $ev.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
104
            \Event::READ | \Event::PERSIST,
105
            function ($fd, $events, $arg) {
0 ignored issues
show
Unused Code introduced by
The parameter $fd is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $events is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $arg is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
106
                while (eio_nreqs()) {
107
                    eio_poll();
108
                }
109
            }
110
        );
111
        self::$ev->add();
112
    }
113
114
    /**
115
     * Checks if file exists and readable
116
     * @param  string $path Path
117
     * @return boolean      Exists and readable?
118
     */
119
    public static function checkFileReadable($path)
120
    {
121
        return is_file($path) && is_readable($path);
122
    }
123
124
    /**
125
     * Block until all FS events are completed
126
     * @return void
127
     */
128
    public static function waitAllEvents()
129
    {
130
        if (!self::$supported) {
131
            return;
132
        }
133
        while (eio_nreqs()) {
134
            eio_poll();
135
        }
136
    }
137
138
    /**
139
     * Called when config is updated
140
     * @return void
141
     */
142
    public static function updateConfig()
143
    {
144
        if (Daemon::$config->eiosetmaxidle->value !== null) {
145
            eio_set_max_idle(Daemon::$config->eiosetmaxidle->value);
146
        }
147
        if (Daemon::$config->eiosetmaxparallel->value !== null) {
148
            eio_set_max_parallel(Daemon::$config->eiosetmaxparallel->value);
149
        }
150
        if (Daemon::$config->eiosetmaxpollreqs->value !== null) {
151
            eio_set_max_poll_reqs(Daemon::$config->eiosetmaxpollreqs->value);
152
        }
153
        if (Daemon::$config->eiosetmaxpolltime->value !== null) {
154
            eio_set_max_poll_time(Daemon::$config->eiosetmaxpolltime->value);
155
        }
156
        if (Daemon::$config->eiosetminparallel->value !== null) {
157
            eio_set_min_parallel(Daemon::$config->eiosetminparallel->value);
158
        }
159
    }
160
161
    /**
162
     * Sanitize path
163
     * @param  string $path Path
164
     * @return string       Sanitized path
165
     */
166
    public static function sanitizePath($path)
167
    {
168
        return str_replace(["\x00", "../"], '', $path);
169
    }
170
171
    /**
172
     * Prepare value of stat()
173
     * @param  mixed $stat Data
174
     * @return array hash
175
     */
176
    public static function statPrepare($stat)
177
    {
178
        if ($stat === -1 || !$stat) {
179
            return -1;
180
        }
181
        $stat['type'] = FileSystem::$modeTypes[$stat['mode'] & 0170000];
182
        return $stat;
183
    }
184
185
    /**
186
     * Gets stat() information
187
     * @param  string $path Path
188
     * @param  callable $cb Callback
189
     * @param  integer $pri Priority
190
     * @return resource|true
191
     */
192 View Code Duplication
    public static function stat($path, $cb, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
    {
194
        $cb = CallbackWrapper::forceWrap($cb);
195
        if (!self::$supported) {
196
            $cb($path, FileSystem::statPrepare(@stat($path)));
197
            return true;
198
        }
199
        return eio_stat($path, $pri, function ($path, $stat) use ($cb) {
200
            $cb($path, FileSystem::statPrepare($stat));
201
        }, $path);
202
    }
203
204
    /**
205
     * Unlink file
206
     * @param  string $path Path
207
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
208
     * @param  integer $pri Priority
209
     * @return resource|boolean
210
     */
211
    public static function unlink($path, $cb = null, $pri = EIO_PRI_DEFAULT)
212
    {
213
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 213 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
214
        if (!self::$supported) {
215
            $r = unlink($path);
216
            if ($cb) {
217
                $cb($path, $r);
218
            }
219
            return $r;
220
        }
221
        return eio_unlink($path, $pri, $cb, $path);
222
    }
223
224
    /**
225
     * Rename
226
     * @param  string $path Path
227
     * @param  string $newpath New path
228
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
229
     * @param  integer $pri Priority
230
     * @return resource|boolean
231
     */
232 View Code Duplication
    public static function rename($path, $newpath, $cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
233
    {
234
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 234 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
235
        if (!self::$supported) {
236
            $r = rename($path, $newpath);
237
            if ($cb) {
238
                $cb($path, $newpath, $r);
239
            }
240
            return $r;
241
        }
242
        return eio_rename($path, $newpath, $pri, $cb, $path);
243
    }
244
245
    /**
246
     * statvfs()
247
     * @param  string $path Path
248
     * @param  callable $cb Callback
249
     * @param  integer $pri Priority
250
     * @return resource|false
251
     */
252 View Code Duplication
    public static function statvfs($path, $cb, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
    {
254
        $cb = CallbackWrapper::forceWrap($cb);
255
        if (!self::$supported) {
256
            $cb($path, false);
257
            return false;
258
        }
259
        return eio_statvfs($path, $pri, $cb, $path);
260
    }
261
262
    /**
263
     * lstat()
264
     * @param  string $path Path
265
     * @param  callable $cb Callback
266
     * @param  integer $pri Priority
267
     * @return resource|true
268
     */
269 View Code Duplication
    public static function lstat($path, $cb, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
    {
271
        $cb = CallbackWrapper::forceWrap($cb);
272
        if (!self::$supported) {
273
            $cb($path, FileSystem::statPrepare(lstat($path)));
274
            return true;
275
        }
276
        return eio_lstat($path, $pri, function ($path, $stat) use ($cb) {
277
            $cb($path, FileSystem::statPrepare($stat));
278
        }, $path);
279
    }
280
281
    /**
282
     * realpath()
283
     * @param  string $path Path
284
     * @param  callable $cb Callback
285
     * @param  integer $pri Priority
286
     * @return resource|true
287
     */
288 View Code Duplication
    public static function realpath($path, $cb, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
    {
290
        $cb = CallbackWrapper::forceWrap($cb);
291
        if (!self::$supported) {
292
            $cb($path, realpath($path));
293
            return true;
294
        }
295
        return eio_realpath($path, $pri, $cb, $path);
296
    }
297
298
    /**
299
     * sync()
300
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
301
     * @param  integer $pri Priority
302
     * @return resource|false
303
     */
304 View Code Duplication
    public static function sync($cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
    {
306
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 306 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
307
        if (!self::$supported) {
308
            if ($cb) {
309
                $cb(false);
310
            }
311
            return false;
312
        }
313
        return eio_sync($pri, $cb);
314
    }
315
316
    /**
317
     * statfs()
318
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
319
     * @param  integer $pri Priority
320
     * @return resource|false
321
     */
322 View Code Duplication
    public static function syncfs($cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
323
    {
324
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 324 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
325
        if (!self::$supported) {
326
            if ($cb) {
327
                $cb(false);
328
            }
329
            return false;
330
        }
331
        return eio_syncfs($pri, $cb);
332
    }
333
334
    /**
335
     * touch()
336
     * @param  string $path Path
337
     * @param  integer $mtime Last modification time
338
     * @param  integer $atime Last access time
0 ignored issues
show
Documentation introduced by
Should the type for parameter $atime not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
339
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
340
     * @param  integer $pri Priority
341
     * @return resource|boolean
342
     */
343 View Code Duplication
    public static function touch($path, $mtime, $atime = null, $cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
344
    {
345
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 345 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
346
        if (!FileSystem::$supported) {
347
            $r = touch($path, $mtime, $atime);
348
            if ($cb) {
349
                $cb($r);
350
            }
351
            return $r;
352
        }
353
        return eio_utime($path, $atime, $mtime, $pri, $cb, $path);
354
    }
355
356
    /**
357
     * Removes empty directory
358
     * @param  string $path Path
359
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
360
     * @param  integer $pri Priority
361
     * @return resource|boolean
362
     */
363
    public static function rmdir($path, $cb = null, $pri = EIO_PRI_DEFAULT)
364
    {
365
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 365 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
366
        if (!FileSystem::$supported) {
367
            $r = rmdir($path);
368
            if ($cb) {
369
                $cb($path, $r);
370
            }
371
            return $r;
372
        }
373
        return eio_rmdir($path, $pri, $cb, $path);
374
    }
375
376
    /**
377
     * Creates directory
378
     * @param  string $path Path
379
     * @param  integer $mode Mode (octal)
380
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
381
     * @param  integer $pri Priority
382
     * @return resource|boolean
383
     */
384 View Code Duplication
    public static function mkdir($path, $mode, $cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
385
    {
386
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 386 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
387
        if (!FileSystem::$supported) {
388
            $r = mkdir($path, $mode);
389
            if ($cb) {
390
                $cb($path, $r);
391
            }
392
            return $r;
393
        }
394
        return eio_mkdir($path, $mode, $pri, $cb, $path);
395
    }
396
397
    /**
398
     * Readdir()
399
     * @param  string $path Path
400
     * @param  callable $cb = null Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
401
     * @param  integer $flags = null Flags
0 ignored issues
show
Documentation introduced by
Should the type for parameter $flags not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
402
     * @param  integer $pri = EIO_PRI_DEFAULT Priority
403
     * @return resource|true
404
     */
405
    public static function readdir($path, $cb = null, $flags = null, $pri = EIO_PRI_DEFAULT)
406
    {
407
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 407 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
408
        if (!FileSystem::$supported) {
409
            $r = glob($path);
410
            if ($cb) {
411
                $cb($path, $r);
412
            }
413
            return true;
414
        }
415
        return eio_readdir($path, $flags, $pri, $cb, $path);
416
    }
417
418
    /**
419
     * Truncate file
420
     * @param  string $path Path
421
     * @param  integer $offset Offset
422
     * @param  callable $cb Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
423
     * @param  integer $pri Priority
424
     * @return resource|boolean
425
     */
426 View Code Duplication
    public static function truncate($path, $offset = 0, $cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
427
    {
428
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 428 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
429
        if (!FileSystem::$supported) {
430
            $fp = fopen($path, 'r+');
431
            $r = $fp && ftruncate($fp, $offset);
432
            if ($cb) {
433
                $cb($path, $r);
434
            }
435
            return $r;
436
        }
437
        return eio_truncate($path, $offset, $pri, $cb, $path);
438
    }
439
440
    /**
441
     * sendfile()
442
     * @param  mixed $outfd File descriptor
443
     * @param  string $path Path
444
     * @param  callable $cb Callback
445
     * @param  callable $startCb Start callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $startCb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
446
     * @param  integer $offset Offset
447
     * @param  integer $length Length
0 ignored issues
show
Documentation introduced by
Should the type for parameter $length not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
448
     * @param  integer $pri Priority
449
     * @return true              Success
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
450
     */
451
    public static function sendfile(
452
        $outfd,
453
        $path,
454
        $cb,
455
        $startCb = null,
456
        $offset = 0,
457
        $length = null,
458
        $pri = EIO_PRI_DEFAULT
459
    ) {
460
        $cb = CallbackWrapper::forceWrap($cb);
461
        if (!self::$supported) {
462
            $cb($path, false);
463
            return false;
464
        }
465
466
        $noncache = true;
467
468
        FileSystem::open(
469
            $path,
470
            'r!',
471
            function ($file) use ($cb, $noncache, $startCb, $path, $pri, $outfd, $offset, $length) {
472
                if (!$file) {
473
                    $cb($path, false);
474
                    return;
475
                }
476
477
                $file->sendfile(
478
                    $outfd,
479
                    function ($file, $success) use ($cb, $noncache) {
480
                        $cb($file->path, $success);
481
                        if ($noncache) {
482
                            $file->close();
483
                        }
484
                    },
485
                    $startCb,
486
                    $offset,
487
                    $length,
488
                    $pri
489
                );
490
            },
491
            $pri
492
        );
493
494
        return true;
495
    }
496
497
    /**
498
     * Changes ownership of file/directory
499
     * @param  string $path Path
500
     * @param  integer $uid User ID
501
     * @param  integer $gid Group ID
502
     * @param  callable $cb = null Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
503
     * @param  integer $pri = EIO_PRI_DEFAULT Priority
504
     * @return resource|boolean
505
     */
506 View Code Duplication
    public static function chown($path, $uid, $gid = -1, $cb = null, $pri = EIO_PRI_DEFAULT)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
507
    {
508
        $cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 508 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
509
        if (!FileSystem::$supported) {
510
            $r = chown($path, $uid);
511
            if ($gid !== -1) {
512
                $r = $r && chgrp($path, $gid);
513
            }
514
            $cb($path, $r);
515
            return $r;
516
        }
517
518
        return eio_chown($path, $uid, $gid, $pri, $cb, $path);
519
    }
520
521
    /**
522
     * Reads whole file
523
     * @param  string $path Path
524
     * @param  callable $cb Callback (Path, Contents)
525
     * @param  integer $pri Priority
526
     * @return resource|true
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|resource?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
527
     */
528
    public static function readfile($path, $cb, $pri = EIO_PRI_DEFAULT)
529
    {
530
        $cb = CallbackWrapper::forceWrap($cb);
531
        if (!FileSystem::$supported) {
532
            $cb($path, file_get_contents($path));
533
            return true;
534
        }
535
        return FileSystem::open($path, 'r!', function ($file) use ($path, $cb, $pri) {
536
            if (!$file) {
537
                $cb($path, false);
538
                return;
539
            }
540
            $file->readAll($cb, $pri);
541
        }, null, $pri);
542
    }
543
544
    /**
545
     * Reads file chunk-by-chunk
546
     * @param  string $path Path
547
     * @param  callable $cb Callback (Path, Success)
548
     * @param  callable $chunkcb Chunk callback (Path, Chunk)
549
     * @param  integer $pri Priority
550
     * @return resource
0 ignored issues
show
Documentation introduced by
Should the return type not be resource|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
551
     */
552
    public static function readfileChunked($path, $cb, $chunkcb, $pri = EIO_PRI_DEFAULT)
553
    {
554
        $cb = CallbackWrapper::forceWrap($cb);
555
        if (!FileSystem::$supported) {
556
            $chunkcb($path, $r = readfile($path));
557
            $cb($r !== false);
558
            return;
559
        }
560
        FileSystem::open($path, 'r!', function ($file) use ($path, $cb, $chunkcb, $pri) {
561
            if (!$file) {
562
                $cb($path, false);
563
                return;
564
            }
565
            $file->readAllChunked($cb, $chunkcb, $pri);
566
        }, null, $pri);
567
    }
568
569
    /**
570
     * Returns random temporary file name
571
     * @param  string $dir Directory
0 ignored issues
show
Documentation introduced by
Should the type for parameter $dir not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
572
     * @param  string $prefix Prefix
573
     * @return string         Path
574
     */
575
    public static function genRndTempnam($dir = null, $prefix = 'php')
576
    {
577
        if (!$dir) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $dir of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
578
            $dir = sys_get_temp_dir();
579
        }
580
581
        static $n = 0;
582
583
        return $dir . '/' . $prefix . str_shuffle(
584
            md5(
585
                str_shuffle(
586
                    microtime(true) . chr(mt_rand(0, 0xFF))
587
                    . Daemon::$process->getPid() . chr(mt_rand(0, 0xFF))
588
                    . (++$n) . mt_rand(0, mt_getrandmax())
589
                )
590
            )
591
        );
592
    }
593
594
    /**
595
     * Returns random temporary file name
596
     * @param  string $dir Directory
597
     * @param  string $prefix Prefix
598
     * @return string         Path
599
     */
600
    public static function genRndTempnamPrefix($dir, $prefix)
601
    {
602
        if (!$dir) {
603
            $dir = sys_get_temp_dir();
604
        }
605
        return $dir . '/' . $prefix;
606
    }
607
608
    /**
609
     * Generates closure tempnam handler
610
     * @param  $dir
611
     * @param  $prefix
612
     * @param  $cb
613
     * @param  $tries
614
     */
615
    protected static function tempnamHandler($dir, $prefix, $cb, &$tries)
616
    {
617
        $cb = CallbackWrapper::forceWrap($cb);
618
        if (++$tries >= 3) {
619
            $cb(false);
620
            return;
621
        }
622
        $path = FileSystem::genRndTempnam($dir, $prefix);
623
        FileSystem::open($path, 'x+!', function ($file) use ($dir, $prefix, $cb, &$tries) {
624
            if (!$file) {
625
                static::tempnamHandler($dir, $prefix, $cb, $tries);
626
                return;
627
            }
628
            $cb($file);
629
        });
630
    }
631
632
    /**
633
     * Obtain exclusive temporary file
634
     * @param  string $dir Directory
635
     * @param  string $prefix Prefix
636
     * @param  callable $cb Callback (File)
637
     * @return resource
0 ignored issues
show
Documentation introduced by
Should the return type not be resource|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
638
     */
639
    public static function tempnam($dir, $prefix, $cb)
640
    {
641
        $cb = CallbackWrapper::forceWrap($cb);
642
        if (!FileSystem::$supported) {
643
            FileSystem::open(tempnam($dir, $prefix), 'w!', $cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 641 can be null; however, PHPDaemon\FS\FileSystem::open() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
644
        }
645
        $tries = 0;
646
        static::tempnamHandler($dir, $prefix, $cb, $tries);
647
    }
648
649
    /**
650
     * Open file
651
     * @param  string $path Path
652
     * @param  string $flags Flags
653
     * @param  callable $cb Callback (File)
654
     * @param  integer $mode Mode (see EIO_S_I* constants)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $mode not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
655
     * @param  integer $pri Priority
656
     * @return resource
657
     */
658
    public static function open($path, $flags, $cb, $mode = null, $pri = EIO_PRI_DEFAULT)
659
    {
660
        $cb = CallbackWrapper::forceWrap($cb);
661
        if (!FileSystem::$supported) {
662
            $mode = File::convertFlags($flags, true);
663
            $fd = fopen($path, $mode);
664
            if (!$fd) {
665
                $cb(false);
666
                return false;
667
            }
668
            $file = new File($fd, $path);
669
            $cb($file);
670
            return true;
671
        }
672
        $fdCacheKey = $path . "\x00" . $flags;
673
        $noncache = mb_orig_strpos($flags, '!') !== false;
674
        $flags = File::convertFlags($flags);
675
        if (!$noncache && ($item = FileSystem::$fdCache->get($fdCacheKey))) { // cache hit
676
            $file = $item->getValue();
677
            if ($file === null) { // operation in progress
678
                $item->addListener($cb);
679
            } else { // hit
680
                $cb($file);
681
            }
682
            return null;
683
        } elseif (!$noncache) {
684
            $item = FileSystem::$fdCache->put($fdCacheKey, null);
685
            $item->addListener($cb);
686
        }
687
        return eio_open($path, $flags, $mode, $pri, function ($path, $fd) use ($cb, $flags, $fdCacheKey, $noncache) {
688
            if ($fd === -1) {
689
                if ($noncache) {
690
                    $cb(false);
691
                } else {
692
                    FileSystem::$fdCache->put($fdCacheKey, false, self::$badFDttl);
693
                }
694
                return;
695
            }
696
            $file = new File($fd, $path);
697
            $file->append = ($flags | EIO_O_APPEND) === $flags;
698
            if ($file->append) {
699
                $file->stat(function ($file, $stat) use ($cb, $noncache, $fdCacheKey) {
700
                    $file->offset = $stat['size'];
701 View Code Duplication
                    if (!$noncache) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
702
                        $file->fdCacheKey = $fdCacheKey;
703
                        FileSystem::$fdCache->put($fdCacheKey, $file);
704
                    } else {
705
                        $cb($file);
706
                    }
707
                });
708 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
709
                if (!$noncache) {
710
                    $file->fdCacheKey = $fdCacheKey;
711
                    FileSystem::$fdCache->put($fdCacheKey, $file);
712
                } else {
713
                    $cb($file);
714
                }
715
            }
716
        }, $path);
717
    }
718
}
719
720
if (!defined('EIO_PRI_DEFAULT')) {
721
    define('EIO_PRI_DEFAULT', 0);
722
}
723