1 |
dpavlin |
4 |
<?xml version="1.0" encoding="UTF-8"?> |
2 |
|
|
<leo_file> |
3 |
|
|
<leo_header file_format="2" tnodes="0" max_tnode_index="69" clone_windows="0"/> |
4 |
|
|
<globals body_outline_ratio="0.2448559670781893"> |
5 |
|
|
<global_window_position top="129" left="90" height="631" width="1124"/> |
6 |
|
|
<global_log_window_position top="0" left="0" height="0" width="0"/> |
7 |
|
|
</globals> |
8 |
|
|
<preferences> |
9 |
|
|
</preferences> |
10 |
|
|
<find_panel_settings> |
11 |
|
|
<find_string></find_string> |
12 |
|
|
<change_string></change_string> |
13 |
|
|
</find_panel_settings> |
14 |
|
|
<vnodes> |
15 |
|
|
<v t="davidmcnab.121303142957" a="E"><vh>fuse python bindings</vh> |
16 |
|
|
<v t="davidmcnab.121303142957.1" a="E" tnodeList="davidmcnab.121303142957.1,davidmcnab.121303142957.2,davidmcnab.121303142957.3,davidmcnab.121303142957.4,davidmcnab.121303142957.5,davidmcnab.121303142957.6,davidmcnab.121303142957.7,davidmcnab.121303142957.8,davidmcnab.121303142957.9,davidmcnab.121303142957.10,davidmcnab.121303142957.11,davidmcnab.121303142957.12,davidmcnab.121303142957.13,davidmcnab.121303142957.14,davidmcnab.121303142957.15,davidmcnab.121303142957.16,davidmcnab.121303142957.17,davidmcnab.121303142957.18,davidmcnab.121303142957.19,davidmcnab.121303142957.20,davidmcnab.121303142957.21,davidmcnab.121303142957.22,davidmcnab.121303142957.23,davidmcnab.121303142957.24,davidmcnab.121303144441,davidmcnab.121303144441.1,davidmcnab.121303142957.25,davidmcnab.121303142957.26,davidmcnab.121303142957.27,davidmcnab.121303142957.28"><vh>@file _fusemodule.c</vh> |
17 |
|
|
<v t="davidmcnab.121303142957.2"><vh>includes</vh></v> |
18 |
|
|
<v t="davidmcnab.121303142957.3" a="M"><vh>globals</vh></v> |
19 |
|
|
<v t="davidmcnab.121303142957.4"><vh>PROLOGUE</vh></v> |
20 |
|
|
<v t="davidmcnab.121303142957.5"><vh>EPILOGUE</vh></v> |
21 |
|
|
<v t="davidmcnab.121303142957.6"><vh>getattr_func</vh></v> |
22 |
|
|
<v t="davidmcnab.121303142957.7"><vh>readlink_func</vh></v> |
23 |
|
|
<v t="davidmcnab.121303142957.8"><vh>getdir_add_entry</vh></v> |
24 |
|
|
<v t="davidmcnab.121303142957.9"><vh>getdir_func</vh></v> |
25 |
|
|
<v t="davidmcnab.121303142957.10"><vh>mknod_func</vh></v> |
26 |
|
|
<v t="davidmcnab.121303142957.11"><vh>mkdir_func</vh></v> |
27 |
|
|
<v t="davidmcnab.121303142957.12"><vh>unlink_func</vh></v> |
28 |
|
|
<v t="davidmcnab.121303142957.13"><vh>rmdir_func</vh></v> |
29 |
|
|
<v t="davidmcnab.121303142957.14"><vh>symlink_func</vh></v> |
30 |
|
|
<v t="davidmcnab.121303142957.15"><vh>rename_func</vh></v> |
31 |
|
|
<v t="davidmcnab.121303142957.16"><vh>link_func</vh></v> |
32 |
|
|
<v t="davidmcnab.121303142957.17"><vh>chmod_func</vh></v> |
33 |
|
|
<v t="davidmcnab.121303142957.18"><vh>chown_func</vh></v> |
34 |
|
|
<v t="davidmcnab.121303142957.19"><vh>truncate_func</vh></v> |
35 |
|
|
<v t="davidmcnab.121303142957.20"><vh>utime_func</vh></v> |
36 |
|
|
<v t="davidmcnab.121303142957.21"><vh>read_func</vh></v> |
37 |
|
|
<v t="davidmcnab.121303142957.22"><vh>write_func</vh></v> |
38 |
|
|
<v t="davidmcnab.121303142957.23"><vh>open_func</vh></v> |
39 |
|
|
<v t="davidmcnab.121303142957.24" a="M"><vh>release_func</vh></v> |
40 |
|
|
<v t="davidmcnab.121303144441"><vh>statfs_func</vh></v> |
41 |
|
|
<v t="davidmcnab.121303144441.1"><vh>fsync_func</vh></v> |
42 |
|
|
<v t="davidmcnab.121303142957.25" a="M"><vh>process_cmd</vh></v> |
43 |
|
|
<v t="davidmcnab.121303142957.26"><vh>pyfuse_loop_mt</vh></v> |
44 |
|
|
<v t="davidmcnab.121303142957.27" a="M"><vh>Fuse_main</vh></v> |
45 |
|
|
<v t="davidmcnab.121303142957.28"><vh>DL_EXPORT</vh></v> |
46 |
|
|
</v> |
47 |
|
|
<v t="davidmcnab.121303142957.29" tnodeList="davidmcnab.121303142957.29,davidmcnab.121303142957.30,davidmcnab.121303142957.31,davidmcnab.121303142957.32,davidmcnab.121303142957.33,davidmcnab.121303142957.34,davidmcnab.121303142957.35,davidmcnab.121303142957.36,davidmcnab.121303142957.37"><vh>@file fuse.py</vh> |
48 |
|
|
<v t="davidmcnab.121303142957.30"><vh>imports</vh></v> |
49 |
|
|
<v t="davidmcnab.121303142957.31" a="E"><vh>class ErrnoWrapper</vh> |
50 |
|
|
<v t="davidmcnab.121303142957.32"><vh>__init__</vh></v> |
51 |
|
|
<v t="davidmcnab.121303142957.33"><vh>__call__</vh></v> |
52 |
|
|
</v> |
53 |
|
|
<v t="davidmcnab.121303142957.34" a="E"><vh>class Fuse</vh> |
54 |
|
|
<v t="davidmcnab.121303142957.35" a="M"><vh>attribs</vh></v> |
55 |
|
|
<v t="davidmcnab.121303142957.36"><vh>__init__</vh></v> |
56 |
|
|
<v t="davidmcnab.121303142957.37"><vh>main</vh></v> |
57 |
|
|
</v> |
58 |
|
|
</v> |
59 |
|
|
<v t="davidmcnab.121303142957.38" tnodeList="davidmcnab.121303142957.38"><vh>@file Makefile</vh></v> |
60 |
|
|
<v t="davidmcnab.121303142957.39" a="E" tnodeList="davidmcnab.121303142957.39,davidmcnab.121303142957.40,davidmcnab.121303142957.41,davidmcnab.121303142957.42,davidmcnab.121303142957.43,davidmcnab.121303142957.44,davidmcnab.121303142957.45,davidmcnab.121303142957.46,davidmcnab.121303142957.47,davidmcnab.121303142957.48,davidmcnab.121303142957.49,davidmcnab.121303142957.50,davidmcnab.121303142957.51,davidmcnab.121303142957.52,davidmcnab.121303142957.53,davidmcnab.121303142957.54,davidmcnab.121303142957.55,davidmcnab.121303142957.56,davidmcnab.121303142957.57,davidmcnab.121303142957.58,davidmcnab.121303142957.59,davidmcnab.121303142957.60,davidmcnab.121303142957.61,davidmcnab.121303142957.62,davidmcnab.121303144134,davidmcnab.121303144134.1,davidmcnab.121303142957.63"><vh>@file xmp.py</vh> |
61 |
|
|
<v t="davidmcnab.121303142957.40"><vh>imports</vh></v> |
62 |
|
|
<v t="davidmcnab.121303142957.41" a="E"><vh>class Xmp</vh> |
63 |
|
|
<v t="davidmcnab.121303142957.42"><vh>__init__</vh></v> |
64 |
|
|
<v t="davidmcnab.121303142957.43"><vh>mythread</vh></v> |
65 |
|
|
<v t="davidmcnab.121303142957.44"><vh>attribs</vh></v> |
66 |
|
|
<v t="davidmcnab.121303142957.45"><vh>getattr</vh></v> |
67 |
|
|
<v t="davidmcnab.121303142957.46"><vh>readlink</vh></v> |
68 |
|
|
<v t="davidmcnab.121303142957.47"><vh>getdir</vh></v> |
69 |
|
|
<v t="davidmcnab.121303142957.48"><vh>unlink</vh></v> |
70 |
|
|
<v t="davidmcnab.121303142957.49"><vh>rmdir</vh></v> |
71 |
|
|
<v t="davidmcnab.121303142957.50"><vh>symlink</vh></v> |
72 |
|
|
<v t="davidmcnab.121303142957.51"><vh>rename</vh></v> |
73 |
|
|
<v t="davidmcnab.121303142957.52"><vh>link</vh></v> |
74 |
|
|
<v t="davidmcnab.121303142957.53"><vh>chmod</vh></v> |
75 |
|
|
<v t="davidmcnab.121303142957.54"><vh>chown</vh></v> |
76 |
|
|
<v t="davidmcnab.121303142957.55"><vh>truncate</vh></v> |
77 |
|
|
<v t="davidmcnab.121303142957.56"><vh>mknod</vh></v> |
78 |
|
|
<v t="davidmcnab.121303142957.57"><vh>mkdir</vh></v> |
79 |
|
|
<v t="davidmcnab.121303142957.58"><vh>utime</vh></v> |
80 |
|
|
<v t="davidmcnab.121303142957.59"><vh>open</vh></v> |
81 |
|
|
<v t="davidmcnab.121303142957.60"><vh>read</vh></v> |
82 |
|
|
<v t="davidmcnab.121303142957.61"><vh>write</vh></v> |
83 |
|
|
<v t="davidmcnab.121303142957.62" a="M"><vh>release</vh></v> |
84 |
|
|
<v t="davidmcnab.121303144134"><vh>statfs</vh></v> |
85 |
|
|
<v t="davidmcnab.121303144134.1"><vh>fsync</vh></v> |
86 |
|
|
</v> |
87 |
|
|
<v t="davidmcnab.121303142957.63"><vh>mainline</vh></v> |
88 |
|
|
</v> |
89 |
|
|
<v t="davidmcnab.121303142957.64" tnodeList="davidmcnab.121303142957.64"><vh>@file setup.py</vh></v> |
90 |
|
|
<v t="davidmcnab.121303142957.65" tnodeList="davidmcnab.121303142957.65"><vh>@file README</vh></v> |
91 |
|
|
<v t="davidmcnab.121303142957.67" a="E" tnodeList="davidmcnab.121303142957.67"><vh>@file mount.fuse</vh></v> |
92 |
|
|
<v t="davidmcnab.121403050157" a="E"><vh>@file fuse.py</vh> |
93 |
|
|
<v t="davidmcnab.121403050157.1"><vh><< fuse declarations >></vh></v> |
94 |
|
|
<v t="davidmcnab.121403050157.2" a="E"><vh>class ErrnoWrapper</vh> |
95 |
|
|
<v t="davidmcnab.121403050157.3"><vh><< class ErrnoWrapper declarations >></vh></v> |
96 |
|
|
<v t="davidmcnab.121403050157.4"><vh>__init__</vh></v> |
97 |
|
|
<v t="davidmcnab.121403050157.5" a="V"><vh>__call__</vh></v> |
98 |
|
|
</v> |
99 |
|
|
<v t="davidmcnab.121403050157.6" a="E"><vh>class Fuse</vh> |
100 |
|
|
<v t="davidmcnab.121403050157.7"><vh><< class Fuse declarations >></vh></v> |
101 |
|
|
<v t="davidmcnab.121403050157.8"><vh>__init__</vh></v> |
102 |
|
|
<v t="davidmcnab.121403050157.9"><vh>main</vh></v> |
103 |
|
|
</v> |
104 |
|
|
</v> |
105 |
|
|
</v> |
106 |
|
|
</vnodes> |
107 |
|
|
<tnodes> |
108 |
|
|
<t tx="davidmcnab.121303142957"></t> |
109 |
|
|
<t tx="davidmcnab.121303142957.1">@language c |
110 |
|
|
/* |
111 |
|
|
Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> |
112 |
|
|
|
113 |
|
|
This program can be distributed under the terms of the GNU GPL. |
114 |
|
|
See the file COPYING. |
115 |
|
|
*/ |
116 |
|
|
|
117 |
|
|
@others |
118 |
|
|
|
119 |
|
|
</t> |
120 |
|
|
<t tx="davidmcnab.121303142957.2">#include <Python.h> |
121 |
|
|
#include <fuse.h> |
122 |
|
|
#include <time.h> |
123 |
|
|
</t> |
124 |
|
|
<t tx="davidmcnab.121303142957.3"> |
125 |
|
|
static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL, |
126 |
|
|
*mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL, |
127 |
|
|
*symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL, |
128 |
|
|
*chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL, |
129 |
|
|
*open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL, |
130 |
|
|
*statfs_cb=NULL, *fsync_cb=NULL |
131 |
|
|
; |
132 |
|
|
</t> |
133 |
|
|
<t tx="davidmcnab.121303142957.4">#define PROLOGUE \ |
134 |
|
|
int ret = -EINVAL; \ |
135 |
|
|
if (!v) { PyErr_Print(); goto OUT; } \ |
136 |
|
|
if(v == Py_None) { ret = 0; goto OUT_DECREF; } \ |
137 |
|
|
if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; } |
138 |
|
|
|
139 |
|
|
</t> |
140 |
|
|
<t tx="davidmcnab.121303142957.5">#define EPILOGUE \ |
141 |
|
|
OUT_DECREF: \ |
142 |
|
|
Py_DECREF(v); \ |
143 |
|
|
OUT: \ |
144 |
|
|
return ret; |
145 |
|
|
</t> |
146 |
|
|
<t tx="davidmcnab.121303142957.6"> |
147 |
|
|
/* |
148 |
|
|
* Local Variables: |
149 |
|
|
* indent-tabs-mode: t |
150 |
|
|
* c-basic-offset: 8 |
151 |
|
|
* End: |
152 |
|
|
* Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons. |
153 |
|
|
* Namely, replacing PyTuple_* with PySequence_*, and checking numerical values |
154 |
|
|
* with both PyInt_Check and PyLong_Check. |
155 |
|
|
*/ |
156 |
|
|
|
157 |
|
|
static int getattr_func(const char *path, struct stat *st) |
158 |
|
|
{ |
159 |
|
|
int i; |
160 |
|
|
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path); |
161 |
|
|
PROLOGUE |
162 |
|
|
|
163 |
|
|
if(!PySequence_Check(v)) { goto OUT_DECREF; } |
164 |
|
|
if(PySequence_Size(v) < 10) { goto OUT_DECREF; } |
165 |
|
|
for(i=0; i<10; i++) |
166 |
|
|
{ |
167 |
|
|
PyObject *tmp = PySequence_GetItem(v, i); |
168 |
|
|
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF; |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0)); |
172 |
|
|
st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1)); |
173 |
|
|
st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2)); |
174 |
|
|
st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3)); |
175 |
|
|
st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4)); |
176 |
|
|
st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5)); |
177 |
|
|
st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6)); |
178 |
|
|
st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7)); |
179 |
|
|
st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8)); |
180 |
|
|
st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9)); |
181 |
|
|
|
182 |
|
|
/* Fill in fields not provided by Python lstat() */ |
183 |
|
|
st->st_blksize= 4096; |
184 |
|
|
st->st_blocks= (st->st_size + 511)/512; |
185 |
|
|
st->st_ino = 0; |
186 |
|
|
|
187 |
|
|
ret = 0; |
188 |
|
|
EPILOGUE |
189 |
|
|
} |
190 |
|
|
|
191 |
|
|
</t> |
192 |
|
|
<t tx="davidmcnab.121303142957.7"> |
193 |
|
|
static int readlink_func(const char *path, char *link, size_t size) |
194 |
|
|
{ |
195 |
|
|
PyObject *v = PyObject_CallFunction(readlink_cb, "s", path); |
196 |
|
|
char *s; |
197 |
|
|
PROLOGUE |
198 |
|
|
|
199 |
|
|
if(!PyString_Check(v)) { ret = -EINVAL; goto OUT_DECREF; } |
200 |
|
|
s = PyString_AsString(v); |
201 |
|
|
strncpy(link, s, size); |
202 |
|
|
link[size-1] = '\0'; |
203 |
|
|
ret = 0; |
204 |
|
|
|
205 |
|
|
EPILOGUE |
206 |
|
|
} |
207 |
|
|
</t> |
208 |
|
|
<t tx="davidmcnab.121303142957.8"> |
209 |
|
|
static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df) |
210 |
|
|
{ |
211 |
|
|
PyObject *o0; |
212 |
|
|
PyObject *o1; |
213 |
|
|
int ret = -EINVAL; |
214 |
|
|
|
215 |
|
|
if(!PySequence_Check(w)) { |
216 |
|
|
printf("getdir item not sequence\n"); |
217 |
|
|
goto out; |
218 |
|
|
} |
219 |
|
|
if(PySequence_Length(w) != 2) { |
220 |
|
|
printf("getdir item not len 2\n"); |
221 |
|
|
goto out; |
222 |
|
|
} |
223 |
|
|
o0 = PySequence_GetItem(w, 0); |
224 |
|
|
o1 = PySequence_GetItem(w, 1); |
225 |
|
|
|
226 |
|
|
if(!PyString_Check(o0)) { |
227 |
|
|
printf("getdir item[0] not string\n"); |
228 |
|
|
goto out_decref; |
229 |
|
|
} |
230 |
|
|
if(!PyInt_Check(o1)) { |
231 |
|
|
printf("getdir item[1] not int\n"); |
232 |
|
|
goto out_decref; |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
ret = df(dh, PyString_AsString(o0), PyInt_AsLong(o1)); |
236 |
|
|
|
237 |
|
|
out_decref: |
238 |
|
|
Py_DECREF(o0); |
239 |
|
|
Py_DECREF(o1); |
240 |
|
|
|
241 |
|
|
out: |
242 |
|
|
return ret; |
243 |
|
|
} |
244 |
|
|
</t> |
245 |
|
|
<t tx="davidmcnab.121303142957.9"> |
246 |
|
|
static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df) |
247 |
|
|
{ |
248 |
|
|
PyObject *v = PyObject_CallFunction(getdir_cb, "s", path); |
249 |
|
|
int i; |
250 |
|
|
PROLOGUE |
251 |
|
|
|
252 |
|
|
if(!PySequence_Check(v)) { |
253 |
|
|
printf("getdir_func not sequence\n"); |
254 |
|
|
goto OUT_DECREF; |
255 |
|
|
} |
256 |
|
|
for(i=0; i < PySequence_Length(v); i++) { |
257 |
|
|
PyObject *w = PySequence_GetItem(v, i); |
258 |
|
|
ret = getdir_add_entry(w, dh, df); |
259 |
|
|
Py_DECREF(w); |
260 |
|
|
if(ret != 0) |
261 |
|
|
goto OUT_DECREF; |
262 |
|
|
} |
263 |
|
|
ret = 0; |
264 |
|
|
|
265 |
|
|
EPILOGUE |
266 |
|
|
} |
267 |
|
|
</t> |
268 |
|
|
<t tx="davidmcnab.121303142957.10"> |
269 |
|
|
static int mknod_func(const char *path, mode_t m, dev_t d) |
270 |
|
|
{ |
271 |
|
|
PyObject *v = PyObject_CallFunction(mknod_cb, "sii", path, m, d); |
272 |
|
|
PROLOGUE |
273 |
|
|
EPILOGUE |
274 |
|
|
} |
275 |
|
|
</t> |
276 |
|
|
<t tx="davidmcnab.121303142957.11"> |
277 |
|
|
static int mkdir_func(const char *path, mode_t m) |
278 |
|
|
{ |
279 |
|
|
PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m); |
280 |
|
|
PROLOGUE |
281 |
|
|
EPILOGUE |
282 |
|
|
} |
283 |
|
|
</t> |
284 |
|
|
<t tx="davidmcnab.121303142957.12"> |
285 |
|
|
static int unlink_func(const char *path) |
286 |
|
|
{ |
287 |
|
|
PyObject *v = PyObject_CallFunction(unlink_cb, "s", path); |
288 |
|
|
PROLOGUE |
289 |
|
|
EPILOGUE |
290 |
|
|
} |
291 |
|
|
</t> |
292 |
|
|
<t tx="davidmcnab.121303142957.13"> |
293 |
|
|
static int rmdir_func(const char *path) |
294 |
|
|
{ |
295 |
|
|
PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path); |
296 |
|
|
PROLOGUE |
297 |
|
|
EPILOGUE |
298 |
|
|
} |
299 |
|
|
</t> |
300 |
|
|
<t tx="davidmcnab.121303142957.14"> |
301 |
|
|
static int symlink_func(const char *path, const char *path1) |
302 |
|
|
{ |
303 |
|
|
PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1); |
304 |
|
|
PROLOGUE |
305 |
|
|
EPILOGUE |
306 |
|
|
} |
307 |
|
|
</t> |
308 |
|
|
<t tx="davidmcnab.121303142957.15"> |
309 |
|
|
static int rename_func(const char *path, const char *path1) |
310 |
|
|
{ |
311 |
|
|
PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1); |
312 |
|
|
PROLOGUE |
313 |
|
|
EPILOGUE |
314 |
|
|
} |
315 |
|
|
</t> |
316 |
|
|
<t tx="davidmcnab.121303142957.16"> |
317 |
|
|
static int link_func(const char *path, const char *path1) |
318 |
|
|
{ |
319 |
|
|
PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1); |
320 |
|
|
PROLOGUE |
321 |
|
|
EPILOGUE |
322 |
|
|
} |
323 |
|
|
</t> |
324 |
|
|
<t tx="davidmcnab.121303142957.17"> |
325 |
|
|
static int chmod_func(const char *path, mode_t m) |
326 |
|
|
{ |
327 |
|
|
PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m); |
328 |
|
|
PROLOGUE |
329 |
|
|
EPILOGUE |
330 |
|
|
} |
331 |
|
|
</t> |
332 |
|
|
<t tx="davidmcnab.121303142957.18"> |
333 |
|
|
static int chown_func(const char *path, uid_t u, gid_t g) |
334 |
|
|
{ |
335 |
|
|
PyObject *v = PyObject_CallFunction(chown_cb, "sii", path, u, g); |
336 |
|
|
PROLOGUE |
337 |
|
|
EPILOGUE |
338 |
|
|
} |
339 |
|
|
</t> |
340 |
|
|
<t tx="davidmcnab.121303142957.19"> |
341 |
|
|
static int truncate_func(const char *path, off_t o) |
342 |
|
|
{ |
343 |
|
|
PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o); |
344 |
|
|
PROLOGUE |
345 |
|
|
EPILOGUE |
346 |
|
|
} |
347 |
|
|
</t> |
348 |
|
|
<t tx="davidmcnab.121303142957.20"> |
349 |
|
|
static int utime_func(const char *path, struct utimbuf *u) { |
350 |
|
|
int actime = u ? u->actime : time(NULL); |
351 |
|
|
int modtime = u ? u->modtime : actime; |
352 |
|
|
PyObject *v = PyObject_CallFunction(utime_cb, "s(ii)", |
353 |
|
|
path, actime, modtime); |
354 |
|
|
PROLOGUE |
355 |
|
|
EPILOGUE |
356 |
|
|
} |
357 |
|
|
</t> |
358 |
|
|
<t tx="davidmcnab.121303142957.21"> |
359 |
|
|
static int read_func(const char *path, char *buf, size_t s, off_t off) |
360 |
|
|
{ |
361 |
|
|
PyObject *v = PyObject_CallFunction(read_cb, "sii", path, s, off); |
362 |
|
|
PROLOGUE |
363 |
|
|
if(PyString_Check(v)) { |
364 |
|
|
if(PyString_Size(v) > s) goto OUT_DECREF; |
365 |
|
|
memcpy(buf, PyString_AsString(v), PyString_Size(v)); |
366 |
|
|
ret = PyString_Size(v); |
367 |
|
|
} |
368 |
|
|
EPILOGUE |
369 |
|
|
} |
370 |
|
|
</t> |
371 |
|
|
<t tx="davidmcnab.121303142957.22"> |
372 |
|
|
static int write_func(const char *path, const char *buf, size_t t, off_t off) |
373 |
|
|
{ |
374 |
|
|
PyObject *v = PyObject_CallFunction(write_cb,"ss#i", path, buf, t, off); |
375 |
|
|
PROLOGUE |
376 |
|
|
EPILOGUE |
377 |
|
|
} |
378 |
|
|
</t> |
379 |
|
|
<t tx="davidmcnab.121303142957.23"> |
380 |
|
|
static int open_func(const char *path, int mode) |
381 |
|
|
{ |
382 |
|
|
PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode); |
383 |
|
|
PROLOGUE |
384 |
|
|
printf("open_func: path=%s\n", path); |
385 |
|
|
EPILOGUE |
386 |
|
|
} |
387 |
|
|
</t> |
388 |
|
|
<t tx="davidmcnab.121303142957.24">static int release_func(const char *path, int flags) |
389 |
|
|
{ |
390 |
|
|
PyObject *v = PyObject_CallFunction(release_cb, "si", path, flags); |
391 |
|
|
PROLOGUE |
392 |
|
|
//printf("release_func: path=%s flags=%d\n", path, flags); |
393 |
|
|
EPILOGUE |
394 |
|
|
} |
395 |
|
|
</t> |
396 |
|
|
<t tx="davidmcnab.121303142957.25"> |
397 |
|
|
static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data) |
398 |
|
|
{ |
399 |
|
|
PyInterpreterState *interp = (PyInterpreterState *) data; |
400 |
|
|
PyThreadState *state; |
401 |
|
|
|
402 |
|
|
PyEval_AcquireLock(); |
403 |
|
|
state = PyThreadState_New(interp); |
404 |
|
|
PyThreadState_Swap(state); |
405 |
|
|
__fuse_process_cmd(f, cmd); |
406 |
|
|
PyThreadState_Clear(state); |
407 |
|
|
PyThreadState_Swap(NULL); |
408 |
|
|
PyThreadState_Delete(state); |
409 |
|
|
PyEval_ReleaseLock(); |
410 |
|
|
} |
411 |
|
|
</t> |
412 |
|
|
<t tx="davidmcnab.121303142957.26"> |
413 |
|
|
static void pyfuse_loop_mt(struct fuse *f) |
414 |
|
|
{ |
415 |
|
|
PyInterpreterState *interp; |
416 |
|
|
PyThreadState *save; |
417 |
|
|
|
418 |
|
|
PyEval_InitThreads(); |
419 |
|
|
interp = PyThreadState_Get()->interp; |
420 |
|
|
save = PyEval_SaveThread(); |
421 |
|
|
__fuse_loop_mt(f, process_cmd, interp); |
422 |
|
|
/* Not yet reached: */ |
423 |
|
|
PyEval_RestoreThread(save); |
424 |
|
|
} |
425 |
|
|
</t> |
426 |
|
|
<t tx="davidmcnab.121303142957.27"> |
427 |
|
|
|
428 |
|
|
static PyObject * |
429 |
|
|
Fuse_main(PyObject *self, PyObject *args, PyObject *kw) |
430 |
|
|
{ |
431 |
|
|
int flags=0; |
432 |
|
|
int multithreaded=0; |
433 |
|
|
static struct fuse *fuse=NULL; |
434 |
|
|
|
435 |
|
|
struct fuse_operations op; |
436 |
|
|
|
437 |
|
|
static char *kwlist[] = { |
438 |
|
|
"getattr", "readlink", "getdir", "mknod", |
439 |
|
|
"mkdir", "unlink", "rmdir", "symlink", "rename", |
440 |
|
|
"link", "chmod", "chown", "truncate", "utime", |
441 |
|
|
"open", "read", "write", "release", "statfs", "fsync", |
442 |
|
|
"flags", "multithreaded", NULL}; |
443 |
|
|
|
444 |
|
|
memset(&op, 0, sizeof(op)); |
445 |
|
|
|
446 |
|
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOii", |
447 |
|
|
kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb, |
448 |
|
|
&mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb, |
449 |
|
|
&link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb, |
450 |
|
|
&open_cb, &read_cb, &write_cb, &release_cb, &statfs_cb, &fsync_cb, |
451 |
|
|
&flags, &multithreaded)) |
452 |
|
|
return NULL; |
453 |
|
|
|
454 |
|
|
#define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; } |
455 |
|
|
|
456 |
|
|
DO_ONE_ATTR(getattr); |
457 |
|
|
DO_ONE_ATTR(readlink); |
458 |
|
|
DO_ONE_ATTR(getdir); |
459 |
|
|
DO_ONE_ATTR(mknod); |
460 |
|
|
DO_ONE_ATTR(mkdir); |
461 |
|
|
DO_ONE_ATTR(unlink); |
462 |
|
|
DO_ONE_ATTR(rmdir); |
463 |
|
|
DO_ONE_ATTR(symlink); |
464 |
|
|
DO_ONE_ATTR(rename); |
465 |
|
|
DO_ONE_ATTR(link); |
466 |
|
|
DO_ONE_ATTR(chmod); |
467 |
|
|
DO_ONE_ATTR(chown); |
468 |
|
|
DO_ONE_ATTR(truncate); |
469 |
|
|
DO_ONE_ATTR(utime); |
470 |
|
|
DO_ONE_ATTR(open); |
471 |
|
|
DO_ONE_ATTR(read); |
472 |
|
|
DO_ONE_ATTR(write); |
473 |
|
|
DO_ONE_ATTR(release); |
474 |
|
|
DO_ONE_ATTR(statfs); |
475 |
|
|
DO_ONE_ATTR(fsync); |
476 |
|
|
|
477 |
|
|
fuse = fuse_new(0, flags, &op); |
478 |
|
|
if(multithreaded) |
479 |
|
|
pyfuse_loop_mt(fuse); |
480 |
|
|
else |
481 |
|
|
fuse_loop(fuse); |
482 |
|
|
|
483 |
|
|
//printf("Fuse_main: called\n"); |
484 |
|
|
|
485 |
|
|
Py_INCREF(Py_None); |
486 |
|
|
return Py_None; |
487 |
|
|
} |
488 |
|
|
</t> |
489 |
|
|
<t tx="davidmcnab.121303142957.28">@ List of functions defined in the module |
490 |
|
|
@c |
491 |
|
|
|
492 |
|
|
static PyMethodDef Fuse_methods[] = { |
493 |
|
|
{"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS}, |
494 |
|
|
{NULL, NULL} /* sentinel */ |
495 |
|
|
}; |
496 |
|
|
|
497 |
|
|
|
498 |
|
|
/* Initialization function for the module (*must* be called init_fuse) */ |
499 |
|
|
|
500 |
|
|
DL_EXPORT(void) |
501 |
|
|
init_fuse(void) |
502 |
|
|
{ |
503 |
|
|
PyObject *m, *d; |
504 |
|
|
static PyObject *ErrorObject; |
505 |
|
|
|
506 |
|
|
/* Create the module and add the functions */ |
507 |
|
|
m = Py_InitModule("_fuse", Fuse_methods); |
508 |
|
|
|
509 |
|
|
/* Add some symbolic constants to the module */ |
510 |
|
|
d = PyModule_GetDict(m); |
511 |
|
|
ErrorObject = PyErr_NewException("fuse.error", NULL, NULL); |
512 |
|
|
PyDict_SetItemString(d, "error", ErrorObject); |
513 |
|
|
PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG)); |
514 |
|
|
} |
515 |
|
|
</t> |
516 |
|
|
<t tx="davidmcnab.121303142957.29"># |
517 |
|
|
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> |
518 |
|
|
# |
519 |
|
|
# This program can be distributed under the terms of the GNU GPL. |
520 |
|
|
# See the file COPYING. |
521 |
|
|
# |
522 |
|
|
|
523 |
|
|
|
524 |
|
|
@language python |
525 |
|
|
@others |
526 |
|
|
</t> |
527 |
|
|
<t tx="davidmcnab.121303142957.30"># suppress version mismatch warnings |
528 |
|
|
try: |
529 |
|
|
import warnings |
530 |
|
|
warnings.filterwarnings('ignore', |
531 |
|
|
'Python C API version mismatch', |
532 |
|
|
RuntimeWarning, |
533 |
|
|
) |
534 |
|
|
except: |
535 |
|
|
pass |
536 |
|
|
|
537 |
|
|
from _fuse import main, DEBUG |
538 |
|
|
import os, sys |
539 |
|
|
from errno import * |
540 |
|
|
|
541 |
|
|
</t> |
542 |
|
|
<t tx="davidmcnab.121303142957.31">class ErrnoWrapper: |
543 |
|
|
@others |
544 |
|
|
</t> |
545 |
|
|
<t tx="davidmcnab.121303142957.32">def __init__(self, func): |
546 |
|
|
self.func = func |
547 |
|
|
</t> |
548 |
|
|
<t tx="davidmcnab.121303142957.33">def __call__(self, *args, **kw): |
549 |
|
|
try: |
550 |
|
|
return apply(self.func, args, kw) |
551 |
|
|
except (IOError, OSError), detail: |
552 |
|
|
# Sometimes this is an int, sometimes an instance... |
553 |
|
|
if hasattr(detail, "errno"): detail = detail.errno |
554 |
|
|
return -detail |
555 |
|
|
</t> |
556 |
|
|
<t tx="davidmcnab.121303142957.34">class Fuse: |
557 |
|
|
|
558 |
|
|
@others |
559 |
|
|
</t> |
560 |
|
|
<t tx="davidmcnab.121303142957.35">_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', |
561 |
|
|
'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', |
562 |
|
|
'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release', |
563 |
|
|
'statfs', 'fsync'] |
564 |
|
|
|
565 |
|
|
flags = 0 |
566 |
|
|
multithreaded = 0 |
567 |
|
|
|
568 |
|
|
</t> |
569 |
|
|
<t tx="davidmcnab.121303142957.36">def __init__(self, *args, **kw): |
570 |
|
|
|
571 |
|
|
# default attributes |
572 |
|
|
self.optlist = [] |
573 |
|
|
self.optdict = {} |
574 |
|
|
self.mountpoint = None |
575 |
|
|
|
576 |
|
|
# grab arguments, if any |
577 |
|
|
argv = sys.argv |
578 |
|
|
argc = len(argv) |
579 |
|
|
if argc > 1: |
580 |
|
|
# we've been given the mountpoint |
581 |
|
|
self.mountpoint = argv[1] |
582 |
|
|
if argc > 2: |
583 |
|
|
# we've received mount args |
584 |
|
|
optstr = argv[2] |
585 |
|
|
opts = optstr.split(",") |
586 |
|
|
for o in opts: |
587 |
|
|
try: |
588 |
|
|
k, v = o.split("=", 1) |
589 |
|
|
self.optdict[k] = v |
590 |
|
|
except: |
591 |
|
|
self.optlist.append(o) |
592 |
|
|
</t> |
593 |
|
|
<t tx="davidmcnab.121303142957.37">def main(self): |
594 |
|
|
d = {'flags': self.flags} |
595 |
|
|
d['multithreaded'] = self.multithreaded |
596 |
|
|
for a in self._attrs: |
597 |
|
|
if hasattr(self,a): |
598 |
|
|
d[a] = ErrnoWrapper(getattr(self, a)) |
599 |
|
|
apply(main, (), d) |
600 |
|
|
</t> |
601 |
|
|
<t tx="davidmcnab.121303142957.38"># Makefile now uses distutils |
602 |
|
|
|
603 |
|
|
_fusemodule.so: _fusemodule.c |
604 |
|
|
#gcc -g3 -I/usr/include/python2.1 _fusemodule.c -Wl,-shared -o _fusemodule.so -Wimplicit -lfuse && python -c 'import _fuse' |
605 |
|
|
python setup.py build_ext --inplace |
606 |
|
|
|
607 |
|
|
install: _fusemodule.so |
608 |
|
|
python setup.py install |
609 |
|
|
|
610 |
|
|
clean: |
611 |
|
|
rm -rf _fusemodule.so *.pyc *.pyo *~ build |
612 |
|
|
</t> |
613 |
|
|
<t tx="davidmcnab.121303142957.39">@first #!/usr/bin/env python |
614 |
|
|
# |
615 |
|
|
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> |
616 |
|
|
# |
617 |
|
|
# This program can be distributed under the terms of the GNU GPL. |
618 |
|
|
# See the file COPYING. |
619 |
|
|
# |
620 |
|
|
|
621 |
|
|
@others |
622 |
|
|
</t> |
623 |
|
|
<t tx="davidmcnab.121303142957.40"> |
624 |
|
|
from fuse import Fuse |
625 |
|
|
import os |
626 |
|
|
from errno import * |
627 |
|
|
from stat import * |
628 |
|
|
|
629 |
|
|
import thread |
630 |
|
|
</t> |
631 |
|
|
<t tx="davidmcnab.121303142957.41">class Xmp(Fuse): |
632 |
|
|
|
633 |
|
|
@others |
634 |
|
|
</t> |
635 |
|
|
<t tx="davidmcnab.121303142957.42">def __init__(self, *args, **kw): |
636 |
|
|
|
637 |
|
|
Fuse.__init__(self, *args, **kw) |
638 |
|
|
|
639 |
|
|
if 0: |
640 |
|
|
print "xmp.py:Xmp:mountpoint: %s" % repr(self.mountpoint) |
641 |
|
|
print "xmp.py:Xmp:unnamed mount options: %s" % self.optlist |
642 |
|
|
print "xmp.py:Xmp:named mount options: %s" % self.optdict |
643 |
|
|
|
644 |
|
|
# do stuff to set up your filesystem here, if you want |
645 |
|
|
#thread.start_new_thread(self.mythread, ()) |
646 |
|
|
pass |
647 |
|
|
</t> |
648 |
|
|
<t tx="davidmcnab.121303142957.43">def mythread(self): |
649 |
|
|
|
650 |
|
|
""" |
651 |
|
|
The beauty of the FUSE python implementation is that with the python interp |
652 |
|
|
running in foreground, you can have threads |
653 |
|
|
""" |
654 |
|
|
print "mythread: started" |
655 |
|
|
#while 1: |
656 |
|
|
# time.sleep(120) |
657 |
|
|
# print "mythread: ticking" |
658 |
|
|
|
659 |
|
|
</t> |
660 |
|
|
<t tx="davidmcnab.121303142957.44">flags = 1 |
661 |
|
|
|
662 |
|
|
</t> |
663 |
|
|
<t tx="davidmcnab.121303142957.45">def getattr(self, path): |
664 |
|
|
return os.lstat(path) |
665 |
|
|
</t> |
666 |
|
|
<t tx="davidmcnab.121303142957.46">def readlink(self, path): |
667 |
|
|
return os.readlink(path) |
668 |
|
|
</t> |
669 |
|
|
<t tx="davidmcnab.121303142957.47">def getdir(self, path): |
670 |
|
|
return map(lambda x: (x,0), os.listdir(path)) |
671 |
|
|
</t> |
672 |
|
|
<t tx="davidmcnab.121303142957.48">def unlink(self, path): |
673 |
|
|
return os.unlink(path) |
674 |
|
|
</t> |
675 |
|
|
<t tx="davidmcnab.121303142957.49">def rmdir(self, path): |
676 |
|
|
return os.rmdir(path) |
677 |
|
|
</t> |
678 |
|
|
<t tx="davidmcnab.121303142957.50">def symlink(self, path, path1): |
679 |
|
|
return os.symlink(path, path1) |
680 |
|
|
</t> |
681 |
|
|
<t tx="davidmcnab.121303142957.51">def rename(self, path, path1): |
682 |
|
|
return os.rename(path, path1) |
683 |
|
|
</t> |
684 |
|
|
<t tx="davidmcnab.121303142957.52">def link(self, path, path1): |
685 |
|
|
return os.link(path, path1) |
686 |
|
|
</t> |
687 |
|
|
<t tx="davidmcnab.121303142957.53">def chmod(self, path, mode): |
688 |
|
|
return os.chmod(path, mode) |
689 |
|
|
</t> |
690 |
|
|
<t tx="davidmcnab.121303142957.54">def chown(self, path, user, group): |
691 |
|
|
return os.chown(path, user, group) |
692 |
|
|
</t> |
693 |
|
|
<t tx="davidmcnab.121303142957.55">def truncate(self, path, size): |
694 |
|
|
f = open(path, "w+") |
695 |
|
|
return f.truncate(size) |
696 |
|
|
</t> |
697 |
|
|
<t tx="davidmcnab.121303142957.56">def mknod(self, path, mode, dev): |
698 |
|
|
""" Python has no os.mknod, so we can only do some things """ |
699 |
|
|
if S_ISREG(mode): |
700 |
|
|
open(path, "w") |
701 |
|
|
else: |
702 |
|
|
return -EINVAL |
703 |
|
|
</t> |
704 |
|
|
<t tx="davidmcnab.121303142957.57">def mkdir(self, path, mode): |
705 |
|
|
return os.mkdir(path, mode) |
706 |
|
|
</t> |
707 |
|
|
<t tx="davidmcnab.121303142957.58">def utime(self, path, times): |
708 |
|
|
return os.utime(path, times) |
709 |
|
|
</t> |
710 |
|
|
<t tx="davidmcnab.121303142957.59">def open(self, path, flags): |
711 |
|
|
#print "xmp.py:Xmp:open: %s" % path |
712 |
|
|
os.close(os.open(path, flags)) |
713 |
|
|
return 0 |
714 |
|
|
|
715 |
|
|
</t> |
716 |
|
|
<t tx="davidmcnab.121303142957.60">def read(self, path, len, offset): |
717 |
|
|
#print "xmp.py:Xmp:read: %s" % path |
718 |
|
|
f = open(path, "r") |
719 |
|
|
f.seek(offset) |
720 |
|
|
return f.read(len) |
721 |
|
|
|
722 |
|
|
</t> |
723 |
|
|
<t tx="davidmcnab.121303142957.61">def write(self, path, buf, off): |
724 |
|
|
#print "xmp.py:Xmp:write: %s" % path |
725 |
|
|
f = open(path, "r+") |
726 |
|
|
f.seek(off) |
727 |
|
|
f.write(buf) |
728 |
|
|
return len(buf) |
729 |
|
|
|
730 |
|
|
</t> |
731 |
|
|
<t tx="davidmcnab.121303142957.62">def release(self, path, flags): |
732 |
|
|
print "xmp.py:Xmp:release: %s %s" % (path, flags) |
733 |
|
|
return 0 |
734 |
|
|
</t> |
735 |
|
|
<t tx="davidmcnab.121303142957.63"> |
736 |
|
|
if __name__ == '__main__': |
737 |
|
|
|
738 |
|
|
server = Xmp() |
739 |
|
|
server.flags = 0 |
740 |
|
|
server.multithreaded = 1; |
741 |
|
|
server.main() |
742 |
|
|
</t> |
743 |
|
|
<t tx="davidmcnab.121303142957.64">""" |
744 |
|
|
distutils script for FUSE python module |
745 |
|
|
""" |
746 |
|
|
|
747 |
|
|
from distutils.core import setup, Extension |
748 |
|
|
|
749 |
|
|
setup(name="fuse", |
750 |
|
|
version="0.1", |
751 |
|
|
ext_modules=[Extension("_fusemodule", ["_fusemodule.c"], |
752 |
|
|
library_dirs=["../lib",], |
753 |
|
|
libraries=["fuse",], |
754 |
|
|
), |
755 |
|
|
], |
756 |
|
|
py_modules=["fuse"], |
757 |
|
|
) |
758 |
|
|
|
759 |
|
|
</t> |
760 |
|
|
<t tx="davidmcnab.121303142957.65">@language |
761 |
|
|
|
762 |
|
|
Refer to the INSTALL file for build/install instructions |
763 |
|
|
|
764 |
|
|
General Information |
765 |
|
|
=================== |
766 |
|
|
|
767 |
|
|
This is a Python[1] interface to FUSE[2]. |
768 |
|
|
|
769 |
|
|
FUSE (Filesystem in USErspace) is a simple interface for userspace |
770 |
|
|
programs to export a virtual filesystem to the linux kernel. FUSE |
771 |
|
|
also aims to provide a secure method for non privileged users to |
772 |
|
|
create and mount their own filesystem implementations. |
773 |
|
|
|
774 |
|
|
When run from the commandline, "fuse.py" simply reexports the root |
775 |
|
|
filesystem within the mount point as example/fusexmp does in the main |
776 |
|
|
FUSE distribution. It also offers a class, fuse.Fuse, which can be |
777 |
|
|
subclassed to create a filesystem. fuse.Xmp is the example filesystem |
778 |
|
|
implementation. |
779 |
|
|
|
780 |
|
|
In your subclass of fuse, add attributes with the expected names |
781 |
|
|
("getattr", "readlink", etc) and call signatures (refer to fuse.Xmp) |
782 |
|
|
then call main(). Make it runnable as a #! script, and mount with |
783 |
|
|
fusermount <mount point> <script name> |
784 |
|
|
for some reason, |
785 |
|
|
fusermount <mount point> python <script name> |
786 |
|
|
does not seem to work. (why?) |
787 |
|
|
|
788 |
|
|
Update |
789 |
|
|
====== |
790 |
|
|
|
791 |
|
|
Updated 13-Dec-2003 by David McNab <david@rebirthing.co.nz> |
792 |
|
|
|
793 |
|
|
- changed Makefile to use Pyton distutils |
794 |
|
|
- added setup.py for distutils |
795 |
|
|
|
796 |
|
|
- added 'code.leo' file for convenience of those who use the Leo |
797 |
|
|
code editor (leo.sf.net) |
798 |
|
|
|
799 |
|
|
- added support for 'statfs' and 'fsync' methods (refer xmp.py) |
800 |
|
|
|
801 |
|
|
Updated Dec 2003 by David McNab <david@rebirthing.co.nz>: |
802 |
|
|
|
803 |
|
|
- added support for 'release' events (ie when file gets closed) |
804 |
|
|
- added __init__ to base class, which picks off parameters and |
805 |
|
|
stores them as instance attributes: |
806 |
|
|
- self.mountpoint - the mountpoint as given in the mount command |
807 |
|
|
- self.optlist - unnamed options (eg 'rw', 'exec' etc) |
808 |
|
|
- self.optdict - named options (eg, '-o arg1=val1,arg2=val2...' from mount cmd) |
809 |
|
|
- fixed incompatibility issues with recent pythons (original was broken |
810 |
|
|
under python2.3) |
811 |
|
|
|
812 |
|
|
Limitations |
813 |
|
|
=========== |
814 |
|
|
|
815 |
|
|
This is minimally tested, though I think I have exercised each function. |
816 |
|
|
There's no documentation, docstrings, or tests. |
817 |
|
|
|
818 |
|
|
Python's lstat() does not return some fields which must be filled in |
819 |
|
|
(st_blksize, st_blocks, st_ino), and _fusemodule assumes that the return |
820 |
|
|
value from the lstat() method is identical to Python's lstat(). This |
821 |
|
|
limitation should be lifted, and some standard order chosen for these |
822 |
|
|
three values. For now, though, default values are chosen and du returns a |
823 |
|
|
number similar to the "real" one. |
824 |
|
|
|
825 |
|
|
The Python Global Interpreter Lock is not handled, so using |
826 |
|
|
fuse.MULTITHREAD will not work. Modifying the PROLOGUE and EPILOGUE |
827 |
|
|
functions may take care of this. For now, just run without |
828 |
|
|
fuse.MULTITHREAD in flags. |
829 |
|
|
|
830 |
|
|
Author |
831 |
|
|
====== |
832 |
|
|
|
833 |
|
|
I'm Jeff Epler <jepler@unpythonic.dhs.org>. I've been dabbling in |
834 |
|
|
Python for nearly 7 years now, and interested (despite the lack of a |
835 |
|
|
real practical use) in userspace filesystems ever since I couldn't get |
836 |
|
|
userfs to compile way back in '93 or so. FUSE is cool, but i'm still |
837 |
|
|
not sure what it's good for in practical terms. |
838 |
|
|
|
839 |
|
|
I don't know how high a level of interest I'll maintain in this project, |
840 |
|
|
so if you want to do something with it feel free to do so. Like FUSE, |
841 |
|
|
this software is distributed under the terms of the GNU General Public |
842 |
|
|
License, Version 2. Future versions, if any, will be available at [3]. |
843 |
|
|
|
844 |
|
|
|
845 |
|
|
[1] http://www.python.org |
846 |
|
|
[2] http://sourceforge.net/projects/avf/ |
847 |
|
|
[3] http://unpythonic.dhs.org/~jepler/fuse/ |
848 |
|
|
</t> |
849 |
|
|
<t tx="davidmcnab.121303142957.67">@first #!/usr/bin/env python |
850 |
|
|
|
851 |
|
|
""" |
852 |
|
|
This utility allows FUSE filesystems to be mounted with the regular *nix |
853 |
|
|
'mount' command, or even be listed in /etc/fstab |
854 |
|
|
|
855 |
|
|
To enable this, you need to: |
856 |
|
|
1. set execute-permission on this script |
857 |
|
|
2. symlink this script into /sbin/mount.fuse |
858 |
|
|
|
859 |
|
|
Usage: |
860 |
|
|
|
861 |
|
|
You can use this in 3 ways: |
862 |
|
|
1. mount -t fuse /path/to/script/or/program /path/of/mount/point [options] |
863 |
|
|
2. mount -t fuse none /path/of/mount/point -o fs=/path/to/script/or/prog[,opt=val...] |
864 |
|
|
3. in /etc/fstab, add: |
865 |
|
|
/path/to/script/or/prog /path/of/mount/point fuse noauto[,...] |
866 |
|
|
""" |
867 |
|
|
|
868 |
|
|
import sys, os, time |
869 |
|
|
|
870 |
|
|
progname = sys.argv[0] |
871 |
|
|
|
872 |
|
|
def usage(ret): |
873 |
|
|
print "Usage: %s /path/to/fuse/fs /path/of/mountpoint [-o options]" % progname |
874 |
|
|
print "or: %s none /path/of/mountpoint [-o fs=/path/to/fuse/fs[,...]]" % progname |
875 |
|
|
sys.exit(ret) |
876 |
|
|
|
877 |
|
|
def main(): |
878 |
|
|
|
879 |
|
|
# initial sanity check |
880 |
|
|
argc = len(sys.argv) |
881 |
|
|
if argc < 3 or sys.argv[3] != "-o": |
882 |
|
|
usage(1) |
883 |
|
|
|
884 |
|
|
dev = sys.argv[1] |
885 |
|
|
mountpoint = sys.argv[2] |
886 |
|
|
|
887 |
|
|
# grab options, if any |
888 |
|
|
optdict = {} |
889 |
|
|
optlist = [] |
890 |
|
|
if argc > 4: |
891 |
|
|
odata = sys.argv[4] |
892 |
|
|
opts = odata.split(",") |
893 |
|
|
#print opts |
894 |
|
|
for o in opts: |
895 |
|
|
try: |
896 |
|
|
k, v = o.split("=", 1) |
897 |
|
|
optdict[k] = v |
898 |
|
|
except: |
899 |
|
|
optlist.append(o) |
900 |
|
|
else: |
901 |
|
|
odata = "" |
902 |
|
|
|
903 |
|
|
#print sys.argv |
904 |
|
|
if dev == 'none': |
905 |
|
|
if not optdict.has_key("fs"): |
906 |
|
|
print "%s: Must specify python file with 'fs' option\n" % progname |
907 |
|
|
usage(1) |
908 |
|
|
pyfile = optdict['fs'] |
909 |
|
|
else: |
910 |
|
|
pyfile = dev |
911 |
|
|
|
912 |
|
|
if not os.path.isfile(pyfile): |
913 |
|
|
print "%s: file %s doesn't exist, or is not a file" % (progname, pyfile) |
914 |
|
|
sys.exit(1) |
915 |
|
|
pypath = os.path.abspath(pyfile) |
916 |
|
|
|
917 |
|
|
#print optdict, optlist |
918 |
|
|
|
919 |
|
|
# all seems ok - run our fuse fs as a child |
920 |
|
|
if os.fork() == 0: |
921 |
|
|
os.system("fusermount -c -x %s %s %s %s" % (mountpoint, pypath, mountpoint, odata)) |
922 |
|
|
else: |
923 |
|
|
#print "parent exiting..." |
924 |
|
|
pass |
925 |
|
|
|
926 |
|
|
if __name__ == '__main__': |
927 |
|
|
main() |
928 |
|
|
|
929 |
|
|
</t> |
930 |
|
|
<t tx="davidmcnab.121303144134">def statfs(self): |
931 |
|
|
""" |
932 |
|
|
Should return a tuple with the following 6 elements: |
933 |
|
|
- blocksize - size of file blocks, in bytes |
934 |
|
|
- totalblocks - total number of blocks in the filesystem |
935 |
|
|
- freeblocks - number of free blocks |
936 |
|
|
- totalfiles - total number of file inodes |
937 |
|
|
- freefiles - nunber of free file inodes |
938 |
|
|
|
939 |
|
|
Feel free to set any of the above values to 0, which tells |
940 |
|
|
the kernel that the info is not available. |
941 |
|
|
""" |
942 |
|
|
print "xmp.py:Xmp:statfs: returning fictitious values" |
943 |
|
|
blocks_size = 1024 |
944 |
|
|
blocks = 100000 |
945 |
|
|
blocks_free = 25000 |
946 |
|
|
files = 100000 |
947 |
|
|
files_free = 60000 |
948 |
|
|
namelen = 80 |
949 |
|
|
return (blocks_size, blocks, blocks_free, files, files_free, namelen) |
950 |
|
|
</t> |
951 |
|
|
<t tx="davidmcnab.121303144134.1">def fsync(self, path, isfsyncfile): |
952 |
|
|
print "xmp.py:Xmp:fsync: path=%s, isfsyncfile=%s" % (path, isfsyncfile) |
953 |
|
|
return 0 |
954 |
|
|
|
955 |
|
|
</t> |
956 |
|
|
<t tx="davidmcnab.121303144441">static int statfs_func(struct fuse_statfs *fst) |
957 |
|
|
{ |
958 |
|
|
int i; |
959 |
|
|
long retvalues[6]; |
960 |
|
|
PyObject *v = PyObject_CallFunction(statfs_cb, ""); |
961 |
|
|
PROLOGUE |
962 |
|
|
|
963 |
|
|
if (!PySequence_Check(v)) |
964 |
|
|
{ goto OUT_DECREF; } |
965 |
|
|
if (PySequence_Size(v) < 6) |
966 |
|
|
{ goto OUT_DECREF; } |
967 |
|
|
for(i=0; i<6; i++) |
968 |
|
|
{ |
969 |
|
|
PyObject *tmp = PySequence_GetItem(v, i); |
970 |
|
|
retvalues[i] = PyInt_Check(tmp) |
971 |
|
|
? PyInt_AsLong(tmp) |
972 |
|
|
: (PyLong_Check(tmp) |
973 |
|
|
? PyLong_AsLong(tmp) |
974 |
|
|
: 0); |
975 |
|
|
} |
976 |
|
|
|
977 |
|
|
fst->block_size = retvalues[0]; |
978 |
|
|
fst->blocks = retvalues[1]; |
979 |
|
|
fst->blocks_free = retvalues[2]; |
980 |
|
|
fst->files = retvalues[3]; |
981 |
|
|
fst->files_free = retvalues[4]; |
982 |
|
|
fst->namelen = retvalues[5]; |
983 |
|
|
ret = 0; |
984 |
|
|
|
985 |
|
|
#ifdef IGNORE_THIS |
986 |
|
|
printf("block_size=%ld, blocks=%ld, blocks_free=%ld, files=%ld, files_free=%ld, namelen=%ld\n", |
987 |
|
|
retvalues[0], retvalues[1], retvalues[2], retvalues[3], retvalues[4], retvalues[5]); |
988 |
|
|
#endif |
989 |
|
|
|
990 |
|
|
EPILOGUE |
991 |
|
|
|
992 |
|
|
} |
993 |
|
|
|
994 |
|
|
</t> |
995 |
|
|
<t tx="davidmcnab.121303144441.1">static int fsync_func(const char *path, int isfsyncfile) |
996 |
|
|
{ |
997 |
|
|
PyObject *v = PyObject_CallFunction(fsync_cb, "si", path, isfsyncfile); |
998 |
|
|
PROLOGUE |
999 |
|
|
EPILOGUE |
1000 |
|
|
} |
1001 |
|
|
|
1002 |
|
|
</t> |
1003 |
|
|
<t tx="davidmcnab.121403050157">@ignore |
1004 |
|
|
@language python |
1005 |
|
|
<< fuse declarations >> |
1006 |
|
|
@others |
1007 |
|
|
#@-node:main |
1008 |
|
|
#@-others |
1009 |
|
|
#@-node:class Fuse |
1010 |
|
|
#@-others |
1011 |
|
|
#@-node:@file fuse.py |
1012 |
|
|
#@-leo |
1013 |
|
|
</t> |
1014 |
|
|
<t tx="davidmcnab.121403050157.1">#@+leo-ver=4 |
1015 |
|
|
#@+node:@file fuse.py |
1016 |
|
|
# |
1017 |
|
|
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> |
1018 |
|
|
# |
1019 |
|
|
# This program can be distributed under the terms of the GNU GPL. |
1020 |
|
|
# See the file COPYING. |
1021 |
|
|
# |
1022 |
|
|
|
1023 |
|
|
|
1024 |
|
|
#@@language python |
1025 |
|
|
#@+others |
1026 |
|
|
#@+node:imports |
1027 |
|
|
# suppress version mismatch warnings |
1028 |
|
|
try: |
1029 |
|
|
import warnings |
1030 |
|
|
warnings.filterwarnings('ignore', |
1031 |
|
|
'Python C API version mismatch', |
1032 |
|
|
RuntimeWarning, |
1033 |
|
|
) |
1034 |
|
|
except: |
1035 |
|
|
pass |
1036 |
|
|
|
1037 |
|
|
from _fuse import main, DEBUG |
1038 |
|
|
import os, sys |
1039 |
|
|
from errno import * |
1040 |
|
|
|
1041 |
|
|
#@-node:imports |
1042 |
|
|
#@+node:class ErrnoWrapper |
1043 |
|
|
</t> |
1044 |
|
|
<t tx="davidmcnab.121403050157.2">class ErrnoWrapper: |
1045 |
|
|
<< class ErrnoWrapper declarations >> |
1046 |
|
|
@others |
1047 |
|
|
</t> |
1048 |
|
|
<t tx="davidmcnab.121403050157.3"> #@ @+others |
1049 |
|
|
#@+node:__init__ |
1050 |
|
|
</t> |
1051 |
|
|
<t tx="davidmcnab.121403050157.4">def __init__(self, func): |
1052 |
|
|
self.func = func |
1053 |
|
|
</t> |
1054 |
|
|
<t tx="davidmcnab.121403050157.5">#@-node:__init__ |
1055 |
|
|
#@+node:__call__ |
1056 |
|
|
def __call__(self, *args, **kw): |
1057 |
|
|
try: |
1058 |
|
|
return apply(self.func, args, kw) |
1059 |
|
|
except (IOError, OSError), detail: |
1060 |
|
|
# Sometimes this is an int, sometimes an instance... |
1061 |
|
|
if hasattr(detail, "errno"): detail = detail.errno |
1062 |
|
|
return -detail |
1063 |
|
|
</t> |
1064 |
|
|
<t tx="davidmcnab.121403050157.6"> #@-node:__call__ |
1065 |
|
|
#@-others |
1066 |
|
|
#@-node:class ErrnoWrapper |
1067 |
|
|
#@+node:class Fuse |
1068 |
|
|
class Fuse: |
1069 |
|
|
<< class Fuse declarations >> |
1070 |
|
|
@others |
1071 |
|
|
</t> |
1072 |
|
|
<t tx="davidmcnab.121403050157.7">#@ @+others |
1073 |
|
|
#@+node:attribs |
1074 |
|
|
_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', |
1075 |
|
|
'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', |
1076 |
|
|
'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release', |
1077 |
|
|
'statfs', 'fsync'] |
1078 |
|
|
|
1079 |
|
|
flags = 0 |
1080 |
|
|
multithreaded = 0 |
1081 |
|
|
|
1082 |
|
|
#@-node:attribs |
1083 |
|
|
#@+node:__init__ |
1084 |
|
|
</t> |
1085 |
|
|
<t tx="davidmcnab.121403050157.8">def __init__(self, *args, **kw): |
1086 |
|
|
|
1087 |
|
|
# default attributes |
1088 |
|
|
self.optlist = [] |
1089 |
|
|
self.optdict = {} |
1090 |
|
|
self.mountpoint = None |
1091 |
|
|
|
1092 |
|
|
# grab arguments, if any |
1093 |
|
|
argv = sys.argv |
1094 |
|
|
argc = len(argv) |
1095 |
|
|
if argc > 1: |
1096 |
|
|
# we've been given the mountpoint |
1097 |
|
|
self.mountpoint = argv[1] |
1098 |
|
|
if argc > 2: |
1099 |
|
|
# we've received mount args |
1100 |
|
|
optstr = argv[2] |
1101 |
|
|
opts = optstr.split(",") |
1102 |
|
|
for o in opts: |
1103 |
|
|
try: |
1104 |
|
|
k, v = o.split("=", 1) |
1105 |
|
|
self.optdict[k] = v |
1106 |
|
|
except: |
1107 |
|
|
self.optlist.append(o) |
1108 |
|
|
</t> |
1109 |
|
|
<t tx="davidmcnab.121403050157.9">#@-node:__init__ |
1110 |
|
|
#@+node:main |
1111 |
|
|
def main(self): |
1112 |
|
|
d = {'flags': self.flags} |
1113 |
|
|
d['multithreaded'] = self.multithreaded |
1114 |
|
|
for a in self._attrs: |
1115 |
|
|
if hasattr(self,a): |
1116 |
|
|
d[a] = ErrnoWrapper(getattr(self, a)) |
1117 |
|
|
apply(main, (), d) |
1118 |
|
|
</t> |
1119 |
|
|
</tnodes> |
1120 |
|
|
</leo_file> |