1 /*
2 * Permission is hereby granted, free of charge, to any person obtaining a copy
3 * of this software and associated documentation files (the "Software"), to
4 * deal in the Software without restriction, including without limitation the
5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6 * sell copies of the Software, and to permit persons to whom the Software is
7 * furnished to do so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in
10 * all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 * DEALINGS IN THE SOFTWARE.
19 *
20 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
21 * Use is subject to license terms.
22 */
23
24 #include <Python.h>
25
26 #include <xenfsimage.h>
27 #include <stdlib.h>
28
29 typedef struct fsimage_fs {
30 PyObject_HEAD
31 fsi_t *fs;
32 } fsimage_fs_t;
33
34 typedef struct fsimage_file {
35 PyObject_HEAD
36 fsimage_fs_t *fs;
37 fsi_file_t *file;
38 } fsimage_file_t;
39
40 static PyObject *
fsimage_file_read(fsimage_file_t * file,PyObject * args,PyObject * kwargs)41 fsimage_file_read(fsimage_file_t *file, PyObject *args, PyObject *kwargs)
42 {
43 static char *kwlist[] = { "size", "offset", NULL };
44 int bufsize;
45 int size = 0;
46 uint64_t offset = 0;
47 ssize_t bytesread = 0;
48 PyObject * buffer;
49
50 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iL", kwlist,
51 &size, &offset))
52 return (NULL);
53
54 bufsize = size ? size : 4096;
55
56 buffer =
57 #if PY_MAJOR_VERSION < 3
58 PyString_FromStringAndSize(NULL, bufsize);
59 #else
60 PyBytes_FromStringAndSize(NULL, bufsize);
61 #endif
62
63 if (buffer == NULL)
64 return (NULL);
65
66 while (1) {
67 int err;
68 void *buf =
69 #if PY_MAJOR_VERSION < 3
70 PyString_AS_STRING(buffer) + bytesread;
71 #else
72 PyBytes_AS_STRING(buffer) + bytesread;
73 #endif
74
75 err = fsi_pread_file(file->file, buf, bufsize,
76 bytesread + offset);
77
78 if (err == -1) {
79 Py_DECREF(buffer);
80 PyErr_SetFromErrno(PyExc_IOError);
81 return (NULL);
82 } else if (err == 0) {
83 break;
84 }
85
86 bytesread += err;
87
88 if (size != 0) {
89 bufsize -= bytesread;
90 if (bufsize == 0)
91 break;
92 } else {
93 #if PY_MAJOR_VERSION < 3
94 if (_PyString_Resize(&buffer, bytesread + bufsize) < 0)
95 #else
96 if (_PyBytes_Resize(&buffer, bytesread + bufsize) < 0)
97 #endif
98 return (NULL);
99 }
100 }
101
102 #if PY_MAJOR_VERSION < 3
103 _PyString_Resize(&buffer, bytesread);
104 #else
105 _PyBytes_Resize(&buffer, bytesread);
106 #endif
107 return (buffer);
108 }
109
110 PyDoc_STRVAR(fsimage_file_read__doc__,
111 "read(file, [size=size, offset=off])\n"
112 "\n"
113 "Read size bytes (or all bytes if not set) from the given "
114 "file. If offset is specified as well, read from the given "
115 "offset.\n");
116
117 static struct PyMethodDef fsimage_file_methods[] = {
118 { "read", (PyCFunction) fsimage_file_read,
119 METH_VARARGS|METH_KEYWORDS, fsimage_file_read__doc__ },
120 { NULL, NULL, 0, NULL }
121 };
122
123 #if PY_MAJOR_VERSION < 3
124 static PyObject *
fsimage_file_getattr(fsimage_file_t * file,char * name)125 fsimage_file_getattr(fsimage_file_t *file, char *name)
126 {
127 return (Py_FindMethod(fsimage_file_methods, (PyObject *)file, name));
128 }
129 #endif
130
131 static void
fsimage_file_dealloc(fsimage_file_t * file)132 fsimage_file_dealloc(fsimage_file_t *file)
133 {
134 if (file->file != NULL)
135 fsi_close_file(file->file);
136 Py_XDECREF(file->fs);
137 PyObject_DEL(file);
138 }
139
140 static char fsimage_file_type__doc__[] = "Filesystem image file";
141 PyTypeObject fsimage_file_type = {
142 PyVarObject_HEAD_INIT(&PyType_Type, 0)
143 .tp_name = "xenfsimage.file",
144 .tp_basicsize = sizeof(fsimage_file_t),
145 .tp_dealloc = (destructor) fsimage_file_dealloc,
146 #if PY_MAJOR_VERSION < 3
147 .tp_getattr = (getattrfunc) fsimage_file_getattr,
148 #endif
149 .tp_flags = Py_TPFLAGS_DEFAULT,
150 .tp_doc = fsimage_file_type__doc__,
151 #if PY_MAJOR_VERSION >= 3
152 .tp_methods = fsimage_file_methods,
153 #endif
154 };
155
156 static PyObject *
fsimage_fs_open_file(fsimage_fs_t * fs,PyObject * args,PyObject * kwargs)157 fsimage_fs_open_file(fsimage_fs_t *fs, PyObject *args, PyObject *kwargs)
158 {
159 static char *kwlist[] = { "name", NULL };
160 fsimage_file_t *file;
161 char *name;
162
163 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
164 return (NULL);
165
166 file = (fsimage_file_t *)PyObject_NEW(fsimage_file_t, &fsimage_file_type);
167
168 if (file == NULL)
169 return (NULL);
170
171 file->fs = fs;
172
173 Py_INCREF(file->fs);
174 if ((file->file = fsi_open_file(fs->fs, name)) == NULL) {
175 Py_DECREF(file->fs);
176 file->fs = NULL;
177 PyErr_SetFromErrno(PyExc_IOError);
178 return (NULL);
179 }
180
181 return ((PyObject *)file);
182 }
183
184 static PyObject *
fsimage_fs_file_exists(fsimage_fs_t * fs,PyObject * args,PyObject * kwargs)185 fsimage_fs_file_exists(fsimage_fs_t *fs, PyObject *args, PyObject *kwargs)
186 {
187 static char *kwlist[] = { "name", NULL };
188 char *name;
189
190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
191 return (NULL);
192
193 if (fsi_file_exists(fs->fs, name)) {
194 Py_INCREF(Py_True);
195 return (Py_True);
196 }
197
198 Py_INCREF(Py_False);
199 return (Py_False);
200 }
201
202 PyDoc_STRVAR(fsimage_fs_open_file__doc__,
203 "open_file(fs, filename) - lookup name in the given fs and return the file");
204 PyDoc_STRVAR(fsimage_fs_file_exists__doc__,
205 "file_exists(fs, name) - lookup name in the given fs and return "
206 "True if it exists");
207
208 static struct PyMethodDef fsimage_fs_methods[] = {
209 { "open_file", (PyCFunction) fsimage_fs_open_file,
210 METH_VARARGS|METH_KEYWORDS, fsimage_fs_open_file__doc__ },
211 { "file_exists", (PyCFunction) fsimage_fs_file_exists,
212 METH_VARARGS|METH_KEYWORDS, fsimage_fs_file_exists__doc__ },
213 { NULL, NULL, 0, NULL }
214 };
215
216 #if PY_MAJOR_VERSION < 3
217 static PyObject *
fsimage_fs_getattr(fsimage_fs_t * fs,char * name)218 fsimage_fs_getattr(fsimage_fs_t *fs, char *name)
219 {
220 return (Py_FindMethod(fsimage_fs_methods, (PyObject *)fs, name));
221 }
222 #endif
223
224 static void
fsimage_fs_dealloc(fsimage_fs_t * fs)225 fsimage_fs_dealloc (fsimage_fs_t *fs)
226 {
227 if (fs->fs != NULL)
228 fsi_close_fsimage(fs->fs);
229 PyObject_DEL(fs);
230 }
231
232 PyDoc_STRVAR(fsimage_fs_type__doc__, "Filesystem image");
233
234 PyTypeObject fsimage_fs_type = {
235 PyVarObject_HEAD_INIT(&PyType_Type, 0)
236 .tp_name = "xenfsimage.fs",
237 .tp_basicsize = sizeof(fsimage_fs_t),
238 .tp_dealloc = (destructor) fsimage_fs_dealloc,
239 #if PY_MAJOR_VERSION < 3
240 .tp_getattr = (getattrfunc) fsimage_fs_getattr,
241 #endif
242 .tp_flags = Py_TPFLAGS_DEFAULT,
243 .tp_doc = fsimage_fs_type__doc__,
244 #if PY_MAJOR_VERSION >= 3
245 .tp_methods = fsimage_fs_methods,
246 #endif
247 };
248
249 static PyObject *
fsimage_open(PyObject * o,PyObject * args,PyObject * kwargs)250 fsimage_open(PyObject *o, PyObject *args, PyObject *kwargs)
251 {
252 static char *kwlist[] = { "name", "offset", "options", NULL };
253 char *name;
254 char *options = NULL;
255 uint64_t offset = 0;
256 fsimage_fs_t *fs;
257
258 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Ls", kwlist,
259 &name, &offset, &options))
260 return (NULL);
261
262 if ((fs = PyObject_NEW(fsimage_fs_t, &fsimage_fs_type)) == NULL)
263 return (NULL);
264
265 if ((fs->fs = fsi_open_fsimage(name, offset, options)) == NULL) {
266 PyErr_SetFromErrno(PyExc_IOError);
267 return (NULL);
268 }
269
270 return (PyObject *)fs;
271 }
272
273 static PyObject *
fsimage_getbootstring(PyObject * o,PyObject * args)274 fsimage_getbootstring(PyObject *o, PyObject *args)
275 {
276 PyObject *fs;
277 char *bootstring;
278 fsi_t *fsi;
279
280 if (!PyArg_ParseTuple(args, "O", &fs))
281 return (NULL);
282
283 fsi = ((fsimage_fs_t *)fs)->fs;
284 bootstring = fsi_fs_bootstring(fsi);
285
286 return Py_BuildValue("s", bootstring);
287 }
288
289 PyDoc_STRVAR(fsimage_open__doc__,
290 "open(name, [offset=off]) - Open the given file as a filesystem image.\n"
291 "\n"
292 "name - name of file to open.\n"
293 "offset - offset of file system within file image.\n"
294 "options - mount options string.\n");
295
296 PyDoc_STRVAR(fsimage_getbootstring__doc__,
297 "getbootstring(fs) - Return the boot string needed for this file system "
298 "or NULL if none is needed.\n");
299
300 static struct PyMethodDef fsimage_module_methods[] = {
301 { "open", (PyCFunction)fsimage_open,
302 METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ },
303 { "getbootstring", (PyCFunction)fsimage_getbootstring,
304 METH_VARARGS, fsimage_getbootstring__doc__ },
305 { NULL, NULL, 0, NULL }
306 };
307
308 #if PY_MAJOR_VERSION >= 3
309 static struct PyModuleDef fsimage_module_def = {
310 PyModuleDef_HEAD_INIT,
311 .m_name = "xenfsimage",
312 .m_size = -1,
313 .m_methods = fsimage_module_methods,
314 };
315 #endif
316
317 PyMODINIT_FUNC
318 #if PY_MAJOR_VERSION >= 3
PyInit_xenfsimage(void)319 PyInit_xenfsimage(void)
320 #else
321 initxenfsimage(void)
322 #endif
323 {
324 #if PY_MAJOR_VERSION < 3
325 Py_InitModule("xenfsimage", fsimage_module_methods);
326 #else
327 if (PyType_Ready(&fsimage_fs_type) < 0 || PyType_Ready(&fsimage_file_type) < 0)
328 return NULL;
329 return PyModule_Create(&fsimage_module_def);
330 #endif
331 }
332