1+ <?php
2+
3+ /**
4+ * This file is part of the sj-i/php-fuse package.
5+ *
6+ * (c) sji <sji@sj-i.dev>
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 FFI \CData ;
15+ use Fuse \FilesystemDefaultImplementationTrait ;
16+ use Fuse \FilesystemInterface ;
17+ use Fuse \Fuse ;
18+ use Fuse \Mounter ;
19+
20+ require 'vendor/autoload.php ' ;
21+
22+ const ENOENT = 2 ;
23+ const S_IFDIR = 0040000 ;
24+ const S_IFREG = 0100000 ;
25+
26+ class ArrayFs implements FilesystemInterface
27+ {
28+ use FilesystemDefaultImplementationTrait;
29+
30+ private array $ array ;
31+
32+ public function __construct (array $ array )
33+ {
34+ $ this ->array = $ array ;
35+ }
36+
37+ public function getArray (): array
38+ {
39+ return $ this ->array ;
40+ }
41+
42+ public function getattr (string $ path , \FFI \CData $ stbuf ): int
43+ {
44+ $ typename = 'struct stat ' ;
45+ $ type = Fuse::getInstance ()->ffi ->type (
46+ $ typename
47+ );
48+ $ size = FFI ::sizeof (
49+ $ type
50+ );
51+ echo "attr read {$ path }" . PHP_EOL ;
52+
53+ FFI ::memset ($ stbuf , 0 , $ size );
54+ if ($ path === '/ ' ) {
55+ $ stbuf ->st_mode = S_IFDIR | 0777 ;
56+ $ stbuf ->st_nlink = 2 ;
57+ $ stbuf ->st_uid = getmyuid ();
58+ $ stbuf ->st_gid = getmygid ();
59+ return 0 ;
60+ }
61+
62+ $ element = $ this ->getEntry ($ path );
63+ if (is_null ($ element )) {
64+ return -ENOENT ;
65+ }
66+ if (is_array ($ element )) {
67+ $ stbuf ->st_mode = S_IFDIR | 0777 ;
68+ $ stbuf ->st_nlink = 2 ;
69+ $ stbuf ->st_uid = getmyuid ();
70+ $ stbuf ->st_gid = getmygid ();
71+ return 0 ;
72+ }
73+ $ stbuf ->st_mode = S_IFREG | 0777 ;
74+ $ stbuf ->st_nlink = 1 ;
75+ $ stbuf ->st_size = strlen ((string )$ element );
76+ $ stbuf ->st_uid = getmyuid ();
77+ $ stbuf ->st_gid = getmygid ();
78+ return 0 ;
79+ }
80+
81+ private function &getRecursive (&$ array , array $ offsets , ?callable $ operation = null )
82+ {
83+ $ null = null ;
84+
85+ $ count = count ($ offsets );
86+
87+ if ($ count === 0 ) {
88+ return $ null ;
89+ }
90+ if ($ count === 1 ) {
91+ if (isset ($ array [$ offsets [0 ]])) {
92+ if (!is_null ($ operation )) {
93+ return $ operation ($ array , $ offsets [0 ]);
94+ } else {
95+ return $ array [$ offsets [0 ]];
96+ }
97+ } else {
98+ return $ null ;
99+ }
100+ }
101+
102+ $ offset = array_shift ($ offsets );
103+ if (is_array ($ array [$ offset ])) {
104+ return $ this ->getRecursive ($ array [$ offset ], $ offsets );
105+ } else {
106+ return $ null ;
107+ }
108+ }
109+
110+ /**
111+ * @param string $path
112+ * @return string|array|null
113+ */
114+ private function &getEntry (string $ path )
115+ {
116+ $ splitted = explode ('/ ' , $ path );
117+ array_shift ($ splitted );
118+ return $ this ->getRecursive ($ this ->array , $ splitted );
119+ }
120+
121+ /**
122+ * @param string $path
123+ * @return string|array|null
124+ */
125+ private function &getParentEntry (string $ path )
126+ {
127+ $ splitted = explode ('/ ' , $ path );
128+ array_shift ($ splitted );
129+ array_pop ($ splitted );
130+ if (count ($ splitted ) === 0 ) {
131+ return $ this ->array ;
132+ }
133+ return $ this ->getRecursive ($ this ->array , $ splitted );
134+ }
135+
136+ /**
137+ * @param string $path
138+ */
139+ private function unsetEntry (string $ path ): void
140+ {
141+ $ splitted = explode ('/ ' , $ path );
142+ array_shift ($ splitted );
143+ $ this ->getRecursive ($ this ->array , $ splitted , function &(array &$ array , $ index ) {
144+ $ null = null ;
145+ unset($ array [$ index ]);
146+ return $ null ;
147+ });
148+ }
149+
150+ public function readdir (string $ path , CData $ buf , CData $ filler , int $ offset , CData $ fi ): int
151+ {
152+ $ filler ($ buf , '. ' , null , 0 );
153+ $ filler ($ buf , '.. ' , null , 0 );
154+ foreach ($ this ->array as $ key => $ value ) {
155+ $ filler ($ buf , (string )$ key , null , 0 );
156+ }
157+
158+ return 0 ;
159+ }
160+
161+ public function open (string $ path , CData $ fi ): int
162+ {
163+ $ entry = $ this ->getEntry ($ path );
164+ if (!is_string ($ entry )) {
165+ return -ENOENT ;
166+ }
167+
168+ echo "open {$ path }" . PHP_EOL ;
169+ return 0 ;
170+ }
171+
172+ public function read (string $ path , CData $ buf , int $ size , int $ offset , CData $ fi ): int
173+ {
174+ $ entry = $ this ->getEntry ($ path );
175+
176+ echo "read {$ path }" . PHP_EOL ;
177+
178+ $ len = strlen ($ entry );
179+
180+ if ($ offset + $ size > $ len ) {
181+ $ size = ($ len - $ offset );
182+ }
183+
184+ $ content = substr ($ entry , $ offset , $ size );
185+ FFI ::memcpy ($ buf , $ content , $ size );
186+
187+ return $ size ;
188+ }
189+
190+ public function write (string $ path , string $ buffer , int $ size , int $ offset , CData $ fuse_file_info ): int
191+ {
192+ $ entry = &$ this ->getEntry ($ path );
193+ $ entry = substr_replace ($ entry , $ buffer , $ offset , $ size );
194+
195+ return $ size ;
196+ }
197+
198+ public function create (string $ path , int $ mode , CData $ fuse_file_info ): int
199+ {
200+ $ entry = &$ this ->getParentEntry ($ path );
201+ if (is_array ($ entry )) {
202+ $ segments = explode ('/ ' , $ path );
203+ $ filename = array_pop ($ segments );
204+ $ entry [$ filename ] = '' ;
205+ return 0 ;
206+ } else {
207+ return ENOENT ;
208+ }
209+ }
210+
211+ public function unlink (string $ path ): int
212+ {
213+ $ this ->unsetEntry ($ path );
214+ return 0 ;
215+ }
216+
217+ public function rename (string $ from , string $ to ): int
218+ {
219+ $ fromValue = $ this ->getEntry ($ from );
220+ $ parent_entry = &$ this ->getParentEntry ($ to );
221+ if (is_array ($ parent_entry )) {
222+ $ segments = explode ('/ ' , $ to );
223+ $ filename = array_pop ($ segments );
224+ $ parent_entry [$ filename ] = $ fromValue ;
225+ $ this ->unsetEntry ($ from );
226+ return 0 ;
227+ } else {
228+ return ENOENT ;
229+ }
230+ }
231+ }
232+
233+
234+ $ mounter = new Mounter ();
235+ $ array_fs = new ArrayFs ([
236+ 1 ,
237+ 2 ,
238+ 'foo ' => 'bar ' ,
239+ ]);
240+ $ result = $ mounter ->mount ('/tmp/example/ ' , $ array_fs );
241+ var_dump ($ array_fs ->getArray ());
242+ return $ result ;
0 commit comments