|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
1 |
#!/usr/bin/env python
|
|
47
by Matt Giuca
Applied MIT License text to the top of all files. (Had some questions about licensing.) |
2 |
|
3 |
# -------------------------------------------------------------------
|
|
4 |
# Copyright (c) 2009 Matt Giuca
|
|
5 |
# This software and its accompanying documentation is licensed under the
|
|
6 |
# MIT License.
|
|
7 |
#
|
|
8 |
# Permission is hereby granted, free of charge, to any person
|
|
9 |
# obtaining a copy of this software and associated documentation
|
|
10 |
# files (the "Software"), to deal in the Software without
|
|
11 |
# restriction, including without limitation the rights to use,
|
|
12 |
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13 |
# copies of the Software, and to permit persons to whom the
|
|
14 |
# Software is furnished to do so, subject to the following
|
|
15 |
# conditions:
|
|
16 |
#
|
|
17 |
# The above copyright notice and this permission notice shall be
|
|
18 |
# included in all copies or substantial portions of the Software.
|
|
19 |
#
|
|
20 |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
21 |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
22 |
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
23 |
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
24 |
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
25 |
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
26 |
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
27 |
# OTHER DEALINGS IN THE SOFTWARE.
|
|
28 |
# -------------------------------------------------------------------
|
|
29 |
||
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
30 |
# TemplateFS - A Simple Python Fuse Example
|
31 |
# This file system does absolutely nothing, but it's a complete stubbed-out
|
|
32 |
# file system ready for whatever implementation is desired.
|
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
33 |
#
|
34 |
# Fuse lets you easily create your own filesystems which run entirely in user
|
|
35 |
# mode and with normal user permissions.
|
|
36 |
# This example presents a simple file system.
|
|
37 |
# You mount it by directly running this file.
|
|
38 |
#
|
|
39 |
# Usage:
|
|
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
40 |
# templatefs.py MOUNTPOINT
|
|
45
by Adrian Panasiuk
* describe command line parsing |
41 |
# templatefs.py MOUNTPOINT -o xyz=VALUE
|
42 |
# templatefs.py arg1 arg2 .. MOUNTPOINT argn arg(n+1) ...
|
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
43 |
# To unmount:
|
44 |
# fusermount -u MOUNTPOINT
|
|
45 |
#
|
|
46 |
# Use `tail -f LOG` to read the log in real-time (as it is written).
|
|
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
47 |
# Also, mount with `./templatefs.py MOUNTPOINT -d` to have FUSE print out its own
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
48 |
# debugging messages (which are in some cases more, and some cases less useful
|
49 |
# than mine).
|
|
|
19
by Matt Giuca
mattfs: Added a list of as-yet-unstubbed methods at the top. |
50 |
#
|
|
31
by Matt Giuca
templatefs: Cleaned up / reorganised comments at the top. |
51 |
# Issues with this template
|
52 |
# =========================
|
|
|
19
by Matt Giuca
mattfs: Added a list of as-yet-unstubbed methods at the top. |
53 |
# I have tried to stub out all methods which Fuse will call (including
|
54 |
# undocumented ones, some of which are very important).
|
|
55 |
# I have not yet done the following:
|
|
56 |
# - getxattr
|
|
57 |
# - listxattr
|
|
58 |
# - setxattr
|
|
59 |
# - removexattr
|
|
60 |
# - lock
|
|
61 |
# - bmap
|
|
|
45
by Adrian Panasiuk
* describe command line parsing |
62 |
#
|
63 |
# Note that some of the data in this document come from experimentation.
|
|
64 |
# There is no guarantee that later versions and implementations of FUSE
|
|
65 |
# will behave the same way as the tested version.
|
|
66 |
#
|
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
67 |
|
|
31
by Matt Giuca
templatefs: Cleaned up / reorganised comments at the top. |
68 |
# Notes on implementing this template
|
69 |
# ===================================
|
|
70 |
# The comments in this file are intended to be instructional, and may end up
|
|
71 |
# becoming proper documentation.
|
|
72 |
#
|
|
73 |
# All methods log their inputs to a file called "LOG" by default (in the
|
|
74 |
# current directory), so you can experiment with the filesystem and
|
|
75 |
# note exactly how all the methods get called.
|
|
76 |
#
|
|
77 |
# Most methods just return -errno.EOPNOTSUPP (Operation not supported). If you
|
|
78 |
# plan to implement a method, you could change the stub to -errno.ENOSYS
|
|
79 |
# (Function not implemented). If your system actually doesn't support an
|
|
80 |
# operation, leave it as -errno.EOPNOTSUPP.
|
|
81 |
||
82 |
# Notes on working out all the methods to implement
|
|
83 |
# =================================================
|
|
|
12
by Matt Giuca
mattfs: Notes on working out all the methods to implement. |
84 |
# Python Fuse is fairly poorly documented. The documentation is here:
|
85 |
# http://apps.sourceforge.net/mediawiki/fuse/index.php?
|
|
86 |
# title=FUSE_Python_Reference
|
|
87 |
# But it's very scarce in some cases.
|
|
88 |
#
|
|
89 |
# A better bet is to look at the C reference, but it's very scarce too, and
|
|
90 |
# you have to figure out how it applies to Python (not always obvious):
|
|
91 |
# http://fuse.sourceforge.net/doxygen/structfuse__operations.html
|
|
92 |
#
|
|
93 |
# So finally, I turned to the source code. This is also very difficult to
|
|
94 |
# understand because the functions aren't explicitly defined anywhere. The
|
|
95 |
# only places they are actually defined is in the C wrapping code, which has a
|
|
96 |
# handler for each Fuse C function, and calls a Python function object. From
|
|
97 |
# here, you can tell what it's marshalling between C and Python.
|
|
98 |
# This is found in /fuseparts/_fusemodule.c in the source tree.
|
|
99 |
# Most functions just copy over their arguments into Python, but some are
|
|
100 |
# tricky (such as open).
|
|
101 |
||
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
102 |
import fuse |
103 |
||
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
104 |
import os |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
105 |
import stat |
106 |
import errno |
|
107 |
import datetime |
|
108 |
import time |
|
109 |
import calendar |
|
110 |
import logging |
|
111 |
||
112 |
LOG_FILENAME = "LOG" |
|
|
5
by Matt Giuca
mattfs: getattr now prints as a debug-level message, not info, since it shows |
113 |
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO,) |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
114 |
|
115 |
# FUSE version at the time of writing. Be compatible with this version.
|
|
116 |
fuse.fuse_python_api = (0, 2) |
|
117 |
||
118 |
# First, we define a class deriving from fuse.Stat. This object is used to
|
|
119 |
# describe a file in our virtual file system.
|
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
120 |
# This class is rather large, but the concept is really simple (there's just a
|
121 |
# lot of code here to make construction really easy).
|
|
122 |
# All you have to do is present an object with the following fields, all ints:
|
|
123 |
# st_mode:
|
|
124 |
# Should be stat.S_IFREG or S_IFDIR OR'd with a normal Unix permission
|
|
125 |
# flag, such as 644.
|
|
126 |
# st_ino, st_dev:
|
|
127 |
# 0. Ignored, but required.
|
|
128 |
# st_nlink:
|
|
129 |
# Number of hard links to this file. For files, usually 1. For
|
|
130 |
# directories, usually 2 + number of immediate subdirs (one for parent,
|
|
131 |
# one for self, one for each child).
|
|
132 |
# st_uid, st_gid:
|
|
133 |
# uid/gid of file owner.
|
|
134 |
# st_size:
|
|
135 |
# File size in bytes.
|
|
136 |
# st_atime, st_mtime, st_ctime:
|
|
137 |
# File access times, in seconds since the epoch, UTC time. Last access
|
|
138 |
# time, modification time, stat change time, respectively.
|
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
139 |
class Stat(fuse.Stat): |
140 |
"""
|
|
141 |
A Stat object. Describes the attributes of a file or directory.
|
|
|
34
by Matt Giuca
templatefs: Changed Stat so it presents a 'dt_*time' attribute (as a |
142 |
Has all the st_* attributes, as well as dt_atime, dt_mtime and dt_ctime,
|
143 |
which are datetime.datetime versions of st_*time. The st_*time versions
|
|
144 |
are in epoch time.
|
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
145 |
"""
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
146 |
# Filesize of directories, in bytes.
|
147 |
DIRSIZE = 4096 |
|
148 |
||
149 |
# We can define __init__ however we like, because it's only called by us.
|
|
150 |
# But it has to have certain fields.
|
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
151 |
def __init__(self, st_mode, st_size, st_nlink=1, st_uid=None, st_gid=None, |
|
34
by Matt Giuca
templatefs: Changed Stat so it presents a 'dt_*time' attribute (as a |
152 |
dt_atime=None, dt_mtime=None, dt_ctime=None): |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
153 |
"""
|
154 |
Creates a Stat object.
|
|
155 |
st_mode: Required. Should be stat.S_IFREG or stat.S_IFDIR ORed with a
|
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
156 |
regular Unix permission value like 0644.
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
157 |
st_size: Required. Size of file in bytes. For a directory, should be
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
158 |
Stat.DIRSIZE.
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
159 |
st_nlink: Number of hard-links to the file. Regular files should
|
160 |
usually be 1 (default). Directories should usually be 2 + number
|
|
161 |
of immediate subdirs (one from the parent, one from self, one from
|
|
162 |
each child).
|
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
163 |
st_uid, st_gid: uid/gid of file owner. Defaults to the user who
|
164 |
mounted the file system.
|
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
165 |
st_atime, st_mtime, st_ctime: atime/mtime/ctime of file.
|
166 |
(Access time, modification time, stat change time).
|
|
167 |
These must be datetime.datetime objects, in UTC time.
|
|
168 |
All three values default to the current time.
|
|
169 |
"""
|
|
170 |
self.st_mode = st_mode |
|
171 |
self.st_ino = 0 # Ignored, but required |
|
172 |
self.st_dev = 0 # Ignored, but required |
|
173 |
# Note: Wiki says st_blksize is required (like st_dev, ignored but
|
|
174 |
# required). However, this breaks things and another tutorial I found
|
|
175 |
# did not have this field.
|
|
176 |
self.st_nlink = st_nlink |
|
177 |
if st_uid is None: |
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
178 |
st_uid = os.getuid() |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
179 |
self.st_uid = st_uid |
180 |
if st_gid is None: |
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
181 |
st_gid = os.getgid() |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
182 |
self.st_gid = st_gid |
183 |
self.st_size = st_size |
|
|
34
by Matt Giuca
templatefs: Changed Stat so it presents a 'dt_*time' attribute (as a |
184 |
now = datetime.datetime.utcnow() |
185 |
self.dt_atime = dt_atime or now |
|
186 |
self.dt_mtime = dt_mtime or now |
|
187 |
self.dt_ctime = dt_ctime or now |
|
188 |
||
189 |
def _get_dt_atime(self): |
|
190 |
return self.epoch_datetime(self.st_atime) |
|
191 |
def _set_dt_atime(self, value): |
|
192 |
self.st_atime = self.datetime_epoch(value) |
|
193 |
dt_atime = property(_get_dt_atime, _set_dt_atime) |
|
194 |
||
195 |
def _get_dt_mtime(self): |
|
196 |
return self.epoch_datetime(self.st_mtime) |
|
197 |
def _set_dt_mtime(self, value): |
|
198 |
self.st_mtime = self.datetime_epoch(value) |
|
199 |
dt_mtime = property(_get_dt_mtime, _set_dt_mtime) |
|
200 |
||
201 |
def _get_dt_ctime(self): |
|
202 |
return self.epoch_datetime(self.st_ctime) |
|
203 |
def _set_dt_ctime(self, value): |
|
204 |
self.st_ctime = self.datetime_epoch(value) |
|
205 |
dt_ctime = property(_get_dt_ctime, _set_dt_ctime) |
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
206 |
|
207 |
@staticmethod
|
|
208 |
def datetime_epoch(dt): |
|
209 |
"""
|
|
210 |
Converts a datetime.datetime object which is in UTC time
|
|
211 |
(as returned by datetime.datetime.utcnow()) into an int, which represents
|
|
212 |
the number of seconds since the system epoch (also in UTC time).
|
|
213 |
"""
|
|
214 |
# datetime.datetime.timetuple converts a datetime into a time.struct_time.
|
|
215 |
# calendar.timegm converts a time.struct_time into epoch time, without
|
|
216 |
# modifying for time zone (so UTC time stays in UTC time, unlike
|
|
217 |
# time.mktime).
|
|
218 |
return calendar.timegm(dt.timetuple()) |
|
|
34
by Matt Giuca
templatefs: Changed Stat so it presents a 'dt_*time' attribute (as a |
219 |
@staticmethod
|
220 |
def epoch_datetime(seconds): |
|
221 |
"""
|
|
222 |
Converts an int, the number of seconds since the system epoch in UTC
|
|
223 |
time, into a datetime.datetime object, also in UTC time.
|
|
224 |
"""
|
|
225 |
return datetime.datetime.utcfromtimestamp(seconds) |
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
226 |
|
227 |
# Almost all that is required is the definition of a class deriving from
|
|
228 |
# fuse.Fuse, and implementation of a bunch of methods.
|
|
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
229 |
class TemplateFS(fuse.Fuse): |
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
230 |
"""
|
231 |
A Fuse filesystem object. Implements methods which are called by the Fuse
|
|
232 |
system as a result of the operating system requesting filesystem
|
|
233 |
operations on places where this file system is mounted.
|
|
|
4
by Matt Giuca
mattfs: Better commenting. |
234 |
|
235 |
Unless otherwise documented, all of these methods return an int.
|
|
236 |
This should be 0 on success, or the NEGATIVE of an errno value on failure.
|
|
237 |
For example, to report "no such file or directory", methods return
|
|
238 |
-errno.ENOENT. See the errno manpage for a list of errno values. (Though
|
|
239 |
note that Python's errno is slightly different; see help(errno)).
|
|
240 |
Methods should return errno.EOPNOTSUPP (operation not supported) if they
|
|
241 |
are deliberately not supported, or errno.ENOSYS (function not implemented)
|
|
242 |
if they have not yet been implemented.
|
|
243 |
||
244 |
Unless otherwise documented, all paths should begin with a '/' and be
|
|
245 |
"absolute paths", where "absolute" means relative to the root of the
|
|
246 |
mounted filesystem. There are no references to files outside the
|
|
247 |
filesystem.
|
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
248 |
"""
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
249 |
def __init__(self, *args, **kwargs): |
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
250 |
"""
|
|
45
by Adrian Panasiuk
* describe command line parsing |
251 |
Creates a new TemplateFS object. Needs to call fuse.Fuse.__init__ with
|
252 |
the args (just forward them along). Note that options passed to the
|
|
253 |
filesystem through the command line are not available during the
|
|
254 |
execution of this method.
|
|
255 |
||
256 |
If parsing the command line argument fails, fsdestroy is called
|
|
257 |
without prior calling fsinit.
|
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
258 |
"""
|
|
45
by Adrian Panasiuk
* describe command line parsing |
259 |
logging.info("Preparing to mount file system") |
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
260 |
#self.file_class = File
|
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
261 |
super(TemplateFS, self).__init__(*args, **kwargs) |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
262 |
|
|
45
by Adrian Panasiuk
* describe command line parsing |
263 |
"""
|
264 |
After calling the superconstructor, we may optionally register
|
|
265 |
options to be parsed from the command line arguments. To pass an
|
|
266 |
option, use
|
|
267 |
templatefs.py MOUNTPOINT -o xyz=VALUE -o pqr=
|
|
268 |
which sets xyz to "VALUE" and pqr to "" (empty string).
|
|
269 |
||
270 |
Not offering the equals sign is (eg. templatefs.py MOUNTPOINT -o
|
|
271 |
enable_feature) is equivallent to not passing the option at all.
|
|
272 |
||
273 |
If the same option is passed multiple times, the last one takes
|
|
274 |
takes priority:
|
|
275 |
templatefs.py -o xyz=a,xyz=b MOUNTPOINT -o xyz=c -o xyz=d,def=0,xyz=e
|
|
276 |
||
277 |
Note that the parser will error out when a not registered option
|
|
278 |
is passed on the command line.
|
|
279 |
||
280 |
||
281 |
Apart from options, we can also get non-option arguments from the
|
|
282 |
command-line:
|
|
283 |
templatefs.py arg1 arg2 arg3 -o xyz=pqr,abc=def MOUNTPOINT
|
|
284 |
These may be used, for example, to specify the device to be mounted.
|
|
285 |
The mountpoint is the last non-option argument.
|
|
286 |
||
287 |
||
288 |
You may further customize command line argument parsing setting
|
|
289 |
the parser_class argument in __init__.
|
|
290 |
"""
|
|
|
46
by Matt Giuca
templatefs.py: Wrapped too-long line. |
291 |
self.parser.add_option(mountopt="xyz", |
292 |
help="description which shows up with templatefs.py -h") |
|
|
45
by Adrian Panasiuk
* describe command line parsing |
293 |
|
|
4
by Matt Giuca
mattfs: Better commenting. |
294 |
def fsinit(self): |
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
295 |
"""
|
|
45
by Adrian Panasiuk
* describe command line parsing |
296 |
Will be called after the command line arguments are successfully
|
297 |
parsed. It doesn't have to exist or do anything, but as options to the
|
|
298 |
filesystem are not available in __init__, fsinit is more suitable for
|
|
299 |
the mounting logic than __init__.
|
|
300 |
||
301 |
To access the command line passed options and nonoption arguments, use
|
|
302 |
cmdline.
|
|
303 |
||
304 |
The mountpoint is not stored in cmdline.
|
|
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
305 |
"""
|
|
45
by Adrian Panasiuk
* describe command line parsing |
306 |
logging.info("Nonoption arguments: " + str(self.cmdline[1])) |
307 |
||
308 |
||
309 |
self.xyz = self.cmdline[0].xyz |
|
310 |
if self.xyz != None: |
|
311 |
logging.info("xyz set to '" + self.xyz + "'") |
|
312 |
else: |
|
313 |
logging.info("xyz not set") |
|
314 |
||
315 |
logging.info("Filesystem mounted") |
|
|
2
by Matt Giuca
mattfs: More comments, and fsinit. |
316 |
|
|
18
by Matt Giuca
mattfs: Added fsdestroy. |
317 |
def fsdestroy(self): |
318 |
"""
|
|
319 |
Will be called when the file system is about to be unmounted.
|
|
320 |
It doesn't have to exist, or do anything.
|
|
321 |
"""
|
|
322 |
logging.info("Unmounting file system") |
|
323 |
||
|
20
by Matt Giuca
mattfs.py: Added statfs. |
324 |
def statfs(self): |
325 |
"""
|
|
326 |
Retrieves information about the mounted filesystem.
|
|
327 |
Returns a fuse.StatVfs object containing the details.
|
|
328 |
This is optional. If omitted, Fuse will simply report a bunch of 0s.
|
|
329 |
||
330 |
The StatVfs should have the same fields as described in man 2 statfs
|
|
331 |
(Linux Programmer's Manual), except for f_type.
|
|
332 |
This includes the following:
|
|
333 |
f_bsize (optimal transfer block size)
|
|
334 |
f_blocks (number of blocks total)
|
|
335 |
f_bfree (number of free blocks)
|
|
336 |
f_bavail (number of free blocks available to non-root)
|
|
337 |
f_files (number of file nodes in system)
|
|
338 |
f_ffree (number of free file nodes)
|
|
339 |
f_namemax (max length of filenames)
|
|
340 |
||
341 |
Note f_type, f_frsize, f_favail, f_fsid and f_flag are ignored.
|
|
342 |
"""
|
|
343 |
logging.info("statfs") |
|
344 |
stats = fuse.StatVfs() |
|
345 |
# Fill it in here. All fields take on a default value of 0.
|
|
346 |
return stats |
|
347 |
||
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
348 |
def getattr(self, path): |
|
3
by Matt Giuca
mattfs: Re-commented the methods using docstrings, in a way describing what |
349 |
"""
|
350 |
Retrieves information about a file (the "stat" of a file).
|
|
351 |
Returns a fuse.Stat object containing details about the file or
|
|
352 |
directory.
|
|
353 |
Returns -errno.ENOENT if the file is not found, or another negative
|
|
354 |
errno code if another error occurs.
|
|
355 |
"""
|
|
|
5
by Matt Giuca
mattfs: getattr now prints as a debug-level message, not info, since it shows |
356 |
logging.debug("getattr: %s" % path) |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
357 |
if path == "/": |
358 |
mode = stat.S_IFDIR | 0755 |
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
359 |
st = Stat(st_mode=mode, st_size=Stat.DIRSIZE, st_nlink=2) |
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
360 |
# An example of a regular file:
|
361 |
# mode = stat.S_IFREG | 0644
|
|
362 |
# st = Stat(st_mode=mode, st_size=14)
|
|
363 |
# An example of a symlink (note that size is the size of the link's
|
|
364 |
# target path string):
|
|
365 |
# mode = stat.S_IFLNK | 0777
|
|
366 |
# st = Stat(st_mode=mode, st_size=7)
|
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
367 |
else: |
368 |
return -errno.ENOENT |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
369 |
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
370 |
return st |
371 |
||
|
17
by Matt Giuca
mattfs: Added utime and utimens. |
372 |
# Note: utime is deprecated in favour of utimens.
|
373 |
# utimens takes precedence over utime, so having this here does nothing
|
|
374 |
# unless you delete utimens.
|
|
375 |
def utime(self, path, times): |
|
376 |
"""
|
|
377 |
Sets the access and modification times on a file.
|
|
378 |
times: (atime, mtime) pair. Both ints, in seconds since epoch.
|
|
379 |
Deprecated in favour of utimens.
|
|
380 |
"""
|
|
381 |
atime, mtime = times |
|
382 |
logging.info("utime: %s (atime %s, mtime %s)" % (path, atime, mtime)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
383 |
return -errno.EOPNOTSUPP |
|
17
by Matt Giuca
mattfs: Added utime and utimens. |
384 |
|
385 |
def utimens(self, path, atime, mtime): |
|
386 |
"""
|
|
387 |
Sets the access and modification times on a file, in nanoseconds.
|
|
388 |
atime, mtime: Both fuse.TimeSpec objects, with 'tv_sec' and 'tv_nsec'
|
|
389 |
attributes, which are the seconds and nanoseconds parts,
|
|
390 |
respectively.
|
|
391 |
"""
|
|
392 |
logging.info("utime: %s (atime %s:%s, mtime %s:%s)" |
|
393 |
% (path,atime.tv_sec,atime.tv_nsec,mtime.tv_sec,mtime.tv_nsec)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
394 |
return -errno.EOPNOTSUPP |
|
17
by Matt Giuca
mattfs: Added utime and utimens. |
395 |
|
|
10
by Matt Giuca
mattfs: Added access, open and opendir methods. |
396 |
def access(self, path, flags): |
397 |
"""
|
|
398 |
Checks permissions for accessing a file or directory.
|
|
399 |
flags: As described in man 2 access (Linux Programmer's Manual).
|
|
400 |
Either os.F_OK (test for existence of file), or ORing of
|
|
401 |
os.R_OK, os.W_OK, os.X_OK (test if file is readable, writable and
|
|
402 |
executable, respectively. Must pass all tests).
|
|
403 |
Should return 0 for "allowed", or -errno.EACCES if disallowed.
|
|
404 |
May not always be called. For example, when opening a file, open may
|
|
405 |
be called and access avoided.
|
|
406 |
"""
|
|
407 |
logging.info("access: %s (flags %s)" % (path, oct(flags))) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
408 |
if path == "/": |
409 |
return 0 |
|
410 |
else: |
|
411 |
return -errno.EACCES |
|
|
10
by Matt Giuca
mattfs: Added access, open and opendir methods. |
412 |
|
|
13
by Matt Giuca
mattfs: Added readlink method, and new dummy file "ls" which is a symlink to |
413 |
def readlink(self, path): |
414 |
"""
|
|
415 |
Get the target of a symlink.
|
|
416 |
Returns a bytestring with the contents of a symlink (its target).
|
|
417 |
May also return an int error code.
|
|
418 |
"""
|
|
419 |
logging.info("readlink: %s" % path) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
420 |
return -errno.EOPNOTSUPP |
|
13
by Matt Giuca
mattfs: Added readlink method, and new dummy file "ls" which is a symlink to |
421 |
|
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
422 |
def mknod(self, path, mode, rdev): |
423 |
"""
|
|
424 |
Creates a non-directory file (or a device node).
|
|
425 |
mode: Unix file mode flags for the file being created.
|
|
426 |
rdev: Special properties for creation of character or block special
|
|
427 |
devices (I've never gotten this to work).
|
|
428 |
Always 0 for regular files or FIFO buffers.
|
|
429 |
"""
|
|
430 |
# Note: mode & 0770000 gives you the non-permission bits.
|
|
431 |
# Common ones:
|
|
|
11
by Matt Giuca
mattfs: Implemented "read" function. Can now print out text for some files. |
432 |
# S_IFREG: 0100000 (A regular file)
|
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
433 |
# S_IFIFO: 010000 (A fifo buffer, created with mkfifo)
|
434 |
||
435 |
# Potential ones (I have never seen them):
|
|
436 |
# Note that these could be made by copying special devices or sockets
|
|
437 |
# or using mknod, but I've never gotten FUSE to pass such a request
|
|
438 |
# along.
|
|
439 |
# S_IFCHR: 020000 (A character special device, created with mknod)
|
|
440 |
# S_IFBLK: 060000 (A block special device, created with mknod)
|
|
441 |
# S_IFSOCK: 0140000 (A socket, created with mkfifo)
|
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
442 |
|
443 |
# Also note: You can use self.GetContext() to get a dictionary
|
|
444 |
# {'uid': ?, 'gid': ?}, which tells you the uid/gid of the user
|
|
445 |
# executing the current syscall. This should be handy when creating
|
|
446 |
# new files and directories, because they should be owned by this
|
|
447 |
# user/group.
|
|
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
448 |
logging.info("mknod: %s (mode %s, rdev %s)" % (path, oct(mode), rdev)) |
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
449 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
450 |
|
451 |
def mkdir(self, path, mode): |
|
452 |
"""
|
|
453 |
Creates a directory.
|
|
454 |
mode: Unix file mode flags for the directory being created.
|
|
455 |
"""
|
|
456 |
# Note: mode & 0770000 gives you the non-permission bits.
|
|
457 |
# Should be S_IDIR (040000); I guess you can assume this.
|
|
|
8
by Matt Giuca
mattfs: By default, files are now owned by the user who mounted the drive, NOT |
458 |
# Also see note about self.GetContext() in mknod.
|
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
459 |
logging.info("mkdir: %s (mode %s)" % (path, oct(mode))) |
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
460 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
461 |
|
462 |
def unlink(self, path): |
|
463 |
"""Deletes a file."""
|
|
464 |
logging.info("unlink: %s" % path) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
465 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
466 |
|
|
44
by Matt Giuca
templatefs: Added rmdir (previously forgotten operation). |
467 |
def rmdir(self, path): |
468 |
"""Deletes a directory."""
|
|
469 |
logging.info("rmdir: %s" % path) |
|
470 |
return -errno.EOPNOTSUPP |
|
471 |
||
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
472 |
def symlink(self, target, name): |
473 |
"""
|
|
474 |
Creates a symbolic link from path to target.
|
|
475 |
||
476 |
The 'name' is a regular path like any other method (absolute, but
|
|
477 |
relative to the filesystem root).
|
|
478 |
The 'target' is special - it works just like any symlink target. It
|
|
479 |
may be absolute, in which case it is absolute on the user's system,
|
|
480 |
NOT the mounted filesystem, or it may be relative. It should be
|
|
481 |
treated as an opaque string - the filesystem implementation should not
|
|
482 |
ever need to follow it (that is handled by the OS).
|
|
483 |
||
484 |
Hence, if the operating system creates a link FROM this system TO
|
|
485 |
another system, it will call this method with a target pointing
|
|
486 |
outside the filesystem.
|
|
487 |
If the operating system creates a link FROM some other system TO this
|
|
488 |
system, it will not touch this system at all (symlinks do not depend
|
|
489 |
on the target system unless followed).
|
|
490 |
"""
|
|
491 |
logging.info("symlink: target %s, name: %s" % (target, name)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
492 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
493 |
|
494 |
def link(self, target, name): |
|
495 |
"""
|
|
496 |
Creates a hard link from name to target. Note that both paths are
|
|
497 |
relative to the mounted file system. Hard-links across systems are not
|
|
498 |
supported.
|
|
499 |
"""
|
|
500 |
logging.info("link: target %s, name: %s" % (target, name)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
501 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
502 |
|
503 |
def rename(self, old, new): |
|
504 |
"""
|
|
505 |
Moves a file from old to new. (old and new are both full paths, and
|
|
506 |
may not be in the same directory).
|
|
507 |
|
|
508 |
Note that both paths are relative to the mounted file system.
|
|
509 |
If the operating system needs to move files across systems, it will
|
|
510 |
manually copy and delete the file, and this method will not be called.
|
|
511 |
"""
|
|
512 |
logging.info("rename: target %s, name: %s" % (old, new)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
513 |
return -errno.EOPNOTSUPP |
|
6
by Matt Giuca
mattfs: Added in stubs for all of the other directory operations |
514 |
|
|
15
by Matt Giuca
mattfs: Added chmod and chown (stubs). |
515 |
def chmod(self, path, mode): |
516 |
"""Changes the mode of a file or directory."""
|
|
517 |
logging.info("chmod: %s (mode %s)" % (path, oct(mode))) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
518 |
return -errno.EOPNOTSUPP |
|
15
by Matt Giuca
mattfs: Added chmod and chown (stubs). |
519 |
|
520 |
def chown(self, path, uid, gid): |
|
521 |
"""Changes the owner of a file or directory."""
|
|
522 |
logging.info("chown: %s (uid %s, gid %s)" % (path, uid, gid)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
523 |
return -errno.EOPNOTSUPP |
|
15
by Matt Giuca
mattfs: Added chmod and chown (stubs). |
524 |
|
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
525 |
def truncate(self, path, size): |
526 |
"""
|
|
527 |
Shrink or expand a file to a given size.
|
|
528 |
If 'size' is smaller than the existing file size, truncate it from the
|
|
529 |
end.
|
|
530 |
If 'size' if larger than the existing file size, extend it with null
|
|
531 |
bytes.
|
|
532 |
"""
|
|
533 |
logging.info("truncate: %s (size %s)" % (path, size)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
534 |
return -errno.EOPNOTSUPP |
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
535 |
|
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
536 |
### DIRECTORY OPERATION METHODS ###
|
537 |
# Methods in this section are operations for opening directories and
|
|
538 |
# working on open directories.
|
|
539 |
# "opendir" is the method for opening directories. It *may* return an
|
|
540 |
# arbitrary Python object (not None or int), which is used as a dir
|
|
541 |
# handle by the methods for working on directories.
|
|
542 |
# All the other methods (readdir, fsyncdir, releasedir) are methods for
|
|
543 |
# working on directories. They should all be prepared to accept an
|
|
544 |
# optional dir-handle argument, which is whatever object "opendir"
|
|
545 |
# returned.
|
|
546 |
||
547 |
def opendir(self, path): |
|
548 |
"""
|
|
549 |
Checks permissions for listing a directory.
|
|
550 |
This should check the 'r' (read) permission on the directory.
|
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
551 |
|
552 |
On success, *may* return an arbitrary Python object, which will be
|
|
553 |
used as the "fh" argument to all the directory operation methods on
|
|
554 |
the directory. Or, may just return None on success.
|
|
555 |
On failure, should return a negative errno code.
|
|
556 |
Should return -errno.EACCES if disallowed.
|
|
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
557 |
"""
|
558 |
logging.info("opendir: %s" % path) |
|
559 |
if path == "/": |
|
560 |
return 0 |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
561 |
else: |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
562 |
return -errno.EACCES |
563 |
||
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
564 |
def releasedir(self, path, dh=None): |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
565 |
"""
|
566 |
Closes an open directory. Allows filesystem to clean up.
|
|
567 |
"""
|
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
568 |
logging.info("releasedir: %s (dh %s)" % (path, dh)) |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
569 |
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
570 |
def fsyncdir(self, path, datasync, dh=None): |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
571 |
"""
|
572 |
Synchronises an open directory.
|
|
573 |
datasync: If True, only flush user data, not metadata.
|
|
574 |
"""
|
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
575 |
logging.info("fsyncdir: %s (datasync %s, dh %s)" |
576 |
% (path, datasync, dh)) |
|
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
577 |
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
578 |
def readdir(self, path, offset, dh=None): |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
579 |
"""
|
580 |
Generator function. Produces a directory listing.
|
|
581 |
Yields individual fuse.Direntry objects, one per file in the
|
|
582 |
directory. Should always yield at least "." and "..".
|
|
583 |
Should yield nothing if the file is not a directory or does not exist.
|
|
584 |
(Does not need to raise an error).
|
|
585 |
||
586 |
offset: I don't know what this does, but I think it allows the OS to
|
|
587 |
request starting the listing partway through (which I clearly don't
|
|
588 |
yet support). Seems to always be 0 anyway.
|
|
589 |
"""
|
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
590 |
logging.info("readdir: %s (offset %s, dh %s)" % (path, offset, dh)) |
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
591 |
if path == "/": |
592 |
yield fuse.Direntry(".") |
|
593 |
yield fuse.Direntry("..") |
|
594 |
||
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
595 |
### FILE OPERATION METHODS ###
|
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
596 |
# Methods in this section are operations for opening files and working on
|
597 |
# open files.
|
|
598 |
# "open" and "create" are methods for opening files. They *may* return an
|
|
599 |
# arbitrary Python object (not None or int), which is used as a file
|
|
600 |
# handle by the methods for working on files.
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
601 |
# All the other methods (fgetattr, release, read, write, fsync, flush,
|
|
26
by Matt Giuca
mattfs: Added section "directory operation methods", commented it, and moved |
602 |
# ftruncate and lock) are methods for working on files. They should all be
|
603 |
# prepared to accept an optional file-handle argument, which is whatever
|
|
604 |
# object "open" or "create" returned.
|
|
|
10
by Matt Giuca
mattfs: Added access, open and opendir methods. |
605 |
|
606 |
def open(self, path, flags): |
|
607 |
"""
|
|
608 |
Open a file for reading/writing, and check permissions.
|
|
609 |
flags: As described in man 2 open (Linux Programmer's Manual).
|
|
610 |
ORing of several access flags, including one of os.O_RDONLY,
|
|
611 |
os.O_WRONLY or os.O_RDWR. All other flags are in os as well.
|
|
|
27
by Matt Giuca
mattfs: Added dir-handle arguments to all the directory operations, and more |
612 |
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
613 |
On success, *may* return an arbitrary Python object, which will be
|
614 |
used as the "fh" argument to all the file operation methods on the
|
|
615 |
file. Or, may just return None on success.
|
|
616 |
On failure, should return a negative errno code.
|
|
617 |
Should return -errno.EACCES if disallowed.
|
|
|
10
by Matt Giuca
mattfs: Added access, open and opendir methods. |
618 |
"""
|
619 |
logging.info("open: %s (flags %s)" % (path, oct(flags))) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
620 |
return -errno.EOPNOTSUPP |
|
10
by Matt Giuca
mattfs: Added access, open and opendir methods. |
621 |
|
|
24
by Matt Giuca
mattfs.py: Minor (moved create near open). |
622 |
def create(self, path, mode, rdev): |
623 |
"""
|
|
624 |
Creates a file and opens it for writing.
|
|
625 |
Will be called in favour of mknod+open, but it's optional (OS will
|
|
626 |
fall back on that sequence).
|
|
627 |
mode: Unix file mode flags for the file being created.
|
|
628 |
rdev: Special properties for creation of character or block special
|
|
629 |
devices (I've never gotten this to work).
|
|
630 |
Always 0 for regular files or FIFO buffers.
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
631 |
See "open" for return value.
|
|
24
by Matt Giuca
mattfs.py: Minor (moved create near open). |
632 |
"""
|
633 |
logging.info("create: %s (mode %s, rdev %s)" % (path,oct(mode),rdev)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
634 |
return -errno.EOPNOTSUPP |
|
24
by Matt Giuca
mattfs.py: Minor (moved create near open). |
635 |
|
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
636 |
def fgetattr(self, path, fh=None): |
637 |
"""
|
|
638 |
Retrieves information about a file (the "stat" of a file).
|
|
639 |
Same as Fuse.getattr, but may be given a file handle to an open file,
|
|
640 |
so it can use that instead of having to look up the path.
|
|
641 |
"""
|
|
642 |
logging.debug("fgetattr: %s (fh %s)" % (path, fh)) |
|
643 |
# We could use fh for a more efficient lookup. Here we just call the
|
|
644 |
# non-file-handle version, getattr.
|
|
645 |
return self.getattr(path) |
|
646 |
||
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
647 |
def release(self, path, flags, fh=None): |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
648 |
"""
|
649 |
Closes an open file. Allows filesystem to clean up.
|
|
650 |
flags: The same flags the file was opened with (see open).
|
|
651 |
"""
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
652 |
logging.info("release: %s (flags %s, fh %s)" % (path, oct(flags), fh)) |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
653 |
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
654 |
def fsync(self, path, datasync, fh=None): |
|
22
by Matt Giuca
mattfs: Added fsyncdir, fsync, flush. |
655 |
"""
|
656 |
Synchronises an open file.
|
|
657 |
datasync: If True, only flush user data, not metadata.
|
|
658 |
"""
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
659 |
logging.info("fsync: %s (datasync %s, fh %s)" % (path, datasync, fh)) |
|
22
by Matt Giuca
mattfs: Added fsyncdir, fsync, flush. |
660 |
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
661 |
def flush(self, path, fh=None): |
|
22
by Matt Giuca
mattfs: Added fsyncdir, fsync, flush. |
662 |
"""
|
663 |
Flush cached data to the file system.
|
|
664 |
This is NOT an fsync (I think the difference is fsync goes both ways,
|
|
665 |
while flush is just one-way).
|
|
666 |
"""
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
667 |
logging.info("flush: %s (fh %s)" % (path, fh)) |
|
22
by Matt Giuca
mattfs: Added fsyncdir, fsync, flush. |
668 |
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
669 |
def read(self, path, size, offset, fh=None): |
|
11
by Matt Giuca
mattfs: Implemented "read" function. Can now print out text for some files. |
670 |
"""
|
671 |
Get all or part of the contents of a file.
|
|
672 |
size: Size in bytes to read.
|
|
673 |
offset: Offset in bytes from the start of the file to read from.
|
|
674 |
Does not need to check access rights (operating system will always
|
|
675 |
call access or open first).
|
|
676 |
Returns a byte string with the contents of the file, with a length no
|
|
677 |
greater than 'size'. May also return an int error code.
|
|
678 |
||
679 |
If the length of the returned string is 0, it indicates the end of the
|
|
680 |
file, and the OS will not request any more. If the length is nonzero,
|
|
681 |
the OS may request more bytes later.
|
|
682 |
To signal that it is NOT the end of file, but no bytes are presently
|
|
683 |
available (and it is a non-blocking read), return -errno.EAGAIN.
|
|
684 |
If it is a blocking read, just block until ready.
|
|
685 |
"""
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
686 |
logging.info("read: %s (size %s, offset %s, fh %s)" |
687 |
% (path, size, offset, fh)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
688 |
return -errno.EOPNOTSUPP |
|
11
by Matt Giuca
mattfs: Implemented "read" function. Can now print out text for some files. |
689 |
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
690 |
def write(self, path, buf, offset, fh=None): |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
691 |
"""
|
692 |
Write over part of a file.
|
|
693 |
buf: Byte string containing the text to write.
|
|
694 |
offset: Offset in bytes from the start of the file to write to.
|
|
695 |
Does not need to check access rights (operating system will always
|
|
696 |
call access or open first).
|
|
697 |
Should only overwrite the part of the file from offset to
|
|
698 |
offset+len(buf).
|
|
699 |
||
700 |
Must return an int: the number of bytes successfully written (should
|
|
701 |
be equal to len(buf) unless an error occured). May also be a negative
|
|
702 |
int, which is an errno code.
|
|
703 |
"""
|
|
|
25
by Matt Giuca
mattfs.py: Added filehandle arguments to all file access methods, and added |
704 |
logging.info("write: %s (offset %s, fh %s)" % (path, offset, fh)) |
|
16
by Matt Giuca
mattfs: Write and truncate now succeed, pretending they were successful, |
705 |
logging.debug(" buf: %r" % buf) |
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
706 |
return -errno.EOPNOTSUPP |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
707 |
|
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
708 |
def ftruncate(self, path, size, fh=None): |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
709 |
"""
|
710 |
Shrink or expand a file to a given size.
|
|
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
711 |
Same as Fuse.truncate, but may be given a file handle to an open file,
|
712 |
so it can use that instead of having to look up the path.
|
|
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
713 |
"""
|
|
23
by Matt Giuca
mattfs.py: Added fgetattr and ftruncate methods. I discovered these are |
714 |
logging.info("ftruncate: %s (size %s, fh %s)" % (path, size, fh)) |
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
715 |
return -errno.EOPNOTSUPP |
|
14
by Matt Giuca
Added releasedir, release, write and truncate methods (stubs). |
716 |
|
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
717 |
class File(object): |
718 |
"""
|
|
719 |
An open File handle. Like Fuse objects, supports a number of
|
|
720 |
specially-named methods which are called when the filesystem needs to
|
|
721 |
access the file in question.
|
|
722 |
||
723 |
Note: Implementing this class is an *alternative* to implementing the
|
|
724 |
above "file operation methods" in Fuse itself. If this class is
|
|
725 |
implemented, the following line should appear in Fuse.__init__:
|
|
726 |
||
727 |
self.file_class = File
|
|
728 |
||
729 |
Also, all of the "file operation methods" should be removed from Fuse, as
|
|
730 |
they take priority over the File class.
|
|
731 |
||
732 |
The File class is simply a more object oriented way to implement the same
|
|
733 |
methods.
|
|
734 |
"""
|
|
735 |
def __init__(self, path, flags, mode=None): |
|
736 |
"""
|
|
737 |
File-class version of "open" and "create" combined.
|
|
738 |
Opens a file (possibly creating it, if mode is supplied).
|
|
739 |
||
740 |
Note that you have no way to see the Fuse object which created it.
|
|
741 |
The documentation suggests a workaround (search for
|
|
742 |
"wrapped_file_class"). Note that this class is supposed to go inside
|
|
743 |
Fuse.__init__.
|
|
744 |
http://apps.sourceforge.net/mediawiki/fuse/index.php
|
|
745 |
?title=FUSE_Python_Reference
|
|
746 |
This alone might be a reason to avoid using the File class, and
|
|
747 |
instead go with the more direct approach.
|
|
748 |
"""
|
|
749 |
logging.info("File.__init__: %s (flags %s, mode %s)" |
|
750 |
% (path, oct(flags), None if mode is None else oct(mode))) |
|
751 |
self.path = path |
|
752 |
||
753 |
def __repr__(self): |
|
754 |
return "<File %r>" % self.path |
|
755 |
||
756 |
def fgetattr(self): |
|
757 |
"""
|
|
758 |
File-class version of "getattr".
|
|
759 |
Retrieves information about a file (the "stat" of a file).
|
|
760 |
"""
|
|
761 |
logging.info("%r.fgetattr" % self) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
762 |
return -errno.EOPNOTSUPP |
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
763 |
|
764 |
def release(self, flags): |
|
765 |
"""
|
|
766 |
File-class version of "release".
|
|
767 |
Closes an open file. Allows filesystem to clean up.
|
|
768 |
"""
|
|
769 |
logging.info("%r.release (flags %s)" % (self, oct(flags))) |
|
770 |
||
771 |
def fsync(self, datasync): |
|
772 |
"""
|
|
773 |
File-class version of "fsync".
|
|
774 |
Synchronises an open file.
|
|
775 |
"""
|
|
776 |
logging.info("%r.fsync (datasync %s)" % (self, datasync)) |
|
777 |
||
778 |
def flush(self): |
|
779 |
"""
|
|
780 |
File-class version of "flush".
|
|
781 |
Flush cached data to the file system.
|
|
782 |
"""
|
|
783 |
logging.info("%r.flush" % self) |
|
784 |
||
785 |
def read(self, size, offset): |
|
786 |
"""
|
|
787 |
File-class version of "read".
|
|
788 |
Get all or part of the contents of a file.
|
|
789 |
"""
|
|
790 |
logging.info("%r.read (size %s, offset %s)" % (self, size, offset)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
791 |
return -errno.EOPNOTSUPP |
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
792 |
|
793 |
def write(self, buf, offset): |
|
794 |
"""
|
|
795 |
File-class version of "write".
|
|
796 |
Write over part of a file.
|
|
797 |
"""
|
|
798 |
logging.info("%r.write (offset %s)" % (self, offset)) |
|
799 |
logging.debug(" buf: %r" % buf) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
800 |
return -errno.EOPNOTSUPP |
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
801 |
|
802 |
def ftruncate(self, size): |
|
803 |
"""
|
|
804 |
File-class version of "ftruncate".
|
|
805 |
Shrink or expand a file to a given size.
|
|
806 |
"""
|
|
807 |
logging.info("%r.ftruncate (size %s)" % (self, size)) |
|
|
32
by Matt Giuca
templatefs: Rewrote many of the methods' implementations, so most now simply |
808 |
return -errno.EOPNOTSUPP |
|
28
by Matt Giuca
mattfs: Added File class, and extensive documentation. But it's disabled by |
809 |
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
810 |
# Now all we need is a main function.
|
811 |
# Fuse modules are actual Python scripts, which are user-executable. The main
|
|
812 |
# function needs to tell Fuse to mount themselves.
|
|
813 |
def main(): |
|
814 |
# Our custom usage message
|
|
815 |
usage = """ |
|
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
816 |
TemplateFS: A demo FUSE file system.
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
817 |
""" + fuse.Fuse.fusage |
|
30
by Matt Giuca
Renamed MattFS to TemplateFS. This will now serve as a template for |
818 |
server = TemplateFS(version="%prog " + fuse.__version__, |
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
819 |
usage=usage, dash_s_do='setsingle') |
820 |
server.parse(errex=1) |
|
|
36
by Matt Giuca
templatefs: Added server.multithreaded = 0. |
821 |
# multithreaded = 0 appears to be very important.
|
822 |
# I've had more complex filesystems freeze up without this.
|
|
823 |
server.multithreaded = 0 |
|
|
1
by Matt Giuca
mattfs.py: A first cut at a simple fuse example (hello in a directory). |
824 |
try: |
825 |
server.main() |
|
826 |
except fuse.FuseError, e: |
|
827 |
print str(e) |
|
828 |
||
829 |
if __name__ == '__main__': |
|
830 |
main() |
|
831 |
||
|
18
by Matt Giuca
mattfs: Added fsdestroy. |
832 |
logging.info("File system unmounted") |