1
|
|
-# This is an embedded copy of fuse.py taken from the following upstream commit:
|
2
|
|
-#
|
3
|
|
-# https://github.com/terencehonles/fusepy/commit/0eafeb557e0e70926ed9450008ef17057d302391
|
4
|
|
-#
|
5
|
|
-# Our local modifications are recorded in the Git history of this repo.
|
6
|
|
-
|
7
|
|
-# Copyright (c) 2012 Terence Honles <terence honles com> (maintainer)
|
8
|
|
-# Copyright (c) 2008 Giorgos Verigakis <verigak gmail com> (author)
|
9
|
|
-#
|
10
|
|
-# Permission to use, copy, modify, and distribute this software for any
|
11
|
|
-# purpose with or without fee is hereby granted, provided that the above
|
12
|
|
-# copyright notice and this permission notice appear in all copies.
|
13
|
|
-#
|
14
|
|
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
15
|
|
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
16
|
|
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
17
|
|
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
18
|
|
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
19
|
|
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
20
|
|
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
21
|
|
-
|
22
|
|
-# pylint: skip-file
|
23
|
|
-
|
24
|
|
-from __future__ import print_function, absolute_import, division
|
25
|
|
-
|
26
|
|
-from ctypes import *
|
27
|
|
-from ctypes.util import find_library
|
28
|
|
-from errno import *
|
29
|
|
-from os import strerror
|
30
|
|
-from platform import machine, system
|
31
|
|
-from signal import signal, SIGINT, SIG_DFL
|
32
|
|
-from stat import S_IFDIR
|
33
|
|
-from traceback import print_exc
|
34
|
|
-
|
35
|
|
-import logging
|
36
|
|
-
|
37
|
|
-try:
|
38
|
|
- from functools import partial
|
39
|
|
-except ImportError:
|
40
|
|
- # http://docs.python.org/library/functools.html#functools.partial
|
41
|
|
- def partial(func, *args, **keywords):
|
42
|
|
- def newfunc(*fargs, **fkeywords):
|
43
|
|
- newkeywords = keywords.copy()
|
44
|
|
- newkeywords.update(fkeywords)
|
45
|
|
- return func(*(args + fargs), **newkeywords)
|
46
|
|
-
|
47
|
|
- newfunc.func = func
|
48
|
|
- newfunc.args = args
|
49
|
|
- newfunc.keywords = keywords
|
50
|
|
- return newfunc
|
51
|
|
-
|
52
|
|
-try:
|
53
|
|
- basestring
|
54
|
|
-except NameError:
|
55
|
|
- basestring = str
|
56
|
|
-
|
57
|
|
-class c_timespec(Structure):
|
58
|
|
- _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
|
59
|
|
-
|
60
|
|
-class c_utimbuf(Structure):
|
61
|
|
- _fields_ = [('actime', c_timespec), ('modtime', c_timespec)]
|
62
|
|
-
|
63
|
|
-class c_stat(Structure):
|
64
|
|
- pass # Platform dependent
|
65
|
|
-
|
66
|
|
-_system = system()
|
67
|
|
-_machine = machine()
|
68
|
|
-
|
69
|
|
-if _system == 'Darwin':
|
70
|
|
- _libiconv = CDLL(find_library('iconv'), RTLD_GLOBAL) # libfuse dependency
|
71
|
|
- _libfuse_path = (find_library('fuse4x') or find_library('osxfuse') or
|
72
|
|
- find_library('fuse'))
|
73
|
|
-else:
|
74
|
|
- _libfuse_path = find_library('fuse')
|
75
|
|
-
|
76
|
|
-if not _libfuse_path:
|
77
|
|
- raise EnvironmentError('Unable to find libfuse')
|
78
|
|
-else:
|
79
|
|
- _libfuse = CDLL(_libfuse_path)
|
80
|
|
-
|
81
|
|
-if _system == 'Darwin' and hasattr(_libfuse, 'macfuse_version'):
|
82
|
|
- _system = 'Darwin-MacFuse'
|
83
|
|
-
|
84
|
|
-
|
85
|
|
-if _system in ('Darwin', 'Darwin-MacFuse', 'FreeBSD'):
|
86
|
|
- ENOTSUP = 45
|
87
|
|
- c_dev_t = c_int32
|
88
|
|
- c_fsblkcnt_t = c_ulong
|
89
|
|
- c_fsfilcnt_t = c_ulong
|
90
|
|
- c_gid_t = c_uint32
|
91
|
|
- c_mode_t = c_uint16
|
92
|
|
- c_off_t = c_int64
|
93
|
|
- c_pid_t = c_int32
|
94
|
|
- c_uid_t = c_uint32
|
95
|
|
- setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
96
|
|
- c_size_t, c_int, c_uint32)
|
97
|
|
- getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
98
|
|
- c_size_t, c_uint32)
|
99
|
|
- if _system == 'Darwin':
|
100
|
|
- c_stat._fields_ = [
|
101
|
|
- ('st_dev', c_dev_t),
|
102
|
|
- ('st_mode', c_mode_t),
|
103
|
|
- ('st_nlink', c_uint16),
|
104
|
|
- ('st_ino', c_uint64),
|
105
|
|
- ('st_uid', c_uid_t),
|
106
|
|
- ('st_gid', c_gid_t),
|
107
|
|
- ('st_rdev', c_dev_t),
|
108
|
|
- ('st_atimespec', c_timespec),
|
109
|
|
- ('st_mtimespec', c_timespec),
|
110
|
|
- ('st_ctimespec', c_timespec),
|
111
|
|
- ('st_birthtimespec', c_timespec),
|
112
|
|
- ('st_size', c_off_t),
|
113
|
|
- ('st_blocks', c_int64),
|
114
|
|
- ('st_blksize', c_int32),
|
115
|
|
- ('st_flags', c_int32),
|
116
|
|
- ('st_gen', c_int32),
|
117
|
|
- ('st_lspare', c_int32),
|
118
|
|
- ('st_qspare', c_int64)]
|
119
|
|
- else:
|
120
|
|
- c_stat._fields_ = [
|
121
|
|
- ('st_dev', c_dev_t),
|
122
|
|
- ('st_ino', c_uint32),
|
123
|
|
- ('st_mode', c_mode_t),
|
124
|
|
- ('st_nlink', c_uint16),
|
125
|
|
- ('st_uid', c_uid_t),
|
126
|
|
- ('st_gid', c_gid_t),
|
127
|
|
- ('st_rdev', c_dev_t),
|
128
|
|
- ('st_atimespec', c_timespec),
|
129
|
|
- ('st_mtimespec', c_timespec),
|
130
|
|
- ('st_ctimespec', c_timespec),
|
131
|
|
- ('st_size', c_off_t),
|
132
|
|
- ('st_blocks', c_int64),
|
133
|
|
- ('st_blksize', c_int32)]
|
134
|
|
-elif _system == 'Linux':
|
135
|
|
- ENOTSUP = 95
|
136
|
|
- c_dev_t = c_ulonglong
|
137
|
|
- c_fsblkcnt_t = c_ulonglong
|
138
|
|
- c_fsfilcnt_t = c_ulonglong
|
139
|
|
- c_gid_t = c_uint
|
140
|
|
- c_mode_t = c_uint
|
141
|
|
- c_off_t = c_longlong
|
142
|
|
- c_pid_t = c_int
|
143
|
|
- c_uid_t = c_uint
|
144
|
|
- setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
145
|
|
- c_size_t, c_int)
|
146
|
|
-
|
147
|
|
- getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
148
|
|
- c_size_t)
|
149
|
|
-
|
150
|
|
- if _machine == 'x86_64':
|
151
|
|
- c_stat._fields_ = [
|
152
|
|
- ('st_dev', c_dev_t),
|
153
|
|
- ('st_ino', c_ulong),
|
154
|
|
- ('st_nlink', c_ulong),
|
155
|
|
- ('st_mode', c_mode_t),
|
156
|
|
- ('st_uid', c_uid_t),
|
157
|
|
- ('st_gid', c_gid_t),
|
158
|
|
- ('__pad0', c_int),
|
159
|
|
- ('st_rdev', c_dev_t),
|
160
|
|
- ('st_size', c_off_t),
|
161
|
|
- ('st_blksize', c_long),
|
162
|
|
- ('st_blocks', c_long),
|
163
|
|
- ('st_atimespec', c_timespec),
|
164
|
|
- ('st_mtimespec', c_timespec),
|
165
|
|
- ('st_ctimespec', c_timespec)]
|
166
|
|
- elif _machine == 'mips':
|
167
|
|
- c_stat._fields_ = [
|
168
|
|
- ('st_dev', c_dev_t),
|
169
|
|
- ('__pad1_1', c_ulong),
|
170
|
|
- ('__pad1_2', c_ulong),
|
171
|
|
- ('__pad1_3', c_ulong),
|
172
|
|
- ('st_ino', c_ulong),
|
173
|
|
- ('st_mode', c_mode_t),
|
174
|
|
- ('st_nlink', c_ulong),
|
175
|
|
- ('st_uid', c_uid_t),
|
176
|
|
- ('st_gid', c_gid_t),
|
177
|
|
- ('st_rdev', c_dev_t),
|
178
|
|
- ('__pad2_1', c_ulong),
|
179
|
|
- ('__pad2_2', c_ulong),
|
180
|
|
- ('st_size', c_off_t),
|
181
|
|
- ('__pad3', c_ulong),
|
182
|
|
- ('st_atimespec', c_timespec),
|
183
|
|
- ('__pad4', c_ulong),
|
184
|
|
- ('st_mtimespec', c_timespec),
|
185
|
|
- ('__pad5', c_ulong),
|
186
|
|
- ('st_ctimespec', c_timespec),
|
187
|
|
- ('__pad6', c_ulong),
|
188
|
|
- ('st_blksize', c_long),
|
189
|
|
- ('st_blocks', c_long),
|
190
|
|
- ('__pad7_1', c_ulong),
|
191
|
|
- ('__pad7_2', c_ulong),
|
192
|
|
- ('__pad7_3', c_ulong),
|
193
|
|
- ('__pad7_4', c_ulong),
|
194
|
|
- ('__pad7_5', c_ulong),
|
195
|
|
- ('__pad7_6', c_ulong),
|
196
|
|
- ('__pad7_7', c_ulong),
|
197
|
|
- ('__pad7_8', c_ulong),
|
198
|
|
- ('__pad7_9', c_ulong),
|
199
|
|
- ('__pad7_10', c_ulong),
|
200
|
|
- ('__pad7_11', c_ulong),
|
201
|
|
- ('__pad7_12', c_ulong),
|
202
|
|
- ('__pad7_13', c_ulong),
|
203
|
|
- ('__pad7_14', c_ulong)]
|
204
|
|
- elif _machine == 'ppc':
|
205
|
|
- c_stat._fields_ = [
|
206
|
|
- ('st_dev', c_dev_t),
|
207
|
|
- ('st_ino', c_ulonglong),
|
208
|
|
- ('st_mode', c_mode_t),
|
209
|
|
- ('st_nlink', c_uint),
|
210
|
|
- ('st_uid', c_uid_t),
|
211
|
|
- ('st_gid', c_gid_t),
|
212
|
|
- ('st_rdev', c_dev_t),
|
213
|
|
- ('__pad2', c_ushort),
|
214
|
|
- ('st_size', c_off_t),
|
215
|
|
- ('st_blksize', c_long),
|
216
|
|
- ('st_blocks', c_longlong),
|
217
|
|
- ('st_atimespec', c_timespec),
|
218
|
|
- ('st_mtimespec', c_timespec),
|
219
|
|
- ('st_ctimespec', c_timespec)]
|
220
|
|
- elif _machine == 'ppc64' or _machine == 'ppc64le':
|
221
|
|
- c_stat._fields_ = [
|
222
|
|
- ('st_dev', c_dev_t),
|
223
|
|
- ('st_ino', c_ulong),
|
224
|
|
- ('st_nlink', c_ulong),
|
225
|
|
- ('st_mode', c_mode_t),
|
226
|
|
- ('st_uid', c_uid_t),
|
227
|
|
- ('st_gid', c_gid_t),
|
228
|
|
- ('__pad', c_uint),
|
229
|
|
- ('st_rdev', c_dev_t),
|
230
|
|
- ('st_size', c_off_t),
|
231
|
|
- ('st_blksize', c_long),
|
232
|
|
- ('st_blocks', c_long),
|
233
|
|
- ('st_atimespec', c_timespec),
|
234
|
|
- ('st_mtimespec', c_timespec),
|
235
|
|
- ('st_ctimespec', c_timespec)]
|
236
|
|
- elif _machine == 'aarch64':
|
237
|
|
- c_stat._fields_ = [
|
238
|
|
- ('st_dev', c_dev_t),
|
239
|
|
- ('st_ino', c_ulong),
|
240
|
|
- ('st_mode', c_mode_t),
|
241
|
|
- ('st_nlink', c_uint),
|
242
|
|
- ('st_uid', c_uid_t),
|
243
|
|
- ('st_gid', c_gid_t),
|
244
|
|
- ('st_rdev', c_dev_t),
|
245
|
|
- ('__pad1', c_ulong),
|
246
|
|
- ('st_size', c_off_t),
|
247
|
|
- ('st_blksize', c_int),
|
248
|
|
- ('__pad2', c_int),
|
249
|
|
- ('st_blocks', c_long),
|
250
|
|
- ('st_atimespec', c_timespec),
|
251
|
|
- ('st_mtimespec', c_timespec),
|
252
|
|
- ('st_ctimespec', c_timespec)]
|
253
|
|
- else:
|
254
|
|
- # i686, use as fallback for everything else
|
255
|
|
- c_stat._fields_ = [
|
256
|
|
- ('st_dev', c_dev_t),
|
257
|
|
- ('__pad1', c_ushort),
|
258
|
|
- ('__st_ino', c_ulong),
|
259
|
|
- ('st_mode', c_mode_t),
|
260
|
|
- ('st_nlink', c_uint),
|
261
|
|
- ('st_uid', c_uid_t),
|
262
|
|
- ('st_gid', c_gid_t),
|
263
|
|
- ('st_rdev', c_dev_t),
|
264
|
|
- ('__pad2', c_ushort),
|
265
|
|
- ('st_size', c_off_t),
|
266
|
|
- ('st_blksize', c_long),
|
267
|
|
- ('st_blocks', c_longlong),
|
268
|
|
- ('st_atimespec', c_timespec),
|
269
|
|
- ('st_mtimespec', c_timespec),
|
270
|
|
- ('st_ctimespec', c_timespec),
|
271
|
|
- ('st_ino', c_ulonglong)]
|
272
|
|
-else:
|
273
|
|
- raise NotImplementedError('{} is not supported.'.format(_system))
|
274
|
|
-
|
275
|
|
-
|
276
|
|
-class c_statvfs(Structure):
|
277
|
|
- _fields_ = [
|
278
|
|
- ('f_bsize', c_ulong),
|
279
|
|
- ('f_frsize', c_ulong),
|
280
|
|
- ('f_blocks', c_fsblkcnt_t),
|
281
|
|
- ('f_bfree', c_fsblkcnt_t),
|
282
|
|
- ('f_bavail', c_fsblkcnt_t),
|
283
|
|
- ('f_files', c_fsfilcnt_t),
|
284
|
|
- ('f_ffree', c_fsfilcnt_t),
|
285
|
|
- ('f_favail', c_fsfilcnt_t),
|
286
|
|
- ('f_fsid', c_ulong),
|
287
|
|
- #('unused', c_int),
|
288
|
|
- ('f_flag', c_ulong),
|
289
|
|
- ('f_namemax', c_ulong)]
|
290
|
|
-
|
291
|
|
-if _system == 'FreeBSD':
|
292
|
|
- c_fsblkcnt_t = c_uint64
|
293
|
|
- c_fsfilcnt_t = c_uint64
|
294
|
|
- setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
295
|
|
- c_size_t, c_int)
|
296
|
|
-
|
297
|
|
- getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
|
298
|
|
- c_size_t)
|
299
|
|
-
|
300
|
|
- class c_statvfs(Structure):
|
301
|
|
- _fields_ = [
|
302
|
|
- ('f_bavail', c_fsblkcnt_t),
|
303
|
|
- ('f_bfree', c_fsblkcnt_t),
|
304
|
|
- ('f_blocks', c_fsblkcnt_t),
|
305
|
|
- ('f_favail', c_fsfilcnt_t),
|
306
|
|
- ('f_ffree', c_fsfilcnt_t),
|
307
|
|
- ('f_files', c_fsfilcnt_t),
|
308
|
|
- ('f_bsize', c_ulong),
|
309
|
|
- ('f_flag', c_ulong),
|
310
|
|
- ('f_frsize', c_ulong)]
|
311
|
|
-
|
312
|
|
-class fuse_file_info(Structure):
|
313
|
|
- _fields_ = [
|
314
|
|
- ('flags', c_int),
|
315
|
|
- ('fh_old', c_ulong),
|
316
|
|
- ('writepage', c_int),
|
317
|
|
- ('direct_io', c_uint, 1),
|
318
|
|
- ('keep_cache', c_uint, 1),
|
319
|
|
- ('flush', c_uint, 1),
|
320
|
|
- ('padding', c_uint, 29),
|
321
|
|
- ('fh', c_uint64),
|
322
|
|
- ('lock_owner', c_uint64)]
|
323
|
|
-
|
324
|
|
-class fuse_context(Structure):
|
325
|
|
- _fields_ = [
|
326
|
|
- ('fuse', c_voidp),
|
327
|
|
- ('uid', c_uid_t),
|
328
|
|
- ('gid', c_gid_t),
|
329
|
|
- ('pid', c_pid_t),
|
330
|
|
- ('private_data', c_voidp)]
|
331
|
|
-
|
332
|
|
-_libfuse.fuse_get_context.restype = POINTER(fuse_context)
|
333
|
|
-
|
334
|
|
-
|
335
|
|
-class fuse_operations(Structure):
|
336
|
|
- _fields_ = [
|
337
|
|
- ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))),
|
338
|
|
- ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
|
339
|
|
- ('getdir', c_voidp), # Deprecated, use readdir
|
340
|
|
- ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)),
|
341
|
|
- ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
|
342
|
|
- ('unlink', CFUNCTYPE(c_int, c_char_p)),
|
343
|
|
- ('rmdir', CFUNCTYPE(c_int, c_char_p)),
|
344
|
|
- ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)),
|
345
|
|
- ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)),
|
346
|
|
- ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)),
|
347
|
|
- ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
|
348
|
|
- ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)),
|
349
|
|
- ('truncate', CFUNCTYPE(c_int, c_char_p, c_off_t)),
|
350
|
|
- ('utime', c_voidp), # Deprecated, use utimens
|
351
|
|
- ('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
|
352
|
|
-
|
353
|
|
- ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
|
354
|
|
- c_off_t, POINTER(fuse_file_info))),
|
355
|
|
-
|
356
|
|
- ('write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
|
357
|
|
- c_off_t, POINTER(fuse_file_info))),
|
358
|
|
-
|
359
|
|
- ('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))),
|
360
|
|
- ('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
|
361
|
|
- ('release', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
|
362
|
|
- ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
|
363
|
|
- ('setxattr', setxattr_t),
|
364
|
|
- ('getxattr', getxattr_t),
|
365
|
|
- ('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
|
366
|
|
- ('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)),
|
367
|
|
- ('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
|
368
|
|
-
|
369
|
|
- ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp,
|
370
|
|
- CFUNCTYPE(c_int, c_voidp, c_char_p,
|
371
|
|
- POINTER(c_stat), c_off_t),
|
372
|
|
- c_off_t, POINTER(fuse_file_info))),
|
373
|
|
-
|
374
|
|
- ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
|
375
|
|
-
|
376
|
|
- ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int,
|
377
|
|
- POINTER(fuse_file_info))),
|
378
|
|
-
|
379
|
|
- ('init', CFUNCTYPE(c_voidp, c_voidp)),
|
380
|
|
- ('destroy', CFUNCTYPE(c_voidp, c_voidp)),
|
381
|
|
- ('access', CFUNCTYPE(c_int, c_char_p, c_int)),
|
382
|
|
-
|
383
|
|
- ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t,
|
384
|
|
- POINTER(fuse_file_info))),
|
385
|
|
-
|
386
|
|
- ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t,
|
387
|
|
- POINTER(fuse_file_info))),
|
388
|
|
-
|
389
|
|
- ('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat),
|
390
|
|
- POINTER(fuse_file_info))),
|
391
|
|
-
|
392
|
|
- ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info),
|
393
|
|
- c_int, c_voidp)),
|
394
|
|
-
|
395
|
|
- ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))),
|
396
|
|
- ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong))),
|
397
|
|
- ('flag_nullpath_ok', c_uint, 1),
|
398
|
|
- ('flag_nopath', c_uint, 1),
|
399
|
|
- ('flag_utime_omit_ok', c_uint, 1),
|
400
|
|
- ('flag_reserved', c_uint, 29),
|
401
|
|
- ]
|
402
|
|
-
|
403
|
|
-
|
404
|
|
-def time_of_timespec(ts):
|
405
|
|
- return ts.tv_sec + ts.tv_nsec / 10 ** 9
|
406
|
|
-
|
407
|
|
-def set_st_attrs(st, attrs):
|
408
|
|
- for key, val in attrs.items():
|
409
|
|
- if key in ('st_atime', 'st_mtime', 'st_ctime', 'st_birthtime'):
|
410
|
|
- timespec = getattr(st, key + 'spec', None)
|
411
|
|
- if timespec is None:
|
412
|
|
- continue
|
413
|
|
- timespec.tv_sec = int(val)
|
414
|
|
- timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9)
|
415
|
|
- elif hasattr(st, key):
|
416
|
|
- setattr(st, key, val)
|
417
|
|
-
|
418
|
|
-
|
419
|
|
-def fuse_get_context():
|
420
|
|
- 'Returns a (uid, gid, pid) tuple'
|
421
|
|
-
|
422
|
|
- ctxp = _libfuse.fuse_get_context()
|
423
|
|
- ctx = ctxp.contents
|
424
|
|
- return ctx.uid, ctx.gid, ctx.pid
|
425
|
|
-
|
426
|
|
-
|
427
|
|
-class FuseOSError(OSError):
|
428
|
|
- def __init__(self, errno):
|
429
|
|
- super(FuseOSError, self).__init__(errno, strerror(errno))
|
430
|
|
-
|
431
|
|
-
|
432
|
|
-class FUSE(object):
|
433
|
|
- '''
|
434
|
|
- This class is the lower level interface and should not be subclassed under
|
435
|
|
- normal use. Its methods are called by fuse.
|
436
|
|
-
|
437
|
|
- Assumes API version 2.6 or later.
|
438
|
|
- '''
|
439
|
|
-
|
440
|
|
- OPTIONS = (
|
441
|
|
- ('foreground', '-f'),
|
442
|
|
- ('debug', '-d'),
|
443
|
|
- ('nothreads', '-s'),
|
444
|
|
- )
|
445
|
|
-
|
446
|
|
- def __init__(self, operations, mountpoint, raw_fi=False, encoding='utf-8',
|
447
|
|
- **kwargs):
|
448
|
|
-
|
449
|
|
- '''
|
450
|
|
- Setting raw_fi to True will cause FUSE to pass the fuse_file_info
|
451
|
|
- class as is to Operations, instead of just the fh field.
|
452
|
|
-
|
453
|
|
- This gives you access to direct_io, keep_cache, etc.
|
454
|
|
- '''
|
455
|
|
-
|
456
|
|
- self.operations = operations
|
457
|
|
- self.raw_fi = raw_fi
|
458
|
|
- self.encoding = encoding
|
459
|
|
-
|
460
|
|
- args = ['fuse']
|
461
|
|
-
|
462
|
|
- args.extend(flag for arg, flag in self.OPTIONS
|
463
|
|
- if kwargs.pop(arg, False))
|
464
|
|
-
|
465
|
|
- kwargs.setdefault('fsname', operations.__class__.__name__)
|
466
|
|
- args.append('-o')
|
467
|
|
- args.append(','.join(self._normalize_fuse_options(**kwargs)))
|
468
|
|
- args.append(mountpoint)
|
469
|
|
-
|
470
|
|
- args = [arg.encode(encoding) for arg in args]
|
471
|
|
- argv = (c_char_p * len(args))(*args)
|
472
|
|
-
|
473
|
|
- fuse_ops = fuse_operations()
|
474
|
|
- for ent in fuse_operations._fields_:
|
475
|
|
- name, prototype = ent[:2]
|
476
|
|
-
|
477
|
|
- val = getattr(operations, name, None)
|
478
|
|
- if val is None:
|
479
|
|
- continue
|
480
|
|
-
|
481
|
|
- # Function pointer members are tested for using the
|
482
|
|
- # getattr(operations, name) above but are dynamically
|
483
|
|
- # invoked using self.operations(name)
|
484
|
|
- if hasattr(prototype, 'argtypes'):
|
485
|
|
- val = prototype(partial(self._wrapper, getattr(self, name)))
|
486
|
|
-
|
487
|
|
- setattr(fuse_ops, name, val)
|
488
|
|
-
|
489
|
|
- try:
|
490
|
|
- old_handler = signal(SIGINT, SIG_DFL)
|
491
|
|
- except ValueError:
|
492
|
|
- old_handler = SIG_DFL
|
493
|
|
-
|
494
|
|
- err = _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops),
|
495
|
|
- sizeof(fuse_ops), None)
|
496
|
|
-
|
497
|
|
- try:
|
498
|
|
- signal(SIGINT, old_handler)
|
499
|
|
- except ValueError:
|
500
|
|
- pass
|
501
|
|
-
|
502
|
|
- del self.operations # Invoke the destructor
|
503
|
|
- if err:
|
504
|
|
- raise RuntimeError(err)
|
505
|
|
-
|
506
|
|
- @staticmethod
|
507
|
|
- def _normalize_fuse_options(**kargs):
|
508
|
|
- for key, value in kargs.items():
|
509
|
|
- if isinstance(value, bool):
|
510
|
|
- if value is True: yield key
|
511
|
|
- else:
|
512
|
|
- yield '{}={}'.format(key, value)
|
513
|
|
-
|
514
|
|
- @staticmethod
|
515
|
|
- def _wrapper(func, *args, **kwargs):
|
516
|
|
- 'Decorator for the methods that follow'
|
517
|
|
-
|
518
|
|
- try:
|
519
|
|
- return func(*args, **kwargs) or 0
|
520
|
|
- except OSError as e:
|
521
|
|
- return -(e.errno or EFAULT)
|
522
|
|
- except:
|
523
|
|
- print_exc()
|
524
|
|
- return -EFAULT
|
525
|
|
-
|
526
|
|
- def _decode_optional_path(self, path):
|
527
|
|
- # NB: this method is intended for fuse operations that
|
528
|
|
- # allow the path argument to be NULL,
|
529
|
|
- # *not* as a generic path decoding method
|
530
|
|
- if path is None:
|
531
|
|
- return None
|
532
|
|
- return path.decode(self.encoding)
|
533
|
|
-
|
534
|
|
- def getattr(self, path, buf):
|
535
|
|
- return self.fgetattr(path, buf, None)
|
536
|
|
-
|
537
|
|
- def readlink(self, path, buf, bufsize):
|
538
|
|
- ret = self.operations('readlink', path.decode(self.encoding)) \
|
539
|
|
- .encode(self.encoding)
|
540
|
|
-
|
541
|
|
- # copies a string into the given buffer
|
542
|
|
- # (null terminated and truncated if necessary)
|
543
|
|
- data = create_string_buffer(ret[:bufsize - 1])
|
544
|
|
- memmove(buf, data, len(data))
|
545
|
|
- return 0
|
546
|
|
-
|
547
|
|
- def mknod(self, path, mode, dev):
|
548
|
|
- return self.operations('mknod', path.decode(self.encoding), mode, dev)
|
549
|
|
-
|
550
|
|
- def mkdir(self, path, mode):
|
551
|
|
- return self.operations('mkdir', path.decode(self.encoding), mode)
|
552
|
|
-
|
553
|
|
- def unlink(self, path):
|
554
|
|
- return self.operations('unlink', path.decode(self.encoding))
|
555
|
|
-
|
556
|
|
- def rmdir(self, path):
|
557
|
|
- return self.operations('rmdir', path.decode(self.encoding))
|
558
|
|
-
|
559
|
|
- def symlink(self, source, target):
|
560
|
|
- 'creates a symlink `target -> source` (e.g. ln -s source target)'
|
561
|
|
-
|
562
|
|
- return self.operations('symlink', target.decode(self.encoding),
|
563
|
|
- source.decode(self.encoding))
|
564
|
|
-
|
565
|
|
- def rename(self, old, new):
|
566
|
|
- return self.operations('rename', old.decode(self.encoding),
|
567
|
|
- new.decode(self.encoding))
|
568
|
|
-
|
569
|
|
- def link(self, source, target):
|
570
|
|
- 'creates a hard link `target -> source` (e.g. ln source target)'
|
571
|
|
-
|
572
|
|
- return self.operations('link', target.decode(self.encoding),
|
573
|
|
- source.decode(self.encoding))
|
574
|
|
-
|
575
|
|
- def chmod(self, path, mode):
|
576
|
|
- return self.operations('chmod', path.decode(self.encoding), mode)
|
577
|
|
-
|
578
|
|
- def chown(self, path, uid, gid):
|
579
|
|
- # Check if any of the arguments is a -1 that has overflowed
|
580
|
|
- if c_uid_t(uid + 1).value == 0:
|
581
|
|
- uid = -1
|
582
|
|
- if c_gid_t(gid + 1).value == 0:
|
583
|
|
- gid = -1
|
584
|
|
-
|
585
|
|
- return self.operations('chown', path.decode(self.encoding), uid, gid)
|
586
|
|
-
|
587
|
|
- def truncate(self, path, length):
|
588
|
|
- return self.operations('truncate', path.decode(self.encoding), length)
|
589
|
|
-
|
590
|
|
- def open(self, path, fip):
|
591
|
|
- fi = fip.contents
|
592
|
|
- if self.raw_fi:
|
593
|
|
- return self.operations('open', path.decode(self.encoding), fi)
|
594
|
|
- else:
|
595
|
|
- fi.fh = self.operations('open', path.decode(self.encoding),
|
596
|
|
- fi.flags)
|
597
|
|
-
|
598
|
|
- return 0
|
599
|
|
-
|
600
|
|
- def read(self, path, buf, size, offset, fip):
|
601
|
|
- if self.raw_fi:
|
602
|
|
- fh = fip.contents
|
603
|
|
- else:
|
604
|
|
- fh = fip.contents.fh
|
605
|
|
-
|
606
|
|
- ret = self.operations('read', self._decode_optional_path(path), size,
|
607
|
|
- offset, fh)
|
608
|
|
-
|
609
|
|
- if not ret: return 0
|
610
|
|
-
|
611
|
|
- retsize = len(ret)
|
612
|
|
- assert retsize <= size, \
|
613
|
|
- 'actual amount read {:d} greater than expected {:d}'.format(retsize, size)
|
614
|
|
-
|
615
|
|
- data = create_string_buffer(ret, retsize)
|
616
|
|
- memmove(buf, data, retsize)
|
617
|
|
- return retsize
|
618
|
|
-
|
619
|
|
- def write(self, path, buf, size, offset, fip):
|
620
|
|
- data = string_at(buf, size)
|
621
|
|
-
|
622
|
|
- if self.raw_fi:
|
623
|
|
- fh = fip.contents
|
624
|
|
- else:
|
625
|
|
- fh = fip.contents.fh
|
626
|
|
-
|
627
|
|
- return self.operations('write', self._decode_optional_path(path), data,
|
628
|
|
- offset, fh)
|
629
|
|
-
|
630
|
|
- def statfs(self, path, buf):
|
631
|
|
- stv = buf.contents
|
632
|
|
- attrs = self.operations('statfs', path.decode(self.encoding))
|
633
|
|
- for key, val in attrs.items():
|
634
|
|
- if hasattr(stv, key):
|
635
|
|
- setattr(stv, key, val)
|
636
|
|
-
|
637
|
|
- return 0
|
638
|
|
-
|
639
|
|
- def flush(self, path, fip):
|
640
|
|
- if self.raw_fi:
|
641
|
|
- fh = fip.contents
|
642
|
|
- else:
|
643
|
|
- fh = fip.contents.fh
|
644
|
|
-
|
645
|
|
- return self.operations('flush', self._decode_optional_path(path), fh)
|
646
|
|
-
|
647
|
|
- def release(self, path, fip):
|
648
|
|
- if self.raw_fi:
|
649
|
|
- fh = fip.contents
|
650
|
|
- else:
|
651
|
|
- fh = fip.contents.fh
|
652
|
|
-
|
653
|
|
- return self.operations('release', self._decode_optional_path(path), fh)
|
654
|
|
-
|
655
|
|
- def fsync(self, path, datasync, fip):
|
656
|
|
- if self.raw_fi:
|
657
|
|
- fh = fip.contents
|
658
|
|
- else:
|
659
|
|
- fh = fip.contents.fh
|
660
|
|
-
|
661
|
|
- return self.operations('fsync', self._decode_optional_path(path), datasync,
|
662
|
|
- fh)
|
663
|
|
-
|
664
|
|
- def setxattr(self, path, name, value, size, options, *args):
|
665
|
|
- return self.operations('setxattr', path.decode(self.encoding),
|
666
|
|
- name.decode(self.encoding),
|
667
|
|
- string_at(value, size), options, *args)
|
668
|
|
-
|
669
|
|
- def getxattr(self, path, name, value, size, *args):
|
670
|
|
- ret = self.operations('getxattr', path.decode(self.encoding),
|
671
|
|
- name.decode(self.encoding), *args)
|
672
|
|
-
|
673
|
|
- retsize = len(ret)
|
674
|
|
- # allow size queries
|
675
|
|
- if not value: return retsize
|
676
|
|
-
|
677
|
|
- # do not truncate
|
678
|
|
- if retsize > size: return -ERANGE
|
679
|
|
-
|
680
|
|
- buf = create_string_buffer(ret, retsize) # Does not add trailing 0
|
681
|
|
- memmove(value, buf, retsize)
|
682
|
|
-
|
683
|
|
- return retsize
|
684
|
|
-
|
685
|
|
- def listxattr(self, path, namebuf, size):
|
686
|
|
- attrs = self.operations('listxattr', path.decode(self.encoding)) or ''
|
687
|
|
- ret = '\x00'.join(attrs).encode(self.encoding)
|
688
|
|
- if len(ret) > 0:
|
689
|
|
- ret += '\x00'.encode(self.encoding)
|
690
|
|
-
|
691
|
|
- retsize = len(ret)
|
692
|
|
- # allow size queries
|
693
|
|
- if not namebuf: return retsize
|
694
|
|
-
|
695
|
|
- # do not truncate
|
696
|
|
- if retsize > size: return -ERANGE
|
697
|
|
-
|
698
|
|
- buf = create_string_buffer(ret, retsize)
|
699
|
|
- memmove(namebuf, buf, retsize)
|
700
|
|
-
|
701
|
|
- return retsize
|
702
|
|
-
|
703
|
|
- def removexattr(self, path, name):
|
704
|
|
- return self.operations('removexattr', path.decode(self.encoding),
|
705
|
|
- name.decode(self.encoding))
|
706
|
|
-
|
707
|
|
- def opendir(self, path, fip):
|
708
|
|
- # Ignore raw_fi
|
709
|
|
- fip.contents.fh = self.operations('opendir',
|
710
|
|
- path.decode(self.encoding))
|
711
|
|
-
|
712
|
|
- return 0
|
713
|
|
-
|
714
|
|
- def readdir(self, path, buf, filler, offset, fip):
|
715
|
|
- # Ignore raw_fi
|
716
|
|
- for item in self.operations('readdir', self._decode_optional_path(path),
|
717
|
|
- fip.contents.fh):
|
718
|
|
-
|
719
|
|
- if isinstance(item, basestring):
|
720
|
|
- name, st, offset = item, None, 0
|
721
|
|
- else:
|
722
|
|
- name, attrs, offset = item
|
723
|
|
- if attrs:
|
724
|
|
- st = c_stat()
|
725
|
|
- set_st_attrs(st, attrs)
|
726
|
|
- else:
|
727
|
|
- st = None
|
728
|
|
-
|
729
|
|
- if filler(buf, name.encode(self.encoding), st, offset) != 0:
|
730
|
|
- break
|
731
|
|
-
|
732
|
|
- return 0
|
733
|
|
-
|
734
|
|
- def releasedir(self, path, fip):
|
735
|
|
- # Ignore raw_fi
|
736
|
|
- return self.operations('releasedir', self._decode_optional_path(path),
|
737
|
|
- fip.contents.fh)
|
738
|
|
-
|
739
|
|
- def fsyncdir(self, path, datasync, fip):
|
740
|
|
- # Ignore raw_fi
|
741
|
|
- return self.operations('fsyncdir', self._decode_optional_path(path),
|
742
|
|
- datasync, fip.contents.fh)
|
743
|
|
-
|
744
|
|
- def init(self, conn):
|
745
|
|
- return self.operations('init', '/')
|
746
|
|
-
|
747
|
|
- def destroy(self, private_data):
|
748
|
|
- return self.operations('destroy', '/')
|
749
|
|
-
|
750
|
|
- def access(self, path, amode):
|
751
|
|
- return self.operations('access', path.decode(self.encoding), amode)
|
752
|
|
-
|
753
|
|
- def create(self, path, mode, fip):
|
754
|
|
- fi = fip.contents
|
755
|
|
- path = path.decode(self.encoding)
|
756
|
|
-
|
757
|
|
- if self.raw_fi:
|
758
|
|
- return self.operations('create', path, mode, fi)
|
759
|
|
- else:
|
760
|
|
- # This line is different from upstream to fix issues
|
761
|
|
- # reading file opened with O_CREAT|O_RDWR.
|
762
|
|
- # See issue #143.
|
763
|
|
- fi.fh = self.operations('create', path, mode, fi.flags)
|
764
|
|
- # END OF MODIFICATION
|
765
|
|
- return 0
|
766
|
|
-
|
767
|
|
- def ftruncate(self, path, length, fip):
|
768
|
|
- if self.raw_fi:
|
769
|
|
- fh = fip.contents
|
770
|
|
- else:
|
771
|
|
- fh = fip.contents.fh
|
772
|
|
-
|
773
|
|
- return self.operations('truncate', self._decode_optional_path(path),
|
774
|
|
- length, fh)
|
775
|
|
-
|
776
|
|
- def fgetattr(self, path, buf, fip):
|
777
|
|
- memset(buf, 0, sizeof(c_stat))
|
778
|
|
-
|
779
|
|
- st = buf.contents
|
780
|
|
- if not fip:
|
781
|
|
- fh = fip
|
782
|
|
- elif self.raw_fi:
|
783
|
|
- fh = fip.contents
|
784
|
|
- else:
|
785
|
|
- fh = fip.contents.fh
|
786
|
|
-
|
787
|
|
- attrs = self.operations('getattr', self._decode_optional_path(path), fh)
|
788
|
|
- set_st_attrs(st, attrs)
|
789
|
|
- return 0
|
790
|
|
-
|
791
|
|
- def lock(self, path, fip, cmd, lock):
|
792
|
|
- if self.raw_fi:
|
793
|
|
- fh = fip.contents
|
794
|
|
- else:
|
795
|
|
- fh = fip.contents.fh
|
796
|
|
-
|
797
|
|
- return self.operations('lock', self._decode_optional_path(path), fh, cmd,
|
798
|
|
- lock)
|
799
|
|
-
|
800
|
|
- def utimens(self, path, buf):
|
801
|
|
- if buf:
|
802
|
|
- atime = time_of_timespec(buf.contents.actime)
|
803
|
|
- mtime = time_of_timespec(buf.contents.modtime)
|
804
|
|
- times = (atime, mtime)
|
805
|
|
- else:
|
806
|
|
- times = None
|
807
|
|
-
|
808
|
|
- return self.operations('utimens', path.decode(self.encoding), times)
|
809
|
|
-
|
810
|
|
- def bmap(self, path, blocksize, idx):
|
811
|
|
- return self.operations('bmap', path.decode(self.encoding), blocksize,
|
812
|
|
- idx)
|
813
|
|
-
|
814
|
|
-
|
815
|
|
-class Operations(object):
|
816
|
|
- '''
|
817
|
|
- This class should be subclassed and passed as an argument to FUSE on
|
818
|
|
- initialization. All operations should raise a FuseOSError exception on
|
819
|
|
- error.
|
820
|
|
-
|
821
|
|
- When in doubt of what an operation should do, check the FUSE header file
|
822
|
|
- or the corresponding system call man page.
|
823
|
|
- '''
|
824
|
|
-
|
825
|
|
- def __call__(self, op, *args):
|
826
|
|
- if not hasattr(self, op):
|
827
|
|
- raise FuseOSError(EFAULT)
|
828
|
|
- return getattr(self, op)(*args)
|
829
|
|
-
|
830
|
|
- def access(self, path, amode):
|
831
|
|
- return 0
|
832
|
|
-
|
833
|
|
- bmap = None
|
834
|
|
-
|
835
|
|
- def chmod(self, path, mode):
|
836
|
|
- raise FuseOSError(EROFS)
|
837
|
|
-
|
838
|
|
- def chown(self, path, uid, gid):
|
839
|
|
- raise FuseOSError(EROFS)
|
840
|
|
-
|
841
|
|
- def create(self, path, mode, fi=None):
|
842
|
|
- '''
|
843
|
|
- When raw_fi is False (default case), fi is None and create should
|
844
|
|
- return a numerical file handle.
|
845
|
|
-
|
846
|
|
- When raw_fi is True the file handle should be set directly by create
|
847
|
|
- and return 0.
|
848
|
|
- '''
|
849
|
|
-
|
850
|
|
- raise FuseOSError(EROFS)
|
851
|
|
-
|
852
|
|
- def destroy(self, path):
|
853
|
|
- 'Called on filesystem destruction. Path is always /'
|
854
|
|
-
|
855
|
|
- pass
|
856
|
|
-
|
857
|
|
- def flush(self, path, fh):
|
858
|
|
- return 0
|
859
|
|
-
|
860
|
|
- def fsync(self, path, datasync, fh):
|
861
|
|
- return 0
|
862
|
|
-
|
863
|
|
- def fsyncdir(self, path, datasync, fh):
|
864
|
|
- return 0
|
865
|
|
-
|
866
|
|
- def getattr(self, path, fh=None):
|
867
|
|
- '''
|
868
|
|
- Returns a dictionary with keys identical to the stat C structure of
|
869
|
|
- stat(2).
|
870
|
|
-
|
871
|
|
- st_atime, st_mtime and st_ctime should be floats.
|
872
|
|
-
|
873
|
|
- NOTE: There is an incombatibility between Linux and Mac OS X
|
874
|
|
- concerning st_nlink of directories. Mac OS X counts all files inside
|
875
|
|
- the directory, while Linux counts only the subdirectories.
|
876
|
|
- '''
|
877
|
|
-
|
878
|
|
- if path != '/':
|
879
|
|
- raise FuseOSError(ENOENT)
|
880
|
|
- return dict(st_mode=(S_IFDIR | 0o755), st_nlink=2)
|
881
|
|
-
|
882
|
|
- def getxattr(self, path, name, position=0):
|
883
|
|
- raise FuseOSError(ENOTSUP)
|
884
|
|
-
|
885
|
|
- def init(self, path):
|
886
|
|
- '''
|
887
|
|
- Called on filesystem initialization. (Path is always /)
|
888
|
|
-
|
889
|
|
- Use it instead of __init__ if you start threads on initialization.
|
890
|
|
- '''
|
891
|
|
-
|
892
|
|
- pass
|
893
|
|
-
|
894
|
|
- def link(self, target, source):
|
895
|
|
- 'creates a hard link `target -> source` (e.g. ln source target)'
|
896
|
|
-
|
897
|
|
- raise FuseOSError(EROFS)
|
898
|
|
-
|
899
|
|
- def listxattr(self, path):
|
900
|
|
- return []
|
901
|
|
-
|
902
|
|
- lock = None
|
903
|
|
-
|
904
|
|
- def mkdir(self, path, mode):
|
905
|
|
- raise FuseOSError(EROFS)
|
906
|
|
-
|
907
|
|
- def mknod(self, path, mode, dev):
|
908
|
|
- raise FuseOSError(EROFS)
|
909
|
|
-
|
910
|
|
- def open(self, path, flags):
|
911
|
|
- '''
|
912
|
|
- When raw_fi is False (default case), open should return a numerical
|
913
|
|
- file handle.
|
914
|
|
-
|
915
|
|
- When raw_fi is True the signature of open becomes:
|
916
|
|
- open(self, path, fi)
|
917
|
|
-
|
918
|
|
- and the file handle should be set directly.
|
919
|
|
- '''
|
920
|
|
-
|
921
|
|
- return 0
|
922
|
|
-
|
923
|
|
- def opendir(self, path):
|
924
|
|
- 'Returns a numerical file handle.'
|
925
|
|
-
|
926
|
|
- return 0
|
927
|
|
-
|
928
|
|
- def read(self, path, size, offset, fh):
|
929
|
|
- 'Returns a string containing the data requested.'
|
930
|
|
-
|
931
|
|
- raise FuseOSError(EIO)
|
932
|
|
-
|
933
|
|
- def readdir(self, path, fh):
|
934
|
|
- '''
|
935
|
|
- Can return either a list of names, or a list of (name, attrs, offset)
|
936
|
|
- tuples. attrs is a dict as in getattr.
|
937
|
|
- '''
|
938
|
|
-
|
939
|
|
- return ['.', '..']
|
940
|
|
-
|
941
|
|
- def readlink(self, path):
|
942
|
|
- raise FuseOSError(ENOENT)
|
943
|
|
-
|
944
|
|
- def release(self, path, fh):
|
945
|
|
- return 0
|
946
|
|
-
|
947
|
|
- def releasedir(self, path, fh):
|
948
|
|
- return 0
|
949
|
|
-
|
950
|
|
- def removexattr(self, path, name):
|
951
|
|
- raise FuseOSError(ENOTSUP)
|
952
|
|
-
|
953
|
|
- def rename(self, old, new):
|
954
|
|
- raise FuseOSError(EROFS)
|
955
|
|
-
|
956
|
|
- def rmdir(self, path):
|
957
|
|
- raise FuseOSError(EROFS)
|
958
|
|
-
|
959
|
|
- def setxattr(self, path, name, value, options, position=0):
|
960
|
|
- raise FuseOSError(ENOTSUP)
|
961
|
|
-
|
962
|
|
- def statfs(self, path):
|
963
|
|
- '''
|
964
|
|
- Returns a dictionary with keys identical to the statvfs C structure of
|
965
|
|
- statvfs(3).
|
966
|
|
-
|
967
|
|
- On Mac OS X f_bsize and f_frsize must be a power of 2
|
968
|
|
- (minimum 512).
|
969
|
|
- '''
|
970
|
|
-
|
971
|
|
- return {}
|
972
|
|
-
|
973
|
|
- def symlink(self, target, source):
|
974
|
|
- 'creates a symlink `target -> source` (e.g. ln -s source target)'
|
975
|
|
-
|
976
|
|
- raise FuseOSError(EROFS)
|
977
|
|
-
|
978
|
|
- def truncate(self, path, length, fh=None):
|
979
|
|
- raise FuseOSError(EROFS)
|
980
|
|
-
|
981
|
|
- def unlink(self, path):
|
982
|
|
- raise FuseOSError(EROFS)
|
983
|
|
-
|
984
|
|
- def utimens(self, path, times=None):
|
985
|
|
- 'Times is a (atime, mtime) tuple. If None use current time.'
|
986
|
|
-
|
987
|
|
- return 0
|
988
|
|
-
|
989
|
|
- def write(self, path, data, offset, fh):
|
990
|
|
- raise FuseOSError(EROFS)
|
991
|
|
-
|
992
|
|
-
|
993
|
|
-class LoggingMixIn:
|
994
|
|
- log = logging.getLogger('fuse.log-mixin')
|
995
|
|
-
|
996
|
|
- def __call__(self, op, path, *args):
|
997
|
|
- self.log.debug('-> %s %s %s', op, path, repr(args))
|
998
|
|
- ret = '[Unhandled Exception]'
|
999
|
|
- try:
|
1000
|
|
- ret = getattr(self, op)(path, *args)
|
1001
|
|
- return ret
|
1002
|
|
- except OSError as e:
|
1003
|
|
- ret = str(e)
|
1004
|
|
- raise
|
1005
|
|
- finally:
|
1006
|
|
- self.log.debug('<- %s %s', op, repr(ret))
|