Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pyfs
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
pyfs
Commits
41efb9b7
Commit
41efb9b7
authored
Feb 26, 2014
by
willmcgugan@gmail.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Test fixes
parent
ea7f6b43
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
105 additions
and
105 deletions
+105
-105
LICENSE.txt
+4
-4
fs/__init__.py
+1
-1
fs/errors.py
+4
-0
fs/expose/fuse/fuse3.py
+82
-81
fs/osfs/__init__.py
+10
-14
fs/tests/__init__.py
+2
-3
fs/watch.py
+2
-2
No files found.
LICENSE.txt
View file @
41efb9b7
Copyright (c) 2009-201
2
, Will McGugan <will@willmcgugan.com> and contributors.
Copyright (c) 2009-201
4
, Will McGugan <will@willmcgugan.com> and contributors.
All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
documentation and/or other materials provided with the distribution.
...
...
fs/__init__.py
View file @
41efb9b7
...
@@ -15,7 +15,7 @@ implementations of this interface such as:
...
@@ -15,7 +15,7 @@ implementations of this interface such as:
"""
"""
__version__
=
"0.
4.1
"
__version__
=
"0.
5.0-dev
"
__author__
=
"Will McGugan (will@willmcgugan.com)"
__author__
=
"Will McGugan (will@willmcgugan.com)"
# provide these by default so people can use 'fs.path.basename' etc.
# provide these by default so people can use 'fs.path.basename' etc.
...
...
fs/errors.py
View file @
41efb9b7
...
@@ -266,6 +266,10 @@ def convert_os_errors(func):
...
@@ -266,6 +266,10 @@ def convert_os_errors(func):
raise
OperationFailedError
(
opname
,
details
=
e
),
None
,
tb
raise
OperationFailedError
(
opname
,
details
=
e
),
None
,
tb
if
e
.
errno
==
errno
.
ENOENT
:
if
e
.
errno
==
errno
.
ENOENT
:
raise
ResourceNotFoundError
(
path
,
opname
=
opname
,
details
=
e
),
None
,
tb
raise
ResourceNotFoundError
(
path
,
opname
=
opname
,
details
=
e
),
None
,
tb
if
e
.
errno
==
errno
.
EFAULT
:
# This can happen when listdir a directory that is deleted by another thread
# Best to interpret it as a resource not found
raise
ResourceNotFoundError
(
path
,
opname
=
opname
,
details
=
e
),
None
,
tb
if
e
.
errno
==
errno
.
ESRCH
:
if
e
.
errno
==
errno
.
ESRCH
:
raise
ResourceNotFoundError
(
path
,
opname
=
opname
,
details
=
e
),
None
,
tb
raise
ResourceNotFoundError
(
path
,
opname
=
opname
,
details
=
e
),
None
,
tb
if
e
.
errno
==
errno
.
ENOTEMPTY
:
if
e
.
errno
==
errno
.
ENOTEMPTY
:
...
...
fs/expose/fuse/fuse3.py
View file @
41efb9b7
# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com>
# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com>
#
#
# Permission to use, copy, modify, and distribute this software for any
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
# copyright notice and this permission notice appear in all copies.
#
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
...
@@ -74,7 +74,7 @@ elif _system == 'Linux':
...
@@ -74,7 +74,7 @@ elif _system == 'Linux':
c_uid_t
=
c_uint
c_uid_t
=
c_uint
setxattr_t
=
CFUNCTYPE
(
c_int
,
c_char_p
,
c_char_p
,
POINTER
(
c_byte
),
c_size_t
,
c_int
)
setxattr_t
=
CFUNCTYPE
(
c_int
,
c_char_p
,
c_char_p
,
POINTER
(
c_byte
),
c_size_t
,
c_int
)
getxattr_t
=
CFUNCTYPE
(
c_int
,
c_char_p
,
c_char_p
,
POINTER
(
c_byte
),
c_size_t
)
getxattr_t
=
CFUNCTYPE
(
c_int
,
c_char_p
,
c_char_p
,
POINTER
(
c_byte
),
c_size_t
)
_machine
=
machine
()
_machine
=
machine
()
if
_machine
==
'x86_64'
:
if
_machine
==
'x86_64'
:
c_stat
.
_fields_
=
[
c_stat
.
_fields_
=
[
...
@@ -256,12 +256,12 @@ class FUSE(object):
...
@@ -256,12 +256,12 @@ class FUSE(object):
"""This class is the lower level interface and should not be subclassed
"""This class is the lower level interface and should not be subclassed
under normal use. Its methods are called by fuse.
under normal use. Its methods are called by fuse.
Assumes API version 2.6 or later."""
Assumes API version 2.6 or later."""
def
__init__
(
self
,
operations
,
mountpoint
,
raw_fi
=
False
,
**
kwargs
):
def
__init__
(
self
,
operations
,
mountpoint
,
raw_fi
=
False
,
**
kwargs
):
"""Setting raw_fi to True will cause FUSE to pass the fuse_file_info
"""Setting raw_fi to True will cause FUSE to pass the fuse_file_info
class as is to Operations, instead of just the fh field.
class as is to Operations, instead of just the fh field.
This gives you access to direct_io, keep_cache, etc."""
This gives you access to direct_io, keep_cache, etc."""
self
.
operations
=
operations
self
.
operations
=
operations
self
.
raw_fi
=
raw_fi
self
.
raw_fi
=
raw_fi
args
=
[
'fuse'
]
args
=
[
'fuse'
]
...
@@ -277,7 +277,7 @@ class FUSE(object):
...
@@ -277,7 +277,7 @@ class FUSE(object):
for
key
,
val
in
kwargs
.
items
()))
for
key
,
val
in
kwargs
.
items
()))
args
.
append
(
mountpoint
)
args
.
append
(
mountpoint
)
argv
=
(
c_char_p
*
len
(
args
))(
*
args
)
argv
=
(
c_char_p
*
len
(
args
))(
*
args
)
fuse_ops
=
fuse_operations
()
fuse_ops
=
fuse_operations
()
for
name
,
prototype
in
fuse_operations
.
_fields_
:
for
name
,
prototype
in
fuse_operations
.
_fields_
:
if
prototype
!=
c_voidp
and
getattr
(
operations
,
name
,
None
):
if
prototype
!=
c_voidp
and
getattr
(
operations
,
name
,
None
):
...
@@ -286,7 +286,7 @@ class FUSE(object):
...
@@ -286,7 +286,7 @@ class FUSE(object):
_libfuse
.
fuse_main_real
(
len
(
args
),
argv
,
pointer
(
fuse_ops
),
_libfuse
.
fuse_main_real
(
len
(
args
),
argv
,
pointer
(
fuse_ops
),
sizeof
(
fuse_ops
),
None
)
sizeof
(
fuse_ops
),
None
)
del
self
.
operations
# Invoke the destructor
del
self
.
operations
# Invoke the destructor
def
_wrapper_
(
self
,
func
,
*
args
,
**
kwargs
):
def
_wrapper_
(
self
,
func
,
*
args
,
**
kwargs
):
"""Decorator for the methods that follow"""
"""Decorator for the methods that follow"""
try
:
try
:
...
@@ -296,46 +296,46 @@ class FUSE(object):
...
@@ -296,46 +296,46 @@ class FUSE(object):
except
:
except
:
print_exc
()
print_exc
()
return
-
EFAULT
return
-
EFAULT
def
getattr
(
self
,
path
,
buf
):
def
getattr
(
self
,
path
,
buf
):
return
self
.
fgetattr
(
path
,
buf
,
None
)
return
self
.
fgetattr
(
path
,
buf
,
None
)
def
readlink
(
self
,
path
,
buf
,
bufsize
):
def
readlink
(
self
,
path
,
buf
,
bufsize
):
ret
=
self
.
operations
(
'readlink'
,
path
)
.
encode
(
'utf-8'
)
ret
=
self
.
operations
(
'readlink'
,
path
)
.
encode
(
'utf-8'
)
data
=
create_string_buffer
(
ret
[:
bufsize
-
1
])
data
=
create_string_buffer
(
ret
[:
bufsize
-
1
])
memmove
(
buf
,
data
,
len
(
data
))
memmove
(
buf
,
data
,
len
(
data
))
return
0
return
0
def
mknod
(
self
,
path
,
mode
,
dev
):
def
mknod
(
self
,
path
,
mode
,
dev
):
return
self
.
operations
(
'mknod'
,
path
,
mode
,
dev
)
return
self
.
operations
(
'mknod'
,
path
,
mode
,
dev
)
def
mkdir
(
self
,
path
,
mode
):
def
mkdir
(
self
,
path
,
mode
):
return
self
.
operations
(
'mkdir'
,
path
,
mode
)
return
self
.
operations
(
'mkdir'
,
path
,
mode
)
def
unlink
(
self
,
path
):
def
unlink
(
self
,
path
):
return
self
.
operations
(
'unlink'
,
path
)
return
self
.
operations
(
'unlink'
,
path
)
def
rmdir
(
self
,
path
):
def
rmdir
(
self
,
path
):
return
self
.
operations
(
'rmdir'
,
path
)
return
self
.
operations
(
'rmdir'
,
path
)
def
symlink
(
self
,
source
,
target
):
def
symlink
(
self
,
source
,
target
):
return
self
.
operations
(
'symlink'
,
target
,
source
)
return
self
.
operations
(
'symlink'
,
target
,
source
)
def
rename
(
self
,
old
,
new
):
def
rename
(
self
,
old
,
new
):
return
self
.
operations
(
'rename'
,
old
,
new
)
return
self
.
operations
(
'rename'
,
old
,
new
)
def
link
(
self
,
source
,
target
):
def
link
(
self
,
source
,
target
):
return
self
.
operations
(
'link'
,
target
,
source
)
return
self
.
operations
(
'link'
,
target
,
source
)
def
chmod
(
self
,
path
,
mode
):
def
chmod
(
self
,
path
,
mode
):
return
self
.
operations
(
'chmod'
,
path
,
mode
)
return
self
.
operations
(
'chmod'
,
path
,
mode
)
def
chown
(
self
,
path
,
uid
,
gid
):
def
chown
(
self
,
path
,
uid
,
gid
):
return
self
.
operations
(
'chown'
,
path
,
uid
,
gid
)
return
self
.
operations
(
'chown'
,
path
,
uid
,
gid
)
def
truncate
(
self
,
path
,
length
):
def
truncate
(
self
,
path
,
length
):
return
self
.
operations
(
'truncate'
,
path
,
length
)
return
self
.
operations
(
'truncate'
,
path
,
length
)
def
open
(
self
,
path
,
fip
):
def
open
(
self
,
path
,
fip
):
fi
=
fip
.
contents
fi
=
fip
.
contents
if
self
.
raw_fi
:
if
self
.
raw_fi
:
...
@@ -343,7 +343,7 @@ class FUSE(object):
...
@@ -343,7 +343,7 @@ class FUSE(object):
else
:
else
:
fi
.
fh
=
self
.
operations
(
'open'
,
path
,
fi
.
flags
)
fi
.
fh
=
self
.
operations
(
'open'
,
path
,
fi
.
flags
)
return
0
return
0
def
read
(
self
,
path
,
buf
,
size
,
offset
,
fip
):
def
read
(
self
,
path
,
buf
,
size
,
offset
,
fip
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
ret
=
self
.
operations
(
'read'
,
path
,
size
,
offset
,
fh
)
ret
=
self
.
operations
(
'read'
,
path
,
size
,
offset
,
fh
)
...
@@ -352,12 +352,12 @@ class FUSE(object):
...
@@ -352,12 +352,12 @@ class FUSE(object):
data
=
create_string_buffer
(
ret
[:
size
],
size
)
data
=
create_string_buffer
(
ret
[:
size
],
size
)
memmove
(
buf
,
data
,
size
)
memmove
(
buf
,
data
,
size
)
return
size
return
size
def
write
(
self
,
path
,
buf
,
size
,
offset
,
fip
):
def
write
(
self
,
path
,
buf
,
size
,
offset
,
fip
):
data
=
string_at
(
buf
,
size
)
data
=
string_at
(
buf
,
size
)
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'write'
,
path
,
data
,
offset
,
fh
)
return
self
.
operations
(
'write'
,
path
,
data
,
offset
,
fh
)
def
statfs
(
self
,
path
,
buf
):
def
statfs
(
self
,
path
,
buf
):
stv
=
buf
.
contents
stv
=
buf
.
contents
attrs
=
self
.
operations
(
'statfs'
,
path
)
attrs
=
self
.
operations
(
'statfs'
,
path
)
...
@@ -365,23 +365,23 @@ class FUSE(object):
...
@@ -365,23 +365,23 @@ class FUSE(object):
if
hasattr
(
stv
,
key
):
if
hasattr
(
stv
,
key
):
setattr
(
stv
,
key
,
val
)
setattr
(
stv
,
key
,
val
)
return
0
return
0
def
flush
(
self
,
path
,
fip
):
def
flush
(
self
,
path
,
fip
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'flush'
,
path
,
fh
)
return
self
.
operations
(
'flush'
,
path
,
fh
)
def
release
(
self
,
path
,
fip
):
def
release
(
self
,
path
,
fip
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'release'
,
path
,
fh
)
return
self
.
operations
(
'release'
,
path
,
fh
)
def
fsync
(
self
,
path
,
datasync
,
fip
):
def
fsync
(
self
,
path
,
datasync
,
fip
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'fsync'
,
path
,
datasync
,
fh
)
return
self
.
operations
(
'fsync'
,
path
,
datasync
,
fh
)
def
setxattr
(
self
,
path
,
name
,
value
,
size
,
options
,
*
args
):
def
setxattr
(
self
,
path
,
name
,
value
,
size
,
options
,
*
args
):
data
=
string_at
(
value
,
size
)
data
=
string_at
(
value
,
size
)
return
self
.
operations
(
'setxattr'
,
path
,
name
,
data
,
options
,
*
args
)
return
self
.
operations
(
'setxattr'
,
path
,
name
,
data
,
options
,
*
args
)
def
getxattr
(
self
,
path
,
name
,
value
,
size
,
*
args
):
def
getxattr
(
self
,
path
,
name
,
value
,
size
,
*
args
):
ret
=
self
.
operations
(
'getxattr'
,
path
,
name
,
*
args
)
ret
=
self
.
operations
(
'getxattr'
,
path
,
name
,
*
args
)
retsize
=
len
(
ret
)
retsize
=
len
(
ret
)
...
@@ -391,7 +391,7 @@ class FUSE(object):
...
@@ -391,7 +391,7 @@ class FUSE(object):
return
-
ERANGE
return
-
ERANGE
memmove
(
value
,
buf
,
retsize
)
memmove
(
value
,
buf
,
retsize
)
return
retsize
return
retsize
def
listxattr
(
self
,
path
,
namebuf
,
size
):
def
listxattr
(
self
,
path
,
namebuf
,
size
):
ret
=
self
.
operations
(
'listxattr'
,
path
)
ret
=
self
.
operations
(
'listxattr'
,
path
)
buf
=
create_string_buffer
(
'
\x00
'
.
join
(
ret
))
if
ret
else
''
buf
=
create_string_buffer
(
'
\x00
'
.
join
(
ret
))
if
ret
else
''
...
@@ -401,20 +401,21 @@ class FUSE(object):
...
@@ -401,20 +401,21 @@ class FUSE(object):
return
-
ERANGE
return
-
ERANGE
memmove
(
namebuf
,
buf
,
bufsize
)
memmove
(
namebuf
,
buf
,
bufsize
)
return
bufsize
return
bufsize
def
removexattr
(
self
,
path
,
name
):
def
removexattr
(
self
,
path
,
name
):
return
self
.
operations
(
'removexattr'
,
path
,
name
)
return
self
.
operations
(
'removexattr'
,
path
,
name
)
def
opendir
(
self
,
path
,
fip
):
def
opendir
(
self
,
path
,
fip
):
# Ignore raw_fi
# Ignore raw_fi
fip
.
contents
.
fh
=
self
.
operations
(
'opendir'
,
path
)
fip
.
contents
.
fh
=
self
.
operations
(
'opendir'
,
path
)
return
0
return
0
def
readdir
(
self
,
path
,
buf
,
filler
,
offset
,
fip
):
def
readdir
(
self
,
path
,
buf
,
filler
,
offset
,
fip
):
# Ignore raw_fi
# Ignore raw_fi
for
item
in
self
.
operations
(
'readdir'
,
path
,
fip
.
contents
.
fh
):
for
item
in
self
.
operations
(
'readdir'
,
path
,
fip
.
contents
.
fh
):
if
isinstance
(
item
,
str
):
if
isinstance
(
item
,
str
):
name
,
st
,
offset
=
item
,
None
,
0
name
,
st
,
offset
=
item
,
None
,
0
name
=
name
.
encode
(
'utf-8'
)
else
:
else
:
name
,
attrs
,
offset
=
item
name
,
attrs
,
offset
=
item
if
attrs
:
if
attrs
:
...
@@ -422,27 +423,27 @@ class FUSE(object):
...
@@ -422,27 +423,27 @@ class FUSE(object):
set_st_attrs
(
st
,
attrs
)
set_st_attrs
(
st
,
attrs
)
else
:
else
:
st
=
None
st
=
None
if
filler
(
buf
,
name
.
encode
(
'utf-8'
)
,
st
,
offset
)
!=
0
:
if
filler
(
buf
,
name
,
st
,
offset
)
!=
0
:
break
break
return
0
return
0
def
releasedir
(
self
,
path
,
fip
):
def
releasedir
(
self
,
path
,
fip
):
# Ignore raw_fi
# Ignore raw_fi
return
self
.
operations
(
'releasedir'
,
path
,
fip
.
contents
.
fh
)
return
self
.
operations
(
'releasedir'
,
path
,
fip
.
contents
.
fh
)
def
fsyncdir
(
self
,
path
,
datasync
,
fip
):
def
fsyncdir
(
self
,
path
,
datasync
,
fip
):
# Ignore raw_fi
# Ignore raw_fi
return
self
.
operations
(
'fsyncdir'
,
path
,
datasync
,
fip
.
contents
.
fh
)
return
self
.
operations
(
'fsyncdir'
,
path
,
datasync
,
fip
.
contents
.
fh
)
def
init
(
self
,
conn
):
def
init
(
self
,
conn
):
return
self
.
operations
(
'init'
,
'/'
)
return
self
.
operations
(
'init'
,
'/'
)
def
destroy
(
self
,
private_data
):
def
destroy
(
self
,
private_data
):
return
self
.
operations
(
'destroy'
,
'/'
)
return
self
.
operations
(
'destroy'
,
'/'
)
def
access
(
self
,
path
,
amode
):
def
access
(
self
,
path
,
amode
):
return
self
.
operations
(
'access'
,
path
,
amode
)
return
self
.
operations
(
'access'
,
path
,
amode
)
def
create
(
self
,
path
,
mode
,
fip
):
def
create
(
self
,
path
,
mode
,
fip
):
fi
=
fip
.
contents
fi
=
fip
.
contents
if
self
.
raw_fi
:
if
self
.
raw_fi
:
...
@@ -450,11 +451,11 @@ class FUSE(object):
...
@@ -450,11 +451,11 @@ class FUSE(object):
else
:
else
:
fi
.
fh
=
self
.
operations
(
'create'
,
path
,
mode
)
fi
.
fh
=
self
.
operations
(
'create'
,
path
,
mode
)
return
0
return
0
def
ftruncate
(
self
,
path
,
length
,
fip
):
def
ftruncate
(
self
,
path
,
length
,
fip
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'truncate'
,
path
,
length
,
fh
)
return
self
.
operations
(
'truncate'
,
path
,
length
,
fh
)
def
fgetattr
(
self
,
path
,
buf
,
fip
):
def
fgetattr
(
self
,
path
,
buf
,
fip
):
memset
(
buf
,
0
,
sizeof
(
c_stat
))
memset
(
buf
,
0
,
sizeof
(
c_stat
))
st
=
buf
.
contents
st
=
buf
.
contents
...
@@ -462,11 +463,11 @@ class FUSE(object):
...
@@ -462,11 +463,11 @@ class FUSE(object):
attrs
=
self
.
operations
(
'getattr'
,
path
,
fh
)
attrs
=
self
.
operations
(
'getattr'
,
path
,
fh
)
set_st_attrs
(
st
,
attrs
)
set_st_attrs
(
st
,
attrs
)
return
0
return
0
def
lock
(
self
,
path
,
fip
,
cmd
,
lock
):
def
lock
(
self
,
path
,
fip
,
cmd
,
lock
):
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
fh
=
fip
.
contents
if
self
.
raw_fi
else
fip
.
contents
.
fh
return
self
.
operations
(
'lock'
,
path
,
fh
,
cmd
,
lock
)
return
self
.
operations
(
'lock'
,
path
,
fh
,
cmd
,
lock
)
def
utimens
(
self
,
path
,
buf
):
def
utimens
(
self
,
path
,
buf
):
if
buf
:
if
buf
:
atime
=
time_of_timespec
(
buf
.
contents
.
actime
)
atime
=
time_of_timespec
(
buf
.
contents
.
actime
)
...
@@ -475,7 +476,7 @@ class FUSE(object):
...
@@ -475,7 +476,7 @@ class FUSE(object):
else
:
else
:
times
=
None
times
=
None
return
self
.
operations
(
'utimens'
,
path
,
times
)
return
self
.
operations
(
'utimens'
,
path
,
times
)
def
bmap
(
self
,
path
,
blocksize
,
idx
):
def
bmap
(
self
,
path
,
blocksize
,
idx
):
return
self
.
operations
(
'bmap'
,
path
,
blocksize
,
idx
)
return
self
.
operations
(
'bmap'
,
path
,
blocksize
,
idx
)
...
@@ -484,46 +485,46 @@ class Operations(object):
...
@@ -484,46 +485,46 @@ class Operations(object):
"""This class should be subclassed and passed as an argument to FUSE on
"""This class should be subclassed and passed as an argument to FUSE on
initialization. All operations should raise an OSError exception on
initialization. All operations should raise an OSError exception on
error.
error.
When in doubt of what an operation should do, check the FUSE header
When in doubt of what an operation should do, check the FUSE header
file or the corresponding system call man page."""
file or the corresponding system call man page."""
def
__call__
(
self
,
op
,
*
args
):
def
__call__
(
self
,
op
,
*
args
):
if
not
hasattr
(
self
,
op
):
if
not
hasattr
(
self
,
op
):
raise
OSError
(
EFAULT
,
''
)
raise
OSError
(
EFAULT
,
''
)
return
getattr
(
self
,
op
)(
*
args
)
return
getattr
(
self
,
op
)(
*
args
)
def
access
(
self
,
path
,
amode
):
def
access
(
self
,
path
,
amode
):
return
0
return
0
bmap
=
None
bmap
=
None
def
chmod
(
self
,
path
,
mode
):
def
chmod
(
self
,
path
,
mode
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
chown
(
self
,
path
,
uid
,
gid
):
def
chown
(
self
,
path
,
uid
,
gid
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
create
(
self
,
path
,
mode
,
fi
=
None
):
def
create
(
self
,
path
,
mode
,
fi
=
None
):
"""When raw_fi is False (default case), fi is None and create should
"""When raw_fi is False (default case), fi is None and create should
return a numerical file handle.
return a numerical file handle.
When raw_fi is True the file handle should be set directly by create
When raw_fi is True the file handle should be set directly by create
and return 0."""
and return 0."""
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
destroy
(
self
,
path
):
def
destroy
(
self
,
path
):
"""Called on filesystem destruction. Path is always /"""
"""Called on filesystem destruction. Path is always /"""
pass
pass
def
flush
(
self
,
path
,
fh
):
def
flush
(
self
,
path
,
fh
):
return
0
return
0
def
fsync
(
self
,
path
,
datasync
,
fh
):
def
fsync
(
self
,
path
,
datasync
,
fh
):
return
0
return
0
def
fsyncdir
(
self
,
path
,
datasync
,
fh
):
def
fsyncdir
(
self
,
path
,
datasync
,
fh
):
return
0
return
0
def
getattr
(
self
,
path
,
fh
=
None
):
def
getattr
(
self
,
path
,
fh
=
None
):
"""Returns a dictionary with keys identical to the stat C structure
"""Returns a dictionary with keys identical to the stat C structure
of stat(2).
of stat(2).
...
@@ -531,33 +532,33 @@ class Operations(object):
...
@@ -531,33 +532,33 @@ class Operations(object):
NOTE: There is an incombatibility between Linux and Mac OS X concerning
NOTE: There is an incombatibility between Linux and Mac OS X concerning
st_nlink of directories. Mac OS X counts all files inside the directory,
st_nlink of directories. Mac OS X counts all files inside the directory,
while Linux counts only the subdirectories."""
while Linux counts only the subdirectories."""
if
path
!=
'/'
:
if
path
!=
'/'
:
raise
OSError
(
ENOENT
,
''
)
raise
OSError
(
ENOENT
,
''
)
return
dict
(
st_mode
=
(
S_IFDIR
|
0
o755
),
st_nlink
=
2
)
return
dict
(
st_mode
=
(
S_IFDIR
|
0
o755
),
st_nlink
=
2
)
def
getxattr
(
self
,
path
,
name
,
position
=
0
):
def
getxattr
(
self
,
path
,
name
,
position
=
0
):
raise
OSError
(
ENOTSUP
,
''
)
raise
OSError
(
ENOTSUP
,
''
)
def
init
(
self
,
path
):
def
init
(
self
,
path
):
"""Called on filesystem initialization. Path is always /
"""Called on filesystem initialization. Path is always /
Use it instead of __init__ if you start threads on initialization."""
Use it instead of __init__ if you start threads on initialization."""
pass
pass
def
link
(
self
,
target
,
source
):
def
link
(
self
,
target
,
source
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
listxattr
(
self
,
path
):
def
listxattr
(
self
,
path
):
return
[]
return
[]
lock
=
None
lock
=
None
def
mkdir
(
self
,
path
,
mode
):
def
mkdir
(
self
,
path
,
mode
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
mknod
(
self
,
path
,
mode
,
dev
):
def
mknod
(
self
,
path
,
mode
,
dev
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
open
(
self
,
path
,
flags
):
def
open
(
self
,
path
,
flags
):
"""When raw_fi is False (default case), open should return a numerical
"""When raw_fi is False (default case), open should return a numerical
file handle.
file handle.
...
@@ -565,60 +566,60 @@ class Operations(object):
...
@@ -565,60 +566,60 @@ class Operations(object):
open(self, path, fi)
open(self, path, fi)
and the file handle should be set directly."""
and the file handle should be set directly."""
return
0
return
0
def
opendir
(
self
,
path
):
def
opendir
(
self
,
path
):
"""Returns a numerical file handle."""
"""Returns a numerical file handle."""
return
0
return
0
def
read
(
self
,
path
,
size
,
offset
,
fh
):
def
read
(
self
,
path
,
size
,
offset
,
fh
):
"""Returns a string containing the data requested."""
"""Returns a string containing the data requested."""
raise
OSError
(
ENOENT
,
''
)
raise
OSError
(
ENOENT
,
''
)
def
readdir
(
self
,
path
,
fh
):
def
readdir
(
self
,
path
,
fh
):
"""Can return either a list of names, or a list of (name, attrs, offset)
"""Can return either a list of names, or a list of (name, attrs, offset)
tuples. attrs is a dict as in getattr."""
tuples. attrs is a dict as in getattr."""
return
[
'.'
,
'..'
]
return
[
'.'
,
'..'
]
def
readlink
(
self
,
path
):
def
readlink
(
self
,
path
):
raise
OSError
(
ENOENT
,
''
)
raise
OSError
(
ENOENT
,
''
)
def
release
(
self
,
path
,
fh
):
def
release
(
self
,
path
,
fh
):
return
0
return
0
def
releasedir
(
self
,
path
,
fh
):
def
releasedir
(
self
,
path
,
fh
):
return
0
return
0
def
removexattr
(
self
,
path
,
name
):
def
removexattr
(
self
,
path
,
name
):
raise
OSError
(
ENOTSUP
,
''
)
raise
OSError
(
ENOTSUP
,
''
)
def
rename
(
self
,
old
,
new
):
def
rename
(
self
,
old
,
new
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
rmdir
(
self
,
path
):
def
rmdir
(
self
,
path
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
setxattr
(
self
,
path
,
name
,
value
,
options
,
position
=
0
):
def
setxattr
(
self
,
path
,
name
,
value
,
options
,
position
=
0
):
raise
OSError
(
ENOTSUP
,
''
)
raise
OSError
(
ENOTSUP
,
''
)
def
statfs
(
self
,
path
):
def
statfs
(
self
,
path
):
"""Returns a dictionary with keys identical to the statvfs C structure
"""Returns a dictionary with keys identical to the statvfs C structure
of statvfs(3).
of statvfs(3).
On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512)."""
On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512)."""
return
{}
return
{}
def
symlink
(
self
,
target
,
source
):
def
symlink
(
self
,
target
,
source
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
truncate
(
self
,
path
,
length
,
fh
=
None
):
def
truncate
(
self
,
path
,
length
,
fh
=
None
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
unlink
(
self
,
path
):
def
unlink
(
self
,
path
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
def
utimens
(
self
,
path
,
times
=
None
):
def
utimens
(
self
,
path
,
times
=
None
):
"""Times is a (atime, mtime) tuple. If None use current time."""
"""Times is a (atime, mtime) tuple. If None use current time."""
return
0
return
0
def
write
(
self
,
path
,
data
,
offset
,
fh
):
def
write
(
self
,
path
,
data
,
offset
,
fh
):
raise
OSError
(
EROFS
,
''
)
raise
OSError
(
EROFS
,
''
)
...
...
fs/osfs/__init__.py
View file @
41efb9b7
...
@@ -21,6 +21,7 @@ import errno
...
@@ -21,6 +21,7 @@ import errno
import
datetime
import
datetime
import
platform
import
platform
import
io
import
io
import
shutil
from
fs.base
import
*
from
fs.base
import
*
from
fs.path
import
*
from
fs.path
import
*
...
@@ -246,7 +247,9 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
...
@@ -246,7 +247,9 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
@convert_os_errors
@convert_os_errors
def
listdir
(
self
,
path
=
"./"
,
wildcard
=
None
,
full
=
False
,
absolute
=
False
,
dirs_only
=
False
,
files_only
=
False
):
def
listdir
(
self
,
path
=
"./"
,
wildcard
=
None
,
full
=
False
,
absolute
=
False
,
dirs_only
=
False
,
files_only
=
False
):
_decode_path
=
self
.
_decode_path
_decode_path
=
self
.
_decode_path
paths
=
[
_decode_path
(
p
)
for
p
in
os
.
listdir
(
self
.
getsyspath
(
path
))]
sys_path
=
self
.
getsyspath
(
path
)
listing
=
os
.
listdir
(
sys_path
)
paths
=
[
_decode_path
(
p
)
for
p
in
listing
]
return
self
.
_listdir_helper
(
path
,
paths
,
wildcard
,
full
,
absolute
,
dirs_only
,
files_only
)
return
self
.
_listdir_helper
(
path
,
paths
,
wildcard
,
full
,
absolute
,
dirs_only
,
files_only
)
@convert_os_errors
@convert_os_errors
...
@@ -283,22 +286,15 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
...
@@ -283,22 +286,15 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
@convert_os_errors
@convert_os_errors
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
sys_path
=
self
.
getsyspath
(
path
)
if
force
:
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
,
files_only
=
True
):
try
:
self
.
remove
(
path2
)
except
ResourceNotFoundError
:
pass
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
,
dirs_only
=
True
):
try
:
self
.
removedir
(
path2
,
force
=
True
)
except
ResourceNotFoundError
:
pass
# Don't remove the root directory of this FS
# Don't remove the root directory of this FS
if
path
in
(
''
,
'/'
):
if
path
in
(
''
,
'/'
):
raise
RemoveRootError
(
path
)
raise
RemoveRootError
(
path
)
os
.
rmdir
(
sys_path
)
sys_path
=
self
.
getsyspath
(
path
)
if
force
:
# shutil implementation handles concurrency better
shutil
.
rmtree
(
sys_path
,
ignore_errors
=
True
)
else
:
os
.
rmdir
(
sys_path
)
# Using os.removedirs() for this can result in dirs being
# Using os.removedirs() for this can result in dirs being
# removed outside the root of this FS, so we recurse manually.
# removed outside the root of this FS, so we recurse manually.
if
recursive
:
if
recursive
:
...
...
fs/tests/__init__.py
View file @
41efb9b7
...
@@ -137,7 +137,6 @@ class FSTestCases(object):
...
@@ -137,7 +137,6 @@ class FSTestCases(object):
f
.
close
()
f
.
close
()
def
test_createfile
(
self
):
def
test_createfile
(
self
):
"""Test createfile"""
test
=
b
(
'now with content'
)
test
=
b
(
'now with content'
)
self
.
fs
.
createfile
(
"test.txt"
)
self
.
fs
.
createfile
(
"test.txt"
)
self
.
assert_
(
self
.
fs
.
exists
(
"test.txt"
))
self
.
assert_
(
self
.
fs
.
exists
(
"test.txt"
))
...
@@ -396,8 +395,8 @@ class FSTestCases(object):
...
@@ -396,8 +395,8 @@ class FSTestCases(object):
alpha
=
u"
\N{GREEK SMALL LETTER ALPHA}
"
alpha
=
u"
\N{GREEK SMALL LETTER ALPHA}
"
beta
=
u"
\N{GREEK SMALL LETTER BETA}
"
beta
=
u"
\N{GREEK SMALL LETTER BETA}
"
self
.
fs
.
makedir
(
alpha
)
self
.
fs
.
makedir
(
alpha
)
self
.
fs
.
setcontents
(
alpha
+
"/a"
,
b
(
''
))
self
.
fs
.
setcontents
(
alpha
+
"/a"
,
b
(
''
))
self
.
fs
.
setcontents
(
alpha
+
"/"
+
beta
,
b
(
''
))
self
.
fs
.
setcontents
(
alpha
+
"/"
+
beta
,
b
(
''
))
self
.
assertTrue
(
self
.
check
(
alpha
))
self
.
assertTrue
(
self
.
check
(
alpha
))
self
.
assertEquals
(
sorted
(
self
.
fs
.
listdir
(
alpha
)),
[
"a"
,
beta
])
self
.
assertEquals
(
sorted
(
self
.
fs
.
listdir
(
alpha
)),
[
"a"
,
beta
])
...
...
fs/watch.py
View file @
41efb9b7
...
@@ -315,7 +315,7 @@ class WatchableFS(WatchableFSMixin,WrapFS):
...
@@ -315,7 +315,7 @@ class WatchableFS(WatchableFSMixin,WrapFS):
def
setcontents
(
self
,
path
,
data
=
b
''
,
encoding
=
None
,
errors
=
None
,
chunk_size
=
64
*
1024
):
def
setcontents
(
self
,
path
,
data
=
b
''
,
encoding
=
None
,
errors
=
None
,
chunk_size
=
64
*
1024
):
existed
=
self
.
wrapped_fs
.
isfile
(
path
)
existed
=
self
.
wrapped_fs
.
isfile
(
path
)
ret
=
super
(
WatchableFS
,
self
)
.
setcontents
(
path
,
data
,
chunk_size
=
chunk_size
)
ret
=
super
(
WatchableFS
,
self
)
.
setcontents
(
path
,
data
=
data
,
encoding
=
encoding
,
errors
=
errors
,
chunk_size
=
chunk_size
)
if
not
existed
:
if
not
existed
:
self
.
notify_watchers
(
CREATED
,
path
)
self
.
notify_watchers
(
CREATED
,
path
)
self
.
notify_watchers
(
ACCESSED
,
path
)
self
.
notify_watchers
(
ACCESSED
,
path
)
...
@@ -325,7 +325,7 @@ class WatchableFS(WatchableFSMixin,WrapFS):
...
@@ -325,7 +325,7 @@ class WatchableFS(WatchableFSMixin,WrapFS):
def
createfile
(
self
,
path
,
wipe
=
False
):
def
createfile
(
self
,
path
,
wipe
=
False
):
existed
=
self
.
wrapped_fs
.
isfile
(
path
)
existed
=
self
.
wrapped_fs
.
isfile
(
path
)
ret
=
super
(
WatchableFS
,
self
)
.
createfile
(
path
,
wipe
=
Fals
e
)
ret
=
super
(
WatchableFS
,
self
)
.
createfile
(
path
,
wipe
=
wip
e
)
if
not
existed
:
if
not
existed
:
self
.
notify_watchers
(
CREATED
,
path
)
self
.
notify_watchers
(
CREATED
,
path
)
self
.
notify_watchers
(
ACCESSED
,
path
)
self
.
notify_watchers
(
ACCESSED
,
path
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment