copyparty 1.15.2__py3-none-any.whl → 1.15.4__py3-none-any.whl

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