0
# Extended Features
1
2
Advanced FUSE features including extended attributes, file locking, access control, filesystem statistics, and specialized operations for enhanced filesystem functionality.
3
4
## Capabilities
5
6
### Extended Attributes
7
8
Support for extended file attributes (xattrs) that provide additional metadata beyond standard POSIX attributes.
9
10
```python { .api }
11
def getxattr(self, path, name, size):
12
"""
13
Get extended attribute value.
14
15
Args:
16
path (str): Path to file or directory
17
name (str): Attribute name (e.g., 'user.comment')
18
size (int): Maximum size to return (0 = return size needed)
19
20
Returns:
21
bytes: Attribute value
22
int: Size needed (if size=0) or negative errno on error
23
"""
24
25
def setxattr(self, path, name, val, flags):
26
"""
27
Set extended attribute value.
28
29
Args:
30
path (str): Path to file or directory
31
name (str): Attribute name
32
val (bytes): Attribute value
33
flags (int): XATTR_CREATE, XATTR_REPLACE, or 0
34
35
Returns:
36
int: 0 on success, negative errno on error
37
"""
38
39
def listxattr(self, path, size):
40
"""
41
List extended attribute names.
42
43
Args:
44
path (str): Path to file or directory
45
size (int): Maximum size to return (0 = return size needed)
46
47
Returns:
48
bytes: Null-separated attribute names
49
int: Size needed (if size=0) or negative errno on error
50
"""
51
52
def removexattr(self, path, name):
53
"""
54
Remove extended attribute.
55
56
Args:
57
path (str): Path to file or directory
58
name (str): Attribute name to remove
59
60
Returns:
61
int: 0 on success, negative errno on error
62
"""
63
```
64
65
**Usage Example:**
66
67
```python
68
class MyFS(Fuse):
69
def __init__(self, *args, **kwargs):
70
super().__init__(*args, **kwargs)
71
self.xattrs = {} # {path: {name: value}}
72
73
def getxattr(self, path, name, size):
74
if path not in self.xattrs or name not in self.xattrs[path]:
75
return -errno.ENODATA
76
77
value = self.xattrs[path][name]
78
if size == 0:
79
return len(value) # Return size needed
80
81
return value[:size]
82
83
def setxattr(self, path, name, val, flags):
84
if path not in self.files and path not in self.dirs:
85
return -errno.ENOENT
86
87
if path not in self.xattrs:
88
self.xattrs[path] = {}
89
90
exists = name in self.xattrs[path]
91
92
if flags == XATTR_CREATE and exists:
93
return -errno.EEXIST
94
if flags == XATTR_REPLACE and not exists:
95
return -errno.ENODATA
96
97
self.xattrs[path][name] = val
98
return 0
99
100
def listxattr(self, path, size):
101
if path not in self.xattrs:
102
return b''
103
104
names = b'\0'.join(name.encode() for name in self.xattrs[path].keys())
105
if names:
106
names += b'\0' # Null-terminate the list
107
108
if size == 0:
109
return len(names)
110
111
return names[:size]
112
```
113
114
### File Locking
115
116
Advisory file locking operations for coordinating access between processes.
117
118
```python { .api }
119
def lock(self, path, fip, cmd, lock):
120
"""
121
File locking operations.
122
123
Args:
124
path (str): Path to file
125
fip: File info pointer (usually None)
126
cmd (int): Lock command (F_GETLK, F_SETLK, F_SETLKW)
127
lock (Flock): Lock specification
128
129
Returns:
130
int: 0 on success, negative errno on error
131
Flock: Lock information (for F_GETLK)
132
"""
133
```
134
135
**Usage Example:**
136
137
```python
138
import fcntl
139
140
class MyFS(Fuse):
141
def __init__(self, *args, **kwargs):
142
super().__init__(*args, **kwargs)
143
self.locks = {} # {path: [lock_info, ...]}
144
145
def lock(self, path, fip, cmd, lock):
146
if path not in self.files:
147
return -errno.ENOENT
148
149
if cmd == fcntl.F_GETLK:
150
# Check for conflicting locks
151
for existing_lock in self.locks.get(path, []):
152
if self.locks_conflict(lock, existing_lock):
153
return existing_lock
154
155
# No conflict - set type to F_UNLCK
156
result = fuse.Flock()
157
result.l_type = fcntl.F_UNLCK
158
return result
159
160
elif cmd == fcntl.F_SETLK:
161
# Non-blocking lock
162
if self.has_conflicting_lock(path, lock):
163
return -errno.EAGAIN
164
return self.set_lock(path, lock)
165
166
elif cmd == fcntl.F_SETLKW:
167
# Blocking lock (would block in real implementation)
168
return self.set_lock(path, lock)
169
170
def locks_conflict(self, lock1, lock2):
171
# Check if two locks conflict
172
if lock1.l_type == fcntl.F_UNLCK or lock2.l_type == fcntl.F_UNLCK:
173
return False
174
175
if lock1.l_type == fcntl.F_RDLCK and lock2.l_type == fcntl.F_RDLCK:
176
return False # Read locks don't conflict
177
178
# Check range overlap
179
return self.ranges_overlap(lock1, lock2)
180
```
181
182
### Access Control
183
184
Enhanced access permission checking beyond basic POSIX permissions.
185
186
```python { .api }
187
def access(self, path, mode):
188
"""
189
Check file access permissions.
190
191
Args:
192
path (str): Path to file or directory
193
mode (int): Access mode to check (R_OK, W_OK, X_OK, F_OK)
194
195
Returns:
196
int: 0 if access granted, negative errno on error
197
"""
198
```
199
200
**Usage Example:**
201
202
```python
203
import os
204
205
class MyFS(Fuse):
206
def access(self, path, mode):
207
if path not in self.files and path not in self.dirs:
208
return -errno.ENOENT
209
210
# Get current context
211
ctx = self.GetContext()
212
uid = ctx.get('uid', 0)
213
gid = ctx.get('gid', 0)
214
215
# Get file attributes
216
st = self.getattr(path)
217
218
# Check ownership and permissions
219
if uid == 0: # Root can access anything
220
return 0
221
222
# Check user permissions
223
if uid == st.st_uid:
224
user_perms = (st.st_mode >> 6) & 7
225
elif gid == st.st_gid:
226
user_perms = (st.st_mode >> 3) & 7
227
else:
228
user_perms = st.st_mode & 7
229
230
# Check requested access
231
if mode & os.R_OK and not (user_perms & 4):
232
return -errno.EACCES
233
if mode & os.W_OK and not (user_perms & 2):
234
return -errno.EACCES
235
if mode & os.X_OK and not (user_perms & 1):
236
return -errno.EACCES
237
238
return 0
239
```
240
241
### Context Information
242
243
Access information about the current FUSE request context.
244
245
```python { .api }
246
def GetContext(self):
247
"""
248
Get current request context.
249
250
Returns:
251
dict: Context information with keys:
252
- uid: User ID of calling process
253
- gid: Group ID of calling process
254
- pid: Process ID of calling process
255
"""
256
```
257
258
**Usage Example:**
259
260
```python
261
class MyFS(Fuse):
262
def create(self, path, mode, fi):
263
# Get context of calling process
264
ctx = self.GetContext()
265
266
# Set file ownership to calling user
267
st = fuse.Stat()
268
st.st_mode = mode
269
st.st_uid = ctx['uid']
270
st.st_gid = ctx['gid']
271
st.st_size = 0
272
273
# Create file with proper ownership
274
self.files[path] = b''
275
self.file_attrs[path] = st
276
277
return 0
278
```
279
280
### Cache Management
281
282
Control kernel caching behavior for performance optimization.
283
284
```python { .api }
285
def Invalidate(self, path):
286
"""
287
Invalidate cached entry.
288
289
Args:
290
path (str): Path to invalidate in kernel cache
291
292
Returns:
293
int: 0 on success, negative errno on error
294
"""
295
```
296
297
**Usage Example:**
298
299
```python
300
class MyFS(Fuse):
301
def write(self, path, buf, offset):
302
# Update file content
303
result = self.do_write(path, buf, offset)
304
305
# Invalidate cache since file changed
306
if result > 0:
307
self.Invalidate(path)
308
309
return result
310
311
def setxattr(self, path, name, val, flags):
312
result = self.do_setxattr(path, name, val, flags)
313
314
# Invalidate cache for attribute changes
315
if result == 0:
316
self.Invalidate(path)
317
318
return result
319
```
320
321
### I/O Control Operations
322
323
Handle filesystem-specific I/O control operations.
324
325
```python { .api }
326
def ioctl(self, path, cmd, arg, fip, flags, data):
327
"""
328
I/O control operations.
329
330
Args:
331
path (str): Path to file
332
cmd (int): I/O control command
333
arg: Command argument
334
fip: File info pointer
335
flags (int): FUSE I/O control flags
336
data: Input/output data
337
338
Returns:
339
int: 0 on success, negative errno on error
340
bytes: Output data for some operations
341
"""
342
```
343
344
**Usage Example:**
345
346
```python
347
# Define custom ioctl commands
348
MYFS_IOCTL_GET_INFO = 0x1000
349
MYFS_IOCTL_SET_FLAG = 0x1001
350
351
class MyFS(Fuse):
352
def ioctl(self, path, cmd, arg, fip, flags, data):
353
if path not in self.files:
354
return -errno.ENOENT
355
356
if cmd == MYFS_IOCTL_GET_INFO:
357
# Return file information
358
info = {
359
'size': len(self.files[path]),
360
'created': self.file_created[path]
361
}
362
return json.dumps(info).encode()
363
364
elif cmd == MYFS_IOCTL_SET_FLAG:
365
# Set filesystem-specific flag
366
flag_value = struct.unpack('I', data)[0]
367
self.file_flags[path] = flag_value
368
return 0
369
370
else:
371
return -errno.ENOTTY # Inappropriate ioctl
372
```
373
374
### Poll Support
375
376
Support for poll/select operations on files.
377
378
```python { .api }
379
def poll(self, path, fip, ph, reventsp):
380
"""
381
Poll file for events.
382
383
Args:
384
path (str): Path to file
385
fip: File info pointer
386
ph: Poll handle for notifications
387
reventsp: Pointer to returned events
388
389
Returns:
390
int: 0 on success, negative errno on error
391
"""
392
393
def NotifyPoll(self, ph):
394
"""
395
Notify poll completion.
396
397
Args:
398
ph: Poll handle from poll() call
399
"""
400
```
401
402
### Filesystem Lifecycle
403
404
Handle filesystem initialization and cleanup.
405
406
```python { .api }
407
def fsinit(self):
408
"""
409
Initialize filesystem.
410
411
Called when filesystem is mounted.
412
413
Returns:
414
int: 0 on success, negative errno on error
415
"""
416
417
def fsdestroy(self):
418
"""
419
Clean up filesystem.
420
421
Called when filesystem is unmounted.
422
"""
423
```
424
425
**Usage Example:**
426
427
```python
428
class MyFS(Fuse):
429
def fsinit(self):
430
"""Initialize filesystem resources."""
431
print("Filesystem mounting...")
432
433
# Initialize data structures
434
self.files = {}
435
self.dirs = {'/': {}}
436
self.xattrs = {}
437
438
# Load persistent data if needed
439
self.load_filesystem_state()
440
441
return 0
442
443
def fsdestroy(self):
444
"""Clean up filesystem resources."""
445
print("Filesystem unmounting...")
446
447
# Save persistent data
448
self.save_filesystem_state()
449
450
# Clean up resources
451
self.cleanup_resources()
452
```
453
454
## Error Handling
455
456
Extended features may raise specialized exceptions:
457
458
```python { .api }
459
class FuseError(Exception):
460
"""
461
FUSE-specific error.
462
463
Raised by feature checking functions and other FUSE operations
464
when the underlying FUSE library doesn't support a feature or
465
when a FUSE-specific error occurs.
466
"""
467
```
468
469
**Usage Example:**
470
471
```python
472
try:
473
# Check if FUSE library supports extended attributes
474
fuse.feature_assert('has_getxattr', 'has_setxattr')
475
476
# Enable extended attribute support
477
self.supports_xattrs = True
478
479
except fuse.FuseError as e:
480
print(f"Extended attributes not supported: {e}")
481
self.supports_xattrs = False
482
483
def getxattr(self, path, name, size):
484
if not self.supports_xattrs:
485
return -errno.ENOTSUP
486
487
# Implementation here...
488
```
489
490
## Best Practices
491
492
- Implement extended attributes for applications that rely on them
493
- Use file locking for multi-process coordination when needed
494
- Implement proper access control based on process context
495
- Use cache invalidation judiciously to balance performance and consistency
496
- Handle ioctl operations for filesystem-specific functionality
497
- Provide meaningful poll support for applications that need it
498
- Initialize and clean up resources properly in fsinit/fsdestroy
499
- Test extended features with real applications that use them
500
- Use feature checking functions to verify FUSE library capabilities
501
- Handle FuseError exceptions gracefully for unsupported features