0
# Core Classes
1
2
The primary classes that form the foundation of mfusepy's filesystem interface. These provide the essential framework for creating and mounting custom filesystems in Python.
3
4
## Capabilities
5
6
### FUSE Class
7
8
The main interface class that manages the FUSE mount process, handles callback translation between Python and the native FUSE library, and provides mount configuration options.
9
10
```python { .api }
11
class FUSE:
12
"""Lower level interface for FUSE filesystem implementation."""
13
14
OPTIONS = (
15
('foreground', '-f'),
16
('debug', '-d'),
17
('nothreads', '-s'),
18
)
19
20
def __init__(self, operations, mountpoint: str, raw_fi: bool = False,
21
encoding: str = 'utf-8', **kwargs) -> None:
22
"""
23
Mount a FUSE filesystem.
24
25
Args:
26
operations: Instance of Operations subclass implementing filesystem behavior
27
mountpoint: Directory path where filesystem will be mounted
28
raw_fi: If True, pass raw fuse_file_info structures to operations
29
encoding: Character encoding for path/name conversions (default: 'utf-8')
30
**kwargs: Additional FUSE mount options (foreground, debug, nothreads, etc.)
31
"""
32
```
33
34
#### Usage Example
35
36
```python
37
from mfusepy import FUSE, Operations
38
39
class MyFS(Operations):
40
def getattr(self, path, fh=None):
41
# Implement filesystem operations
42
pass
43
44
# Mount with default options
45
filesystem = MyFS()
46
fuse = FUSE(filesystem, '/mnt/myfs')
47
48
# Mount with custom options
49
fuse = FUSE(filesystem, '/mnt/myfs',
50
foreground=True, debug=True,
51
allow_other=True, raw_fi=True)
52
```
53
54
### Operations Base Class
55
56
Abstract base class that defines the interface for filesystem operations. Subclass this to implement custom filesystem behavior by overriding the methods corresponding to the filesystem operations you want to support.
57
58
```python { .api }
59
class Operations:
60
"""Base class to be subclassed for FUSE filesystem operations."""
61
62
# File and Directory Operations
63
def getattr(self, path: str, fh: Optional[int] = None) -> dict[str, Any]:
64
"""
65
Get file attributes (like stat()).
66
67
Args:
68
path: File path
69
fh: File handle (optional)
70
71
Returns:
72
Dictionary with stat-like attributes:
73
- st_mode: File mode (permissions + type)
74
- st_nlink: Number of hard links
75
- st_size: File size in bytes
76
- st_uid: User ID of owner
77
- st_gid: Group ID of owner
78
- st_atime: Access time
79
- st_mtime: Modification time
80
- st_ctime: Change time
81
"""
82
83
def readdir(self, path: str, fh: int) -> ReadDirResult:
84
"""
85
Read directory contents.
86
87
Args:
88
path: Directory path
89
fh: Directory file handle
90
91
Returns:
92
Iterable of directory entries. Each entry can be:
93
- str: Just the filename
94
- tuple[str, dict[str, int], int]: (name, stat_dict, offset)
95
- tuple[str, int, int]: (name, ino, offset)
96
"""
97
98
def readlink(self, path: str) -> str:
99
"""Read the target of a symbolic link."""
100
101
def mknod(self, path: str, mode: int, dev: int) -> int:
102
"""Create a file node (regular file, device special, or named pipe)."""
103
104
def mkdir(self, path: str, mode: int) -> int:
105
"""Create a directory."""
106
107
def unlink(self, path: str) -> int:
108
"""Remove a file."""
109
110
def rmdir(self, path: str) -> int:
111
"""Remove a directory."""
112
113
def symlink(self, target: str, source: str) -> int:
114
"""Create a symbolic link."""
115
116
def rename(self, old: str, new: str) -> int:
117
"""Rename a file or directory."""
118
119
def link(self, target: str, source: str) -> int:
120
"""Create a hard link."""
121
122
def chmod(self, path: str, mode: int) -> int:
123
"""Change file permissions."""
124
125
def chown(self, path: str, uid: int, gid: int) -> int:
126
"""Change file ownership."""
127
128
def truncate(self, path: str, length: int, fh: Optional[int] = None) -> int:
129
"""Truncate a file to a specified length."""
130
131
def utimens(self, path: str, times: Optional[tuple[int, int]] = None) -> int:
132
"""Update file timestamps."""
133
134
# File I/O Operations
135
def open(self, path: str, flags: int) -> int:
136
"""
137
Open a file.
138
139
Args:
140
path: File path
141
flags: Open flags (O_RDONLY, O_WRONLY, O_RDWR, etc.)
142
143
Returns:
144
File handle (integer)
145
"""
146
147
def read(self, path: str, size: int, offset: int, fh: int) -> bytes:
148
"""
149
Read data from a file.
150
151
Args:
152
path: File path
153
size: Number of bytes to read
154
offset: Offset in file to start reading
155
fh: File handle
156
157
Returns:
158
Bytes read from file
159
"""
160
161
def write(self, path: str, data, offset: int, fh: int) -> int:
162
"""
163
Write data to a file.
164
165
Args:
166
path: File path
167
data: Data to write (bytes)
168
offset: Offset in file to start writing
169
fh: File handle
170
171
Returns:
172
Number of bytes written
173
"""
174
175
def flush(self, path: str, fh: int) -> int:
176
"""Flush cached data to storage."""
177
178
def release(self, path: str, fh: int) -> int:
179
"""Release/close an open file."""
180
181
def fsync(self, path: str, datasync: int, fh: int) -> int:
182
"""Synchronize file contents."""
183
184
def create(self, path: str, mode: int, fi=None) -> int:
185
"""Create and open a new file atomically."""
186
187
# Directory Operations
188
def opendir(self, path: str) -> int:
189
"""Open a directory for reading."""
190
191
def releasedir(self, path: str, fh: int) -> int:
192
"""Release/close an open directory."""
193
194
def fsyncdir(self, path: str, datasync: int, fh: int) -> int:
195
"""Synchronize directory contents."""
196
197
# Extended Attributes
198
def setxattr(self, path: str, name: str, value: bytes, options, position=0) -> int:
199
"""Set an extended attribute."""
200
201
def getxattr(self, path: str, name: str, position=0) -> bytes:
202
"""Get an extended attribute."""
203
204
def listxattr(self, path: str) -> Iterable[str]:
205
"""List extended attributes."""
206
207
def removexattr(self, path: str, name: str) -> int:
208
"""Remove an extended attribute."""
209
210
# File System Operations
211
def statfs(self, path: str) -> dict[str, int]:
212
"""
213
Get filesystem statistics.
214
215
Returns:
216
Dictionary with filesystem statistics:
217
- f_bsize: Block size
218
- f_frsize: Fragment size
219
- f_blocks: Total blocks
220
- f_bfree: Free blocks
221
- f_bavail: Available blocks
222
- f_files: Total inodes
223
- f_ffree: Free inodes
224
- f_favail: Available inodes
225
"""
226
227
def access(self, path: str, amode: int) -> int:
228
"""Check file access permissions."""
229
230
# Lifecycle Operations
231
def init(self, path: str) -> None:
232
"""Initialize filesystem (called after mount)."""
233
234
def init_with_config(self, conn_info: Optional['fuse_conn_info'],
235
config_3: Optional['fuse_config']) -> None:
236
"""Initialize filesystem with FUSE 3.x configuration."""
237
238
def destroy(self, path: str) -> None:
239
"""Cleanup on unmount."""
240
241
# Advanced Operations
242
def bmap(self, path: str, blocksize: int, idx) -> int:
243
"""Map file block to device block."""
244
245
def ioctl(self, path: str, cmd: int, arg, fh: int, flags: int, data) -> int:
246
"""Device-specific I/O control."""
247
248
def lock(self, path: str, fh: int, cmd: int, lock) -> int:
249
"""POSIX file locking."""
250
251
def poll(self, path: str, fh: int, ph, reventsp) -> int:
252
"""Poll for I/O events."""
253
254
def write_buf(self, path: str, buf, offset: int, fh: int) -> int:
255
"""Write using buffer (FUSE 3.x optimization)."""
256
257
def read_buf(self, path: str, bufpp, size: int, offset: int, fh: int) -> int:
258
"""Read into buffer (FUSE 3.x optimization)."""
259
260
def flock(self, path: str, fh: int, op: int) -> int:
261
"""BSD file locking."""
262
263
def fallocate(self, path: str, mode: int, offset: int, size: int, fh: int) -> int:
264
"""Allocate file space."""
265
266
def copy_file_range(self, path_in: str, fh_in: int, offset_in: int,
267
path_out: str, fh_out: int, offset_out: int,
268
length: int, flags: int) -> int:
269
"""
270
Copy a range of data from one file to another (FUSE 3.x).
271
272
Args:
273
path_in: Source file path
274
fh_in: Source file handle
275
offset_in: Offset in source file
276
path_out: Destination file path
277
fh_out: Destination file handle
278
offset_out: Offset in destination file
279
length: Number of bytes to copy
280
flags: Copy operation flags
281
282
Returns:
283
Number of bytes copied
284
"""
285
286
def lseek(self, path: str, offset: int, whence: int, fh: int) -> int:
287
"""
288
Seek to a position in a file (FUSE 3.x).
289
290
Args:
291
path: File path
292
offset: Byte offset to seek to
293
whence: How to interpret offset (os.SEEK_SET, os.SEEK_CUR, os.SEEK_END)
294
fh: File handle
295
296
Returns:
297
New file position (absolute offset from beginning)
298
"""
299
```
300
301
#### FUSE 3.x Operations Example
302
303
```python
304
class ModernFS(Operations):
305
def copy_file_range(self, path_in, fh_in, offset_in,
306
path_out, fh_out, offset_out, length, flags):
307
"""Efficient file copying using copy_file_range."""
308
try:
309
# Read from source file
310
data = self._read_file_data(path_in, length, offset_in)
311
# Write to destination file
312
written = self._write_file_data(path_out, data, offset_out)
313
return written
314
except IOError:
315
raise FuseOSError(errno.EIO)
316
317
def lseek(self, path, offset, whence, fh):
318
"""Seek within a file."""
319
try:
320
file_obj = self.open_files[fh]
321
if whence == os.SEEK_SET:
322
new_pos = offset
323
elif whence == os.SEEK_CUR:
324
new_pos = file_obj.tell() + offset
325
elif whence == os.SEEK_END:
326
file_size = self._get_file_size(path)
327
new_pos = file_size + offset
328
else:
329
raise FuseOSError(errno.EINVAL)
330
331
return new_pos
332
except (KeyError, IOError):
333
raise FuseOSError(errno.EBADF)
334
```
335
336
#### Implementation Example
337
338
```python
339
import os
340
import errno
341
from mfusepy import Operations, FuseOSError
342
343
class PassthroughFS(Operations):
344
"""A passthrough filesystem that mirrors another directory."""
345
346
def __init__(self, root):
347
self.root = root
348
349
def _full_path(self, partial):
350
if partial.startswith("/"):
351
partial = partial[1:]
352
path = os.path.join(self.root, partial)
353
return path
354
355
def getattr(self, path, fh=None):
356
full_path = self._full_path(path)
357
try:
358
st = os.lstat(full_path)
359
return {
360
'st_mode': st.st_mode,
361
'st_nlink': st.st_nlink,
362
'st_size': st.st_size,
363
'st_uid': st.st_uid,
364
'st_gid': st.st_gid,
365
'st_atime': st.st_atime,
366
'st_mtime': st.st_mtime,
367
'st_ctime': st.st_ctime,
368
}
369
except OSError as e:
370
raise FuseOSError(e.errno)
371
372
def readdir(self, path, fh):
373
full_path = self._full_path(path)
374
try:
375
dirents = ['.', '..']
376
dirents.extend(os.listdir(full_path))
377
return dirents
378
except OSError as e:
379
raise FuseOSError(e.errno)
380
381
def read(self, path, length, offset, fh):
382
full_path = self._full_path(path)
383
try:
384
with open(full_path, 'rb') as f:
385
f.seek(offset)
386
return f.read(length)
387
except OSError as e:
388
raise FuseOSError(e.errno)
389
```
390
391
## C Structure Classes
392
393
These classes represent the C structures used by the FUSE library. They are primarily used internally but may be exposed when using raw_fi=True mode.
394
395
```python { .api }
396
class c_timespec(ctypes.Structure):
397
"""Time specification structure."""
398
399
class c_utimbuf(ctypes.Structure):
400
"""Time buffer structure for file timestamps."""
401
402
class c_stat(ctypes.Structure):
403
"""File status structure."""
404
405
class c_statvfs(ctypes.Structure):
406
"""File system statistics structure."""
407
408
class fuse_file_info(ctypes.Structure):
409
"""FUSE file information structure."""
410
411
class fuse_context(ctypes.Structure):
412
"""FUSE context information structure."""
413
414
class fuse_conn_info(ctypes.Structure):
415
"""FUSE connection information structure."""
416
417
class fuse_config(ctypes.Structure):
418
"""FUSE configuration structure."""
419
420
class fuse_buf(ctypes.Structure):
421
"""FUSE buffer structure."""
422
423
class fuse_bufvec(ctypes.Structure):
424
"""FUSE buffer vector structure."""
425
426
class fuse_operations(ctypes.Structure):
427
"""FUSE operations structure."""
428
429
class c_flock_t(ctypes.Structure):
430
"""File locking structure (platform-specific)."""
431
```
432
433
## Type Definitions
434
435
```python { .api }
436
from typing import Union, Iterable
437
import ctypes
438
439
FieldsEntry = Union[tuple[str, type], tuple[str, type, int]]
440
ReadDirResult = Iterable[Union[str, tuple[str, dict[str, int], int], tuple[str, int, int]]]
441
FuseConfigPointer = ctypes.POINTER(fuse_config)
442
FuseConnInfoPointer = ctypes.POINTER(fuse_conn_info)
443
```