├── .github └── workflows │ ├── phpcs.yml │ ├── phpunit.yml │ └── static-analysis.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── example ├── DummyFs.php ├── array_fs.php ├── dummy_file.php ├── dummy_file_oo.php └── log_unimplemented.php ├── phpcs.xml ├── phpunit.xml.dist ├── psalm.xml ├── renovate.json ├── src ├── FFI │ └── TypedCDataDefaultImplementationTrait.php ├── Filesystem │ ├── BeforeAll │ │ └── BeforeAllFilesystem.php │ ├── Delegation │ │ └── DelegationFilesystemTrait.php │ ├── Log │ │ └── LogUnimplementedFilesystem.php │ ├── Null │ │ └── NullFilesystem.php │ ├── Overlay │ │ └── OverlayFilesystem.php │ └── ReflectionFilesystem.php ├── FilesystemDefaultImplementationTrait.php ├── FilesystemFlagsImplementationTrait.php ├── FilesystemInterface.php ├── Fuse.php ├── FuseLogicException.php ├── FuseOperations.php ├── Headers │ └── fuse.h ├── Libc │ ├── Errno │ │ └── Errno.php │ ├── Fcntl │ │ └── Flock.php │ ├── Fuse │ │ ├── FuseBuf.php │ │ ├── FuseBufVec.php │ │ ├── FuseConnInfo.php │ │ ├── FuseDirFill.php │ │ ├── FuseDirHandle.php │ │ ├── FuseFileInfo.php │ │ ├── FuseFillDir.php │ │ ├── FuseIoctlArgPointer.php │ │ ├── FuseIoctlDataPointer.php │ │ ├── FusePollHandle.php │ │ ├── FusePrivateData.php │ │ └── FuseReadDirBuffer.php │ ├── String │ │ ├── CBytesBuffer.php │ │ └── CStringBuffer.php │ ├── Sys │ │ ├── Stat │ │ │ └── Stat.php │ │ └── StatVfs │ │ │ └── StatVfs.php │ ├── Time │ │ └── TimeSpec.php │ └── Utime │ │ └── UtimBuf.php ├── Mountable.php ├── MountableFilesystemTrait.php └── Mounter.php ├── tests ├── FFI │ └── TypedCDataWrapperTest.php └── Filesystem │ ├── Log │ └── LogUnimplementedFilesystemTest.php │ └── ReflectionFilesystemTest.php └── tools └── stubs ├── FFI └── CData.php └── Fuse ├── FuseCData.php └── FuseFFI.php /.github/workflows/phpcs.yml: -------------------------------------------------------------------------------- 1 | name: PHP Coding Style Checker 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | 13 | phpcs: 14 | name: phpcs check codestyles 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Setup PHP Action 20 | uses: shivammathur/setup-php@v2 21 | with: 22 | php-version: 7.4 23 | extensions: dom, mbstring 24 | coverage: none 25 | tools: cs2pr 26 | 27 | - name: Get Composer Cache Directory 28 | id: composer-cache 29 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 30 | 31 | - name: Cache dependencies 32 | uses: actions/cache@v2 33 | with: 34 | path: ${{ steps.composer-cache.outputs.dir }} 35 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 36 | restore-keys: ${{ runner.os }}-composer- 37 | 38 | - name: Install Dependencies 39 | run: composer install --prefer-dist --no-progress --no-suggest 40 | 41 | - name: Run phpcs 42 | run: vendor/bin/phpcs --standard=./phpcs.xml --report=checkstyle -q ./src ./tests | cs2pr 43 | -------------------------------------------------------------------------------- /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | 13 | phpunit-test: 14 | name: phpunit test 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Setup PHP Action 20 | uses: shivammathur/setup-php@v2 21 | with: 22 | php-version: 7.4 23 | extensions: ffi, dom, mbstring 24 | coverage: pcov 25 | 26 | - name: Install libfuse 27 | run: sudo apt-get install libfuse-dev 28 | 29 | - name: Get Composer Cache Directory 30 | id: composer-cache 31 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 32 | 33 | - name: Cache dependencies 34 | uses: actions/cache@v2 35 | with: 36 | path: ${{ steps.composer-cache.outputs.dir }} 37 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 38 | restore-keys: ${{ runner.os }}-composer- 39 | 40 | - name: Validate composer.json and composer.lock 41 | run: composer validate 42 | 43 | - name: Install dependencies 44 | run: composer install --prefer-dist --no-progress --no-suggest 45 | 46 | - name: Setup problem matchers for PHP 47 | run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" 48 | 49 | - name: Setup Problem Matchers for PHPUnit 50 | run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 51 | 52 | - name: Run test suite 53 | run: | 54 | mkdir -p build/logs 55 | ./vendor/bin/phpunit --coverage-clover build/logs/clover.xml 56 | 57 | - name: Send to coveralls 58 | env: 59 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | run: ./vendor/bin/php-coveralls -v 61 | -------------------------------------------------------------------------------- /.github/workflows/static-analysis.yml: -------------------------------------------------------------------------------- 1 | name: PHP Static Analysis 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | 13 | psalm-analysis: 14 | name: psalm static code analysis 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Setup PHP Action 20 | uses: shivammathur/setup-php@v2 21 | with: 22 | php-version: 7.4 23 | extensions: dom, mbstring 24 | coverage: none 25 | 26 | - name: Get Composer Cache Directory 27 | id: composer-cache 28 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 29 | 30 | - name: Cache dependencies 31 | uses: actions/cache@v2 32 | with: 33 | path: ${{ steps.composer-cache.outputs.dir }} 34 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 35 | restore-keys: ${{ runner.os }}-composer- 36 | 37 | - name: "Psalm cache" 38 | uses: actions/cache@v2 39 | with: 40 | path: /tmp/psalm 41 | key: "psalm-cache" 42 | 43 | - name: Install Dependencies 44 | run: composer install --prefer-dist --no-progress --no-suggest 45 | 46 | - name: Run psalm 47 | run: ./vendor/bin/psalm --shepherd --show-info=true --output-format=github 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) sji 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-fuse 2 | 3 | ![Minimum PHP version: 7.4.0](https://img.shields.io/badge/php-7.4.0%2B-blue.svg) 4 | [![Packagist](https://img.shields.io/packagist/v/sj-i/php-fuse.svg)](https://packagist.org/packages/sj-i/php-fuse) 5 | [![Github Actions](https://github.com/sj-i/php-fuse/workflows/build/badge.svg)](https://github.com/sj-i/php-fuse/actions) 6 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sj-i/php-fuse/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/sj-i/php-fuse/?branch=master) 7 | [![Coverage Status](https://coveralls.io/repos/github/sj-i/php-fuse/badge.svg?branch=master)](https://coveralls.io/github/sj-i/php-fuse?branch=master) 8 | ![Psalm coverage](https://shepherd.dev/github/sj-i/php-fuse/coverage.svg?) 9 | ![stability-experimental](https://img.shields.io/badge/stability-experimental-orange.svg) 10 | 11 | PHP FFI bindings for [libfuse](https://github.com/libfuse/libfuse). 12 | 13 | You can write your own filesystems in PHP. 14 | 15 | ## Installation 16 | ```bash 17 | composer require sj-i/php-fuse 18 | ``` 19 | 20 | ## Requirements 21 | - PHP 7.4+ (NTS / ZTS) 22 | - 64bit Linux x86_64 23 | - FFI extension 24 | - libfuse(currently based on 2.9.9) 25 | 26 | ## Documentation 27 | - Currently, no documentation is provided. :-( 28 | - If you want to write a filesystem in PHP by using this library, see [examples](https://github.com/sj-i/php-fuse/tree/master/example) in this repository and [the libfuse API documentation](https://libfuse.github.io/doxygen/index.html) for now. 29 | 30 | ## Todo 31 | - [ ] bump libfuse to 3.9 32 | - [ ] add more tests 33 | - [ ] add documentation 34 | - [ ] support multithreading 35 | 36 | 37 | ## LICENSE 38 | - MIT 39 | 40 | ## Example 41 | ```bash 42 | mkdir /tmp/example 43 | php example/dummy_file.php 44 | ``` 45 | 46 | ```bash 47 | $ ls -la /tmp/example/ 48 | total 180 49 | drwxr-xr-x 2 sji sji 0 1月 1 1970 . 50 | drwxrwxrwt 25 root root 180224 12月 28 07:14 .. 51 | -rwxrwxrwx 1 sji sji 20 1月 1 1970 example 52 | $ cat /tmp/example/example 53 | hello FUSE from PHP 54 | $ umount /tmp/example 55 | ``` 56 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sj-i/php-fuse", 3 | "description": "PHP FFI bindings for FUSE", 4 | "type": "library", 5 | "minimum-stability": "dev", 6 | "license": "MIT", 7 | "keywords": [ 8 | "php", 9 | "fuse", 10 | "ffi" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "sji", 15 | "homepage": "https://twitter.com/sji_ch" 16 | } 17 | ], 18 | "autoload": { 19 | "psr-4": { 20 | "Fuse\\" : "src/" 21 | } 22 | }, 23 | "require": { 24 | "php": "^7.4|^8.0", 25 | "ext-ffi": "*", 26 | "sj-i/phpdoc-type-reader": "0.1.1", 27 | "sj-i/typed-cdata": "0.0.5", 28 | "psr/log": "^1.1" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "9.5.9", 32 | "squizlabs/php_codesniffer": "3.6.0", 33 | "php-coveralls/php-coveralls": "2.4.3", 34 | "vimeo/psalm": "4.10.0", 35 | "jetbrains/phpstorm-stubs": "dev-master" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/DummyFs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | use Fuse\FilesystemDefaultImplementationTrait; 15 | use Fuse\FilesystemInterface; 16 | use Fuse\Libc\Errno\Errno; 17 | use Fuse\Libc\Fuse\FuseFileInfo; 18 | use Fuse\Libc\Fuse\FuseFillDir; 19 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 20 | use Fuse\Libc\String\CBytesBuffer; 21 | use Fuse\Libc\Sys\Stat\Stat; 22 | 23 | class DummyFs implements FilesystemInterface 24 | { 25 | use FilesystemDefaultImplementationTrait; 26 | 27 | const FILE_PATH = '/example'; 28 | const FILE_NAME = 'example'; 29 | const FILE_CONTENT = 'hello FUSE from PHP' . PHP_EOL; 30 | 31 | public function getattr(string $path, Stat $stat): int 32 | { 33 | echo "attr read {$path}" . PHP_EOL; 34 | 35 | if ($path === '/') { 36 | $stat->st_mode = Stat::S_IFDIR | 0755; 37 | $stat->st_nlink = 2; 38 | $stat->st_uid = getmyuid(); 39 | $stat->st_gid = getmygid(); 40 | return 0; 41 | } 42 | 43 | if ($path === self::FILE_PATH) { 44 | $stat->st_mode = Stat::S_IFREG | 0777; 45 | $stat->st_nlink = 1; 46 | $stat->st_size = strlen(self::FILE_CONTENT); 47 | $stat->st_uid = getmyuid(); 48 | $stat->st_gid = getmygid(); 49 | return 0; 50 | } 51 | 52 | return -Errno::ENOENT; 53 | } 54 | 55 | public function readdir( 56 | string $path, 57 | FuseReadDirBuffer $buf, 58 | FuseFillDir $filler, 59 | int $offset, 60 | FuseFileInfo $fuse_file_info 61 | ): int { 62 | $filler($buf, '.', null, 0); 63 | $filler($buf, '..', null, 0); 64 | $filler($buf, self::FILE_NAME, null, 0); 65 | 66 | return 0; 67 | } 68 | 69 | public function open(string $path, FuseFileInfo $fuse_file_info): int 70 | { 71 | echo "open {$path}" . PHP_EOL; 72 | 73 | if ($path !== self::FILE_PATH) { 74 | return -Errno::ENOENT; 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 81 | { 82 | echo "read {$path}" . PHP_EOL; 83 | 84 | $len = strlen(self::FILE_CONTENT); 85 | 86 | if ($offset + $size > $len) { 87 | $size = ($len - $offset); 88 | } 89 | 90 | $content = substr(self::FILE_CONTENT, $offset, $size); 91 | $buffer->write($content, $size); 92 | 93 | return $size; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /example/array_fs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | use Fuse\FilesystemDefaultImplementationTrait; 15 | use Fuse\FilesystemInterface; 16 | use Fuse\Libc\Errno\Errno; 17 | use Fuse\Libc\Fuse\FuseFileInfo; 18 | use Fuse\Libc\Fuse\FuseFillDir; 19 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 20 | use Fuse\Libc\String\CBytesBuffer; 21 | use Fuse\Libc\Sys\Stat\Stat; 22 | use Fuse\Mounter; 23 | 24 | require 'vendor/autoload.php'; 25 | 26 | /** 27 | * @psalm-type NodeType=scalar|array|null 28 | */ 29 | class ArrayFs implements FilesystemInterface 30 | { 31 | use FilesystemDefaultImplementationTrait; 32 | 33 | /** @var NodeType[] */ 34 | private array $array; 35 | 36 | /** 37 | * ArrayFs constructor. 38 | * @param NodeType[] $array 39 | */ 40 | public function __construct(array $array) 41 | { 42 | $this->array = $array; 43 | } 44 | 45 | public function getArray(): array 46 | { 47 | return $this->array; 48 | } 49 | 50 | public function getattr(string $path, Stat $stat): int 51 | { 52 | echo "attr read {$path}" . PHP_EOL; 53 | 54 | if ($path === '/') { 55 | $stat->st_mode = Stat::S_IFDIR | 0777; 56 | $stat->st_nlink = 2; 57 | $stat->st_uid = getmyuid(); 58 | $stat->st_gid = getmygid(); 59 | return 0; 60 | } 61 | 62 | $element = $this->getEntry($path); 63 | if (is_null($element)) { 64 | return -Errno::ENOENT; 65 | } 66 | if (is_array($element)) { 67 | $stat->st_mode = Stat::S_IFDIR | 0777; 68 | $stat->st_nlink = 2; 69 | $stat->st_uid = getmyuid(); 70 | $stat->st_gid = getmygid(); 71 | return 0; 72 | } 73 | $stat->st_mode = Stat::S_IFREG | 0777; 74 | $stat->st_nlink = 1; 75 | $stat->st_size = strlen((string)$element); 76 | $stat->st_uid = getmyuid(); 77 | $stat->st_gid = getmygid(); 78 | return 0; 79 | } 80 | 81 | /** 82 | * @param NodeType[] $array 83 | * @param list $offsets 84 | * @param callable(array, string):NodeType $operation 85 | * @return NodeType 86 | */ 87 | private function &getRecursive(&$array, array $offsets, ?callable $operation = null) 88 | { 89 | $null = null; 90 | 91 | $count = count($offsets); 92 | 93 | if ($count === 0) { 94 | return $null; 95 | } 96 | if ($count === 1) { 97 | if (isset($array[$offsets[0]])) { 98 | if (!is_null($operation)) { 99 | return $operation($array, $offsets[0]); 100 | } else { 101 | /** @var NodeType */ 102 | return $array[$offsets[0]]; 103 | } 104 | } else { 105 | return $null; 106 | } 107 | } 108 | 109 | $offset = array_shift($offsets); 110 | if (is_array($array[$offset])) { 111 | /** @var NodeType[] $next_array */ 112 | $next_array =& $array[$offset]; 113 | return $this->getRecursive($next_array, $offsets); 114 | } else { 115 | return $null; 116 | } 117 | } 118 | 119 | /** 120 | * @param string $path 121 | * @return scalar|array|null 122 | */ 123 | private function &getEntry(string $path) 124 | { 125 | if ($path === '/') { 126 | return $this->array; 127 | } 128 | $splitted = explode('/', $path); 129 | array_shift($splitted); 130 | return $this->getRecursive($this->array, $splitted); 131 | } 132 | 133 | /** 134 | * @param string $path 135 | * @return NodeType 136 | */ 137 | private function &getParentEntry(string $path) 138 | { 139 | $splitted = explode('/', $path); 140 | array_shift($splitted); 141 | array_pop($splitted); 142 | if (count($splitted) === 0) { 143 | return $this->array; 144 | } 145 | return $this->getRecursive($this->array, $splitted); 146 | } 147 | 148 | /** 149 | * @param string $path 150 | */ 151 | private function unsetEntry(string $path): void 152 | { 153 | $splitted = explode('/', $path); 154 | array_shift($splitted); 155 | $this->getRecursive( 156 | $this->array, 157 | $splitted, 158 | function &(array &$array, string $index) { 159 | $null = null; 160 | unset($array[$index]); 161 | return $null; 162 | } 163 | ); 164 | } 165 | 166 | public function readdir( 167 | string $path, 168 | FuseReadDirBuffer $buf, 169 | FuseFillDir $filler, 170 | int $offset, 171 | FuseFileInfo $fuse_file_info 172 | ): int { 173 | $filler($buf, '.', null, 0); 174 | $filler($buf, '..', null, 0); 175 | $entry = $this->getEntry($path); 176 | if (!is_array($entry)) { 177 | return -Errno::ENOTDIR; 178 | } 179 | foreach ($entry as $key => $_) { 180 | $filler($buf, (string)$key, null, 0); 181 | } 182 | 183 | return 0; 184 | } 185 | 186 | public function open(string $path, FuseFileInfo $fuse_file_info): int 187 | { 188 | $entry = $this->getEntry($path); 189 | if (!is_scalar($entry)) { 190 | return Errno::ENOENT; 191 | } 192 | 193 | echo "open {$path}" . PHP_EOL; 194 | return 0; 195 | } 196 | 197 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 198 | { 199 | $entry = $this->getEntry($path); 200 | 201 | echo "read {$path}" . PHP_EOL; 202 | 203 | assert(!is_array($entry)); 204 | $len = strlen((string)$entry); 205 | 206 | if ($offset + $size > $len) { 207 | $size = ($len - $offset); 208 | } 209 | 210 | $content = substr((string)$entry, $offset, $size); 211 | $buffer->write($content, $size); 212 | 213 | return $size; 214 | } 215 | 216 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 217 | { 218 | $entry = &$this->getEntry($path); 219 | assert(!is_array($entry)); 220 | $entry = substr_replace((string)$entry, $buffer, $offset, $size); 221 | 222 | return $size; 223 | } 224 | 225 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int 226 | { 227 | $entry = &$this->getParentEntry($path); 228 | if (is_array($entry)) { 229 | $segments = explode('/', $path); 230 | $filename = array_pop($segments); 231 | $entry[$filename] = ''; 232 | return 0; 233 | } else { 234 | return Errno::ENOENT; 235 | } 236 | } 237 | 238 | public function unlink(string $path): int 239 | { 240 | $this->unsetEntry($path); 241 | return 0; 242 | } 243 | 244 | public function rename(string $from, string $to): int 245 | { 246 | $fromValue = $this->getEntry($from); 247 | $parent_entry = &$this->getParentEntry($to); 248 | if (is_array($parent_entry)) { 249 | $segments = explode('/', $to); 250 | $filename = array_pop($segments); 251 | $parent_entry[$filename] = $fromValue; 252 | $this->unsetEntry($from); 253 | return 0; 254 | } else { 255 | return -Errno::ENOENT; 256 | } 257 | } 258 | } 259 | 260 | $e = new \DateTimeImmutable(); 261 | 262 | $mounter = new Mounter(); 263 | /** @psalm-suppress MixedArgumentTypeCoercion */ 264 | $array_fs = new ArrayFs([ 265 | 1, 266 | 2, 267 | 'foo' => 'bar', 268 | 'e' => json_decode(json_encode($e), true) 269 | ]); 270 | $result = $mounter->mount('/tmp/example/', $array_fs); 271 | /** @psalm-suppress ForbiddenCode */ 272 | var_dump($array_fs->getArray()); 273 | return $result; -------------------------------------------------------------------------------- /example/dummy_file.php: -------------------------------------------------------------------------------- 1 | ffi->type( 20 | $typename 21 | ); 22 | $size = FFI::sizeof( 23 | $type 24 | ); 25 | echo "attr read {$path}" . PHP_EOL; 26 | 27 | FFI::memset($stbuf, 0, $size); 28 | if ($path === '/') { 29 | $stbuf->st_mode = Stat::S_IFDIR | 0755; 30 | $stbuf->st_nlink = 2; 31 | $stbuf->st_uid = getmyuid(); 32 | $stbuf->st_gid = getmygid(); 33 | return 0; 34 | } 35 | 36 | if ($path === FILE_PATH) { 37 | $stbuf->st_mode = Stat::S_IFREG | 0777; 38 | $stbuf->st_nlink = 1; 39 | $stbuf->st_size = strlen(FILE_CONTENT); 40 | $stbuf->st_uid = getmyuid(); 41 | $stbuf->st_gid = getmygid(); 42 | return 0; 43 | } 44 | 45 | return -Errno::ENOENT; 46 | } 47 | 48 | function readdir_cb(string $path, CData $buf, CData $filler, int $offset, CData $fi): int 49 | { 50 | $filler($buf, '.', null, 0); 51 | $filler($buf, '..', null, 0); 52 | $filler($buf, FILE_NAME, null, 0); 53 | 54 | return 0; 55 | } 56 | 57 | function open_cb(string $path, CData $fi): int 58 | { 59 | if ($path !== FILE_PATH) { 60 | return -Errno::ENOENT; 61 | } 62 | 63 | echo "open {$path}" . PHP_EOL; 64 | return 0; 65 | } 66 | 67 | function read_cb(string $path, CData $buf, int $size, int $offset, CData $fi): int 68 | { 69 | echo "read {$path}" . PHP_EOL; 70 | 71 | $len = strlen(FILE_CONTENT); 72 | 73 | if ($offset + $size > $len) { 74 | $size = ($len - $offset); 75 | } 76 | 77 | $content = substr(FILE_CONTENT, $offset, $size); 78 | FFI::memcpy($buf, $content, $size); 79 | 80 | return $size; 81 | } 82 | 83 | $fuse_operations = new FuseOperations(); 84 | $fuse_operations->getattr = 'getattr_cb'; 85 | $fuse_operations->open = 'open_cb'; 86 | $fuse_operations->read = 'read_cb'; 87 | $fuse_operations->readdir = 'readdir_cb'; 88 | 89 | $mounter = new Mounter(); 90 | return $mounter->mount('/tmp/example/', $fuse_operations); 91 | -------------------------------------------------------------------------------- /example/dummy_file_oo.php: -------------------------------------------------------------------------------- 1 | mount('/tmp/example/', new DummyFs()); 12 | -------------------------------------------------------------------------------- /example/log_unimplemented.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | include __DIR__ . "/../vendor/autoload.php"; 15 | include __DIR__ . "/DummyFs.php"; 16 | 17 | use Fuse\Filesystem\Log\LogUnimplementedFilesystem; 18 | use Fuse\Mounter; 19 | use Psr\Log\LoggerInterface; 20 | use Psr\Log\LoggerTrait; 21 | 22 | $mounter = new Mounter(); 23 | 24 | return $mounter->mount( 25 | '/tmp/example/', 26 | new LogUnimplementedFilesystem( 27 | new DummyFs(), 28 | new class() implements LoggerInterface { 29 | use LoggerTrait; 30 | 31 | public function log($level, $message, array $context = []) 32 | { 33 | echo \json_encode(['message' => $message] + $context), PHP_EOL; 34 | } 35 | } 36 | ) 37 | ); 38 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | php-fuse 4 | 5 | 6 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | tests 20 | 21 | 22 | 23 | 24 | 25 | src 26 | 27 | 28 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/FFI/TypedCDataDefaultImplementationTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\FFI; 15 | 16 | use FFI; 17 | use Fuse\Fuse; 18 | use TypedCData\TypedCDataDefaultImplementationTrait as BaseTrait; 19 | 20 | trait TypedCDataDefaultImplementationTrait 21 | { 22 | use BaseTrait; 23 | 24 | protected static function getFFI(): FFI 25 | { 26 | return Fuse::getInstance()->ffi; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Filesystem/BeforeAll/BeforeAllFilesystem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\BeforeAll; 15 | 16 | use Fuse\FilesystemFlagsImplementationTrait; 17 | use Fuse\FilesystemInterface; 18 | use Fuse\Libc\Fcntl\Flock; 19 | use Fuse\Libc\Fuse\FuseBufVec; 20 | use Fuse\Libc\Fuse\FuseConnInfo; 21 | use Fuse\Libc\Fuse\FuseDirFill; 22 | use Fuse\Libc\Fuse\FuseDirHandle; 23 | use Fuse\Libc\Fuse\FuseFileInfo; 24 | use Fuse\Libc\Fuse\FuseFillDir; 25 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 26 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 27 | use Fuse\Libc\Fuse\FusePollHandle; 28 | use Fuse\Libc\Fuse\FusePrivateData; 29 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 30 | use Fuse\Libc\String\CBytesBuffer; 31 | use Fuse\Libc\String\CStringBuffer; 32 | use Fuse\Libc\Sys\Stat\Stat; 33 | use Fuse\Libc\Sys\StatVfs\StatVfs; 34 | use Fuse\Libc\Time\TimeSpec; 35 | use Fuse\Libc\Utime\UtimBuf; 36 | use Fuse\MountableFilesystemTrait; 37 | use TypedCData\TypedCDataArray; 38 | 39 | final class BeforeAllFilesystem implements FilesystemInterface 40 | { 41 | use MountableFilesystemTrait; 42 | use FilesystemFlagsImplementationTrait; 43 | 44 | /** @var callable */ 45 | private $callback; 46 | private FilesystemInterface $filesystem; 47 | 48 | /** 49 | * @param callable(string,array):void $callback 50 | */ 51 | public function __construct( 52 | callable $callback, 53 | FilesystemInterface $filesystem 54 | ) { 55 | $this->callback = $callback; 56 | $this->filesystem = $filesystem; 57 | } 58 | 59 | private function getFilesystem(): FilesystemInterface 60 | { 61 | return $this->filesystem; 62 | } 63 | 64 | public function getattr(string $path, Stat $stat): int 65 | { 66 | ($this->callback)(__FUNCTION__, func_get_args()); 67 | return $this->getFilesystem()->getattr($path, $stat); 68 | } 69 | 70 | public function readlink(string $path, CStringBuffer $buffer, int $size): int 71 | { 72 | ($this->callback)(__FUNCTION__, func_get_args()); 73 | return $this->getFilesystem()->readlink($path, $buffer, $size); 74 | } 75 | 76 | /** @deprecated */ 77 | public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int 78 | { 79 | ($this->callback)(__FUNCTION__, func_get_args()); 80 | /** @psalm-suppress DeprecatedMethod */ 81 | return $this->getFilesystem()->getdir($path, $dirhandle, $dirfill); 82 | } 83 | 84 | public function mknod(string $path, int $mode, int $dev): int 85 | { 86 | ($this->callback)(__FUNCTION__, func_get_args()); 87 | return $this->getFilesystem()->mknod($path, $mode, $dev); 88 | } 89 | 90 | public function mkdir(string $path, int $mode): int 91 | { 92 | ($this->callback)(__FUNCTION__, func_get_args()); 93 | return $this->getFilesystem()->mkdir($path, $mode); 94 | } 95 | 96 | public function unlink(string $path): int 97 | { 98 | ($this->callback)(__FUNCTION__, func_get_args()); 99 | return $this->getFilesystem()->unlink($path); 100 | } 101 | 102 | public function rmdir(string $path): int 103 | { 104 | ($this->callback)(__FUNCTION__, func_get_args()); 105 | return $this->getFilesystem()->rmdir($path); 106 | } 107 | 108 | public function symlink(string $path, string $link): int 109 | { 110 | ($this->callback)(__FUNCTION__, func_get_args()); 111 | return $this->getFilesystem()->symlink($path, $link); 112 | } 113 | 114 | public function rename(string $from, string $to): int 115 | { 116 | ($this->callback)(__FUNCTION__, func_get_args()); 117 | return $this->getFilesystem()->rename($from, $to); 118 | } 119 | 120 | public function link(string $path, string $link): int 121 | { 122 | ($this->callback)(__FUNCTION__, func_get_args()); 123 | return $this->getFilesystem()->link($path, $link); 124 | } 125 | 126 | public function chmod(string $path, int $mode): int 127 | { 128 | ($this->callback)(__FUNCTION__, func_get_args()); 129 | return $this->getFilesystem()->chmod($path, $mode); 130 | } 131 | 132 | public function chown(string $path, int $uid, int $gid): int 133 | { 134 | ($this->callback)(__FUNCTION__, func_get_args()); 135 | return $this->getFilesystem()->chown($path, $uid, $gid); 136 | } 137 | 138 | public function truncate(string $path, int $offset): int 139 | { 140 | ($this->callback)(__FUNCTION__, func_get_args()); 141 | return $this->getFilesystem()->truncate($path, $offset); 142 | } 143 | 144 | public function utime(string $path, UtimBuf $utime_buf): int 145 | { 146 | ($this->callback)(__FUNCTION__, func_get_args()); 147 | return $this->getFilesystem()->utime($path, $utime_buf); 148 | } 149 | 150 | public function open(string $path, FuseFileInfo $fuse_file_info): int 151 | { 152 | ($this->callback)(__FUNCTION__, func_get_args()); 153 | return $this->getFilesystem()->open($path, $fuse_file_info); 154 | } 155 | 156 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 157 | { 158 | ($this->callback)(__FUNCTION__, func_get_args()); 159 | return $this->getFilesystem()->read($path, $buffer, $size, $offset, $fuse_file_info); 160 | } 161 | 162 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 163 | { 164 | ($this->callback)(__FUNCTION__, func_get_args()); 165 | return $this->getFilesystem()->write($path, $buffer, $size, $offset, $fuse_file_info); 166 | } 167 | 168 | public function statfs(string $path, StatVfs $statvfs): int 169 | { 170 | ($this->callback)(__FUNCTION__, func_get_args()); 171 | return $this->getFilesystem()->statfs($path, $statvfs); 172 | } 173 | 174 | public function flush(string $path, FuseFileInfo $fuse_file_info): int 175 | { 176 | ($this->callback)(__FUNCTION__, func_get_args()); 177 | return $this->getFilesystem()->flush($path, $fuse_file_info); 178 | } 179 | 180 | public function release(string $path, FuseFileInfo $fuse_file_info): int 181 | { 182 | ($this->callback)(__FUNCTION__, func_get_args()); 183 | return $this->getFilesystem()->release($path, $fuse_file_info); 184 | } 185 | 186 | public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int 187 | { 188 | ($this->callback)(__FUNCTION__, func_get_args()); 189 | return $this->getFilesystem()->fsync($path, $flags, $fuse_file_info); 190 | } 191 | 192 | public function setxattr(string $path, string $name, string $value, int $size): int 193 | { 194 | ($this->callback)(__FUNCTION__, func_get_args()); 195 | return $this->getFilesystem()->setxattr($path, $name, $value, $size); 196 | } 197 | 198 | public function getxattr(string $path, string $name, ?string &$value, int $size): int 199 | { 200 | ($this->callback)(__FUNCTION__, func_get_args()); 201 | return $this->getFilesystem()->getxattr($path, $name, $value, $size); 202 | } 203 | 204 | public function listxattr(string $path, ?string &$value, int $size): int 205 | { 206 | ($this->callback)(__FUNCTION__, func_get_args()); 207 | return $this->getFilesystem()->listxattr($path, $value, $size); 208 | } 209 | 210 | public function removexattr(string $path, string $name): int 211 | { 212 | ($this->callback)(__FUNCTION__, func_get_args()); 213 | return $this->getFilesystem()->removexattr($path, $name); 214 | } 215 | 216 | public function opendir(string $path, FuseFileInfo $fuse_file_info): int 217 | { 218 | ($this->callback)(__FUNCTION__, func_get_args()); 219 | return $this->getFilesystem()->opendir($path, $fuse_file_info); 220 | } 221 | 222 | public function readdir( 223 | string $path, 224 | FuseReadDirBuffer $buf, 225 | FuseFillDir $filler, 226 | int $offset, 227 | FuseFileInfo $fuse_file_info 228 | ): int { 229 | ($this->callback)(__FUNCTION__, func_get_args()); 230 | return $this->getFilesystem()->readdir($path, $buf, $filler, $offset, $fuse_file_info); 231 | } 232 | 233 | public function releasedir(string $path, FuseFileInfo $fuse_file_info): int 234 | { 235 | ($this->callback)(__FUNCTION__, func_get_args()); 236 | return $this->getFilesystem()->releasedir($path, $fuse_file_info); 237 | } 238 | 239 | public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int 240 | { 241 | ($this->callback)(__FUNCTION__, func_get_args()); 242 | return $this->getFilesystem()->fsyncdir($path, $fuse_file_info); 243 | } 244 | 245 | public function init(FuseConnInfo $conn): ?FusePrivateData 246 | { 247 | ($this->callback)(__FUNCTION__, func_get_args()); 248 | return $this->getFilesystem()->init($conn); 249 | } 250 | 251 | public function destroy(?FusePrivateData $private_data): void 252 | { 253 | ($this->callback)(__FUNCTION__, func_get_args()); 254 | $this->getFilesystem()->destroy($private_data); 255 | } 256 | 257 | public function access(string $path, int $mode): int 258 | { 259 | ($this->callback)(__FUNCTION__, func_get_args()); 260 | return $this->getFilesystem()->access($path, $mode); 261 | } 262 | 263 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int 264 | { 265 | ($this->callback)(__FUNCTION__, func_get_args()); 266 | return $this->getFilesystem()->create($path, $mode, $fuse_file_info); 267 | } 268 | 269 | public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int 270 | { 271 | ($this->callback)(__FUNCTION__, func_get_args()); 272 | return $this->getFilesystem()->ftruncate($path, $offset, $fuse_file_info); 273 | } 274 | 275 | public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int 276 | { 277 | ($this->callback)(__FUNCTION__, func_get_args()); 278 | return $this->getFilesystem()->fgetattr($path, $stat, $fuse_file_info); 279 | } 280 | 281 | public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int 282 | { 283 | ($this->callback)(__FUNCTION__, func_get_args()); 284 | return $this->getFilesystem()->lock($path, $fuse_file_info, $cmd, $flock); 285 | } 286 | 287 | /** 288 | * @param TypedCDataArray $tv 289 | */ 290 | public function utimens(string $path, TypedCDataArray $tv): int 291 | { 292 | ($this->callback)(__FUNCTION__, func_get_args()); 293 | return $this->getFilesystem()->utimens($path, $tv); 294 | } 295 | 296 | public function bmap(string $path, int $blocksize, int &$idx): int 297 | { 298 | ($this->callback)(__FUNCTION__, func_get_args()); 299 | return $this->getFilesystem()->bmap($path, $blocksize, $idx); 300 | } 301 | 302 | public function ioctl( 303 | string $path, 304 | int $cmd, 305 | FuseIoctlArgPointer $arg, 306 | FuseFileInfo $fuse_file_info, 307 | int $flags, 308 | FuseIoctlDataPointer $data 309 | ): int { 310 | ($this->callback)(__FUNCTION__, func_get_args()); 311 | return $this->getFilesystem()->ioctl($path, $cmd, $arg, $fuse_file_info, $flags, $data); 312 | } 313 | 314 | public function poll( 315 | string $path, 316 | FuseFileInfo $fuse_file_info, 317 | FusePollHandle $fuse_pollhandle, 318 | int &$reventsp 319 | ): int { 320 | ($this->callback)(__FUNCTION__, func_get_args()); 321 | return $this->getFilesystem()->poll($path, $fuse_file_info, $fuse_pollhandle, $reventsp); 322 | } 323 | 324 | public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int 325 | { 326 | ($this->callback)(__FUNCTION__, func_get_args()); 327 | return $this->getFilesystem()->writeBuf($path, $buf, $offset, $fuse_file_info); 328 | } 329 | 330 | /** 331 | * @param TypedCDataArray $bufp 332 | */ 333 | public function readBuf( 334 | string $path, 335 | TypedCDataArray $bufp, 336 | int $size, 337 | int $offset, 338 | FuseFileInfo $fuse_file_info 339 | ): int { 340 | ($this->callback)(__FUNCTION__, func_get_args()); 341 | return $this->getFilesystem()->readBuf($path, $bufp, $size, $offset, $fuse_file_info); 342 | } 343 | 344 | public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int 345 | { 346 | ($this->callback)(__FUNCTION__, func_get_args()); 347 | return $this->getFilesystem()->flock($path, $fuse_file_info, $op); 348 | } 349 | 350 | public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int 351 | { 352 | ($this->callback)(__FUNCTION__, func_get_args()); 353 | return $this->getFilesystem()->fallocate($path, $mode, $offset, $fuse_file_info); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/Filesystem/Delegation/DelegationFilesystemTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\Delegation; 15 | 16 | use Fuse\FilesystemFlagsImplementationTrait; 17 | use Fuse\FilesystemInterface; 18 | use Fuse\Libc\Fcntl\Flock; 19 | use Fuse\Libc\Fuse\FuseBufVec; 20 | use Fuse\Libc\Fuse\FuseConnInfo; 21 | use Fuse\Libc\Fuse\FuseDirFill; 22 | use Fuse\Libc\Fuse\FuseDirHandle; 23 | use Fuse\Libc\Fuse\FuseFileInfo; 24 | use Fuse\Libc\Fuse\FuseFillDir; 25 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 26 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 27 | use Fuse\Libc\Fuse\FusePollHandle; 28 | use Fuse\Libc\Fuse\FusePrivateData; 29 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 30 | use Fuse\Libc\String\CBytesBuffer; 31 | use Fuse\Libc\String\CStringBuffer; 32 | use Fuse\Libc\Sys\Stat\Stat; 33 | use Fuse\Libc\Sys\StatVfs\StatVfs; 34 | use Fuse\Libc\Time\TimeSpec; 35 | use Fuse\Libc\Utime\UtimBuf; 36 | use Fuse\MountableFilesystemTrait; 37 | use TypedCData\TypedCDataArray; 38 | 39 | trait DelegationFilesystemTrait 40 | { 41 | use MountableFilesystemTrait; 42 | use FilesystemFlagsImplementationTrait; 43 | 44 | private FilesystemInterface $filesystem; 45 | 46 | private function setDelegation(FilesystemInterface $filesystem): void 47 | { 48 | $this->filesystem = $filesystem; 49 | } 50 | 51 | /** @return int|null|FusePrivateData|void */ 52 | private function delegate(string $method_name, array $args) 53 | { 54 | /** @var int|null|FusePrivateData|void */ 55 | return $this->filesystem->$method_name(...$args); 56 | } 57 | 58 | /** 59 | * int (*getattr) (const char *, struct stat *); 60 | */ 61 | public function getattr(string $path, Stat $stat): int 62 | { 63 | /** @var int */ 64 | return $this->delegate(__FUNCTION__, func_get_args()); 65 | } 66 | 67 | /** 68 | * int (*readlink) (const char *, char *, size_t); 69 | */ 70 | public function readlink(string $path, CStringBuffer $buffer, int $size): int 71 | { 72 | /** @var int */ 73 | return $this->delegate(__FUNCTION__, func_get_args()); 74 | } 75 | 76 | /** 77 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 78 | * 79 | * @deprecated 80 | */ 81 | public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int 82 | { 83 | /** @var int */ 84 | return $this->delegate(__FUNCTION__, func_get_args()); 85 | } 86 | 87 | /** 88 | * int (*mknod) (const char *, mode_t, dev_t); 89 | */ 90 | public function mknod(string $path, int $mode, int $dev): int 91 | { 92 | /** @var int */ 93 | return $this->delegate(__FUNCTION__, func_get_args()); 94 | } 95 | 96 | /** 97 | * int (*mkdir) (const char *, mode_t); 98 | */ 99 | public function mkdir(string $path, int $mode): int 100 | { 101 | /** @var int */ 102 | return $this->delegate(__FUNCTION__, func_get_args()); 103 | } 104 | 105 | /** 106 | * int (*unlink) (const char *); 107 | */ 108 | public function unlink(string $path): int 109 | { 110 | /** @var int */ 111 | return $this->delegate(__FUNCTION__, func_get_args()); 112 | } 113 | 114 | /** 115 | * int (*rmdir) (const char *); 116 | */ 117 | public function rmdir(string $path): int 118 | { 119 | /** @var int */ 120 | return $this->delegate(__FUNCTION__, func_get_args()); 121 | } 122 | 123 | /** 124 | * int (*symlink) (const char *, const char *); 125 | */ 126 | public function symlink(string $path, string $link): int 127 | { 128 | /** @var int */ 129 | return $this->delegate(__FUNCTION__, func_get_args()); 130 | } 131 | 132 | /** 133 | * int (*rename) (const char *, const char *); 134 | */ 135 | public function rename(string $from, string $to): int 136 | { 137 | /** @var int */ 138 | return $this->delegate(__FUNCTION__, func_get_args()); 139 | } 140 | 141 | /** 142 | * int (*link) (const char *, const char *); 143 | */ 144 | public function link(string $path, string $link): int 145 | { 146 | /** @var int */ 147 | return $this->delegate(__FUNCTION__, func_get_args()); 148 | } 149 | 150 | /** 151 | * int (*chmod) (const char *, mode_t); 152 | */ 153 | public function chmod(string $path, int $mode): int 154 | { 155 | /** @var int */ 156 | return $this->delegate(__FUNCTION__, func_get_args()); 157 | } 158 | 159 | /** 160 | * int (*chown) (const char *, uid_t, gid_t); 161 | */ 162 | public function chown(string $path, int $uid, int $gid): int 163 | { 164 | /** @var int */ 165 | return $this->delegate(__FUNCTION__, func_get_args()); 166 | } 167 | 168 | /** 169 | * int (*truncate) (const char *, off_t); 170 | */ 171 | public function truncate(string $path, int $offset): int 172 | { 173 | /** @var int */ 174 | return $this->delegate(__FUNCTION__, func_get_args()); 175 | } 176 | 177 | /** 178 | * int (*utime) (const char *, struct utimbuf *); 179 | */ 180 | public function utime(string $path, UtimBuf $utime_buf): int 181 | { 182 | /** @var int */ 183 | return $this->delegate(__FUNCTION__, func_get_args()); 184 | } 185 | 186 | /** 187 | * int (*open) (const char *, struct fuse_file_info *); 188 | */ 189 | public function open(string $path, FuseFileInfo $fuse_file_info): int 190 | { 191 | /** @var int */ 192 | return $this->delegate(__FUNCTION__, func_get_args()); 193 | } 194 | 195 | /** 196 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 197 | */ 198 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 199 | { 200 | /** @var int */ 201 | return $this->delegate(__FUNCTION__, func_get_args()); 202 | } 203 | 204 | /** 205 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 206 | */ 207 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 208 | { 209 | /** @var int */ 210 | return $this->delegate(__FUNCTION__, func_get_args()); 211 | } 212 | 213 | /** 214 | * int (*statfs) (const char *, struct statvfs *); 215 | */ 216 | public function statfs(string $path, StatVfs $statvfs): int 217 | { 218 | /** @var int */ 219 | return $this->delegate(__FUNCTION__, func_get_args()); 220 | } 221 | 222 | /** 223 | * int (*flush) (const char *, struct fuse_file_info *); 224 | */ 225 | public function flush(string $path, FuseFileInfo $fuse_file_info): int 226 | { 227 | /** @var int */ 228 | return $this->delegate(__FUNCTION__, func_get_args()); 229 | } 230 | 231 | /** 232 | * int (*release) (const char *, struct fuse_file_info *); 233 | */ 234 | public function release(string $path, FuseFileInfo $fuse_file_info): int 235 | { 236 | /** @var int */ 237 | return $this->delegate(__FUNCTION__, func_get_args()); 238 | } 239 | 240 | /** 241 | * int (*fsync) (const char *, int, struct fuse_file_info *); 242 | */ 243 | public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int 244 | { 245 | /** @var int */ 246 | return $this->delegate(__FUNCTION__, func_get_args()); 247 | } 248 | 249 | /** 250 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 251 | */ 252 | public function setxattr(string $path, string $name, string $value, int $size): int 253 | { 254 | /** @var int */ 255 | return $this->delegate(__FUNCTION__, func_get_args()); 256 | } 257 | 258 | /** 259 | * int (*getxattr) (const char *, const char *, char *, size_t); 260 | */ 261 | public function getxattr(string $path, string $name, ?string &$value, int $size): int 262 | { 263 | /** @var int */ 264 | return $this->delegate(__FUNCTION__, func_get_args()); 265 | } 266 | 267 | /** 268 | * int (*listxattr) (const char *, char *, size_t);* 269 | */ 270 | public function listxattr(string $path, ?string &$value, int $size): int 271 | { 272 | /** @var int */ 273 | return $this->delegate(__FUNCTION__, func_get_args()); 274 | } 275 | 276 | /** 277 | * int (*removexattr) (const char *, const char *); 278 | */ 279 | public function removexattr(string $path, string $name): int 280 | { 281 | /** @var int */ 282 | return $this->delegate(__FUNCTION__, func_get_args()); 283 | } 284 | 285 | /** 286 | * int (*opendir) (const char *, struct fuse_file_info *); 287 | */ 288 | public function opendir(string $path, FuseFileInfo $fuse_file_info): int 289 | { 290 | /** @var int */ 291 | return $this->delegate(__FUNCTION__, func_get_args()); 292 | } 293 | 294 | /** 295 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 296 | */ 297 | public function readdir( 298 | string $path, 299 | FuseReadDirBuffer $buf, 300 | FuseFillDir $filler, 301 | int $offset, 302 | FuseFileInfo $fuse_file_info 303 | ): int { 304 | /** @var int */ 305 | return $this->delegate(__FUNCTION__, func_get_args()); 306 | } 307 | 308 | /** 309 | * int (*releasedir) (const char *, struct fuse_file_info *); 310 | */ 311 | public function releasedir(string $path, FuseFileInfo $fuse_file_info): int 312 | { 313 | /** @var int */ 314 | return $this->delegate(__FUNCTION__, func_get_args()); 315 | } 316 | 317 | /** 318 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 319 | */ 320 | public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int 321 | { 322 | /** @var int */ 323 | return $this->delegate(__FUNCTION__, func_get_args()); 324 | } 325 | 326 | /** 327 | * void *(*init) (struct fuse_conn_info *conn); 328 | */ 329 | public function init(FuseConnInfo $conn): ?FusePrivateData 330 | { 331 | /** @var ?FusePrivateData */ 332 | return $this->delegate(__FUNCTION__, func_get_args()); 333 | } 334 | 335 | /** 336 | * void (*destroy) (void *); 337 | */ 338 | public function destroy(?FusePrivateData $private_data): void 339 | { 340 | $this->delegate(__FUNCTION__, func_get_args()); 341 | } 342 | 343 | /** 344 | * int (*access) (const char *, int); 345 | */ 346 | public function access(string $path, int $mode): int 347 | { 348 | /** @var int */ 349 | return $this->delegate(__FUNCTION__, func_get_args()); 350 | } 351 | 352 | /** 353 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 354 | */ 355 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int 356 | { 357 | /** @var int */ 358 | return $this->delegate(__FUNCTION__, func_get_args()); 359 | } 360 | 361 | /** 362 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 363 | */ 364 | public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int 365 | { 366 | /** @var int */ 367 | return $this->delegate(__FUNCTION__, func_get_args()); 368 | } 369 | 370 | /** 371 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 372 | */ 373 | public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int 374 | { 375 | /** @var int */ 376 | return $this->delegate(__FUNCTION__, func_get_args()); 377 | } 378 | 379 | /** 380 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 381 | */ 382 | public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int 383 | { 384 | /** @var int */ 385 | return $this->delegate(__FUNCTION__, func_get_args()); 386 | } 387 | 388 | /** 389 | * int (*utimens) (const char *, const struct timespec tv[2]); 390 | * 391 | * @param TypedCDataArray $tv 392 | */ 393 | public function utimens(string $path, TypedCDataArray $tv): int 394 | { 395 | /** @var int */ 396 | return $this->delegate(__FUNCTION__, func_get_args()); 397 | } 398 | 399 | /** 400 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 401 | */ 402 | public function bmap(string $path, int $blocksize, int &$idx): int 403 | { 404 | /** @var int */ 405 | return $this->delegate(__FUNCTION__, func_get_args()); 406 | } 407 | 408 | /** 409 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 410 | */ 411 | public function ioctl( 412 | string $path, 413 | int $cmd, 414 | FuseIoctlArgPointer $arg, 415 | FuseFileInfo $fuse_file_info, 416 | int $flags, 417 | FuseIoctlDataPointer $data 418 | ): int { 419 | /** @var int */ 420 | return $this->delegate(__FUNCTION__, func_get_args()); 421 | } 422 | 423 | /** 424 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 425 | */ 426 | public function poll( 427 | string $path, 428 | FuseFileInfo $fuse_file_info, 429 | FusePollHandle $fuse_pollhandle, 430 | int &$reventsp 431 | ): int { 432 | /** @var int */ 433 | return $this->delegate(__FUNCTION__, func_get_args()); 434 | } 435 | 436 | /** 437 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 438 | */ 439 | public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int 440 | { 441 | /** @var int */ 442 | return $this->delegate(__FUNCTION__, func_get_args()); 443 | } 444 | 445 | /** 446 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 447 | * 448 | * @param TypedCDataArray $bufp 449 | */ 450 | public function readBuf( 451 | string $path, 452 | TypedCDataArray $bufp, 453 | int $size, 454 | int $offset, 455 | FuseFileInfo $fuse_file_info 456 | ): int { 457 | /** @var int */ 458 | return $this->delegate(__FUNCTION__, func_get_args()); 459 | } 460 | 461 | /** 462 | * int (*flock) (const char *, struct fuse_file_info *, int op); 463 | */ 464 | public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int 465 | { 466 | /** @var int */ 467 | return $this->delegate(__FUNCTION__, func_get_args()); 468 | } 469 | 470 | /** 471 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 472 | */ 473 | public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int 474 | { 475 | /** @var int */ 476 | return $this->delegate(__FUNCTION__, func_get_args()); 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /src/Filesystem/Log/LogUnimplementedFilesystem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\Log; 15 | 16 | use Fuse\Filesystem\BeforeAll\BeforeAllFilesystem; 17 | use Fuse\Filesystem\Delegation\DelegationFilesystemTrait; 18 | use Fuse\Filesystem\Null\NullFilesystem; 19 | use Fuse\Filesystem\Overlay\OverlayFilesystem; 20 | use Fuse\FilesystemInterface; 21 | use Psr\Log\LoggerInterface; 22 | use Psr\Log\LogLevel; 23 | 24 | final class LogUnimplementedFilesystem implements FilesystemInterface 25 | { 26 | use DelegationFilesystemTrait; 27 | 28 | private const DEFAULT_MESSAGE = 'An unimplemented FUSE API is called'; 29 | 30 | private const LOG_LEVELS = [ 31 | LogLevel::EMERGENCY, 32 | LogLevel::ALERT, 33 | LogLevel::CRITICAL, 34 | LogLevel::ERROR, 35 | LogLevel::WARNING, 36 | LogLevel::NOTICE, 37 | LogLevel::INFO, 38 | LogLevel::DEBUG, 39 | ]; 40 | 41 | private LoggerInterface $logger; 42 | private string $log_level; 43 | private string $message; 44 | 45 | /** @param value-of $log_level */ 46 | public function __construct( 47 | FilesystemInterface $filesystem, 48 | LoggerInterface $logger, 49 | string $log_level = LogLevel::DEBUG, 50 | string $message = self::DEFAULT_MESSAGE 51 | ) { 52 | $this->initialize($filesystem); 53 | $this->logger = $logger; 54 | $this->log_level = $log_level; 55 | $this->message = $message; 56 | } 57 | 58 | private function initialize(FilesystemInterface $filesystem): void 59 | { 60 | $this->setDelegation( 61 | new OverlayFilesystem( 62 | $filesystem, 63 | new BeforeAllFilesystem( 64 | fn(string $method, array $args) => $this->log($method, $args), 65 | new NullFilesystem() 66 | ) 67 | ) 68 | ); 69 | } 70 | 71 | private function log(string $method, array $args): void 72 | { 73 | $this->logger->log( 74 | $this->log_level, 75 | $this->message, 76 | [ 77 | 'method' => $method, 78 | 'args' => $args 79 | ] 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Filesystem/Null/NullFilesystem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\Null; 15 | 16 | use Fuse\FilesystemDefaultImplementationTrait; 17 | use Fuse\FilesystemInterface; 18 | 19 | final class NullFilesystem implements FilesystemInterface 20 | { 21 | use FilesystemDefaultImplementationTrait; 22 | } 23 | -------------------------------------------------------------------------------- /src/Filesystem/Overlay/OverlayFilesystem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\Overlay; 15 | 16 | use Fuse\Filesystem\ReflectionFilesystem; 17 | use Fuse\FilesystemFlagsImplementationTrait; 18 | use Fuse\FilesystemInterface; 19 | use Fuse\Libc\Fcntl\Flock; 20 | use Fuse\Libc\Fuse\FuseBufVec; 21 | use Fuse\Libc\Fuse\FuseConnInfo; 22 | use Fuse\Libc\Fuse\FuseDirFill; 23 | use Fuse\Libc\Fuse\FuseDirHandle; 24 | use Fuse\Libc\Fuse\FuseFileInfo; 25 | use Fuse\Libc\Fuse\FuseFillDir; 26 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 27 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 28 | use Fuse\Libc\Fuse\FusePollHandle; 29 | use Fuse\Libc\Fuse\FusePrivateData; 30 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 31 | use Fuse\Libc\String\CBytesBuffer; 32 | use Fuse\Libc\String\CStringBuffer; 33 | use Fuse\Libc\Sys\Stat\Stat; 34 | use Fuse\Libc\Sys\StatVfs\StatVfs; 35 | use Fuse\Libc\Time\TimeSpec; 36 | use Fuse\Libc\Utime\UtimBuf; 37 | use Fuse\MountableFilesystemTrait; 38 | use TypedCData\TypedCDataArray; 39 | 40 | final class OverlayFilesystem implements FilesystemInterface 41 | { 42 | use MountableFilesystemTrait; 43 | use FilesystemFlagsImplementationTrait; 44 | 45 | private FilesystemInterface $main; 46 | private FilesystemInterface $fallback; 47 | 48 | public function __construct( 49 | FilesystemInterface $main, 50 | FilesystemInterface $fallback 51 | ) { 52 | $this->main = $main; 53 | $this->fallback = $fallback; 54 | } 55 | 56 | /** @return int|FusePrivateData|null|void */ 57 | private function fallbackIfDefault(string $method_name, array $args) 58 | { 59 | if (ReflectionFilesystem::instance($this->main)->isDefault($method_name)) { 60 | /** @var int|FusePrivateData|null|void */ 61 | return $this->fallback->$method_name(...$args); 62 | } 63 | /** @var int|FusePrivateData|null|void */ 64 | return $this->main->$method_name(...$args); 65 | } 66 | 67 | /** 68 | * int (*getattr) (const char *, struct stat *); 69 | */ 70 | public function getattr(string $path, Stat $stat): int 71 | { 72 | /** @var int */ 73 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 74 | } 75 | 76 | /** 77 | * int (*readlink) (const char *, char *, size_t); 78 | */ 79 | public function readlink(string $path, CStringBuffer $buffer, int $size): int 80 | { 81 | /** @var int */ 82 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 83 | } 84 | 85 | /** 86 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 87 | * 88 | * @deprecated 89 | */ 90 | public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int 91 | { 92 | /** @var int */ 93 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 94 | } 95 | 96 | /** 97 | * int (*mknod) (const char *, mode_t, dev_t); 98 | */ 99 | public function mknod(string $path, int $mode, int $dev): int 100 | { 101 | /** @var int */ 102 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 103 | } 104 | 105 | /** 106 | * int (*mkdir) (const char *, mode_t); 107 | */ 108 | public function mkdir(string $path, int $mode): int 109 | { 110 | /** @var int */ 111 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 112 | } 113 | 114 | /** 115 | * int (*unlink) (const char *); 116 | */ 117 | public function unlink(string $path): int 118 | { 119 | /** @var int */ 120 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 121 | } 122 | 123 | /** 124 | * int (*rmdir) (const char *); 125 | */ 126 | public function rmdir(string $path): int 127 | { 128 | /** @var int */ 129 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 130 | } 131 | 132 | /** 133 | * int (*symlink) (const char *, const char *); 134 | */ 135 | public function symlink(string $path, string $link): int 136 | { 137 | /** @var int */ 138 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 139 | } 140 | 141 | /** 142 | * int (*rename) (const char *, const char *); 143 | */ 144 | public function rename(string $from, string $to): int 145 | { 146 | /** @var int */ 147 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 148 | } 149 | 150 | /** 151 | * int (*link) (const char *, const char *); 152 | */ 153 | public function link(string $path, string $link): int 154 | { 155 | /** @var int */ 156 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 157 | } 158 | 159 | /** 160 | * int (*chmod) (const char *, mode_t); 161 | */ 162 | public function chmod(string $path, int $mode): int 163 | { 164 | /** @var int */ 165 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 166 | } 167 | 168 | /** 169 | * int (*chown) (const char *, uid_t, gid_t); 170 | */ 171 | public function chown(string $path, int $uid, int $gid): int 172 | { 173 | /** @var int */ 174 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 175 | } 176 | 177 | /** 178 | * int (*truncate) (const char *, off_t); 179 | */ 180 | public function truncate(string $path, int $offset): int 181 | { 182 | /** @var int */ 183 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 184 | } 185 | 186 | /** 187 | * int (*utime) (const char *, struct utimbuf *); 188 | */ 189 | public function utime(string $path, UtimBuf $utime_buf): int 190 | { 191 | /** @var int */ 192 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 193 | } 194 | 195 | /** 196 | * int (*open) (const char *, struct fuse_file_info *); 197 | */ 198 | public function open(string $path, FuseFileInfo $fuse_file_info): int 199 | { 200 | /** @var int */ 201 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 202 | } 203 | 204 | /** 205 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 206 | */ 207 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 208 | { 209 | /** @var int */ 210 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 211 | } 212 | 213 | /** 214 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 215 | */ 216 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 217 | { 218 | /** @var int */ 219 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 220 | } 221 | 222 | /** 223 | * int (*statfs) (const char *, struct statvfs *); 224 | */ 225 | public function statfs(string $path, StatVfs $statvfs): int 226 | { 227 | /** @var int */ 228 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 229 | } 230 | 231 | /** 232 | * int (*flush) (const char *, struct fuse_file_info *); 233 | */ 234 | public function flush(string $path, FuseFileInfo $fuse_file_info): int 235 | { 236 | /** @var int */ 237 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 238 | } 239 | 240 | /** 241 | * int (*release) (const char *, struct fuse_file_info *); 242 | */ 243 | public function release(string $path, FuseFileInfo $fuse_file_info): int 244 | { 245 | /** @var int */ 246 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 247 | } 248 | 249 | /** 250 | * int (*fsync) (const char *, int, struct fuse_file_info *); 251 | */ 252 | public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int 253 | { 254 | /** @var int */ 255 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 256 | } 257 | 258 | /** 259 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 260 | */ 261 | public function setxattr(string $path, string $name, string $value, int $size): int 262 | { 263 | /** @var int */ 264 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 265 | } 266 | 267 | /** 268 | * int (*getxattr) (const char *, const char *, char *, size_t); 269 | */ 270 | public function getxattr(string $path, string $name, ?string &$value, int $size): int 271 | { 272 | /** @var int */ 273 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 274 | } 275 | 276 | /** 277 | * int (*listxattr) (const char *, char *, size_t);* 278 | */ 279 | public function listxattr(string $path, ?string &$value, int $size): int 280 | { 281 | /** @var int */ 282 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 283 | } 284 | 285 | /** 286 | * int (*removexattr) (const char *, const char *); 287 | */ 288 | public function removexattr(string $path, string $name): int 289 | { 290 | /** @var int */ 291 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 292 | } 293 | 294 | /** 295 | * int (*opendir) (const char *, struct fuse_file_info *); 296 | */ 297 | public function opendir(string $path, FuseFileInfo $fuse_file_info): int 298 | { 299 | /** @var int */ 300 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 301 | } 302 | 303 | /** 304 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 305 | */ 306 | public function readdir( 307 | string $path, 308 | FuseReadDirBuffer $buf, 309 | FuseFillDir $filler, 310 | int $offset, 311 | FuseFileInfo $fuse_file_info 312 | ): int { 313 | /** @var int */ 314 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 315 | } 316 | 317 | /** 318 | * int (*releasedir) (const char *, struct fuse_file_info *); 319 | */ 320 | public function releasedir(string $path, FuseFileInfo $fuse_file_info): int 321 | { 322 | /** @var int */ 323 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 324 | } 325 | 326 | /** 327 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 328 | */ 329 | public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int 330 | { 331 | /** @var int */ 332 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 333 | } 334 | 335 | /** 336 | * void *(*init) (struct fuse_conn_info *conn); 337 | */ 338 | public function init(FuseConnInfo $conn): ?FusePrivateData 339 | { 340 | /** @var null|FusePrivateData */ 341 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 342 | } 343 | 344 | /** 345 | * void (*destroy) (void *); 346 | */ 347 | public function destroy(?FusePrivateData $private_data): void 348 | { 349 | $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 350 | } 351 | 352 | /** 353 | * int (*access) (const char *, int); 354 | */ 355 | public function access(string $path, int $mode): int 356 | { 357 | /** @var int */ 358 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 359 | } 360 | 361 | /** 362 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 363 | */ 364 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int 365 | { 366 | /** @var int */ 367 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 368 | } 369 | 370 | /** 371 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 372 | */ 373 | public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int 374 | { 375 | /** @var int */ 376 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 377 | } 378 | 379 | /** 380 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 381 | */ 382 | public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int 383 | { 384 | /** @var int */ 385 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 386 | } 387 | 388 | /** 389 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 390 | */ 391 | public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int 392 | { 393 | /** @var int */ 394 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 395 | } 396 | 397 | /** 398 | * int (*utimens) (const char *, const struct timespec tv[2]); 399 | * 400 | * @param TypedCDataArray $tv 401 | */ 402 | public function utimens(string $path, TypedCDataArray $tv): int 403 | { 404 | /** @var int */ 405 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 406 | } 407 | 408 | /** 409 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 410 | */ 411 | public function bmap(string $path, int $blocksize, int &$idx): int 412 | { 413 | /** @var int */ 414 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 415 | } 416 | 417 | /** 418 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 419 | */ 420 | public function ioctl( 421 | string $path, 422 | int $cmd, 423 | FuseIoctlArgPointer $arg, 424 | FuseFileInfo $fuse_file_info, 425 | int $flags, 426 | FuseIoctlDataPointer $data 427 | ): int { 428 | /** @var int */ 429 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 430 | } 431 | 432 | /** 433 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 434 | */ 435 | public function poll( 436 | string $path, 437 | FuseFileInfo $fuse_file_info, 438 | FusePollHandle $fuse_pollhandle, 439 | int &$reventsp 440 | ): int { 441 | /** @var int */ 442 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 443 | } 444 | 445 | /** 446 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 447 | */ 448 | public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int 449 | { 450 | /** @var int */ 451 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 452 | } 453 | 454 | /** 455 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 456 | * 457 | * @param TypedCDataArray $bufp 458 | */ 459 | public function readBuf( 460 | string $path, 461 | TypedCDataArray $bufp, 462 | int $size, 463 | int $offset, 464 | FuseFileInfo $fuse_file_info 465 | ): int { 466 | /** @var int */ 467 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 468 | } 469 | 470 | /** 471 | * int (*flock) (const char *, struct fuse_file_info *, int op); 472 | */ 473 | public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int 474 | { 475 | /** @var int */ 476 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 477 | } 478 | 479 | /** 480 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 481 | */ 482 | public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int 483 | { 484 | /** @var int */ 485 | return $this->fallbackIfDefault(__FUNCTION__, func_get_args()); 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /src/Filesystem/ReflectionFilesystem.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem; 15 | 16 | use Fuse\FilesystemDefaultImplementationTrait; 17 | use Fuse\FilesystemInterface; 18 | use ReflectionClass; 19 | 20 | final class ReflectionFilesystem 21 | { 22 | private FilesystemInterface $filesystem; 23 | 24 | public function __construct(FilesystemInterface $filesystem) 25 | { 26 | $this->filesystem = $filesystem; 27 | } 28 | 29 | public static function instance(FilesystemInterface $filesystem): self 30 | { 31 | return new self($filesystem); 32 | } 33 | 34 | public function isDefault(string $method_name): bool 35 | { 36 | $class = new ReflectionClass($this->filesystem); 37 | $method = $class->getMethod($method_name); 38 | $trait = new ReflectionClass(FilesystemDefaultImplementationTrait::class); 39 | return $method->getFileName() === $trait->getFileName(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/FilesystemDefaultImplementationTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use Fuse\Libc\Errno\Errno; 17 | use Fuse\Libc\Fcntl\Flock; 18 | use Fuse\Libc\Fuse\FuseBufVec; 19 | use Fuse\Libc\Fuse\FuseConnInfo; 20 | use Fuse\Libc\Fuse\FuseDirFill; 21 | use Fuse\Libc\Fuse\FuseDirHandle; 22 | use Fuse\Libc\Fuse\FuseFileInfo; 23 | use Fuse\Libc\Fuse\FuseFillDir; 24 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 25 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 26 | use Fuse\Libc\Fuse\FusePollHandle; 27 | use Fuse\Libc\Fuse\FusePrivateData; 28 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 29 | use Fuse\Libc\String\CBytesBuffer; 30 | use Fuse\Libc\String\CStringBuffer; 31 | use Fuse\Libc\Sys\Stat\Stat; 32 | use Fuse\Libc\Sys\StatVfs\StatVfs; 33 | use Fuse\Libc\Time\TimeSpec; 34 | use Fuse\Libc\Utime\UtimBuf; 35 | use TypedCData\TypedCDataArray; 36 | 37 | trait FilesystemDefaultImplementationTrait 38 | { 39 | use MountableFilesystemTrait; 40 | use FilesystemFlagsImplementationTrait; 41 | 42 | /** 43 | * int (*getattr) (const char *, struct stat *); 44 | */ 45 | public function getattr(string $path, Stat $stat): int 46 | { 47 | return -Errno::ENOSYS; 48 | } 49 | 50 | /** 51 | * int (*readlink) (const char *, char *, size_t); 52 | */ 53 | public function readlink(string $path, CStringBuffer $buffer, int $size): int 54 | { 55 | return -Errno::ENOSYS; 56 | } 57 | 58 | /** 59 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 60 | * 61 | * @deprecated 62 | */ 63 | public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int 64 | { 65 | return -Errno::ENOSYS; 66 | } 67 | 68 | /** 69 | * int (*mknod) (const char *, mode_t, dev_t); 70 | */ 71 | public function mknod(string $path, int $mode, int $dev): int 72 | { 73 | return -Errno::ENOSYS; 74 | } 75 | 76 | /** 77 | * int (*mkdir) (const char *, mode_t); 78 | */ 79 | public function mkdir(string $path, int $mode): int 80 | { 81 | return -Errno::ENOSYS; 82 | } 83 | 84 | /** 85 | * int (*unlink) (const char *); 86 | */ 87 | public function unlink(string $path): int 88 | { 89 | return -Errno::ENOSYS; 90 | } 91 | 92 | /** 93 | * int (*rmdir) (const char *); 94 | */ 95 | public function rmdir(string $path): int 96 | { 97 | return -Errno::ENOSYS; 98 | } 99 | 100 | /** 101 | * int (*symlink) (const char *, const char *); 102 | */ 103 | public function symlink(string $path, string $link): int 104 | { 105 | return -Errno::ENOSYS; 106 | } 107 | 108 | /** 109 | * int (*rename) (const char *, const char *); 110 | */ 111 | public function rename(string $from, string $to): int 112 | { 113 | return -Errno::ENOSYS; 114 | } 115 | 116 | /** 117 | * int (*link) (const char *, const char *); 118 | */ 119 | public function link(string $path, string $link): int 120 | { 121 | return -Errno::ENOSYS; 122 | } 123 | 124 | /** 125 | * int (*chmod) (const char *, mode_t); 126 | */ 127 | public function chmod(string $path, int $mode): int 128 | { 129 | return -Errno::ENOSYS; 130 | } 131 | 132 | /** 133 | * int (*chown) (const char *, uid_t, gid_t); 134 | */ 135 | public function chown(string $path, int $uid, int $gid): int 136 | { 137 | return -Errno::ENOSYS; 138 | } 139 | 140 | /** 141 | * int (*truncate) (const char *, off_t); 142 | */ 143 | public function truncate(string $path, int $offset): int 144 | { 145 | return -Errno::ENOSYS; 146 | } 147 | 148 | /** 149 | * int (*utime) (const char *, struct utimbuf *); 150 | */ 151 | public function utime(string $path, UtimBuf $utime_buf): int 152 | { 153 | return -Errno::ENOSYS; 154 | } 155 | 156 | /** 157 | * int (*open) (const char *, struct fuse_file_info *); 158 | */ 159 | public function open(string $path, FuseFileInfo $fuse_file_info): int 160 | { 161 | return 0; 162 | } 163 | 164 | /** 165 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 166 | */ 167 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 168 | { 169 | return -Errno::ENOSYS; 170 | } 171 | 172 | /** 173 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 174 | */ 175 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 176 | { 177 | return -Errno::ENOSYS; 178 | } 179 | 180 | /** 181 | * int (*statfs) (const char *, struct statvfs *); 182 | */ 183 | public function statfs(string $path, StatVfs $statvfs): int 184 | { 185 | return -Errno::ENOSYS; 186 | } 187 | 188 | /** 189 | * int (*flush) (const char *, struct fuse_file_info *); 190 | */ 191 | public function flush(string $path, FuseFileInfo $fuse_file_info): int 192 | { 193 | return -Errno::ENOSYS; 194 | } 195 | 196 | /** 197 | * int (*release) (const char *, struct fuse_file_info *); 198 | */ 199 | public function release(string $path, FuseFileInfo $fuse_file_info): int 200 | { 201 | return -Errno::ENOSYS; 202 | } 203 | 204 | /** 205 | * int (*fsync) (const char *, int, struct fuse_file_info *); 206 | */ 207 | public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int 208 | { 209 | return -Errno::ENOSYS; 210 | } 211 | 212 | /** 213 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 214 | */ 215 | public function setxattr(string $path, string $name, string $value, int $size): int 216 | { 217 | return -Errno::ENOSYS; 218 | } 219 | 220 | /** 221 | * int (*getxattr) (const char *, const char *, char *, size_t); 222 | */ 223 | public function getxattr(string $path, string $name, ?string &$value, int $size): int 224 | { 225 | return -Errno::ENOSYS; 226 | } 227 | 228 | /** 229 | * int (*listxattr) (const char *, char *, size_t);* 230 | */ 231 | public function listxattr(string $path, ?string &$value, int $size): int 232 | { 233 | return -Errno::ENOSYS; 234 | } 235 | 236 | /** 237 | * int (*removexattr) (const char *, const char *); 238 | */ 239 | public function removexattr(string $path, string $name): int 240 | { 241 | return -Errno::ENOSYS; 242 | } 243 | 244 | /** 245 | * int (*opendir) (const char *, struct fuse_file_info *); 246 | */ 247 | public function opendir(string $path, FuseFileInfo $fuse_file_info): int 248 | { 249 | return 0; 250 | } 251 | 252 | /** 253 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 254 | */ 255 | public function readdir( 256 | string $path, 257 | FuseReadDirBuffer $buf, 258 | FuseFillDir $filler, 259 | int $offset, 260 | FuseFileInfo $fuse_file_info 261 | ): int { 262 | return -Errno::ENOSYS; 263 | } 264 | 265 | /** 266 | * int (*releasedir) (const char *, struct fuse_file_info *); 267 | */ 268 | public function releasedir(string $path, FuseFileInfo $fuse_file_info): int 269 | { 270 | return -Errno::ENOSYS; 271 | } 272 | 273 | /** 274 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 275 | */ 276 | public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int 277 | { 278 | return -Errno::ENOSYS; 279 | } 280 | 281 | /** 282 | * void *(*init) (struct fuse_conn_info *conn); 283 | */ 284 | public function init(FuseConnInfo $conn): ?FusePrivateData 285 | { 286 | return null; 287 | } 288 | 289 | /** 290 | * void (*destroy) (void *); 291 | */ 292 | public function destroy(?FusePrivateData $private_data): void 293 | { 294 | } 295 | 296 | /** 297 | * int (*access) (const char *, int); 298 | */ 299 | public function access(string $path, int $mode): int 300 | { 301 | return -Errno::ENOSYS; 302 | } 303 | 304 | /** 305 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 306 | */ 307 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int 308 | { 309 | return -Errno::ENOSYS; 310 | } 311 | 312 | /** 313 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 314 | */ 315 | public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int 316 | { 317 | return -Errno::ENOSYS; 318 | } 319 | 320 | /** 321 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 322 | */ 323 | public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int 324 | { 325 | return -Errno::ENOSYS; 326 | } 327 | 328 | /** 329 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 330 | */ 331 | public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int 332 | { 333 | return -Errno::ENOSYS; 334 | } 335 | 336 | /** 337 | * int (*utimens) (const char *, const struct timespec tv[2]); 338 | * 339 | * @param TypedCDataArray $tv 340 | */ 341 | public function utimens(string $path, TypedCDataArray $tv): int 342 | { 343 | return -Errno::ENOSYS; 344 | } 345 | 346 | /** 347 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 348 | */ 349 | public function bmap(string $path, int $blocksize, int &$idx): int 350 | { 351 | return -Errno::ENOSYS; 352 | } 353 | 354 | /** 355 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 356 | */ 357 | public function ioctl( 358 | string $path, 359 | int $cmd, 360 | FuseIoctlArgPointer $arg, 361 | FuseFileInfo $fuse_file_info, 362 | int $flags, 363 | FuseIoctlDataPointer $data 364 | ): int { 365 | return -Errno::ENOSYS; 366 | } 367 | 368 | /** 369 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 370 | */ 371 | public function poll( 372 | string $path, 373 | FuseFileInfo $fuse_file_info, 374 | FusePollHandle $fuse_pollhandle, 375 | int &$reventsp 376 | ): int { 377 | return -Errno::ENOSYS; 378 | } 379 | 380 | /** 381 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 382 | */ 383 | public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int 384 | { 385 | return -Errno::ENOSYS; 386 | } 387 | 388 | /** 389 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 390 | * 391 | * @param TypedCDataArray $bufp 392 | */ 393 | public function readBuf( 394 | string $path, 395 | TypedCDataArray $bufp, 396 | int $size, 397 | int $offset, 398 | FuseFileInfo $fuse_file_info 399 | ): int { 400 | return -Errno::ENOSYS; 401 | } 402 | 403 | /** 404 | * int (*flock) (const char *, struct fuse_file_info *, int op); 405 | */ 406 | public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int 407 | { 408 | return -Errno::ENOSYS; 409 | } 410 | 411 | /** 412 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 413 | */ 414 | public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int 415 | { 416 | return -Errno::ENOSYS; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /src/FilesystemFlagsImplementationTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | trait FilesystemFlagsImplementationTrait 17 | { 18 | /** 19 | * unsigned int flag_nullpath_ok:1; 20 | * unsigned int flag_nopath:1; 21 | * unsigned int flag_utime_omit_ok:1; 22 | * unsigned int flag_reserved:29; 23 | */ 24 | private bool $flag_nullpath_ok = false; 25 | private bool $flag_nopath = false; 26 | private bool $flag_utime_omit_ok = false; 27 | 28 | public function setFlagNullpathOk(bool $flag): void 29 | { 30 | $this->flag_nullpath_ok = $flag; 31 | } 32 | 33 | public function getFlagNullpathOk(): bool 34 | { 35 | return $this->flag_nullpath_ok; 36 | } 37 | 38 | public function setFlagNopath(bool $flag): void 39 | { 40 | $this->flag_nopath = $flag; 41 | } 42 | 43 | public function getFlagNopath(): bool 44 | { 45 | return $this->flag_nopath; 46 | } 47 | 48 | public function setFlagUtimeOmitOk(bool $flag): void 49 | { 50 | $this->flag_utime_omit_ok = $flag; 51 | } 52 | 53 | public function getFlagUtimeOmitOk(): bool 54 | { 55 | return $this->flag_utime_omit_ok; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/FilesystemInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use Fuse\Libc\Fcntl\Flock; 17 | use Fuse\Libc\Fuse\FuseBufVec; 18 | use Fuse\Libc\Fuse\FuseConnInfo; 19 | use Fuse\Libc\Fuse\FuseDirFill; 20 | use Fuse\Libc\Fuse\FuseDirHandle; 21 | use Fuse\Libc\Fuse\FuseFileInfo; 22 | use Fuse\Libc\Fuse\FuseFillDir; 23 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 24 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 25 | use Fuse\Libc\Fuse\FusePollHandle; 26 | use Fuse\Libc\Fuse\FusePrivateData; 27 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 28 | use Fuse\Libc\String\CBytesBuffer; 29 | use Fuse\Libc\String\CStringBuffer; 30 | use Fuse\Libc\Sys\Stat\Stat; 31 | use Fuse\Libc\Sys\StatVfs\StatVfs; 32 | use Fuse\Libc\Time\TimeSpec; 33 | use Fuse\Libc\Utime\UtimBuf; 34 | use TypedCData\TypedCDataArray; 35 | 36 | interface FilesystemInterface extends Mountable 37 | { 38 | /** 39 | * int (*getattr) (const char *, struct stat *); 40 | */ 41 | public function getattr(string $path, Stat $stat): int; 42 | 43 | /** 44 | * int (*readlink) (const char *, char *, size_t); 45 | */ 46 | public function readlink(string $path, CStringBuffer $buffer, int $size): int; 47 | 48 | /** 49 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 50 | * 51 | * @deprecated 52 | */ 53 | public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int; 54 | 55 | /** 56 | * int (*mknod) (const char *, mode_t, dev_t); 57 | */ 58 | public function mknod(string $path, int $mode, int $dev): int; 59 | 60 | /** 61 | * int (*mkdir) (const char *, mode_t); 62 | */ 63 | public function mkdir(string $path, int $mode): int; 64 | 65 | /** 66 | * int (*unlink) (const char *); 67 | */ 68 | public function unlink(string $path): int; 69 | 70 | /** 71 | * int (*rmdir) (const char *); 72 | */ 73 | public function rmdir(string $path): int; 74 | 75 | /** 76 | * int (*symlink) (const char *, const char *); 77 | */ 78 | public function symlink(string $path, string $link): int; 79 | 80 | /** 81 | * int (*rename) (const char *, const char *); 82 | */ 83 | public function rename(string $from, string $to): int; 84 | 85 | /** 86 | * int (*link) (const char *, const char *); 87 | */ 88 | public function link(string $path, string $link): int; 89 | 90 | /** 91 | * int (*chmod) (const char *, mode_t); 92 | */ 93 | public function chmod(string $path, int $mode): int; 94 | 95 | /** 96 | * int (*chown) (const char *, uid_t, gid_t); 97 | */ 98 | public function chown(string $path, int $uid, int $gid): int; 99 | 100 | /** 101 | * int (*truncate) (const char *, off_t); 102 | */ 103 | public function truncate(string $path, int $offset): int; 104 | 105 | /** 106 | * int (*utime) (const char *, struct utimbuf *); 107 | */ 108 | public function utime(string $path, UtimBuf $utime_buf): int; 109 | 110 | /** 111 | * int (*open) (const char *, struct fuse_file_info *); 112 | */ 113 | public function open(string $path, FuseFileInfo $fuse_file_info): int; 114 | 115 | /** 116 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 117 | */ 118 | public function read(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int; 119 | 120 | /** 121 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 122 | */ 123 | public function write(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int; 124 | 125 | /** 126 | * int (*statfs) (const char *, struct statvfs *); 127 | */ 128 | public function statfs(string $path, StatVfs $statvfs): int; 129 | 130 | /** 131 | * int (*flush) (const char *, struct fuse_file_info *); 132 | */ 133 | public function flush(string $path, FuseFileInfo $fuse_file_info): int; 134 | 135 | /** 136 | * int (*release) (const char *, struct fuse_file_info *); 137 | */ 138 | public function release(string $path, FuseFileInfo $fuse_file_info): int; 139 | 140 | /** 141 | * int (*fsync) (const char *, int, struct fuse_file_info *); 142 | */ 143 | public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int; 144 | 145 | /** 146 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 147 | */ 148 | public function setxattr(string $path, string $name, string $value, int $size): int; 149 | 150 | /** 151 | * int (*getxattr) (const char *, const char *, char *, size_t); 152 | */ 153 | public function getxattr(string $path, string $name, ?string &$value, int $size): int; 154 | 155 | /** 156 | * int (*listxattr) (const char *, char *, size_t);* 157 | */ 158 | public function listxattr(string $path, ?string &$value, int $size): int; 159 | 160 | /** 161 | * int (*removexattr) (const char *, const char *); 162 | */ 163 | public function removexattr(string $path, string $name): int; 164 | 165 | /** 166 | * int (*opendir) (const char *, struct fuse_file_info *); 167 | */ 168 | public function opendir(string $path, FuseFileInfo $fuse_file_info): int; 169 | 170 | /** 171 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 172 | */ 173 | public function readdir( 174 | string $path, 175 | FuseReadDirBuffer $buf, 176 | FuseFillDir $filler, 177 | int $offset, 178 | FuseFileInfo $fuse_file_info 179 | ): int; 180 | 181 | /** 182 | * int (*releasedir) (const char *, struct fuse_file_info *); 183 | */ 184 | public function releasedir(string $path, FuseFileInfo $fuse_file_info): int; 185 | 186 | /** 187 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 188 | */ 189 | public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int; 190 | 191 | /** 192 | * void *(*init) (struct fuse_conn_info *conn); 193 | */ 194 | public function init(FuseConnInfo $conn): ?FusePrivateData; 195 | 196 | /** 197 | * void (*destroy) (void *); 198 | */ 199 | public function destroy(?FusePrivateData $private_data): void; 200 | 201 | /** 202 | * int (*access) (const char *, int); 203 | */ 204 | public function access(string $path, int $mode): int; 205 | 206 | /** 207 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 208 | */ 209 | public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int; 210 | 211 | /** 212 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 213 | */ 214 | public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int; 215 | 216 | /** 217 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 218 | */ 219 | public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int; 220 | 221 | /** 222 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 223 | */ 224 | public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int; 225 | 226 | /** 227 | * int (*utimens) (const char *, const struct timespec tv[2]); 228 | * 229 | * @param TypedCDataArray $tv 230 | */ 231 | public function utimens(string $path, TypedCDataArray $tv): int; 232 | 233 | /** 234 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 235 | */ 236 | public function bmap(string $path, int $blocksize, int &$idx): int; 237 | 238 | /** 239 | * unsigned int flag_nullpath_ok:1; 240 | * unsigned int flag_nopath:1; 241 | * unsigned int flag_utime_omit_ok:1; 242 | * unsigned int flag_reserved:29; 243 | */ 244 | public function setFlagNullpathOk(bool $flag): void; 245 | public function getFlagNullpathOk(): bool; 246 | public function setFlagNopath(bool $flag): void; 247 | public function getFlagNopath(): bool; 248 | public function setFlagUtimeOmitOk(bool $flag): void; 249 | public function getFlagUtimeOmitOk(): bool; 250 | 251 | /** 252 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 253 | */ 254 | public function ioctl( 255 | string $path, 256 | int $cmd, 257 | FuseIoctlArgPointer $arg, 258 | FuseFileInfo $fuse_file_info, 259 | int $flags, 260 | FuseIoctlDataPointer $data 261 | ): int; 262 | 263 | /** 264 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 265 | */ 266 | public function poll( 267 | string $path, 268 | FuseFileInfo $fuse_file_info, 269 | FusePollHandle $fuse_pollhandle, 270 | int &$reventsp 271 | ): int; 272 | 273 | /** 274 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 275 | */ 276 | public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int; 277 | 278 | /** 279 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 280 | * 281 | * @param TypedCDataArray $bufp 282 | */ 283 | public function readBuf( 284 | string $path, 285 | TypedCDataArray $bufp, 286 | int $size, 287 | int $offset, 288 | FuseFileInfo $fuse_file_info 289 | ): int; 290 | 291 | /** 292 | * int (*flock) (const char *, struct fuse_file_info *, int op); 293 | */ 294 | public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int; 295 | 296 | /** 297 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 298 | */ 299 | public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int; 300 | } 301 | -------------------------------------------------------------------------------- /src/Fuse.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use FFI; 17 | use FFI\CData; 18 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 19 | 20 | final class Fuse 21 | { 22 | private static ?self $instance; 23 | /** @var FuseFFI */ 24 | public FFI $ffi; 25 | 26 | /** 27 | * @param FuseFFI $ffi 28 | */ 29 | private function __construct(FFI $ffi) 30 | { 31 | $this->ffi = $ffi; 32 | } 33 | 34 | /** 35 | * @return FuseFFI 36 | */ 37 | private static function load(): FFI 38 | { 39 | /** @var FuseFFI */ 40 | return FFI::cdef( 41 | file_get_contents(__DIR__ . '/Headers/fuse.h'), 42 | 'libfuse.so' 43 | ); 44 | } 45 | 46 | public static function getInstance(): self 47 | { 48 | if (!isset(self::$instance)) { 49 | self::$instance = new self(self::load()); 50 | } 51 | return self::$instance; 52 | } 53 | 54 | /** 55 | * @param list $args 56 | * @param FuseOperations $fuse_operations 57 | * @param CData|null $user_data 58 | * @return int 59 | */ 60 | public function main(array $args, FuseOperations $fuse_operations, ?CData $user_data = null): int 61 | { 62 | $argc = count($args); 63 | /** @var \FFI\CDataArray $argv_real */ 64 | $argv_real = FFI::new('char *[' . count($args) . ']'); 65 | foreach ($args as $key => $item) { 66 | $item_len = strlen($item); 67 | $item_len_nul = $item_len + 1; 68 | /** @var \FFI\CDataArray $argv_item */ 69 | $argv_item = FFI::new("char[{$item_len_nul}]", false, true); 70 | FFI::memcpy($argv_item, $item, $item_len); 71 | $argv_item[$item_len] = "\0"; 72 | $argv_real[$key] = $argv_item; 73 | } 74 | 75 | return Fuse::getInstance()->ffi->fuse_main_real( 76 | $argc, 77 | $argv_real, 78 | FFI::addr($fuse_operations->getCData()), 79 | $fuse_operations->getSize(), 80 | $user_data 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/FuseLogicException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | /** @deprecated */ 17 | class FuseLogicException extends \LogicException 18 | { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/FuseOperations.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use FFI; 17 | use FFI\CData; 18 | use Fuse\Libc\Fcntl\Flock; 19 | use Fuse\Libc\Fuse\FuseBufVec; 20 | use Fuse\Libc\Fuse\FuseConnInfo; 21 | use Fuse\Libc\Fuse\FuseDirFill; 22 | use Fuse\Libc\Fuse\FuseDirHandle; 23 | use Fuse\Libc\Fuse\FuseFileInfo; 24 | use Fuse\Libc\Fuse\FuseFillDir; 25 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 26 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 27 | use Fuse\Libc\Fuse\FusePollHandle; 28 | use Fuse\Libc\Fuse\FusePrivateData; 29 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 30 | use Fuse\Libc\String\CBytesBuffer; 31 | use Fuse\Libc\String\CStringBuffer; 32 | use Fuse\Libc\Sys\Stat\Stat; 33 | use Fuse\Libc\Sys\StatVfs\StatVfs; 34 | use Fuse\Libc\Time\TimeSpec; 35 | use Fuse\Libc\Utime\UtimBuf; 36 | use ReflectionClass; 37 | use TypedCData\TypedCDataArray; 38 | use TypedCData\TypedCDataWrapper; 39 | 40 | // phpcs:disable Generic.Files.LineLength 41 | /** 42 | * @psalm-type TimeSpecArray = TypedCDataArray 43 | * @psalm-type FuseBufVecArray = TypedCDataArray 44 | * @psalm-type getattr_op = callable(string $path, CData $stat): int 45 | * @psalm-type getattr_typed_op = callable(string $path, Stat $stat): int 46 | * @psalm-type readlink_op = callable(string $path, CData $buffer, int $size): int 47 | * @psalm-type readlink_typed_op = callable(string $path, CStringBuffer $buffer, int $size): int 48 | * @psalm-type getdir_op = callable(string $path, CData $dirhandle, CData $dirfill): int 49 | * @psalm-type getdir_typed_op = callable(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int 50 | * @psalm-type utime_op = callable(string $path, CData $utime_buf): int 51 | * @psalm-type utime_typed_op = callable(string $path, UtimBuf $utime_buf): int 52 | * @psalm-type open_op = callable(string $path, CData $fuse_file_info): int 53 | * @psalm-type open_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 54 | * @psalm-type read_op = callable(string $path, CData $buffer, int $size, int $offset, CData $fuse_file_info): int 55 | * @psalm-type read_typed_op = callable(string $path, CBytesBuffer $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 56 | * @psalm-type write_op = callable(string $path, string $buffer, int $size, int $offset, CData $fuse_file_info): int 57 | * @psalm-type write_typed_op = callable(string $path, string $buffer, int $size, int $offset, FuseFileInfo $fuse_file_info): int 58 | * @psalm-type statfs_op = callable(string $path, CData $statvfs): int 59 | * @psalm-type statfs_typed_op = callable(string $path, StatVfs $statvfs): int 60 | * @psalm-type flush_op = callable(string $path, CData $fuse_file_info): int 61 | * @psalm-type flush_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 62 | * @psalm-type release_op = callable(string $path, CData $fuse_file_info): int 63 | * @psalm-type release_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 64 | * @psalm-type fsync_op = callable(string $path, int $flags, CData $fuse_file_info): int 65 | * @psalm-type fsync_typed_op = callable(string $path, int $flags, FuseFileInfo $fuse_file_info): int 66 | * @psalm-type opendir_op = callable(string $path, CData $fuse_file_info): int 67 | * @psalm-type opendir_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 68 | * @psalm-type readdir_op = callable(string $path, CData $buf, CData $filler, int $offset, CData $fuse_file_info): int 69 | * @psalm-type readdir_typed_op = callable(string $path, FuseReadDirBuffer $buf, FuseFillDir $filler, int $offset, FuseFileInfo $fuse_file_info): int 70 | * @psalm-type releasedir_op = callable(string $path, CData $fuse_file_info): int 71 | * @psalm-type releasedir_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 72 | * @psalm-type fsyncdir_op = callable(string $path, CData $fuse_file_info): int 73 | * @psalm-type fsyncdir_typed_op = callable(string $path, FuseFileInfo $fuse_file_info): int 74 | * @psalm-type init_op = callable(CData $conn): ?CData 75 | * @psalm-type init_typed_op = callable(FuseConnInfo $conn): ?FusePrivateData 76 | * @psalm-type destroy_op = callable(CData $private_data): void 77 | * @psalm-type destroy_typed_op = callable(?FusePrivateData$private_data): void 78 | * @psalm-type create_op = callable(string $path, int $mode, CData $fuse_file_info): int 79 | * @psalm-type create_typed_op = callable(string $path, int $mode, FuseFileInfo $fuse_file_info): int 80 | * @psalm-type ftruncate_op = callable(string $path, int $offset, CData $fuse_file_info): int 81 | * @psalm-type ftruncate_typed_op = callable(string $path, int $offset, FuseFileInfo $fuse_file_info): int 82 | * @psalm-type fgetattr_op = callable(string $path, CData $stat, CData $fuse_file_info): int 83 | * @psalm-type fgetattr_typed_op = callable(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int 84 | * @psalm-type lock_op = callable(string $path, CData $fuse_file_info, int $cmd, CData $flock): int 85 | * @psalm-type lock_typed_op = callable(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int 86 | * @psalm-type utimens_op = callable(string $path, CData $tv): int 87 | * @psalm-type utimens_typed_op = callable(string $path, TimeSpecArray$tv): int 88 | * @psalm-type bmap_op = callable(string $path, int $blocksize, CData $idx): int 89 | * @psalm-type bmap_typed_op = callable(string $path, int $blocksize, int $idx): int 90 | * @psalm-type ioctl_op = callable(string $path, int $cmd, CData $arg, CData $fuse_file_info, int $flags, CData $data): int 91 | * @psalm-type ioctl_typed_op = callable(string $path, int $cmd, FuseIoctlArgPointer $arg, FuseFileInfo $fuse_file_info, int $flags, FuseIoctlDataPointer $data): int 92 | * @psalm-type poll_op = callable(string $path, CData $fuse_file_info, CData $fuse_pollhandle, int $reventsp): int 93 | * @psalm-type poll_typed_op = callable(string $path, FuseFileInfo $fuse_file_info, FusePollHandle $fuse_pollhandle, int $reventsp): int 94 | * @psalm-type write_buf_op = callable(string $path, CData $buf, int $offset, CData $fuse_file_info): int 95 | * @psalm-type write_buf_typed_op = callable(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int 96 | * @psalm-type read_buf_op = callable(string $path, CData $bufp, int $size, int $offset, CData $fuse_file_info): int 97 | * @psalm-type read_buf_typed_op = callable(string $path, FuseBufVecArray $bufp, int $size, int $offset, FuseFileInfo $fuse_file_info): int 98 | * @psalm-type flock_op = callable(string $path, CData $fuse_file_info, int $op): int 99 | * @psalm-type flock_typed_op = callable(string $path, FuseFileInfo $fuse_file_info, int $op): int 100 | * @psalm-type fallocate_op = callable(string $path, int $mode, int $offset, CData $fuse_file_info): int 101 | * @psalm-type fallocate_typed_op = callable(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int 102 | */ 103 | // phpcs:enable Generic.Files.LineLength 104 | final class FuseOperations implements Mountable 105 | { 106 | /** 107 | * int (*getattr) (const char *, struct stat *); 108 | * 109 | * @var null|getattr_op|getattr_typed_op 110 | */ 111 | public $getattr = null; 112 | 113 | /** 114 | * int (*readlink) (const char *, char *, size_t); 115 | * 116 | * @var null|readlink_op|readlink_typed_op 117 | */ 118 | public $readlink = null; 119 | 120 | /** 121 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 122 | * 123 | * @deprecated 124 | * @var null|getdir_op|getdir_typed_op 125 | */ 126 | public $getdir = null; 127 | 128 | /** 129 | * int (*mknod) (const char *, mode_t, dev_t); 130 | * 131 | * @var null|callable(string $path, int $mode, int $dev): int 132 | */ 133 | public $mknod = null; 134 | 135 | /** 136 | * int (*mkdir) (const char *, mode_t); 137 | * 138 | * @var null|callable(string $path, int $mode): int 139 | */ 140 | public $mkdir = null; 141 | 142 | /** 143 | * int (*unlink) (const char *); 144 | * 145 | * @var null|callable(string $path): int 146 | */ 147 | public $unlink = null; 148 | 149 | /** 150 | * int (*rmdir) (const char *); 151 | * 152 | * @var null|callable(string $path): int 153 | */ 154 | public $rmdir = null; 155 | 156 | /** 157 | * int (*symlink) (const char *, const char *); 158 | * 159 | * @var null|callable(string $path, string $link): int 160 | */ 161 | public $symlink = null; 162 | 163 | /** 164 | * int (*rename) (const char *, const char *); 165 | * 166 | * @var null|callable(string $from, string $to): int 167 | */ 168 | public $rename = null; 169 | 170 | /** 171 | * int (*link) (const char *, const char *); 172 | * 173 | * @var null|callable(string $path, string $link): int 174 | */ 175 | public $link = null; 176 | 177 | /** 178 | * int (*chmod) (const char *, mode_t); 179 | * 180 | * @var null|callable(string $path, int $mode): int 181 | */ 182 | public $chmod = null; 183 | 184 | /** 185 | * int (*chown) (const char *, uid_t, gid_t); 186 | * 187 | * @var null|callable(string $path, int $uid, int $gid): int 188 | */ 189 | public $chown = null; 190 | 191 | /** 192 | * int (*truncate) (const char *, off_t); 193 | * 194 | * @var null|callable(string $path, int $offset): int 195 | */ 196 | public $truncate = null; 197 | 198 | /** 199 | * int (*utime) (const char *, struct utimbuf *); 200 | * 201 | * @var null|utime_op|utime_typed_op 202 | */ 203 | public $utime = null; 204 | 205 | /** 206 | * int (*open) (const char *, struct fuse_file_info *); 207 | * 208 | * @var null|open_op|open_typed_op 209 | */ 210 | public $open = null; 211 | 212 | /** 213 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 214 | * 215 | * @var null|read_op|read_typed_op 216 | */ 217 | public $read = null; 218 | 219 | /** 220 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 221 | * 222 | * @var null|write_op|write_typed_op 223 | */ 224 | public $write = null; 225 | 226 | /** 227 | * int (*statfs) (const char *, struct statvfs *); 228 | * 229 | * @var null|statfs_op|statfs_typed_op 230 | */ 231 | public $statfs = null; 232 | 233 | /** 234 | * int (*flush) (const char *, struct fuse_file_info *); 235 | * 236 | * @var null|flush_op|flush_typed_op 237 | */ 238 | public $flush = null; 239 | 240 | /** 241 | * int (*release) (const char *, struct fuse_file_info *); 242 | * 243 | * @var null|release_op|release_typed_op 244 | */ 245 | public $release = null; 246 | 247 | /** 248 | * int (*fsync) (const char *, int, struct fuse_file_info *); 249 | * 250 | * @var null|fsync_op|fsync_typed_op 251 | */ 252 | public $fsync = null; 253 | 254 | /** 255 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 256 | * 257 | * @var null|callable(string $path, string $name, string $value, int $size): int 258 | */ 259 | public $setxattr = null; 260 | 261 | /** 262 | * int (*getxattr) (const char *, const char *, char *, size_t); 263 | * 264 | * @var null|callable(string $path, string $name, string $value, int $size): int 265 | */ 266 | public $getxattr = null; 267 | 268 | /** 269 | * int (*listxattr) (const char *, char *, size_t); 270 | * 271 | * @var null|callable(string $path, string $value, int $size): int 272 | */ 273 | public $listxattr = null; 274 | 275 | /** 276 | * int (*removexattr) (const char *, const char *); 277 | * 278 | * @var null|callable(string $size, string $name): int 279 | */ 280 | public $removexattr = null; 281 | 282 | /** 283 | * int (*opendir) (const char *, struct fuse_file_info *); 284 | * 285 | * @var null|opendir_op|opendir_typed_op 286 | */ 287 | public $opendir = null; 288 | 289 | /** 290 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 291 | * 292 | * @var null|readdir_op|readdir_typed_op 293 | */ 294 | public $readdir = null; 295 | 296 | /** 297 | * int (*releasedir) (const char *, struct fuse_file_info *); 298 | * 299 | * @var null|releasedir_op|releasedir_typed_op 300 | */ 301 | public $releasedir = null; 302 | 303 | /** 304 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 305 | * 306 | * @var null|fsyncdir_op|fsyncdir_typed_op 307 | */ 308 | public $fsyncdir = null; 309 | 310 | /** 311 | * void *(*init) (struct fuse_conn_info *conn); 312 | * 313 | * @var null|init_op|init_typed_op 314 | */ 315 | public $init = null; 316 | 317 | /** 318 | * void (*destroy) (void *); 319 | * 320 | * @var null|destroy_op|destroy_typed_op 321 | */ 322 | public $destroy = null; 323 | 324 | /** 325 | * int (*access) (const char *, int); 326 | * 327 | * @var null|callable(string $path, int $mode): int 328 | */ 329 | public $access = null; 330 | 331 | /** 332 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 333 | * 334 | * @var null|create_op|create_typed_op 335 | */ 336 | public $create = null; 337 | 338 | /** 339 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 340 | * 341 | * @var null|ftruncate_op|ftruncate_typed_op 342 | */ 343 | public $ftruncate = null; 344 | 345 | /** 346 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 347 | * 348 | * @var null|fgetattr_op|fgetattr_typed_op 349 | */ 350 | public $fgetattr = null; 351 | 352 | /** 353 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 354 | * 355 | * @var null|lock_op|lock_typed_op 356 | */ 357 | public $lock = null; 358 | 359 | /** 360 | * int (*utimens) (const char *, const struct timespec tv[2]); 361 | * 362 | * @var null|utimens_op|utimens_typed_op 363 | */ 364 | public $utimens = null; 365 | 366 | /** 367 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 368 | * 369 | * @var null|bmap_op|bmap_typed_op 370 | */ 371 | public $bmap = null; 372 | 373 | /** 374 | * unsigned int flag_nullpath_ok:1; 375 | * unsigned int flag_nopath:1; 376 | * unsigned int flag_utime_omit_ok:1; 377 | * unsigned int flag_reserved:29; 378 | */ 379 | public bool $flag_nullpath_ok = false; 380 | public bool $flag_nopath = false; 381 | public bool $flag_utime_omit_ok = false; 382 | 383 | /** 384 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 385 | * 386 | * @var null|ioctl_op|ioctl_typed_op 387 | */ 388 | public $ioctl = null; 389 | 390 | /** 391 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 392 | * 393 | * @var null|poll_op|poll_typed_op 394 | */ 395 | public $poll = null; 396 | 397 | /** 398 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 399 | * 400 | * @var null|write_buf_op|write_buf_typed_op 401 | */ 402 | public $write_buf = null; 403 | 404 | /** 405 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 406 | * 407 | * @var null|read_buf_op|read_buf_typed_op 408 | */ 409 | public $read_buf = null; 410 | 411 | /** 412 | * int (*flock) (const char *, struct fuse_file_info *, int op); 413 | * 414 | * @var null|flock_op|flock_typed_op 415 | */ 416 | public $flock = null; 417 | 418 | /** 419 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 420 | * 421 | * @var null|fallocate_op|fallocate_typed_op 422 | */ 423 | public $fallocate = null; 424 | 425 | private ?CData $cdata_cache = null; 426 | 427 | 428 | public function getCData(): CData 429 | { 430 | $fuse_operations = Fuse::getInstance()->ffi->new('struct fuse_operations'); 431 | $typed_cdata_wrapper = new TypedCDataWrapper(); 432 | /** 433 | * @psalm-suppress RawObjectIteration 434 | * @var string $name 435 | * @var callable|null|bool $callable 436 | */ 437 | foreach ($this as $name => $callable) { 438 | if (is_null($callable)) { 439 | continue; 440 | } 441 | if (substr_compare($name, 'flag_', 0, 5) === 0) { 442 | continue; 443 | } 444 | assert(is_callable($callable)); 445 | $fuse_operations->$name = $typed_cdata_wrapper->createWrapper($callable); 446 | } 447 | assert(!is_null($fuse_operations)); 448 | return $this->cdata_cache = $fuse_operations; 449 | } 450 | 451 | public function getSize(): int 452 | { 453 | $typename = 'struct fuse_operations'; 454 | $type = Fuse::getInstance()->ffi->type( 455 | $typename 456 | ); 457 | assert(!is_null($type)); 458 | $size = FFI::sizeof( 459 | $type 460 | ); 461 | return $size; 462 | } 463 | 464 | public function getOperations(): FuseOperations 465 | { 466 | return $this; 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /src/Headers/fuse.h: -------------------------------------------------------------------------------- 1 | typedef unsigned int mode_t; 2 | typedef unsigned long int dev_t; 3 | typedef unsigned long int ino_t; 4 | typedef long int off_t; 5 | typedef long int nlink_t; 6 | typedef unsigned int uid_t; 7 | typedef unsigned int gid_t; 8 | typedef int pid_t; 9 | typedef long int blksize_t; 10 | typedef long int blkcnt_t; 11 | typedef unsigned long int fsblkcnt64_t; 12 | typedef unsigned long int uint64_t; 13 | 14 | struct timespec 15 | { 16 | long tv_sec; 17 | long tv_nsec; 18 | }; 19 | 20 | struct utimbuf 21 | { 22 | long actime; 23 | long modtime; 24 | }; 25 | 26 | struct stat 27 | { 28 | dev_t st_dev; 29 | ino_t st_ino; 30 | nlink_t st_nlink; 31 | mode_t st_mode; 32 | uid_t st_uid; 33 | gid_t st_gid; 34 | int __pad0; 35 | dev_t st_rdev; 36 | off_t st_size; 37 | blksize_t st_blksize; 38 | blkcnt_t st_blocks; 39 | struct timespec st_atim; 40 | struct timespec st_mtim; 41 | struct timespec st_ctim; 42 | long int reserved[3]; 43 | }; 44 | 45 | struct fuse_file_info 46 | { 47 | int flags; 48 | unsigned long fh_old; 49 | int writepage; 50 | unsigned int direct_io : 1; 51 | unsigned int keep_cache : 1; 52 | unsigned int flush : 1; 53 | unsigned int nonseekable : 1; 54 | unsigned int flock_release : 1; 55 | unsigned int padding : 27; 56 | uint64_t fh; 57 | uint64_t lock_owner; 58 | }; 59 | 60 | struct statvfs 61 | { 62 | unsigned long int f_bsize; 63 | unsigned long int f_frsize; 64 | fsblkcnt64_t f_blocks; 65 | fsblkcnt64_t f_bfree; 66 | fsblkcnt64_t f_bavail; 67 | fsblkcnt64_t f_files; 68 | fsblkcnt64_t f_ffree; 69 | fsblkcnt64_t f_favail; 70 | unsigned long int f_fsid; 71 | unsigned long int f_flag; 72 | unsigned long int f_namemax; 73 | int __f_spare[6]; 74 | }; 75 | 76 | struct fuse_conn_info { 77 | unsigned proto_major; 78 | unsigned proto_minor; 79 | unsigned async_read; 80 | unsigned max_write; 81 | unsigned max_readahead; 82 | unsigned capable; 83 | unsigned want; 84 | unsigned max_background; 85 | unsigned congestion_threshold; 86 | unsigned reserved[23]; 87 | }; 88 | 89 | struct flock 90 | { 91 | short int l_type; 92 | short int l_whence; 93 | off_t l_start; 94 | off_t l_len; 95 | pid_t l_pid; 96 | }; 97 | 98 | enum fuse_buf_flags 99 | { 100 | FUSE_BUF_IS_FD = (1 << 1), 101 | FUSE_BUF_FD_SEEK = (1 << 2), 102 | FUSE_BUF_FD_RETRY = (1 << 3), 103 | }; 104 | 105 | struct fuse_buf 106 | { 107 | size_t size; 108 | enum fuse_buf_flags flags; 109 | void *mem; 110 | int fd; 111 | off_t pos; 112 | }; 113 | 114 | struct fuse_bufvec 115 | { 116 | size_t count; 117 | size_t idx; 118 | size_t off; 119 | struct fuse_buf buf[1]; 120 | }; 121 | 122 | struct fuse; 123 | struct fuse_cmd; 124 | struct fuse_pollhandle; 125 | 126 | typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off); 127 | typedef struct fuse_dirhandle *fuse_dirh_t; 128 | typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, ino_t ino); 129 | struct fuse_operations 130 | { 131 | int (*getattr) (const char *, struct stat *); 132 | int (*readlink) (const char *, char *, size_t); 133 | int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 134 | int (*mknod) (const char *, mode_t, dev_t); 135 | int (*mkdir) (const char *, mode_t); 136 | int (*unlink) (const char *); 137 | int (*rmdir) (const char *); 138 | int (*symlink) (const char *, const char *); 139 | int (*rename) (const char *, const char *); 140 | int (*link) (const char *, const char *); 141 | int (*chmod) (const char *, mode_t); 142 | int (*chown) (const char *, uid_t, gid_t); 143 | int (*truncate) (const char *, off_t); 144 | int (*utime) (const char *, struct utimbuf *); 145 | int (*open) (const char *, struct fuse_file_info *); 146 | int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 147 | int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 148 | int (*statfs) (const char *, struct statvfs *); 149 | int (*flush) (const char *, struct fuse_file_info *); 150 | int (*release) (const char *, struct fuse_file_info *); 151 | int (*fsync) (const char *, int, struct fuse_file_info *); 152 | int (*setxattr) (const char *, const char *, const char *, size_t, int); 153 | int (*getxattr) (const char *, const char *, char *, size_t); 154 | int (*listxattr) (const char *, char *, size_t); 155 | int (*removexattr) (const char *, const char *); 156 | int (*opendir) (const char *, struct fuse_file_info *); 157 | int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 158 | int (*releasedir) (const char *, struct fuse_file_info *); 159 | int (*fsyncdir) (const char *, int, struct fuse_file_info *); 160 | void *(*init) (struct fuse_conn_info *conn); 161 | void (*destroy) (void *); 162 | int (*access) (const char *, int); 163 | int (*create) (const char *, mode_t, struct fuse_file_info *); 164 | int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 165 | int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 166 | int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 167 | int (*utimens) (const char *, const struct timespec tv[2]); 168 | int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 169 | unsigned int flag_nullpath_ok:1; 170 | unsigned int flag_nopath:1; 171 | unsigned int flag_utime_omit_ok:1; 172 | unsigned int flag_reserved:29; 173 | int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 174 | int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 175 | int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 176 | int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 177 | int (*flock) (const char *, struct fuse_file_info *, int op); 178 | int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 179 | }; 180 | 181 | int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data); 182 | 183 | typedef unsigned long fuse_ino_t; 184 | typedef struct fuse_req *fuse_req_t; 185 | struct fuse_entry_param 186 | { 187 | fuse_ino_t ino; 188 | unsigned long generation; 189 | struct stat attr; 190 | double attr_timeout; 191 | double entry_timeout; 192 | }; 193 | struct fuse_forget_data 194 | { 195 | uint64_t ino; 196 | uint64_t nlookup; 197 | }; 198 | 199 | struct fuse_lowlevel_ops 200 | { 201 | void (*init) (void *userdata, struct fuse_conn_info *conn); 202 | void (*destroy) (void *userdata); 203 | void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); 204 | void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); 205 | void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 206 | void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); 207 | void (*readlink) (fuse_req_t req, fuse_ino_t ino); 208 | void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev); 209 | void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode); 210 | void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); 211 | void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); 212 | void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name); 213 | void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname); 214 | void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); 215 | void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 216 | void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); 217 | void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); 218 | void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 219 | void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 220 | void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); 221 | void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 222 | void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); 223 | void (*releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); 224 | void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); 225 | void (*statfs) (fuse_req_t req, fuse_ino_t ino); 226 | void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); 227 | void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size); 228 | void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); 229 | void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); 230 | void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); 231 | void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi); 232 | void (*getlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock); 233 | void (*setlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep); 234 | void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx); 235 | void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz); 236 | void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph); 237 | void (*write_buf) (fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, off_t off, struct fuse_file_info *fi); 238 | void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv); 239 | void (*forget_multi) (fuse_req_t req, size_t count, struct fuse_forget_data *forgets); 240 | void (*flock) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op); 241 | void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi); 242 | }; 243 | 244 | struct fuse_session; 245 | struct fuse_chan; 246 | struct fuse_args 247 | { 248 | int argc; 249 | char **argv; 250 | int allocated; 251 | }; 252 | enum fuse_buf_copy_flags 253 | { 254 | FUSE_BUF_NO_SPLICE = (1 << 1), 255 | FUSE_BUF_FORCE_SPLICE = (1 << 2), 256 | FUSE_BUF_SPLICE_MOVE = (1 << 3), 257 | FUSE_BUF_SPLICE_NONBLOCK= (1 << 4), 258 | }; 259 | struct iovec 260 | { 261 | void *iov_base; 262 | size_t iov_len; 263 | }; 264 | struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); 265 | 266 | int fuse_reply_err(fuse_req_t req, int err); 267 | 268 | void fuse_reply_none(fuse_req_t req); 269 | 270 | int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); 271 | 272 | int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, 273 | const struct fuse_file_info *fi); 274 | 275 | int fuse_reply_attr(fuse_req_t req, const struct stat *attr, 276 | double attr_timeout); 277 | 278 | int fuse_reply_readlink(fuse_req_t req, const char *link); 279 | 280 | int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); 281 | 282 | int fuse_reply_write(fuse_req_t req, size_t count); 283 | 284 | int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); 285 | 286 | int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, 287 | enum fuse_buf_copy_flags flags); 288 | 289 | int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); 290 | 291 | int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); 292 | 293 | int fuse_reply_xattr(fuse_req_t req, size_t count); 294 | 295 | int fuse_reply_lock(fuse_req_t req, const struct flock *lock); 296 | 297 | int fuse_reply_bmap(fuse_req_t req, uint64_t idx); 298 | 299 | size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, 300 | const char *name, const struct stat *stbuf, 301 | off_t off); 302 | int fuse_reply_ioctl_retry(fuse_req_t req, 303 | const struct iovec *in_iov, size_t in_count, 304 | const struct iovec *out_iov, size_t out_count); 305 | 306 | int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size); 307 | 308 | int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, 309 | int count); 310 | 311 | int fuse_reply_poll(fuse_req_t req, unsigned revents); 312 | 313 | int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); 314 | 315 | int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, 316 | off_t off, off_t len); 317 | 318 | int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, 319 | const char *name, size_t namelen); 320 | 321 | int fuse_lowlevel_notify_delete(struct fuse_chan *ch, 322 | fuse_ino_t parent, fuse_ino_t child, 323 | const char *name, size_t namelen); 324 | 325 | int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, 326 | off_t offset, struct fuse_bufvec *bufv, 327 | enum fuse_buf_copy_flags flags); 328 | int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, 329 | size_t size, off_t offset, void *cookie); 330 | 331 | void *fuse_req_userdata(fuse_req_t req); 332 | 333 | int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, 334 | int *multithreaded, int *foreground); 335 | 336 | struct fuse_session_ops 337 | { 338 | void (*process) (void *data, const char *buf, size_t len, 339 | struct fuse_chan *ch); 340 | void (*exit) (void *data, int val); 341 | int (*exited) (void *data); 342 | void (*destroy) (void *data); 343 | }; 344 | struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); 345 | size_t fuse_buf_size(const struct fuse_bufvec *bufv); 346 | 347 | ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, 348 | enum fuse_buf_copy_flags flags); 349 | 350 | int fuse_set_signal_handlers(struct fuse_session *se); 351 | 352 | void fuse_remove_signal_handlers(struct fuse_session *se); 353 | 354 | int fuse_daemonize(int foreground); 355 | 356 | int fuse_version(void); 357 | 358 | void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); 359 | 360 | void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); 361 | 362 | void fuse_session_remove_chan(struct fuse_chan *ch); 363 | 364 | struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, 365 | struct fuse_chan *ch); 366 | 367 | void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, 368 | struct fuse_chan *ch); 369 | 370 | void fuse_session_process_buf(struct fuse_session *se, 371 | const struct fuse_buf *buf, struct fuse_chan *ch); 372 | 373 | int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, 374 | struct fuse_chan **chp); 375 | 376 | void fuse_session_destroy(struct fuse_session *se); 377 | 378 | void fuse_session_exit(struct fuse_session *se); 379 | 380 | void fuse_session_reset(struct fuse_session *se); 381 | 382 | int fuse_session_exited(struct fuse_session *se); 383 | 384 | void *fuse_session_data(struct fuse_session *se); 385 | struct fuse_opt 386 | { 387 | const char *templ; 388 | unsigned long offset; 389 | int value; 390 | }; 391 | typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, 392 | struct fuse_args *outargs); 393 | 394 | int fuse_opt_parse(struct fuse_args *args, void *data, 395 | const struct fuse_opt opts[], fuse_opt_proc_t proc); 396 | 397 | int fuse_opt_add_opt(char **opts, const char *opt); 398 | 399 | int fuse_opt_add_opt_escaped(char **opts, const char *opt); 400 | 401 | int fuse_opt_add_arg(struct fuse_args *args, const char *arg); 402 | 403 | int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); 404 | 405 | void fuse_opt_free_args(struct fuse_args *args); 406 | 407 | struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args); 408 | 409 | void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); 410 | 411 | int fuse_session_loop(struct fuse_session *se); 412 | 413 | int fuse_session_loop_mt(struct fuse_session *se); -------------------------------------------------------------------------------- /src/Libc/Errno/Errno.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Errno; 15 | 16 | final class Errno 17 | { 18 | public const ENOENT = 2; 19 | public const ENOTDIR = 20; 20 | public const ENOSYS = 38; 21 | } 22 | -------------------------------------------------------------------------------- /src/Libc/Fcntl/Flock.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fcntl; 15 | 16 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * struct flock 21 | * { 22 | * short int l_type; 23 | * short int l_whence; 24 | * off_t l_start; 25 | * off_t l_len; 26 | * pid_t l_pid; 27 | * }; 28 | */ 29 | final class Flock implements TypedCDataInterface 30 | { 31 | use TypedCDataDefaultImplementationTrait; 32 | 33 | public int $l_type; 34 | public int $l_whence; 35 | public int $l_start; 36 | public int $l_len; 37 | public int $l_pid; 38 | 39 | /** 40 | * Flock constructor. 41 | * @param int $l_type 42 | * @param int $l_whence 43 | * @param int $l_start 44 | * @param int $l_len 45 | * @param int $l_pid 46 | */ 47 | public function __construct( 48 | int $l_type = 0, 49 | int $l_whence = 0, 50 | int $l_start = 0, 51 | int $l_len = 0, 52 | int $l_pid = 0 53 | ) { 54 | $this->l_type = $l_type; 55 | $this->l_whence = $l_whence; 56 | $this->l_start = $l_start; 57 | $this->l_len = $l_len; 58 | $this->l_pid = $l_pid; 59 | } 60 | 61 | public static function getCTypeName(): string 62 | { 63 | return 'struct flock'; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseBuf.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 18 | use TypedCData\TypedCDataInterface; 19 | 20 | /** 21 | * struct fuse_buf 22 | * { 23 | * size_t size; 24 | * enum fuse_buf_flags flags; 25 | * void *mem; 26 | * int fd; 27 | * off_t pos; 28 | * }; 29 | */ 30 | final class FuseBuf implements TypedCDataInterface 31 | { 32 | use TypedCDataDefaultImplementationTrait; 33 | 34 | public int $size; 35 | public int $flags; 36 | public ?CData $mem; 37 | public int $fd; 38 | public int $pos; 39 | 40 | public static function getCTypeName(): string 41 | { 42 | return 'struct fuse_buf'; 43 | } 44 | 45 | public function __construct( 46 | int $size = 0, 47 | int $flags = 0, 48 | ?CData $mem = null, 49 | int $fd = 0, 50 | int $pos = 0 51 | ) { 52 | $this->size = $size; 53 | $this->flags = $flags; 54 | $this->mem = $mem; 55 | $this->fd = $fd; 56 | $this->pos = $pos; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseBufVec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 17 | use TypedCData\TypedCDataArray; 18 | use TypedCData\TypedCDataInterface; 19 | 20 | /** 21 | * struct fuse_bufvec 22 | * { 23 | * size_t count; 24 | * size_t idx; 25 | * size_t off; 26 | * struct fuse_buf buf[1]; 27 | * }; 28 | */ 29 | final class FuseBufVec implements TypedCDataInterface 30 | { 31 | use TypedCDataDefaultImplementationTrait; 32 | 33 | public int $count; 34 | public int $idx; 35 | public int $off; 36 | /** @var TypedCDataArray */ 37 | public TypedCDataArray $buf; 38 | 39 | /** 40 | * @param int $count 41 | * @param int $idx 42 | * @param int $off 43 | * @param TypedCDataArray|null $buf 44 | */ 45 | public function __construct( 46 | int $count = 0, 47 | int $idx = 0, 48 | int $off = 0, 49 | ?TypedCDataArray $buf = null 50 | ) { 51 | $this->count = $count; 52 | $this->idx = $idx; 53 | $this->off = $off; 54 | /** @var \FFI\CDataArray $fuse_buf */ 55 | $fuse_buf = FuseBuf::newCData(); 56 | $this->buf = $buf ?? new TypedCDataArray( 57 | $fuse_buf, 58 | FuseBuf::class 59 | ); 60 | } 61 | 62 | public static function getCTypeName(): string 63 | { 64 | return 'struct fuse_bufvec'; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseConnInfo.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 18 | use TypedCData\TypedCDataInterface; 19 | 20 | /** 21 | * struct fuse_conn_info 22 | * { 23 | * unsigned proto_major; 24 | * unsigned proto_minor; 25 | * unsigned async_read; 26 | * unsigned max_write; 27 | * unsigned max_readahead; 28 | * unsigned capable; 29 | * unsigned want; 30 | * unsigned max_background; 31 | * unsigned congestion_threshold; 32 | * unsigned reserved[23]; 33 | * }; 34 | */ 35 | final class FuseConnInfo implements TypedCDataInterface 36 | { 37 | use TypedCDataDefaultImplementationTrait; 38 | 39 | public int $proto_major; 40 | public int $proto_minor; 41 | public int $async_read; 42 | public int $max_write; 43 | public int $max_readahead; 44 | public int $capable; 45 | public int $want; 46 | public int $max_background; 47 | public int $congestion_threshold; 48 | public ?CData $reserved; 49 | 50 | public static function getCTypeName(): string 51 | { 52 | return 'struct fuse_conn_info'; 53 | } 54 | 55 | public function __construct( 56 | int $proto_major = 0, 57 | int $proto_minor = 0, 58 | int $async_read = 0, 59 | int $max_write = 0, 60 | int $max_readahead = 0, 61 | int $capable = 0, 62 | int $want = 0, 63 | int $max_background = 0, 64 | int $congestion_threshold = 0, 65 | ?CData $reserved = null 66 | ) { 67 | $this->proto_major = $proto_major; 68 | $this->proto_minor = $proto_minor; 69 | $this->async_read = $async_read; 70 | $this->max_write = $max_write; 71 | $this->max_readahead = $max_readahead; 72 | $this->capable = $capable; 73 | $this->want = $want; 74 | $this->max_background = $max_background; 75 | $this->congestion_threshold = $congestion_threshold; 76 | $this->reserved = $reserved; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseDirFill.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, ino_t ino); 21 | */ 22 | final class FuseDirFill implements TypedCDataInterface 23 | { 24 | /** @var \Fuse\FuseDirFillCData */ 25 | private CData $cdata; 26 | 27 | public function __invoke(FuseDirHandle $dirhandle, string $name, int $type, int $ino): int 28 | { 29 | /** @var int */ 30 | return ($this->cdata)($dirhandle->toCData(null), $name, $type, $ino); 31 | } 32 | 33 | public static function getCTypeName(): string 34 | { 35 | return 'fuse_dirfil_t'; 36 | } 37 | 38 | /** @param \Fuse\FuseDirFillCData $cdata */ 39 | public function __construct(CData $cdata) 40 | { 41 | $this->cdata = $cdata; 42 | } 43 | 44 | /** @return self */ 45 | public static function fromCData(CData $cdata): self 46 | { 47 | /** @var \Fuse\FuseDirFillCData $cdata */ 48 | return new self($cdata); 49 | } 50 | 51 | public function toCData(CData $cdata): CData 52 | { 53 | return $cdata; 54 | } 55 | 56 | public static function newCData(): CData 57 | { 58 | throw new \LogicException(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseDirHandle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * typedef struct fuse_dirhandle *fuse_dirh_t; 21 | */ 22 | final class FuseDirHandle implements TypedCDataInterface 23 | { 24 | private CData $cdata; 25 | 26 | public static function getCTypeName(): string 27 | { 28 | return 'struct fuse_dirhandle *'; 29 | } 30 | 31 | public function __construct(CData $cdata) 32 | { 33 | $this->cdata = $cdata; 34 | } 35 | 36 | /** @return static */ 37 | public static function fromCData(CData $cdata): TypedCDataInterface 38 | { 39 | return new self($cdata); 40 | } 41 | 42 | public function toCData(?CData $cdata): CData 43 | { 44 | return $this->cdata; 45 | } 46 | 47 | public static function newCData(): CData 48 | { 49 | throw new \LogicException('this type doesn\'t support creation of CData'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseFileInfo.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * struct fuse_file_info 21 | * { 22 | * int flags; 23 | * unsigned long fh_old; 24 | * int writepage; 25 | * unsigned int direct_io : 1; 26 | * unsigned int keep_cache : 1; 27 | * unsigned int flush : 1; 28 | * unsigned int nonseekable : 1; 29 | * unsigned int flock_release : 1; 30 | * unsigned int padding : 27; 31 | * uint64_t fh; 32 | * uint64_t lock_owner; 33 | * }; 34 | */ 35 | final class FuseFileInfo implements TypedCDataInterface 36 | { 37 | use TypedCDataDefaultImplementationTrait; 38 | 39 | public int $flags = 0; 40 | public int $fh_old = 0; 41 | public int $writepage = 0; 42 | public int $direct_io = 0; 43 | public int $keep_cache = 0; 44 | public int $nonseekable = 0; 45 | public int $flock_release = 0; 46 | public int $padding = 0; 47 | public int $fh = 0; 48 | public int $lock_owner = 0; 49 | 50 | public static function getCTypeName(): string 51 | { 52 | return 'struct fuse_file_info'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseFillDir.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use Fuse\Libc\Sys\Stat\Stat; 18 | use TypedCData\TypedCDataInterface; 19 | 20 | /** 21 | * typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off); 22 | */ 23 | final class FuseFillDir implements TypedCDataInterface 24 | { 25 | /** @var \Fuse\FuseFillDirCData */ 26 | private CData $cdata; 27 | 28 | public function __invoke(FuseReadDirBuffer $buf, string $name, ?Stat $stbuf, int $off): int 29 | { 30 | if (!is_null($stbuf)) { 31 | $stbuf = $stbuf->toCData($stbuf->newCData()); 32 | } 33 | /** @var int */ 34 | return ($this->cdata)($buf->toCData(null), $name, $stbuf, $off); 35 | } 36 | 37 | public static function getCTypeName(): string 38 | { 39 | return 'fuse_fill_dir_t'; 40 | } 41 | 42 | /** @param \Fuse\FuseFillDirCData $cdata */ 43 | public function __construct(CData $cdata) 44 | { 45 | $this->cdata = $cdata; 46 | } 47 | 48 | /** @return static */ 49 | public static function fromCData(CData $cdata): self 50 | { 51 | /** @var \Fuse\FuseFillDirCData $cdata */ 52 | return new self($cdata); 53 | } 54 | 55 | public function toCData(CData $cdata): CData 56 | { 57 | return $cdata; 58 | } 59 | 60 | public static function newCData(): CData 61 | { 62 | throw new \LogicException('this type doesn\'t support creation of CData'); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseIoctlArgPointer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class FuseIoctlArgPointer implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public static function getCTypeName(): string 24 | { 25 | return 'void *'; 26 | } 27 | 28 | public function __construct(CData $cdata) 29 | { 30 | $this->cdata = $cdata; 31 | } 32 | 33 | /** @return static */ 34 | public static function fromCData(CData $cdata): TypedCDataInterface 35 | { 36 | return new self($cdata); 37 | } 38 | 39 | public function toCData(?CData $cdata): CData 40 | { 41 | return $this->cdata; 42 | } 43 | 44 | public static function newCData(): CData 45 | { 46 | throw new \LogicException('this type doesn\'t support creation of CData'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseIoctlDataPointer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class FuseIoctlDataPointer implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public static function getCTypeName(): string 24 | { 25 | return 'void *'; 26 | } 27 | 28 | public function __construct(CData $cdata) 29 | { 30 | $this->cdata = $cdata; 31 | } 32 | 33 | /** @return static */ 34 | public static function fromCData(CData $cdata): TypedCDataInterface 35 | { 36 | return new self($cdata); 37 | } 38 | 39 | public function toCData(?CData $cdata): CData 40 | { 41 | return $this->cdata; 42 | } 43 | 44 | public static function newCData(): CData 45 | { 46 | throw new \LogicException('this type doesn\'t support creation of CData'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FusePollHandle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * struct fuse_pollhandle *; 21 | */ 22 | final class FusePollHandle implements TypedCDataInterface 23 | { 24 | private CData $cdata; 25 | 26 | public static function getCTypeName(): string 27 | { 28 | return 'struct fuse_pollhandle *'; 29 | } 30 | 31 | public function __construct(CData $cdata) 32 | { 33 | $this->cdata = $cdata; 34 | } 35 | 36 | /** @return static */ 37 | public static function fromCData(CData $cdata): TypedCDataInterface 38 | { 39 | return new self($cdata); 40 | } 41 | 42 | public function toCData(?CData $cdata): CData 43 | { 44 | return $this->cdata; 45 | } 46 | 47 | public static function newCData(): CData 48 | { 49 | throw new \LogicException('this type doesn\'t support creation of CData'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FusePrivateData.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class FusePrivateData implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public static function getCTypeName(): string 24 | { 25 | return 'void *'; 26 | } 27 | 28 | public function __construct(CData $cdata) 29 | { 30 | $this->cdata = $cdata; 31 | } 32 | 33 | /** @return static */ 34 | public static function fromCData(CData $cdata): TypedCDataInterface 35 | { 36 | return new self($cdata); 37 | } 38 | 39 | public function toCData(?CData $cdata): CData 40 | { 41 | return $this->cdata; 42 | } 43 | 44 | public static function newCData(): CData 45 | { 46 | throw new \LogicException('this type doesn\'t support creation of CData'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Libc/Fuse/FuseReadDirBuffer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Fuse; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class FuseReadDirBuffer implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public static function getCTypeName(): string 24 | { 25 | return 'void *'; 26 | } 27 | 28 | public function __construct(CData $cdata) 29 | { 30 | $this->cdata = $cdata; 31 | } 32 | 33 | /** @return static */ 34 | public static function fromCData(CData $cdata): TypedCDataInterface 35 | { 36 | return new self($cdata); 37 | } 38 | 39 | public function toCData(?CData $cdata): CData 40 | { 41 | return $this->cdata; 42 | } 43 | 44 | public static function newCData(): CData 45 | { 46 | throw new \LogicException('this type doesn\'t support creation of CData'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Libc/String/CBytesBuffer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\String; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class CBytesBuffer implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public function __construct(CData $cdata) 24 | { 25 | $this->cdata = $cdata; 26 | } 27 | 28 | /** @return static */ 29 | public static function fromCData(CData $cdata): self 30 | { 31 | return new self($cdata); 32 | } 33 | 34 | public static function getCTypeName(): string 35 | { 36 | return 'char *'; 37 | } 38 | 39 | public function write(string $content, int $size): void 40 | { 41 | \FFI::memcpy($this->cdata, $content, $size); 42 | } 43 | 44 | public function toCData(CData $cdata): CData 45 | { 46 | return $cdata; 47 | } 48 | 49 | public static function newCData(): CData 50 | { 51 | /** @var CData */ 52 | return \FFI::new('char[1]'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Libc/String/CStringBuffer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\String; 15 | 16 | use FFI\CData; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | final class CStringBuffer implements TypedCDataInterface 20 | { 21 | private CData $cdata; 22 | 23 | public function __construct(CData $cdata) 24 | { 25 | $this->cdata = $cdata; 26 | } 27 | 28 | /** @return static */ 29 | public static function fromCData(CData $cdata): self 30 | { 31 | return new self($cdata); 32 | } 33 | 34 | public static function getCTypeName(): string 35 | { 36 | return 'char *'; 37 | } 38 | 39 | public function toCData(CData $cdata): CData 40 | { 41 | return $cdata; 42 | } 43 | 44 | public static function newCData(): CData 45 | { 46 | /** @var CData */ 47 | return \FFI::new('char[1]'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Libc/Sys/Stat/Stat.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Sys\Stat; 15 | 16 | use FFI\CData; 17 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 18 | use Fuse\Libc\Time\TimeSpec; 19 | use TypedCData\TypedCDataInterface; 20 | 21 | /** 22 | * struct stat 23 | * { 24 | * dev_t st_dev; 25 | * ino_t st_ino; 26 | * nlink_t st_nlink; 27 | * mode_t st_mode; 28 | * uid_t st_uid; 29 | * gid_t st_gid; 30 | * int __pad0; 31 | * dev_t st_rdev; 32 | * off_t st_size; 33 | * blksize_t st_blksize; 34 | * blkcnt_t st_blocks; 35 | * struct timespec st_atim; 36 | * struct timespec st_mtim; 37 | * struct timespec st_ctim; 38 | * long int reserved[3]; 39 | * }; 40 | */ 41 | final class Stat implements TypedCDataInterface 42 | { 43 | use TypedCDataDefaultImplementationTrait; 44 | 45 | public const S_IFDIR = 0040000; 46 | public const S_IFREG = 0100000; 47 | 48 | public static function getCTypeName(): string 49 | { 50 | return 'struct stat'; 51 | } 52 | 53 | public int $st_dev; 54 | public int $st_ino; 55 | public int $st_nlink; 56 | public int $st_mode; 57 | public int $st_uid; 58 | public int $st_gid; 59 | // phpcs:ignore PSR2.Classes.PropertyDeclaration 60 | public int $__pad0; 61 | public int $st_rdev; 62 | public int $st_size; 63 | public int $st_blksize; 64 | public int $st_blocks; 65 | public TimeSpec $st_atim; 66 | public TimeSpec $st_mtim; 67 | public TimeSpec $st_ctim; 68 | public ?CData $reserved; 69 | 70 | public function __construct( 71 | int $st_dev = 0, 72 | int $st_ino = 0, 73 | int $st_nlink = 0, 74 | int $st_mode = 0, 75 | int $st_uid = 0, 76 | int $st_gid = 0, 77 | int $__pad0 = 0, 78 | int $st_rdev = 0, 79 | int $st_size = 0, 80 | int $st_blksize = 0, 81 | int $st_blocks = 0, 82 | ?TimeSpec $st_atim = null, 83 | ?TimeSpec $st_mtim = null, 84 | ?TimeSpec $st_ctim = null, 85 | ?CData $reserved = null 86 | ) { 87 | $this->st_dev = $st_dev; 88 | $this->st_ino = $st_ino; 89 | $this->st_nlink = $st_nlink; 90 | $this->st_mode = $st_mode; 91 | $this->st_uid = $st_uid; 92 | $this->st_gid = $st_gid; 93 | $this->__pad0 = $__pad0; 94 | $this->st_rdev = $st_rdev; 95 | $this->st_size = $st_size; 96 | $this->st_blksize = $st_blksize; 97 | $this->st_blocks = $st_blocks; 98 | $this->st_atim = $st_atim ?? new TimeSpec(); 99 | $this->st_mtim = $st_mtim ?? new TimeSpec(); 100 | $this->st_ctim = $st_ctim ?? new TimeSpec(); 101 | $this->reserved = $reserved; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Libc/Sys/StatVfs/StatVfs.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Sys\StatVfs; 15 | 16 | use FFI\CData; 17 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 18 | use TypedCData\TypedCDataInterface; 19 | 20 | /** 21 | * struct statvfs 22 | * { 23 | * unsigned long int f_bsize; 24 | * unsigned long int f_frsize; 25 | * fsblkcnt64_t f_blocks; 26 | * fsblkcnt64_t f_bfree; 27 | * fsblkcnt64_t f_bavail; 28 | * fsblkcnt64_t f_files; 29 | * fsblkcnt64_t f_ffree; 30 | * fsblkcnt64_t f_favail; 31 | * unsigned long int f_fsid; 32 | * unsigned long int f_flag; 33 | * unsigned long int f_namemax; 34 | * int __f_spare[6]; 35 | * }; 36 | */ 37 | final class StatVfs implements TypedCDataInterface 38 | { 39 | use TypedCDataDefaultImplementationTrait; 40 | 41 | public int $f_bsize; 42 | public int $f_frsize; 43 | public int $f_blocks; 44 | public int $f_bfree; 45 | public int $f_bavail; 46 | public int $f_files; 47 | public int $f_ffree; 48 | public int $f_favail; 49 | public int $f_fsid; 50 | public int $f_flag; 51 | public int $f_namemax; 52 | // phpcs:ignore PSR2.Classes.PropertyDeclaration 53 | public ?CData $__f_spare; 54 | 55 | public function __construct( 56 | int $f_bsize = 0, 57 | int $f_frsize = 0, 58 | int $f_blocks = 0, 59 | int $f_bfree = 0, 60 | int $f_bavail = 0, 61 | int $f_files = 0, 62 | int $f_ffree = 0, 63 | int $f_favail = 0, 64 | int $f_fsid = 0, 65 | int $f_flag = 0, 66 | int $f_namemax = 0, 67 | ?CData $__f_spare = null 68 | ) { 69 | $this->f_bsize = $f_bsize; 70 | $this->f_frsize = $f_frsize; 71 | $this->f_blocks = $f_blocks; 72 | $this->f_bfree = $f_bfree; 73 | $this->f_bavail = $f_bavail; 74 | $this->f_files = $f_files; 75 | $this->f_ffree = $f_ffree; 76 | $this->f_favail = $f_favail; 77 | $this->f_fsid = $f_fsid; 78 | $this->f_flag = $f_flag; 79 | $this->f_namemax = $f_namemax; 80 | $this->__f_spare = $__f_spare; 81 | } 82 | 83 | public static function getCTypeName(): string 84 | { 85 | return 'struct statvfs *'; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Libc/Time/TimeSpec.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Time; 15 | 16 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * struct timespec 21 | * { 22 | * long tv_sec; 23 | * long tv_nsec; 24 | * }; 25 | */ 26 | final class TimeSpec implements TypedCDataInterface 27 | { 28 | use TypedCDataDefaultImplementationTrait; 29 | 30 | public int $tv_sec = 0; 31 | public int $tv_nsec = 0; 32 | 33 | public static function getCTypeName(): string 34 | { 35 | return 'struct timespec'; 36 | } 37 | 38 | public function __construct(int $tv_sec = 0, int $tv_nsec = 0) 39 | { 40 | $this->tv_sec = $tv_sec; 41 | $this->tv_nsec = $tv_nsec; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Libc/Utime/UtimBuf.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Libc\Utime; 15 | 16 | use Fuse\FFI\TypedCDataDefaultImplementationTrait; 17 | use TypedCData\TypedCDataInterface; 18 | 19 | /** 20 | * struct utimbuf 21 | * { 22 | * long actime; 23 | * long modtime; 24 | * }; 25 | */ 26 | final class UtimBuf implements TypedCDataInterface 27 | { 28 | use TypedCDataDefaultImplementationTrait; 29 | 30 | public int $actime; 31 | public int $modtime; 32 | 33 | public static function getCTypeName(): string 34 | { 35 | return 'struct utimbuf'; 36 | } 37 | 38 | public function __construct(int $actime = 0, int $modtime = 0) 39 | { 40 | $this->actime = $actime; 41 | $this->modtime = $modtime; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Mountable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | interface Mountable 17 | { 18 | public function getOperations(): FuseOperations; 19 | } 20 | -------------------------------------------------------------------------------- /src/MountableFilesystemTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use Fuse\Libc\Fcntl\Flock; 17 | use Fuse\Libc\Fuse\FuseBufVec; 18 | use Fuse\Libc\Fuse\FuseConnInfo; 19 | use Fuse\Libc\Fuse\FuseDirFill; 20 | use Fuse\Libc\Fuse\FuseDirHandle; 21 | use Fuse\Libc\Fuse\FuseFileInfo; 22 | use Fuse\Libc\Fuse\FuseFillDir; 23 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 24 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 25 | use Fuse\Libc\Fuse\FusePollHandle; 26 | use Fuse\Libc\Fuse\FusePrivateData; 27 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 28 | use Fuse\Libc\String\CBytesBuffer; 29 | use Fuse\Libc\String\CStringBuffer; 30 | use Fuse\Libc\Sys\Stat\Stat; 31 | use Fuse\Libc\Sys\StatVfs\StatVfs; 32 | use Fuse\Libc\Time\TimeSpec; 33 | use Fuse\Libc\Utime\UtimBuf; 34 | use TypedCData\TypedCDataArray; 35 | 36 | trait MountableFilesystemTrait 37 | { 38 | public function getOperations(): FuseOperations 39 | { 40 | $fuse_operations = new FuseOperations(); 41 | 42 | $fuse_operations->getattr = [$this, 'getattr']; 43 | $fuse_operations->readlink = [$this, 'readlink']; 44 | /** @psalm-suppress DeprecatedProperty */ 45 | $fuse_operations->getdir = [$this, 'getdir']; 46 | $fuse_operations->mknod = [$this, 'mknod']; 47 | $fuse_operations->mkdir = [$this, 'mkdir']; 48 | $fuse_operations->unlink = [$this, 'unlink']; 49 | $fuse_operations->rmdir = [$this, 'rmdir']; 50 | $fuse_operations->symlink = [$this, 'symlink']; 51 | $fuse_operations->rename = [$this, 'rename']; 52 | $fuse_operations->link = [$this, 'link']; 53 | $fuse_operations->chmod = [$this, 'chmod']; 54 | $fuse_operations->chown = [$this, 'chown']; 55 | $fuse_operations->truncate = [$this, 'truncate']; 56 | $fuse_operations->utime = [$this, 'utime']; 57 | $fuse_operations->open = [$this, 'open']; 58 | $fuse_operations->read = [$this, 'read']; 59 | $fuse_operations->write = [$this, 'write']; 60 | $fuse_operations->statfs = [$this, 'statfs']; 61 | $fuse_operations->flush = [$this, 'flush']; 62 | $fuse_operations->release = [$this, 'release']; 63 | $fuse_operations->fsync = [$this, 'fsync']; 64 | $fuse_operations->setxattr = [$this, 'setxattr']; 65 | $fuse_operations->getxattr = [$this, 'getxattr']; 66 | $fuse_operations->listxattr = [$this, 'listxattr']; 67 | $fuse_operations->removexattr = [$this, 'removexattr']; 68 | $fuse_operations->opendir = [$this, 'opendir']; 69 | $fuse_operations->readdir = [$this, 'readdir']; 70 | $fuse_operations->releasedir = [$this, 'releasedir']; 71 | $fuse_operations->fsyncdir = [$this, 'fsyncdir']; 72 | $fuse_operations->init = [$this, 'init']; 73 | $fuse_operations->destroy = [$this, 'destroy']; 74 | $fuse_operations->access = [$this, 'access']; 75 | $fuse_operations->create = [$this, 'create']; 76 | $fuse_operations->ftruncate = [$this, 'ftruncate']; 77 | $fuse_operations->fgetattr = [$this, 'fgetattr']; 78 | $fuse_operations->lock = [$this, 'lock']; 79 | $fuse_operations->utimens = [$this, 'utimens']; 80 | $fuse_operations->bmap = [$this, 'bmap']; 81 | $fuse_operations->ioctl = [$this, 'ioctl']; 82 | $fuse_operations->poll = [$this, 'poll']; 83 | $fuse_operations->write_buf = [$this, 'writeBuf']; 84 | $fuse_operations->read_buf = [$this, 'readBuf']; 85 | $fuse_operations->flock = [$this, 'flock']; 86 | $fuse_operations->fallocate = [$this, 'fallocate']; 87 | $fuse_operations->flag_nullpath_ok = $this->getFlagNullpathOk(); 88 | $fuse_operations->flag_nopath = $this->getFlagNopath(); 89 | $fuse_operations->flag_utime_omit_ok = $this->getFlagUtimeOmitOk(); 90 | 91 | return $fuse_operations; 92 | } 93 | 94 | /** 95 | * int (*getattr) (const char *, struct stat *); 96 | */ 97 | abstract public function getattr(string $path, Stat $stat): int; 98 | 99 | /** 100 | * int (*readlink) (const char *, char *, size_t); 101 | */ 102 | abstract public function readlink(string $path, CStringBuffer $buffer, int $size): int; 103 | 104 | /** 105 | * int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); 106 | * 107 | * @deprecated 108 | */ 109 | abstract public function getdir(string $path, FuseDirHandle $dirhandle, FuseDirFill $dirfill): int; 110 | 111 | /** 112 | * int (*mknod) (const char *, mode_t, dev_t); 113 | */ 114 | abstract public function mknod(string $path, int $mode, int $dev): int; 115 | 116 | /** 117 | * int (*mkdir) (const char *, mode_t); 118 | */ 119 | abstract public function mkdir(string $path, int $mode): int; 120 | 121 | /** 122 | * int (*unlink) (const char *); 123 | */ 124 | abstract public function unlink(string $path): int; 125 | 126 | /** 127 | * int (*rmdir) (const char *); 128 | */ 129 | abstract public function rmdir(string $path): int; 130 | 131 | /** 132 | * int (*symlink) (const char *, const char *); 133 | */ 134 | abstract public function symlink(string $path, string $link): int; 135 | 136 | /** 137 | * int (*rename) (const char *, const char *); 138 | */ 139 | abstract public function rename(string $from, string $to): int; 140 | 141 | /** 142 | * int (*link) (const char *, const char *); 143 | */ 144 | abstract public function link(string $path, string $link): int; 145 | 146 | /** 147 | * int (*chmod) (const char *, mode_t); 148 | */ 149 | abstract public function chmod(string $path, int $mode): int; 150 | 151 | /** 152 | * int (*chown) (const char *, uid_t, gid_t); 153 | */ 154 | abstract public function chown(string $path, int $uid, int $gid): int; 155 | 156 | /** 157 | * int (*truncate) (const char *, off_t); 158 | */ 159 | abstract public function truncate(string $path, int $offset): int; 160 | 161 | /** 162 | * int (*utime) (const char *, struct utimbuf *); 163 | */ 164 | abstract public function utime(string $path, UtimBuf $utime_buf): int; 165 | 166 | /** 167 | * int (*open) (const char *, struct fuse_file_info *); 168 | */ 169 | abstract public function open(string $path, FuseFileInfo $fuse_file_info): int; 170 | 171 | /** 172 | * int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); 173 | */ 174 | abstract public function read( 175 | string $path, 176 | CBytesBuffer $buffer, 177 | int $size, 178 | int $offset, 179 | FuseFileInfo $fuse_file_info 180 | ): int; 181 | 182 | /** 183 | * int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); 184 | */ 185 | abstract public function write( 186 | string $path, 187 | string $buffer, 188 | int $size, 189 | int $offset, 190 | FuseFileInfo $fuse_file_info 191 | ): int; 192 | 193 | /** 194 | * int (*statfs) (const char *, struct statvfs *); 195 | */ 196 | abstract public function statfs(string $path, StatVfs $statvfs): int; 197 | 198 | /** 199 | * int (*flush) (const char *, struct fuse_file_info *); 200 | */ 201 | abstract public function flush(string $path, FuseFileInfo $fuse_file_info): int; 202 | 203 | /** 204 | * int (*release) (const char *, struct fuse_file_info *); 205 | */ 206 | abstract public function release(string $path, FuseFileInfo $fuse_file_info): int; 207 | 208 | /** 209 | * int (*fsync) (const char *, int, struct fuse_file_info *); 210 | */ 211 | abstract public function fsync(string $path, int $flags, FuseFileInfo $fuse_file_info): int; 212 | 213 | /** 214 | * int (*setxattr) (const char *, const char *, const char *, size_t, int); 215 | */ 216 | abstract public function setxattr(string $path, string $name, string $value, int $size): int; 217 | 218 | /** 219 | * int (*getxattr) (const char *, const char *, char *, size_t); 220 | */ 221 | abstract public function getxattr(string $path, string $name, ?string &$value, int $size): int; 222 | 223 | /** 224 | * int (*listxattr) (const char *, char *, size_t);* 225 | */ 226 | abstract public function listxattr(string $path, ?string &$value, int $size): int; 227 | 228 | /** 229 | * int (*removexattr) (const char *, const char *); 230 | */ 231 | abstract public function removexattr(string $path, string $name): int; 232 | 233 | /** 234 | * int (*opendir) (const char *, struct fuse_file_info *); 235 | */ 236 | abstract public function opendir(string $path, FuseFileInfo $fuse_file_info): int; 237 | 238 | /** 239 | * int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); 240 | */ 241 | abstract public function readdir( 242 | string $path, 243 | FuseReadDirBuffer $buf, 244 | FuseFillDir $filler, 245 | int $offset, 246 | FuseFileInfo $fuse_file_info 247 | ): int; 248 | 249 | /** 250 | * int (*releasedir) (const char *, struct fuse_file_info *); 251 | */ 252 | abstract public function releasedir(string $path, FuseFileInfo $fuse_file_info): int; 253 | 254 | /** 255 | * int (*fsyncdir) (const char *, int, struct fuse_file_info *); 256 | */ 257 | abstract public function fsyncdir(string $path, FuseFileInfo $fuse_file_info): int; 258 | 259 | /** 260 | * void *(*init) (struct fuse_conn_info *conn); 261 | */ 262 | abstract public function init(FuseConnInfo $conn): ?FusePrivateData; 263 | 264 | /** 265 | * void (*destroy) (void *); 266 | */ 267 | abstract public function destroy(?FusePrivateData $private_data): void; 268 | 269 | /** 270 | * int (*access) (const char *, int); 271 | */ 272 | abstract public function access(string $path, int $mode): int; 273 | 274 | /** 275 | * int (*create) (const char *, mode_t, struct fuse_file_info *); 276 | */ 277 | abstract public function create(string $path, int $mode, FuseFileInfo $fuse_file_info): int; 278 | 279 | /** 280 | * int (*ftruncate) (const char *, off_t, struct fuse_file_info *); 281 | */ 282 | abstract public function ftruncate(string $path, int $offset, FuseFileInfo $fuse_file_info): int; 283 | 284 | /** 285 | * int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); 286 | */ 287 | abstract public function fgetattr(string $path, Stat $stat, FuseFileInfo $fuse_file_info): int; 288 | 289 | /** 290 | * int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); 291 | */ 292 | abstract public function lock(string $path, FuseFileInfo $fuse_file_info, int $cmd, Flock $flock): int; 293 | 294 | /** 295 | * int (*utimens) (const char *, const struct timespec tv[2]); 296 | * 297 | * @param TypedCDataArray $tv 298 | */ 299 | abstract public function utimens(string $path, TypedCDataArray $tv): int; 300 | 301 | /** 302 | * int (*bmap) (const char *, size_t blocksize, uint64_t *idx); 303 | */ 304 | abstract public function bmap(string $path, int $blocksize, int &$idx): int; 305 | 306 | /** 307 | * unsigned int flag_nullpath_ok:1; 308 | * unsigned int flag_nopath:1; 309 | * unsigned int flag_utime_omit_ok:1; 310 | * unsigned int flag_reserved:29; 311 | */ 312 | abstract public function setFlagNullpathOk(bool $flag): void; 313 | abstract public function getFlagNullpathOk(): bool; 314 | abstract public function setFlagNopath(bool $flag): void; 315 | abstract public function getFlagNopath(): bool; 316 | abstract public function setFlagUtimeOmitOk(bool $flag): void; 317 | abstract public function getFlagUtimeOmitOk(): bool; 318 | 319 | /** 320 | * int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); 321 | */ 322 | abstract public function ioctl( 323 | string $path, 324 | int $cmd, 325 | FuseIoctlArgPointer $arg, 326 | FuseFileInfo $fuse_file_info, 327 | int $flags, 328 | FuseIoctlDataPointer $data 329 | ): int; 330 | 331 | /** 332 | * int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); 333 | */ 334 | abstract public function poll( 335 | string $path, 336 | FuseFileInfo $fuse_file_info, 337 | FusePollHandle $fuse_pollhandle, 338 | int &$reventsp 339 | ): int; 340 | 341 | /** 342 | * int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *); 343 | */ 344 | abstract public function writeBuf(string $path, FuseBufVec $buf, int $offset, FuseFileInfo $fuse_file_info): int; 345 | 346 | /** 347 | * int (*read_buf) (const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *); 348 | * 349 | * @param TypedCDataArray $bufp 350 | */ 351 | abstract public function readBuf( 352 | string $path, 353 | TypedCDataArray $bufp, 354 | int $size, 355 | int $offset, 356 | FuseFileInfo $fuse_file_info 357 | ): int; 358 | 359 | /** 360 | * int (*flock) (const char *, struct fuse_file_info *, int op); 361 | */ 362 | abstract public function flock(string $path, FuseFileInfo $fuse_file_info, int $op): int; 363 | 364 | /** 365 | * int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); 366 | */ 367 | abstract public function fallocate(string $path, int $mode, int $offset, FuseFileInfo $fuse_file_info): int; 368 | } 369 | -------------------------------------------------------------------------------- /src/Mounter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | class Mounter 17 | { 18 | private Fuse $fuse; 19 | 20 | public function __construct(?Fuse $fuse = null) 21 | { 22 | $this->fuse = $fuse ?? Fuse::getInstance(); 23 | } 24 | 25 | /** 26 | * @param string $path 27 | * @param Mountable $mountable 28 | * @param list|null $args 29 | * @return int 30 | */ 31 | public function mount(string $path, Mountable $mountable, array $args = null): int 32 | { 33 | $args ??= [ 34 | '', 35 | '-s', 36 | '-f', 37 | $path 38 | ]; 39 | return $this->fuse->main($args, $mountable->getOperations()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/FFI/TypedCDataWrapperTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\FFI; 15 | 16 | use Fuse\Fuse; 17 | use Fuse\Libc\Fuse\FuseBufVec; 18 | use Fuse\Libc\Sys\Stat\Stat; 19 | use PHPUnit\Framework\TestCase; 20 | use TypedCData\TypedCDataWrapper; 21 | 22 | class TypedCDataWrapperTest extends TestCase 23 | { 24 | public function testCreateWrapperStat() 25 | { 26 | $test_class = new class () { 27 | public function testMethod(Stat $stat): void 28 | { 29 | $stat->st_blocks = 123; 30 | } 31 | }; 32 | $wrapper_creator = new TypedCDataWrapper(); 33 | $wrapper = $wrapper_creator->createWrapper([$test_class, 'testMethod']); 34 | $cdata_stat = Fuse::getInstance()->ffi->new(Stat::getCTypeName()); 35 | $wrapper($cdata_stat); 36 | $this->assertSame(123, $cdata_stat->st_blocks); 37 | } 38 | 39 | public function testCreateWrapperFuseBufVec() 40 | { 41 | $test_class = new class ($this) { 42 | private TestCase $test_case; 43 | public function __construct(TestCase $test_case) 44 | { 45 | $this->test_case = $test_case; 46 | } 47 | public function testMethod(FuseBufVec $fuse_buf_vec): void 48 | { 49 | $this->test_case->assertSame(789, $fuse_buf_vec->buf[0]->size); 50 | $fuse_buf_vec->count = 123; 51 | $fuse_buf_vec->buf[0]->size = 456; 52 | } 53 | }; 54 | $wrapper_creator = new TypedCDataWrapper(); 55 | $wrapper = $wrapper_creator->createWrapper([$test_class, 'testMethod']); 56 | $cdata_stat = Fuse::getInstance()->ffi->new(FuseBufVec::getCTypeName()); 57 | $cdata_stat->buf[0]->size = 789; 58 | $wrapper($cdata_stat); 59 | $this->assertSame(123, $cdata_stat->count); 60 | $this->assertSame(456, $cdata_stat->buf[0]->size); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/Filesystem/Log/LogUnimplementedFilesystemTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem\Log; 15 | 16 | use FFI; 17 | use Fuse\Filesystem\Null\NullFilesystem; 18 | use Fuse\FilesystemDefaultImplementationTrait; 19 | use Fuse\FilesystemInterface; 20 | use Fuse\Libc\Fcntl\Flock; 21 | use Fuse\Libc\Fuse\FuseBufVec; 22 | use Fuse\Libc\Fuse\FuseConnInfo; 23 | use Fuse\Libc\Fuse\FuseDirFill; 24 | use Fuse\Libc\Fuse\FuseDirHandle; 25 | use Fuse\Libc\Fuse\FuseFileInfo; 26 | use Fuse\Libc\Fuse\FuseFillDir; 27 | use Fuse\Libc\Fuse\FuseIoctlArgPointer; 28 | use Fuse\Libc\Fuse\FuseIoctlDataPointer; 29 | use Fuse\Libc\Fuse\FusePollHandle; 30 | use Fuse\Libc\Fuse\FuseReadDirBuffer; 31 | use Fuse\Libc\String\CBytesBuffer; 32 | use Fuse\Libc\String\CStringBuffer; 33 | use Fuse\Libc\Sys\Stat\Stat; 34 | use Fuse\Libc\Sys\StatVfs\StatVfs; 35 | use Fuse\Libc\Time\TimeSpec; 36 | use Fuse\Libc\Utime\UtimBuf; 37 | use PHPUnit\Framework\TestCase; 38 | use Psr\Log\LoggerInterface; 39 | use Psr\Log\LoggerTrait; 40 | use TypedCData\TypedCDataArray; 41 | 42 | final class LogUnimplementedFilesystemTest extends TestCase 43 | { 44 | public function testDoesNotLogImplemented() 45 | { 46 | $filesystem = new class implements FilesystemInterface { 47 | use FilesystemDefaultImplementationTrait; 48 | 49 | public function getattr(string $path, Stat $stat): int 50 | { 51 | return 42; 52 | } 53 | }; 54 | 55 | $sut = new LogUnimplementedFilesystem( 56 | $filesystem, 57 | new class ($this) implements LoggerInterface { 58 | use LoggerTrait; 59 | 60 | private TestCase $test_case; 61 | 62 | public function __construct(TestCase $test_case) 63 | { 64 | $this->test_case = $test_case; 65 | } 66 | 67 | public function log($level, $message, array $context = []) 68 | { 69 | $this->test_case->assertSame('mkdir', $context['method']); 70 | } 71 | } 72 | ); 73 | 74 | $sut->getattr('/', new Stat()); 75 | $sut->mkdir('/', 0); 76 | } 77 | 78 | /** @dataProvider dataProvider */ 79 | public function testLogUnImplemented(string $method, ...$args) 80 | { 81 | $sut = new LogUnimplementedFilesystem( 82 | new NullFilesystem(), 83 | new class ($this, $method) implements LoggerInterface { 84 | use LoggerTrait; 85 | 86 | private TestCase $test_case; 87 | private string $method; 88 | 89 | public function __construct(TestCase $test_case, string $method) 90 | { 91 | $this->test_case = $test_case; 92 | $this->method = $method; 93 | } 94 | 95 | public function log($level, $message, array $context = []) 96 | { 97 | $this->test_case->assertSame($this->method, $context['method']); 98 | } 99 | } 100 | ); 101 | 102 | ([$sut, $method])(...$args); 103 | } 104 | 105 | public function dataProvider(): array 106 | { 107 | return [ 108 | 'getattr' => ['getattr', '/', new Stat()], 109 | 'readlink' => ['readlink', '/', new CStringBuffer(CStringBuffer::newCData()), 1], 110 | 'getdir' => [ 111 | 'getdir', 112 | '/', 113 | new FuseDirHandle(FFI::new(FuseDirHandle::getCTypeName())), 114 | new FuseDirFill(FFI::new('void *')), 115 | ], 116 | 'mknod' => ['mknod', '/', 0, 0], 117 | 'mkdir' => ['mkdir', '/', 0], 118 | 'unlink' => ['unlink', '/'], 119 | 'rmdir' => ['rmdir', '/'], 120 | 'symlink' => ['symlink', 'path', 'link'], 121 | 'rename' => ['rename', '/from', '/to'], 122 | 'link' => ['link', 'path', 'link'], 123 | 'chmod' => ['chmod', '/', 0], 124 | 'chown' => ['chown', '/', 1, 1], 125 | 'truncate' => ['truncate', '/', 0], 126 | 'utime' => ['utime', '/', new UtimBuf()], 127 | 'open' => ['open', '/', new FuseFileInfo()], 128 | 'read' => ['read', '/', new CBytesBuffer(CBytesBuffer::newCData()), 1, 0, new FuseFileInfo()], 129 | 'write' => ['write', '/', 'content', 7, 0, new FuseFileInfo()], 130 | 'statfs' => ['statfs', '/', new StatVfs()], 131 | 'flush' => ['flush', '/', new FuseFileInfo()], 132 | 'release' => ['release', '/', new FuseFileInfo()], 133 | 'fsync' => ['fsync', '/', 0, new FuseFileInfo()], 134 | 'setxattr' => ['setxattr', '/', 'name', 'value', 5], 135 | 'getxattr' => ['getxattr', '/', 'name', '', 5], 136 | 'listxattr' => ['listxattr', '/', '', 0], 137 | 'removexattr' => ['removexattr', '/', 'name'], 138 | 'opendir' => ['opendir', '/', new FuseFileInfo()], 139 | 'readdir' => [ 140 | 'readdir', 141 | '/', 142 | new FuseReadDirBuffer(FFI::new('void *')), 143 | new FuseFillDir(FFI::new('void *')), 144 | 0, 145 | new FuseFileInfo() 146 | ], 147 | 'releasedir' => ['releasedir', '/', new FuseFileInfo()], 148 | 'fsyncdir' => ['fsyncdir', '/', new FuseFileInfo()], 149 | 'init' => ['init', new FuseConnInfo()], 150 | 'destroy' => ['destroy', null], 151 | 'access' => ['access', '/', 0], 152 | 'create' => ['create', '/', 0, new FuseFileInfo()], 153 | 'ftruncate' => ['ftruncate', '/', 0, new FuseFileInfo()], 154 | 'fgetattr' => ['fgetattr', '/', new Stat(), new FuseFileInfo()], 155 | 'lock' => ['lock', '/', new FuseFileInfo(), 0, new Flock()], 156 | 'utimens' => [ 157 | 'utimens', 158 | '/', 159 | new TypedCDataArray( 160 | FFI::new('void *'), 161 | TimeSpec::class 162 | ) 163 | ], 164 | 'bmap' => ['bmap', '/', 0, 0], 165 | 'ioctl' => [ 166 | 'ioctl', 167 | '/', 168 | 0, 169 | new FuseIoctlArgPointer(FFI::new('void *')), 170 | new FuseFileInfo(), 171 | 0, 172 | new FuseIoctlDataPointer(FFI::new('void *')) 173 | ], 174 | 'poll' => [ 175 | 'poll', 176 | '/', 177 | new FuseFileInfo(), 178 | new FusePollHandle(FFI::new('void *')), 179 | 0 180 | ], 181 | 'writeBuf' => ['writeBuf', '/', new FuseBufVec(), 0, new FuseFileInfo()], 182 | 'readBuf' => [ 183 | 'readBuf', 184 | '/', 185 | new TypedCDataArray( 186 | FFI::new('void *'), 187 | FuseBufVec::class 188 | ), 189 | 0, 190 | 0, 191 | new FuseFileInfo() 192 | ], 193 | 'flock' => ['flock', '/', new FuseFileInfo(), 0], 194 | 'fallocate' => ['fallocate', '/', 0, 0, new FuseFileInfo()], 195 | ]; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /tests/Filesystem/ReflectionFilesystemTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse\Filesystem; 15 | 16 | use Fuse\FilesystemDefaultImplementationTrait; 17 | use Fuse\FilesystemInterface; 18 | use Fuse\Libc\Sys\Stat\Stat; 19 | use PHPUnit\Framework\TestCase; 20 | 21 | final class ReflectionFilesystemTest extends TestCase 22 | { 23 | public function testIsDefault() 24 | { 25 | $filesystem = new class implements FilesystemInterface { 26 | use FilesystemDefaultImplementationTrait; 27 | 28 | public function getattr(string $path, Stat $stat): int 29 | { 30 | return 0; 31 | } 32 | }; 33 | 34 | $sut = ReflectionFilesystem::instance($filesystem); 35 | 36 | $this->assertFalse($sut->isDefault('getattr')); 37 | $this->assertTrue($sut->isDefault('readlink')); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/stubs/FFI/CData.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace FFI; 15 | 16 | class CData 17 | { 18 | 19 | } 20 | 21 | /** 22 | * @implements \ArrayAccess 23 | */ 24 | class CDataArray extends CData implements \ArrayAccess 25 | { 26 | 27 | /** 28 | * Whether a offset exists 29 | * @link https://php.net/manual/en/arrayaccess.offsetexists.php 30 | * @param mixed $offset

31 | * An offset to check for. 32 | *

33 | * @return bool true on success or false on failure. 34 | *

35 | *

36 | * The return value will be casted to boolean if non-boolean was returned. 37 | */ 38 | public function offsetExists($offset) 39 | { 40 | // TODO: Implement offsetExists() method. 41 | } 42 | 43 | /** 44 | * @param int $offset 45 | */ 46 | public function offsetGet($offset): CData 47 | { 48 | // TODO: Implement offsetGet() method. 49 | } 50 | 51 | /** 52 | * Offset to set 53 | * @link https://php.net/manual/en/arrayaccess.offsetset.php 54 | * @param mixed $offset

55 | * The offset to assign the value to. 56 | *

57 | * @param mixed $value

58 | * The value to set. 59 | *

60 | * @return void 61 | */ 62 | public function offsetSet($offset, $value) 63 | { 64 | // TODO: Implement offsetSet() method. 65 | } 66 | 67 | /** 68 | * Offset to unset 69 | * @link https://php.net/manual/en/arrayaccess.offsetunset.php 70 | * @param mixed $offset

71 | * The offset to unset. 72 | *

73 | * @return void 74 | */ 75 | public function offsetUnset($offset) 76 | { 77 | // TODO: Implement offsetUnset() method. 78 | } 79 | } -------------------------------------------------------------------------------- /tools/stubs/Fuse/FuseCData.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use FFI\CData; 17 | 18 | class FuseDirFillCData extends CData 19 | { 20 | public function __invoke(CData $dirhandle, string $name, int $type, int $ino): int 21 | { 22 | 23 | } 24 | } 25 | 26 | class FuseFillDirCData extends CData 27 | { 28 | public function __invoke(CData $buf, string $name, ?CData $stbuf, int $off): int 29 | { 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /tools/stubs/Fuse/FuseFFI.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | declare(strict_types=1); 13 | 14 | namespace Fuse; 15 | 16 | use FFI; 17 | use FFI\CData; 18 | 19 | class FuseFFI extends FFI 20 | { 21 | public function fuse_main_real(int $argc, CData $argv, CData $fuse_operation, int $size, ?CData $user_data): int 22 | { 23 | 24 | } 25 | } --------------------------------------------------------------------------------