1 /*
2  * Python object wrapper of libfwsi_item_t type LIBFWSI_ITEM_TYPE_VOLUME
3  *
4  * Copyright (C) 2010-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <types.h>
24 
25 #if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
26 #include <stdlib.h>
27 #endif
28 
29 #include "pyfwsi_error.h"
30 #include "pyfwsi_guid.h"
31 #include "pyfwsi_item.h"
32 #include "pyfwsi_libcerror.h"
33 #include "pyfwsi_libfwsi.h"
34 #include "pyfwsi_python.h"
35 #include "pyfwsi_unused.h"
36 #include "pyfwsi_volume.h"
37 
38 PyMethodDef pyfwsi_volume_object_methods[] = {
39 
40 	{ "get_name",
41 	  (PyCFunction) pyfwsi_volume_get_name,
42 	  METH_NOARGS,
43 	  "get_name() -> Unicode string\n"
44 	  "\n"
45 	  "Retrieves the name." },
46 
47 	{ "get_identifier",
48 	  (PyCFunction) pyfwsi_volume_get_identifier,
49 	  METH_NOARGS,
50 	  "get_identifier() -> Unicode string\n"
51 	  "\n"
52 	  "Retrieves the identifier." },
53 
54 	{ "get_shell_folder_identifier",
55 	  (PyCFunction) pyfwsi_volume_get_shell_folder_identifier,
56 	  METH_NOARGS,
57 	  "get_shell_folder_identifier() -> Unicode string\n"
58 	  "\n"
59 	  "Retrieves the shell folder identifier." },
60 
61 	/* Sentinel */
62 	{ NULL, NULL, 0, NULL }
63 };
64 
65 PyGetSetDef pyfwsi_volume_object_get_set_definitions[] = {
66 
67 	{ "name",
68 	  (getter) pyfwsi_volume_get_name,
69 	  (setter) 0,
70 	  "The name.",
71 	  NULL },
72 
73 	{ "identifier",
74 	  (getter) pyfwsi_volume_get_identifier,
75 	  (setter) 0,
76 	  "The identifier.",
77 	  NULL },
78 
79 	{ "shell_folder_identifier",
80 	  (getter) pyfwsi_volume_get_shell_folder_identifier,
81 	  (setter) 0,
82 	  "The shell folder identifier.",
83 	  NULL },
84 
85 	/* Sentinel */
86 	{ NULL, NULL, NULL, NULL, NULL }
87 };
88 
89 PyTypeObject pyfwsi_volume_type_object = {
90 	PyVarObject_HEAD_INIT( NULL, 0 )
91 
92 	/* tp_name */
93 	"pyfwsi.volume",
94 	/* tp_basicsize */
95 	sizeof( pyfwsi_item_t ),
96 	/* tp_itemsize */
97 	0,
98 	/* tp_dealloc */
99 	0,
100 	/* tp_print */
101 	0,
102 	/* tp_getattr */
103 	0,
104 	/* tp_setattr */
105 	0,
106 	/* tp_compare */
107 	0,
108 	/* tp_repr */
109 	0,
110 	/* tp_as_number */
111 	0,
112 	/* tp_as_sequence */
113 	0,
114 	/* tp_as_mapping */
115 	0,
116 	/* tp_hash */
117 	0,
118 	/* tp_call */
119 	0,
120 	/* tp_str */
121 	0,
122 	/* tp_getattro */
123 	0,
124 	/* tp_setattro */
125 	0,
126 	/* tp_as_buffer */
127 	0,
128 	/* tp_flags */
129 	Py_TPFLAGS_DEFAULT,
130 	/* tp_doc */
131 	"pyfwsi volume object (wraps libfwsi_item_t type LIBFWSI_ITEM_TYPE_VOLUME)",
132 	/* tp_traverse */
133 	0,
134 	/* tp_clear */
135 	0,
136 	/* tp_richcompare */
137 	0,
138 	/* tp_weaklistoffset */
139 	0,
140 	/* tp_iter */
141 	0,
142 	/* tp_iternext */
143 	0,
144 	/* tp_methods */
145 	pyfwsi_volume_object_methods,
146 	/* tp_members */
147 	0,
148 	/* tp_getset */
149 	pyfwsi_volume_object_get_set_definitions,
150 	/* tp_base */
151 	&pyfwsi_item_type_object,
152 	/* tp_dict */
153 	0,
154 	/* tp_descr_get */
155 	0,
156 	/* tp_descr_set */
157 	0,
158 	/* tp_dictoffset */
159 	0,
160 	/* tp_init */
161 	0,
162 	/* tp_alloc */
163 	0,
164 	/* tp_new */
165 	0,
166 	/* tp_free */
167 	0,
168 	/* tp_is_gc */
169 	0,
170 	/* tp_bases */
171 	NULL,
172 	/* tp_mro */
173 	NULL,
174 	/* tp_cache */
175 	NULL,
176 	/* tp_subclasses */
177 	NULL,
178 	/* tp_weaklist */
179 	NULL,
180 	/* tp_del */
181 	0
182 };
183 
184 /* Retrieves the name
185  * Returns a Python object if successful or NULL on error
186  */
pyfwsi_volume_get_name(pyfwsi_item_t * pyfwsi_item,PyObject * arguments PYFWSI_ATTRIBUTE_UNUSED)187 PyObject *pyfwsi_volume_get_name(
188            pyfwsi_item_t *pyfwsi_item,
189            PyObject *arguments PYFWSI_ATTRIBUTE_UNUSED )
190 {
191 	PyObject *string_object  = NULL;
192 	libcerror_error_t *error = NULL;
193 	const char *errors       = NULL;
194 	static char *function    = "pyfwsi_volume_get_name";
195 	char *utf8_string        = NULL;
196 	size_t utf8_string_size  = 0;
197 	int result               = 0;
198 
199 	PYFWSI_UNREFERENCED_PARAMETER( arguments )
200 
201 	if( pyfwsi_item == NULL )
202 	{
203 		PyErr_Format(
204 		 PyExc_ValueError,
205 		 "%s: invalid item.",
206 		 function );
207 
208 		return( NULL );
209 	}
210 	Py_BEGIN_ALLOW_THREADS
211 
212 	result = libfwsi_volume_get_utf8_name_size(
213 	          pyfwsi_item->item,
214 	          &utf8_string_size,
215 	          &error );
216 
217 	Py_END_ALLOW_THREADS
218 
219 	if( result == -1 )
220 	{
221 		pyfwsi_error_raise(
222 		 error,
223 		 PyExc_IOError,
224 		 "%s: unable to determine size of name as UTF-8 string.",
225 		 function );
226 
227 		libcerror_error_free(
228 		 &error );
229 
230 		goto on_error;
231 	}
232 	else if( ( result == 0 )
233 	      || ( utf8_string_size == 0 ) )
234 	{
235 		Py_IncRef(
236 		 Py_None );
237 
238 		return( Py_None );
239 	}
240 	utf8_string = (char *) PyMem_Malloc(
241 	                        sizeof( char ) * utf8_string_size );
242 
243 	if( utf8_string == NULL )
244 	{
245 		PyErr_Format(
246 		 PyExc_MemoryError,
247 		 "%s: unable to create UTF-8 string.",
248 		 function );
249 
250 		goto on_error;
251 	}
252 	Py_BEGIN_ALLOW_THREADS
253 
254 	result = libfwsi_volume_get_utf8_name(
255 	          pyfwsi_item->item,
256 	          (uint8_t *) utf8_string,
257 	          utf8_string_size,
258 	          &error );
259 
260 	Py_END_ALLOW_THREADS
261 
262 	if( result != 1 )
263 	{
264 		pyfwsi_error_raise(
265 		 error,
266 		 PyExc_IOError,
267 		 "%s: unable to retrieve name as UTF-8 string.",
268 		 function );
269 
270 		libcerror_error_free(
271 		 &error );
272 
273 		goto on_error;
274 	}
275 	/* Pass the string length to PyUnicode_DecodeUTF8 otherwise it makes
276 	 * the end of string character is part of the string
277 	 */
278 	string_object = PyUnicode_DecodeUTF8(
279 	                 utf8_string,
280 	                 (Py_ssize_t) utf8_string_size - 1,
281 	                 errors );
282 
283 	if( string_object == NULL )
284 	{
285 		PyErr_Format(
286 		 PyExc_IOError,
287 		 "%s: unable to convert UTF-8 string into Unicode object.",
288 		 function );
289 
290 		goto on_error;
291 	}
292 	PyMem_Free(
293 	 utf8_string );
294 
295 	return( string_object );
296 
297 on_error:
298 	if( utf8_string != NULL )
299 	{
300 		PyMem_Free(
301 		 utf8_string );
302 	}
303 	return( NULL );
304 }
305 
306 /* Retrieves the identifier
307  * Returns a Python object if successful or NULL on error
308  */
pyfwsi_volume_get_identifier(pyfwsi_item_t * pyfwsi_item,PyObject * arguments PYFWSI_ATTRIBUTE_UNUSED)309 PyObject *pyfwsi_volume_get_identifier(
310            pyfwsi_item_t *pyfwsi_item,
311            PyObject *arguments PYFWSI_ATTRIBUTE_UNUSED )
312 {
313 	uint8_t guid_data[ 16 ];
314 
315 	PyObject *string_object  = NULL;
316 	libcerror_error_t *error = NULL;
317 	static char *function    = "pyfwsi_volume_get_identifier";
318 	int result               = 0;
319 
320 	PYFWSI_UNREFERENCED_PARAMETER( arguments )
321 
322 	if( pyfwsi_item == NULL )
323 	{
324 		PyErr_Format(
325 		 PyExc_TypeError,
326 		 "%s: invalid item.",
327 		 function );
328 
329 		return( NULL );
330 	}
331 	Py_BEGIN_ALLOW_THREADS
332 
333 	result = libfwsi_volume_get_identifier(
334 	          pyfwsi_item->item,
335 	          guid_data,
336 	          16,
337 	          &error );
338 
339 	Py_END_ALLOW_THREADS
340 
341 	if( result != 1 )
342 	{
343 		pyfwsi_error_raise(
344 		 error,
345 		 PyExc_IOError,
346 		 "%s: unable to retrieve identifier.",
347 		 function );
348 
349 		libcerror_error_free(
350 		 &error );
351 
352 		return( NULL );
353 	}
354 	string_object = pyfwsi_string_new_from_guid(
355 	                 guid_data,
356 	                 16 );
357 
358 	if( string_object == NULL )
359 	{
360 		PyErr_Format(
361 		 PyExc_IOError,
362 		 "%s: unable to convert GUID into Unicode object.",
363 		 function );
364 
365 		return( NULL );
366 	}
367 	return( string_object );
368 }
369 
370 /* Retrieves the shell folder identifier
371  * Returns a Python object if successful or NULL on error
372  */
pyfwsi_volume_get_shell_folder_identifier(pyfwsi_item_t * pyfwsi_item,PyObject * arguments PYFWSI_ATTRIBUTE_UNUSED)373 PyObject *pyfwsi_volume_get_shell_folder_identifier(
374            pyfwsi_item_t *pyfwsi_item,
375            PyObject *arguments PYFWSI_ATTRIBUTE_UNUSED )
376 {
377 	uint8_t guid_data[ 16 ];
378 
379 	PyObject *string_object  = NULL;
380 	libcerror_error_t *error = NULL;
381 	static char *function    = "pyfwsi_volume_get_shell_folder_identifier";
382 	int result               = 0;
383 
384 	PYFWSI_UNREFERENCED_PARAMETER( arguments )
385 
386 	if( pyfwsi_item == NULL )
387 	{
388 		PyErr_Format(
389 		 PyExc_TypeError,
390 		 "%s: invalid item.",
391 		 function );
392 
393 		return( NULL );
394 	}
395 	Py_BEGIN_ALLOW_THREADS
396 
397 	result = libfwsi_volume_get_shell_folder_identifier(
398 	          pyfwsi_item->item,
399 	          guid_data,
400 	          16,
401 	          &error );
402 
403 	Py_END_ALLOW_THREADS
404 
405 	if( result != 1 )
406 	{
407 		pyfwsi_error_raise(
408 		 error,
409 		 PyExc_IOError,
410 		 "%s: unable to retrieve shell folder identifier.",
411 		 function );
412 
413 		libcerror_error_free(
414 		 &error );
415 
416 		return( NULL );
417 	}
418 	string_object = pyfwsi_string_new_from_guid(
419 	                 guid_data,
420 	                 16 );
421 
422 	if( string_object == NULL )
423 	{
424 		PyErr_Format(
425 		 PyExc_IOError,
426 		 "%s: unable to convert GUID into Unicode object.",
427 		 function );
428 
429 		return( NULL );
430 	}
431 	return( string_object );
432 }
433 
434