1 /*
2 * Mount file system
3 *
4 * Copyright (C) 2013-2020, 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 <memory.h>
24 #include <narrow_string.h>
25 #include <system_string.h>
26 #include <types.h>
27 #include <wide_string.h>
28
29 #if defined( HAVE_SYS_STAT_H )
30 #include <sys/stat.h>
31 #endif
32
33 #if defined( TIME_WITH_SYS_TIME )
34 #include <sys/time.h>
35 #include <time.h>
36 #elif defined( HAVE_SYS_TIME_H )
37 #include <sys/time.h>
38 #else
39 #include <time.h>
40 #endif
41
42 #include "luksdetools_libcdata.h"
43 #include "luksdetools_libcerror.h"
44 #include "luksdetools_libluksde.h"
45 #include "mount_file_system.h"
46
47 /* Creates a file system
48 * Make sure the value file_system is referencing, is set to NULL
49 * Returns 1 if successful or -1 on error
50 */
mount_file_system_initialize(mount_file_system_t ** file_system,libcerror_error_t ** error)51 int mount_file_system_initialize(
52 mount_file_system_t **file_system,
53 libcerror_error_t **error )
54 {
55 #if defined( WINAPI )
56 FILETIME filetime;
57 SYSTEMTIME systemtime;
58
59 #elif defined( HAVE_CLOCK_GETTIME )
60 struct timespec time_structure;
61 #endif
62
63 static char *function = "mount_file_system_initialize";
64
65 #if defined( WINAPI )
66 DWORD error_code = 0;
67 #else
68 int64_t timestamp = 0;
69 #endif
70
71 if( file_system == NULL )
72 {
73 libcerror_error_set(
74 error,
75 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
77 "%s: invalid file system.",
78 function );
79
80 return( -1 );
81 }
82 if( *file_system != NULL )
83 {
84 libcerror_error_set(
85 error,
86 LIBCERROR_ERROR_DOMAIN_RUNTIME,
87 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
88 "%s: invalid file system value already set.",
89 function );
90
91 return( -1 );
92 }
93 *file_system = memory_allocate_structure(
94 mount_file_system_t );
95
96 if( *file_system == NULL )
97 {
98 libcerror_error_set(
99 error,
100 LIBCERROR_ERROR_DOMAIN_MEMORY,
101 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
102 "%s: unable to create file system.",
103 function );
104
105 goto on_error;
106 }
107 if( memory_set(
108 *file_system,
109 0,
110 sizeof( mount_file_system_t ) ) == NULL )
111 {
112 libcerror_error_set(
113 error,
114 LIBCERROR_ERROR_DOMAIN_MEMORY,
115 LIBCERROR_MEMORY_ERROR_SET_FAILED,
116 "%s: unable to clear file system.",
117 function );
118
119 memory_free(
120 *file_system );
121
122 *file_system = NULL;
123
124 return( -1 );
125 }
126 if( libcdata_array_initialize(
127 &( ( *file_system )->volumes_array ),
128 0,
129 error ) != 1 )
130 {
131 libcerror_error_set(
132 error,
133 LIBCERROR_ERROR_DOMAIN_RUNTIME,
134 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
135 "%s: unable to initialize volumes array.",
136 function );
137
138 goto on_error;
139 }
140 #if defined( WINAPI )
141 if( memory_set(
142 &systemtime,
143 0,
144 sizeof( SYSTEMTIME ) ) == NULL )
145 {
146 libcerror_error_set(
147 error,
148 LIBCERROR_ERROR_DOMAIN_MEMORY,
149 LIBCERROR_MEMORY_ERROR_SET_FAILED,
150 "%s: unable to clear systemtime.",
151 function );
152
153 goto on_error;
154 }
155 GetSystemTime(
156 &systemtime );
157
158 if( SystemTimeToFileTime(
159 &systemtime,
160 &filetime ) == 0 )
161 {
162 error_code = GetLastError();
163
164 libcerror_system_set_error(
165 error,
166 LIBCERROR_ERROR_DOMAIN_RUNTIME,
167 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
168 error_code,
169 "%s: unable to retrieve FILETIME of current time.",
170 function );
171
172 goto on_error;
173 }
174 ( *file_system )->mounted_timestamp = ( (uint64_t) filetime.dwHighDateTime << 32 ) | filetime.dwLowDateTime;
175
176 #elif defined( HAVE_CLOCK_GETTIME )
177 if( clock_gettime(
178 CLOCK_REALTIME,
179 &time_structure ) != 0 )
180 {
181 libcerror_error_set(
182 error,
183 LIBCERROR_ERROR_DOMAIN_RUNTIME,
184 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
185 "%s: unable to retrieve current time structure.",
186 function );
187
188 goto on_error;
189 }
190 timestamp = ( (int64_t) time_structure.tv_sec * 1000000000 ) + time_structure.tv_nsec;
191
192 ( *file_system )->mounted_timestamp = (uint64_t) timestamp;
193
194 #else
195 timestamp = (int64_t) time( NULL );
196
197 if( timestamp == -1 )
198 {
199 libcerror_error_set(
200 error,
201 LIBCERROR_ERROR_DOMAIN_RUNTIME,
202 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
203 "%s: unable to retrieve current time.",
204 function );
205
206 goto on_error;
207 }
208 timestamp *= 1000000000;
209
210 ( *file_system )->mounted_timestamp = (uint64_t) timestamp;
211
212 #endif /* defined( HAVE_CLOCK_GETTIME ) */
213
214 return( 1 );
215
216 on_error:
217 if( *file_system != NULL )
218 {
219 memory_free(
220 *file_system );
221
222 *file_system = NULL;
223 }
224 return( -1 );
225 }
226
227 /* Frees a file system
228 * Returns 1 if successful or -1 on error
229 */
mount_file_system_free(mount_file_system_t ** file_system,libcerror_error_t ** error)230 int mount_file_system_free(
231 mount_file_system_t **file_system,
232 libcerror_error_t **error )
233 {
234 static char *function = "mount_file_system_free";
235 int result = 1;
236
237 if( file_system == NULL )
238 {
239 libcerror_error_set(
240 error,
241 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
242 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
243 "%s: invalid file system.",
244 function );
245
246 return( -1 );
247 }
248 if( *file_system != NULL )
249 {
250 if( ( *file_system )->path_prefix != NULL )
251 {
252 memory_free(
253 ( *file_system )->path_prefix );
254 }
255 if( libcdata_array_free(
256 &( ( *file_system )->volumes_array ),
257 NULL,
258 error ) != 1 )
259 {
260 libcerror_error_set(
261 error,
262 LIBCERROR_ERROR_DOMAIN_RUNTIME,
263 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
264 "%s: unable to free volumes array.",
265 function );
266
267 result = -1;
268 }
269 memory_free(
270 *file_system );
271
272 *file_system = NULL;
273 }
274 return( result );
275 }
276
277 /* Signals the file system to abort
278 * Returns 1 if successful or -1 on error
279 */
mount_file_system_signal_abort(mount_file_system_t * file_system,libcerror_error_t ** error)280 int mount_file_system_signal_abort(
281 mount_file_system_t *file_system,
282 libcerror_error_t **error )
283 {
284 libluksde_volume_t *luksde_volume = NULL;
285 static char *function = "mount_file_system_signal_abort";
286 int number_of_volumes = 0;
287 int volume_index = 0;
288
289 if( file_system == NULL )
290 {
291 libcerror_error_set(
292 error,
293 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
294 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
295 "%s: invalid file system.",
296 function );
297
298 return( -1 );
299 }
300 if( libcdata_array_get_number_of_entries(
301 file_system->volumes_array,
302 &number_of_volumes,
303 error ) != 1 )
304 {
305 libcerror_error_set(
306 error,
307 LIBCERROR_ERROR_DOMAIN_RUNTIME,
308 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
309 "%s: unable to retrieve number of volumes.",
310 function );
311
312 return( -1 );
313 }
314 for( volume_index = number_of_volumes - 1;
315 volume_index > 0;
316 volume_index-- )
317 {
318 if( libcdata_array_get_entry_by_index(
319 file_system->volumes_array,
320 volume_index,
321 (intptr_t **) &luksde_volume,
322 error ) != 1 )
323 {
324 libcerror_error_set(
325 error,
326 LIBCERROR_ERROR_DOMAIN_RUNTIME,
327 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
328 "%s: unable to retrieve volume: %d.",
329 function,
330 volume_index );
331
332 return( -1 );
333 }
334 if( libluksde_volume_signal_abort(
335 luksde_volume,
336 error ) != 1 )
337 {
338 libcerror_error_set(
339 error,
340 LIBCERROR_ERROR_DOMAIN_RUNTIME,
341 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
342 "%s: unable to signal volume: %d to abort.",
343 function,
344 volume_index );
345
346 return( -1 );
347 }
348 }
349 return( 1 );
350 }
351
352 /* Sets the path prefix
353 * Returns 1 if successful or -1 on error
354 */
mount_file_system_set_path_prefix(mount_file_system_t * file_system,const system_character_t * path_prefix,size_t path_prefix_size,libcerror_error_t ** error)355 int mount_file_system_set_path_prefix(
356 mount_file_system_t *file_system,
357 const system_character_t *path_prefix,
358 size_t path_prefix_size,
359 libcerror_error_t **error )
360 {
361 static char *function = "mount_file_system_set_path_prefix";
362
363 if( file_system == NULL )
364 {
365 libcerror_error_set(
366 error,
367 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
368 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
369 "%s: invalid file system.",
370 function );
371
372 return( -1 );
373 }
374 if( file_system->path_prefix != NULL )
375 {
376 libcerror_error_set(
377 error,
378 LIBCERROR_ERROR_DOMAIN_RUNTIME,
379 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
380 "%s: invalid file system - path prefix value already set.",
381 function );
382
383 return( -1 );
384 }
385 if( path_prefix == NULL )
386 {
387 libcerror_error_set(
388 error,
389 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
390 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
391 "%s: invalid path prefix.",
392 function );
393
394 return( -1 );
395 }
396 if( path_prefix_size == 0 )
397 {
398 libcerror_error_set(
399 error,
400 LIBCERROR_ERROR_DOMAIN_RUNTIME,
401 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
402 "%s: missing path prefix.",
403 function );
404
405 goto on_error;
406 }
407 if( path_prefix_size > (size_t) ( SSIZE_MAX / sizeof( system_character_t ) ) )
408 {
409 libcerror_error_set(
410 error,
411 LIBCERROR_ERROR_DOMAIN_RUNTIME,
412 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
413 "%s: invalid path prefix size value exceeds maximum.",
414 function );
415
416 goto on_error;
417 }
418 file_system->path_prefix = system_string_allocate(
419 path_prefix_size );
420
421 if( file_system->path_prefix == NULL )
422 {
423 libcerror_error_set(
424 error,
425 LIBCERROR_ERROR_DOMAIN_MEMORY,
426 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
427 "%s: unable to create path prefix string.",
428 function );
429
430 goto on_error;
431 }
432 if( system_string_copy(
433 file_system->path_prefix,
434 path_prefix,
435 path_prefix_size ) == NULL )
436 {
437 libcerror_error_set(
438 error,
439 LIBCERROR_ERROR_DOMAIN_RUNTIME,
440 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
441 "%s: unable to copy path prefix.",
442 function );
443
444 goto on_error;
445 }
446 file_system->path_prefix[ path_prefix_size - 1 ] = 0;
447
448 file_system->path_prefix_size = path_prefix_size;
449
450 return( 1 );
451
452 on_error:
453 if( file_system->path_prefix != NULL )
454 {
455 memory_free(
456 file_system->path_prefix );
457
458 file_system->path_prefix = NULL;
459 }
460 file_system->path_prefix_size = 0;
461
462 return( -1 );
463 }
464
465 /* Retrieves the mounted timestamp
466 * On Windows the timestamp is an unsigned 64-bit FILETIME timestamp
467 * otherwise the timestamp is a signed 64-bit POSIX date and time value in number of nanoseconds
468 * Returns 1 if successful or -1 on error
469 */
mount_file_system_get_mounted_timestamp(mount_file_system_t * file_system,uint64_t * mounted_timestamp,libcerror_error_t ** error)470 int mount_file_system_get_mounted_timestamp(
471 mount_file_system_t *file_system,
472 uint64_t *mounted_timestamp,
473 libcerror_error_t **error )
474 {
475 static char *function = "mount_file_system_get_mounted_timestamp";
476
477 if( file_system == NULL )
478 {
479 libcerror_error_set(
480 error,
481 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
482 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
483 "%s: invalid file system.",
484 function );
485
486 return( -1 );
487 }
488 if( mounted_timestamp == NULL )
489 {
490 libcerror_error_set(
491 error,
492 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
493 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
494 "%s: invalid mounted timestamp.",
495 function );
496
497 return( -1 );
498 }
499 *mounted_timestamp = file_system->mounted_timestamp;
500
501 return( 1 );
502 }
503
504 /* Retrieves the number of volumes
505 * Returns 1 if successful or -1 on error
506 */
mount_file_system_get_number_of_volumes(mount_file_system_t * file_system,int * number_of_volumes,libcerror_error_t ** error)507 int mount_file_system_get_number_of_volumes(
508 mount_file_system_t *file_system,
509 int *number_of_volumes,
510 libcerror_error_t **error )
511 {
512 static char *function = "mount_file_system_get_number_of_volumes";
513
514 if( file_system == NULL )
515 {
516 libcerror_error_set(
517 error,
518 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
519 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
520 "%s: invalid file system.",
521 function );
522
523 return( -1 );
524 }
525 if( libcdata_array_get_number_of_entries(
526 file_system->volumes_array,
527 number_of_volumes,
528 error ) != 1 )
529 {
530 libcerror_error_set(
531 error,
532 LIBCERROR_ERROR_DOMAIN_RUNTIME,
533 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
534 "%s: unable to retrieve number of volumes.",
535 function );
536
537 return( -1 );
538 }
539 return( 1 );
540 }
541
542 /* Retrieves a specific volume
543 * Returns 1 if successful or -1 on error
544 */
mount_file_system_get_volume_by_index(mount_file_system_t * file_system,int volume_index,libluksde_volume_t ** luksde_volume,libcerror_error_t ** error)545 int mount_file_system_get_volume_by_index(
546 mount_file_system_t *file_system,
547 int volume_index,
548 libluksde_volume_t **luksde_volume,
549 libcerror_error_t **error )
550 {
551 static char *function = "mount_file_system_get_volume_by_index";
552
553 if( file_system == NULL )
554 {
555 libcerror_error_set(
556 error,
557 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
558 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
559 "%s: invalid file system.",
560 function );
561
562 return( -1 );
563 }
564 if( libcdata_array_get_entry_by_index(
565 file_system->volumes_array,
566 volume_index,
567 (intptr_t **) luksde_volume,
568 error ) != 1 )
569 {
570 libcerror_error_set(
571 error,
572 LIBCERROR_ERROR_DOMAIN_RUNTIME,
573 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
574 "%s: unable to retrieve volume: %d.",
575 function,
576 volume_index );
577
578 return( -1 );
579 }
580 return( 1 );
581 }
582
583 /* Retrieves the volume for a specific path
584 * Returns 1 if successful, 0 if no such volume or -1 on error
585 */
mount_file_system_get_volume_by_path(mount_file_system_t * file_system,const system_character_t * path,size_t path_length,libluksde_volume_t ** luksde_volume,libcerror_error_t ** error)586 int mount_file_system_get_volume_by_path(
587 mount_file_system_t *file_system,
588 const system_character_t *path,
589 size_t path_length,
590 libluksde_volume_t **luksde_volume,
591 libcerror_error_t **error )
592 {
593 static char *function = "mount_file_system_get_volume_by_path";
594 system_character_t character = 0;
595 size_t path_index = 0;
596 int result = 0;
597 int volume_index = 0;
598
599 if( file_system == NULL )
600 {
601 libcerror_error_set(
602 error,
603 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
604 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
605 "%s: invalid file system.",
606 function );
607
608 return( -1 );
609 }
610 if( file_system->path_prefix == NULL )
611 {
612 libcerror_error_set(
613 error,
614 LIBCERROR_ERROR_DOMAIN_RUNTIME,
615 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
616 "%s: invalid file system - missing path prefix.",
617 function );
618
619 return( -1 );
620 }
621 if( path == NULL )
622 {
623 libcerror_error_set(
624 error,
625 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
626 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
627 "%s: invalid path.",
628 function );
629
630 return( -1 );
631 }
632 if( path_length > (size_t) ( SSIZE_MAX - 1 ) )
633 {
634 libcerror_error_set(
635 error,
636 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
637 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
638 "%s: invalid path length value exceeds maximum.",
639 function );
640
641 return( -1 );
642 }
643 if( luksde_volume == NULL )
644 {
645 libcerror_error_set(
646 error,
647 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
648 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
649 "%s: invalid volume.",
650 function );
651
652 return( -1 );
653 }
654 path_length = system_string_length(
655 path );
656
657 if( ( path_length == 1 )
658 && ( path[ 0 ] == file_system->path_prefix[ 0 ] ) )
659 {
660 *luksde_volume = NULL;
661
662 return( 1 );
663 }
664 if( ( path_length < file_system->path_prefix_size )
665 || ( path_length > ( file_system->path_prefix_size + 3 ) ) )
666 {
667 return( 0 );
668 }
669 #if defined( WINAPI )
670 result = system_string_compare_no_case(
671 path,
672 file_system->path_prefix,
673 file_system->path_prefix_size - 1 );
674 #else
675 result = system_string_compare(
676 path,
677 file_system->path_prefix,
678 file_system->path_prefix_size - 1 );
679 #endif
680 if( result != 0 )
681 {
682 return( 0 );
683 }
684 volume_index = 0;
685
686 path_index = file_system->path_prefix_size - 1;
687
688 while( path_index < path_length )
689 {
690 character = path[ path_index++ ];
691
692 if( ( character < (system_character_t) '0' )
693 || ( character > (system_character_t) '9' ) )
694 {
695 return( 0 );
696 }
697 volume_index *= 10;
698 volume_index += character - (system_character_t) '0';
699 }
700 volume_index -= 1;
701
702 if( libcdata_array_get_entry_by_index(
703 file_system->volumes_array,
704 volume_index,
705 (intptr_t **) luksde_volume,
706 error ) != 1 )
707 {
708 libcerror_error_set(
709 error,
710 LIBCERROR_ERROR_DOMAIN_RUNTIME,
711 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
712 "%s: unable to retrieve volume: %d.",
713 function,
714 volume_index );
715
716 return( -1 );
717 }
718 return( 1 );
719 }
720
721 /* Appends a volume to the file system
722 * Returns 1 if successful or -1 on error
723 */
mount_file_system_append_volume(mount_file_system_t * file_system,libluksde_volume_t * luksde_volume,libcerror_error_t ** error)724 int mount_file_system_append_volume(
725 mount_file_system_t *file_system,
726 libluksde_volume_t *luksde_volume,
727 libcerror_error_t **error )
728 {
729 static char *function = "mount_file_system_append_volume";
730 int entry_index = 0;
731
732 if( file_system == NULL )
733 {
734 libcerror_error_set(
735 error,
736 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
737 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
738 "%s: invalid file system.",
739 function );
740
741 return( -1 );
742 }
743 if( libcdata_array_append_entry(
744 file_system->volumes_array,
745 &entry_index,
746 (intptr_t *) luksde_volume,
747 error ) != 1 )
748 {
749 libcerror_error_set(
750 error,
751 LIBCERROR_ERROR_DOMAIN_RUNTIME,
752 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
753 "%s: unable to append volume to array.",
754 function );
755
756 return( -1 );
757 }
758 return( 1 );
759 }
760
761 /* Retrieves the path from a volume index.
762 * Returns 1 if successful or -1 on error
763 */
mount_file_system_get_path_from_volume_index(mount_file_system_t * file_system,int volume_index,system_character_t * path,size_t path_size,libcerror_error_t ** error)764 int mount_file_system_get_path_from_volume_index(
765 mount_file_system_t *file_system,
766 int volume_index,
767 system_character_t *path,
768 size_t path_size,
769 libcerror_error_t **error )
770 {
771 static char *function = "mount_file_system_get_path_from_volume_index";
772 size_t path_index = 0;
773 size_t required_path_size = 0;
774 int volume_number = 0;
775
776 if( file_system == NULL )
777 {
778 libcerror_error_set(
779 error,
780 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
781 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
782 "%s: invalid file system.",
783 function );
784
785 return( -1 );
786 }
787 if( file_system->path_prefix == NULL )
788 {
789 libcerror_error_set(
790 error,
791 LIBCERROR_ERROR_DOMAIN_RUNTIME,
792 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
793 "%s: invalid file system - missing path prefix.",
794 function );
795
796 return( -1 );
797 }
798 if( path == NULL )
799 {
800 libcerror_error_set(
801 error,
802 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
803 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
804 "%s: invalid path.",
805 function );
806
807 return( -1 );
808 }
809 if( path_size > (size_t) SSIZE_MAX )
810 {
811 libcerror_error_set(
812 error,
813 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
814 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
815 "%s: invalid path length value exceeds maximum.",
816 function );
817
818 return( -1 );
819 }
820 required_path_size = file_system->path_prefix_size;
821
822 volume_number = volume_index + 1;
823
824 while( volume_number > 0 )
825 {
826 required_path_size++;
827
828 volume_number /= 10;
829 }
830 if( path_size <= required_path_size )
831 {
832 libcerror_error_set(
833 error,
834 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
835 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
836 "%s: invalid path size value too small.",
837 function );
838
839 return( -1 );
840 }
841 if( system_string_copy(
842 path,
843 file_system->path_prefix,
844 file_system->path_prefix_size ) == NULL )
845 {
846 libcerror_error_set(
847 error,
848 LIBCERROR_ERROR_DOMAIN_RUNTIME,
849 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
850 "%s: unable to copy path prefix.",
851 function );
852
853 return( -1 );
854 }
855 path_index = required_path_size - 1;
856
857 volume_number = volume_index + 1;
858
859 path[ path_index-- ] = 0;
860
861 while( volume_number > 0 )
862 {
863 path[ path_index-- ] = (system_character_t) '0' + ( volume_number % 10 );
864
865 volume_number /= 10;
866 }
867 return( 1 );
868 }
869
870