| 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)) |