1 /*
2 ** The Sleuth Kit
3 **
4 ** This software is subject to the IBM Public License ver. 1.0,
5 ** which was displayed prior to download and is included in the readme.txt
6 ** file accompanying the Sleuth Kit files. It may also be requested from:
7 ** Crucial Security Inc.
8 ** 14900 Conference Center Drive
9 ** Chantilly, VA 20151
10 **
11 ** Wyatt Banks [wbanks@crucialsecurity.com]
12 ** Copyright (c) 2005 Crucial Security Inc. All rights reserved.
13 **
14 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
15 ** Copyright (c) 2003-2005 Brian Carrier. All rights reserved
16 ** Copyright (c) 2007-2011 Brian Carrier. All rights reserved
17 **
18 ** Copyright (c) 1997,1998,1999, International Business Machines
19 ** Corporation and others. All Rights Reserved.
20 */
21 /* TCT
22 * LICENSE
23 * This software is distributed under the IBM Public License.
24 * AUTHOR(S)
25 * Wietse Venema
26 * IBM T.J. Watson Research
27 * P.O. Box 704
28 * Yorktown Heights, NY 10598, USA
29 --*/
30 /*
31 ** You may distribute the Sleuth Kit, or other software that incorporates
32 ** part of all of the Sleuth Kit, in object code form under a license agreement,
33 ** provided that:
34 ** a) you comply with the terms and conditions of the IBM Public License
35 ** ver 1.0; and
36 ** b) the license agreement
37 ** i) effectively disclaims on behalf of all Contributors all warranties
38 ** and conditions, express and implied, including warranties or
39 ** conditions of title and non-infringement, and implied warranties
40 ** or conditions of merchantability and fitness for a particular
41 ** purpose.
42 ** ii) effectively excludes on behalf of all Contributors liability for
43 ** damages, including direct, indirect, special, incidental and
44 ** consequential damages such as lost profits.
45 ** iii) states that any provisions which differ from IBM Public License
46 ** ver. 1.0 are offered by that Contributor alone and not by any
47 ** other party; and
48 ** iv) states that the source code for the program is available from you,
49 ** and informs licensees how to obtain it in a reasonable manner on or
50 ** through a medium customarily used for software exchange.
51 **
52 ** When the Sleuth Kit or other software that incorporates part or all of
53 ** the Sleuth Kit is made available in source code form:
54 ** a) it must be made available under IBM Public License ver. 1.0; and
55 ** b) a copy of the IBM Public License ver. 1.0 must be included with
56 ** each copy of the program.
57 */
58
59 /**
60 * \file iso9660.c
61 * Contains the internal TSK ISO9660 file system code to handle basic file
62 * system processing for opening file system, processing sectors, and directory entries.
63 */
64
65 #include "tsk_fs_i.h"
66 #include "tsk_iso9660.h"
67 #include <ctype.h>
68
69
70 /* free all memory used by inode linked list */
71 static void
iso9660_inode_list_free(TSK_FS_INFO * fs)72 iso9660_inode_list_free(TSK_FS_INFO * fs)
73 {
74 ISO_INFO *iso = (ISO_INFO *) fs;
75
76 while (iso->in_list) {
77 iso9660_inode_node *tmp = iso->in_list;
78 iso->in_list = iso->in_list->next;
79 free(tmp);
80 }
81 iso->in_list = NULL;
82 }
83
84
85 /**
86 * Process the System Use Sharing Protocol (SUSP) data. Typically,
87 * rockridge data are stored in this.
88 *
89 * @param fs File system to process
90 * @param buf Buffer of data to process
91 * @param count Length of buffer in bytes.
92 * @param hFile File handle to print details to (or NULL for no printing)
93 * @returns NULL on error
94 */
95 static rockridge_ext *
parse_susp(TSK_FS_INFO * fs,char * buf,int count,FILE * hFile)96 parse_susp(TSK_FS_INFO * fs, char *buf, int count, FILE * hFile)
97 {
98 rockridge_ext *rr;
99 ISO_INFO *iso = (ISO_INFO *) fs;
100
101 char *end = buf + count - 1;
102
103 if (tsk_verbose)
104 tsk_fprintf(stderr, "parse_susp: count is: %d\n", count);
105
106 // allocate the output data structure
107 rr = (rockridge_ext *) tsk_malloc(sizeof(rockridge_ext));
108 if (rr == NULL) {
109 return NULL;
110 }
111
112 while ((uintptr_t)buf + sizeof(iso9660_susp_head) <= (uintptr_t)end) {
113 iso9660_susp_head *head = (iso9660_susp_head *) buf;
114
115 if (buf + head->len - 1 > end)
116 break;
117
118 /* Identify the entry type -- listed in the order
119 * that they are listed in the specs */
120
121 // SUSP Continuation Entry
122 if ((head->sig[0] == 'C') && (head->sig[1] == 'E')) {
123 iso9660_susp_ce *ce = (iso9660_susp_ce *) buf;
124
125 if ((uintptr_t)buf + sizeof(iso9660_susp_ce) - 1 > (uintptr_t)end) {
126 if (tsk_verbose)
127 tsk_fprintf(stderr, "parse_susp: not enough room for CE structure\n");
128 break;
129 }
130
131 if (hFile) {
132 fprintf(hFile, "CE Entry\n");
133 fprintf(hFile, "* Block: %" PRIu32 "\n",
134 tsk_getu32(fs->endian, ce->blk_m));
135 fprintf(hFile, "* Offset: %" PRIu32 "\n",
136 tsk_getu32(fs->endian, ce->offset_m));
137 fprintf(hFile, "* Len: %" PRIu32 "\n",
138 tsk_getu32(fs->endian, ce->celen_m));
139 }
140
141 // read the continued buffer and parse it
142 if ((tsk_getu32(fs->endian, ce->blk_m) < fs->last_block) &&
143 (tsk_getu32(fs->endian, ce->offset_m) < fs->block_size)) {
144 TSK_OFF_T off;
145 char *buf2;
146
147 off =
148 tsk_getu32(fs->endian,
149 ce->blk_m) * fs->block_size + tsk_getu32(fs->endian,
150 ce->offset_m);
151 buf2 =
152 (char *) tsk_malloc(tsk_getu32(fs->endian,
153 ce->celen_m));
154
155 if (buf2 != NULL) {
156 ssize_t cnt =
157 tsk_fs_read(fs, off, buf2,
158 tsk_getu32(fs->endian, ce->celen_m));
159 if (cnt == tsk_getu32(fs->endian, ce->celen_m)) {
160 parse_susp(fs, buf2, (int) cnt, hFile);
161 }
162 else if (tsk_verbose) {
163 fprintf(stderr,
164 "parse_susp: error reading CE entry\n");
165 tsk_error_print(stderr);
166 tsk_error_reset();
167 }
168 free(buf2);
169 }
170 else {
171 if (tsk_verbose)
172 fprintf(stderr,
173 "parse_susp: error allocating memory to process CE entry\n");
174 tsk_error_reset();
175 }
176 }
177 else {
178 if (tsk_verbose)
179 fprintf(stderr,
180 "parse_susp: CE offset or block too large to process\n");
181 }
182
183 buf += head->len;
184 }
185 // SUSP Padding Entry
186 else if ((head->sig[0] == 'P') && (head->sig[1] == 'D')) {
187 if (hFile) {
188 fprintf(hFile, "PD Entry\n");
189 }
190 buf += head->len;
191 }
192 // SUSP Sharing Protocol Entry -- we ignore
193 else if ((head->sig[0] == 'S') && (head->sig[1] == 'P')) {
194 iso9660_susp_sp *sp = (iso9660_susp_sp *) buf;
195 if (hFile) {
196 fprintf(hFile, "SP Entry\n");
197 fprintf(hFile, "* SKip Len: %d\n", sp->skip);
198 }
199 buf += head->len;
200 }
201 // SUSP System Terminator
202 else if ((head->sig[0] == 'S') && (head->sig[1] == 'T')) {
203 if (hFile) {
204 fprintf(hFile, "ST Entry\n");
205 }
206 buf += head->len;
207 }
208 // SUSP Extension Registration -- not used
209 else if ((head->sig[0] == 'E') && (head->sig[1] == 'R')) {
210 iso9660_susp_er *er = (iso9660_susp_er *) buf;
211 if (hFile) {
212 char buf[258];
213 fprintf(hFile, "ER Entry\n");
214
215 memcpy(buf, er->ext_id, er->len_id);
216 buf[er->len_id] = '\0';
217 fprintf(hFile, "* Extension ID: %s\n", buf);
218
219 memcpy(buf, er->ext_id + er->len_id, er->len_des);
220 buf[er->len_des] = '\0';
221 fprintf(hFile, "* Extension Descriptor: %s\n", buf);
222
223 memcpy(buf, er->ext_id + er->len_id + er->len_des,
224 er->len_src);
225 buf[er->len_src] = '\0';
226 fprintf(hFile, "* Extension Spec Source: %s\n", buf);
227 }
228 buf += head->len;
229 }
230 // SUSP Extension Sigs -- not used
231 else if ((head->sig[0] == 'E') && (head->sig[1] == 'S')) {
232 if (hFile) {
233 fprintf(hFile, "ES Entry\n");
234 }
235 buf += head->len;
236 }
237
238 /*
239 * Rock Ridge Extensions
240 */
241
242 /* POSIX file attributes */
243 else if ((head->sig[0] == 'P') && (head->sig[1] == 'X')) {
244 iso9660_rr_px_entry *rr_px;
245
246 if ((uintptr_t)buf + sizeof(iso9660_rr_px_entry) - 1> (uintptr_t)end) {
247 if (tsk_verbose)
248 tsk_fprintf(stderr, "parse_susp: not enough room for POSIX structure\n");
249 break;
250 }
251
252 rr_px = (iso9660_rr_px_entry *) buf;
253 rr->uid = tsk_getu32(fs->endian, rr_px->uid_m);
254 rr->gid = tsk_getu32(fs->endian, rr_px->gid_m);
255 rr->mode = tsk_getu16(fs->endian, rr_px->mode_m);
256 rr->nlink = tsk_getu32(fs->endian, rr_px->links_m);
257 if (hFile) {
258 fprintf(hFile, "PX Entry\n");
259 fprintf(hFile, "* UID: %" PRIuUID "\n", rr->uid);
260 fprintf(hFile, "* GID: %" PRIuGID "\n", rr->gid);
261 fprintf(hFile, "* Mode: %d\n", rr->mode);
262 fprintf(hFile, "* Links: %" PRIu32 "\n", rr->nlink);
263 }
264 buf += head->len;
265 }
266
267 // RR - device information
268 else if ((head->sig[0] == 'P') && (head->sig[1] == 'N')) {
269 iso9660_rr_pn_entry *rr_pn = (iso9660_rr_pn_entry *) buf;
270 if (hFile) {
271 fprintf(hFile, "PN Entry\n");
272 fprintf(hFile, "* Device ID High: %" PRIu32 "\n",
273 tsk_getu32(fs->endian, rr_pn->dev_h_m));
274 fprintf(hFile, "* Device ID Low: %" PRIu32 "\n",
275 tsk_getu32(fs->endian, rr_pn->dev_l_m));
276 }
277 buf += head->len;
278 }
279
280 // RR - symbolic link
281 else if ((head->sig[0] == 'S') && (head->sig[1] == 'L')) {
282 //iso9660_rr_sl_entry *rr_sl = (iso9660_rr_sl_entry *) buf;
283 if (hFile) {
284 fprintf(hFile, "SL Entry\n");
285 }
286 buf += head->len;
287 }
288 // RR -- alternative name
289 else if ((head->sig[0] == 'N') && (head->sig[1] == 'M')) {
290 iso9660_rr_nm_entry *rr_nm;
291 int len;
292
293 if ((uintptr_t)buf + sizeof(iso9660_rr_nm_entry) - 1> (uintptr_t)end) {
294 if (tsk_verbose)
295 tsk_fprintf(stderr, "parse_susp: not enough room for RR alternative name structure\n");
296 break;
297 }
298
299 rr_nm = (iso9660_rr_nm_entry *) buf;
300
301 if ((uintptr_t)&rr_nm->name[0] + (int) rr_nm->len - 5 - 1> (uintptr_t)end) {
302 if (tsk_verbose)
303 tsk_fprintf(stderr, "parse_susp: not enough room for RR alternative name\n");
304 break;
305 }
306
307 // Make sure the name will fit in the buffer
308 len = rr_nm->len - 5;
309 if (len >= ISO9660_MAXNAMLEN_RR) {
310 len = ISO9660_MAXNAMLEN_RR - 1;
311 }
312
313 strncpy(rr->fn, &rr_nm->name[0], len);
314 rr->fn[len] = '\0';
315 if (hFile) {
316 fprintf(hFile, "NM Entry\n");
317 fprintf(hFile, "* %s\n", rr->fn);
318 }
319 buf += head->len;
320 }
321 // RR - relocated directory
322 else if ((head->sig[0] == 'C') && (head->sig[1] == 'L')) {
323 if (hFile) {
324 fprintf(hFile, "CL Entry\n");
325 }
326 buf += head->len;
327 }
328 // RR - parent of relocated directory
329 else if ((head->sig[0] == 'P') && (head->sig[1] == 'L')) {
330 if (hFile) {
331 fprintf(hFile, "PL Entry\n");
332 }
333 buf += head->len;
334 }
335 // RR - relocation signal
336 else if ((head->sig[0] == 'R') && (head->sig[1] == 'E')) {
337 if (hFile) {
338 fprintf(hFile, "RE Entry\n");
339 }
340 buf += head->len;
341 }
342 // RR - time stamps
343 else if ((head->sig[0] == 'T') && (head->sig[1] == 'F')) {
344 if (hFile) {
345 fprintf(hFile, "TF Entry\n");
346 }
347 buf += head->len;
348 }
349 // RR - sparse file
350 else if ((head->sig[0] == 'S') && (head->sig[1] == 'F')) {
351 if (hFile) {
352 fprintf(hFile, "SF Entry\n");
353 }
354 buf += head->len;
355 }
356
357 /* RR is a system use field indicating RockRidge, but not part of RockRidge */
358 else if ((head->sig[0] == 'R') && (head->sig[1] == 'R')) {
359 iso->rr_found = 1;
360 if (hFile) {
361 fprintf(hFile, "RR Entry\n");
362 }
363 buf += head->len;
364 }
365
366 else {
367 buf += 2;
368 if ((uintptr_t) buf % 2)
369 buf--;
370 }
371 }
372
373 return rr;
374 }
375
376
377 ///////////////////////////////////////////////////////////////////////////
378 // The following functions are responsible for loading all of the file metadata into memory.
379 // The process is that the Path table is processed first. It contains an entry for each
380 // directory. That info is then used to locate the directory contents and those contents
381 // are then processed.
382 //
383 // Files do not have a corresponding metadata entry, so we assign them based
384 // on the order that they are loaded.
385 ///////////////////////////////////////////////////////////////////////////
386
387
388 /* XXX Instead of loading all of the file metadata, we could instead save a mapping
389 * between inode number and the byte offset of the metadata (and any other data
390 * needed for fast lookups).
391 */
392
393 /** \internal
394 * Process the contents of a directory and load the
395 * information about files in that directory into ISO_INFO. This is called
396 * by the methods that process the path table (which contains pointers to the
397 * various directories). The results in ISO_INFO are used to identify the
398 * inode address of files found from dent_walk and for file lookups.
399 *
400 * Type: ISO9660_TYPE_PVD for primary volume descriptor, ISO9660_TYPE_SVD for
401 * supplementary volume descriptor (do Joliet utf-8 conversion).
402 *
403 * @param fs File system to analyze
404 * @param a_offs Byte offset of directory start
405 * @param count previous file count
406 * @param ctype Character set used for the names
407 * @param a_fn Name of the directory to use for the "." entry (in UTF-8)
408 *
409 * @returns total number of files or -1 on error
410 */
411 static int
iso9660_load_inodes_dir(TSK_FS_INFO * fs,TSK_OFF_T a_offs,int count,int ctype,const char * a_fn,uint8_t is_first)412 iso9660_load_inodes_dir(TSK_FS_INFO * fs, TSK_OFF_T a_offs, int count,
413 int ctype, const char *a_fn, uint8_t is_first)
414 {
415 ISO_INFO *iso = (ISO_INFO *) fs;
416 int s_cnt = 1; // count of sectors needed for dir
417 TSK_OFF_T s_offs = a_offs; // offset for sector reads
418 int i;
419
420 if (tsk_verbose)
421 tsk_fprintf(stderr,
422 "iso9660_load_inodes_dir: offs: %" PRIdOFF
423 " count: %d ctype: %d fn: %s\n", a_offs, count, ctype, a_fn);
424
425 // cycle through each sector -- entries will not cross them
426 for (i = 0; i < s_cnt; i++) {
427 ssize_t cnt1;
428 int b_offs; // offset in buffer
429 char buf[ISO9660_SSIZE_B];
430
431 cnt1 = tsk_fs_read(fs, s_offs, buf, ISO9660_SSIZE_B);
432 if (cnt1 != ISO9660_SSIZE_B) {
433 if (cnt1 >= 0) {
434 tsk_error_reset();
435 tsk_error_set_errno(TSK_ERR_FS_READ);
436 }
437 tsk_error_set_errstr2("iso_get_dentries");
438 return -1;
439 }
440
441 /* process the directory entries */
442 for (b_offs = 0; b_offs < ISO9660_SSIZE_B;) {
443 iso9660_inode_node *in_node = NULL;
444 iso9660_dentry *dentry;
445
446 dentry = (iso9660_dentry *) & buf[b_offs];
447
448 if (dentry->entry_len == 0) {
449 b_offs += 2;
450 continue;
451 }
452 // sanity checks on entry_len
453 else if (dentry->entry_len < sizeof(iso9660_dentry)) {
454 if (tsk_verbose)
455 tsk_fprintf(stderr,
456 "iso9660_load_inodes_dir: entry length is shorter than dentry, bailing\n");
457 break;
458 }
459 else if (b_offs + dentry->entry_len > ISO9660_SSIZE_B) {
460 if (tsk_verbose)
461 tsk_fprintf(stderr,
462 "iso9660_load_inodes_dir: entry is longer than sector, bailing\n");
463 break;
464 }
465
466 /* when processing the other volume descriptor directories, we ignore the
467 * directories because we have no way of detecting if it is a duplicate of
468 * a directory from the other volume descriptor (they use different blocks).
469 * We will see the contents of this directory from the path table anyway. */
470 if ((dentry->flags & ISO9660_FLAG_DIR) && (is_first == 0)) {
471 b_offs += dentry->entry_len;
472 continue;
473 }
474
475 // allocate a node for this entry
476 in_node = (iso9660_inode_node *)
477 tsk_malloc(sizeof(iso9660_inode_node));
478 if (in_node == NULL) {
479 return -1;
480 }
481
482 // the first entry is for the current directory
483 if ((i == 0) && (b_offs == 0)) {
484 // should have no name or '.'
485 if (dentry->fi_len > 1) {
486 if (tsk_verbose)
487 tsk_fprintf(stderr,
488 "iso9660_load_inodes_dir: first entry has name length > 1\n");
489 free(in_node);
490 in_node = NULL;
491 b_offs += dentry->entry_len;
492 continue;
493 }
494
495 /* find how many more sectors are in the directory */
496 s_cnt =
497 tsk_getu32(fs->endian,
498 dentry->data_len_m) / ISO9660_SSIZE_B;
499 if (tsk_verbose)
500 tsk_fprintf(stderr, "iso9660_load_inodes_dir: %d number of additional sectors\n", s_cnt);
501
502 // @@@ Should have a sanity check here on s_cnt, but I'm not sure what it would be...
503
504 /* use the specified name instead of "." */
505 if (strlen(a_fn) > ISO9660_MAXNAMLEN_STD) {
506 tsk_error_reset();
507 tsk_error_set_errno(TSK_ERR_FS_ARG);
508 tsk_error_set_errstr
509 ("iso9660_load_inodes_dir: Name argument specified is too long");
510 free(in_node);
511 return -1;
512 }
513 strncpy(in_node->inode.fn, a_fn, ISO9660_MAXNAMLEN_STD + 1);
514
515 /* for all directories except the root, we skip processing the "." and ".." entries because
516 * they duplicate the other entires and the dent_walk code will rely on the offset
517 * for the entry in the parent directory. */
518 if (count != 0) {
519 free(in_node);
520 in_node = NULL;
521 b_offs += dentry->entry_len;
522 dentry = (iso9660_dentry *) & buf[b_offs];
523 b_offs += dentry->entry_len;
524 continue;
525 }
526 }
527 else {
528 char *file_ver;
529
530 // the entry has a UTF-16 name
531 if (ctype == ISO9660_CTYPE_UTF16) {
532 UTF16 *name16;
533 UTF8 *name8;
534 int retVal;
535
536 if (dentry->entry_len < sizeof(iso9660_dentry) + dentry->fi_len) {
537 if (tsk_verbose)
538 tsk_fprintf(stderr,
539 "iso9660_load_inodes_dir: UTF-16 name length is too large, bailing\n");
540 break;
541 }
542
543 name16 =
544 (UTF16 *) & buf[b_offs + sizeof(iso9660_dentry)];
545 // the name is in UTF-16 BE -- convert to LE if needed
546 if (fs->endian & TSK_LIT_ENDIAN) {
547 int a;
548
549 for (a = 0; a < dentry->fi_len / 2; a++) {
550 name16[a] = ((name16[a] & 0xff) << 8) +
551 ((name16[a] & 0xff00) >> 8);
552 }
553 }
554 name8 = (UTF8 *) in_node->inode.fn;
555
556 retVal =
557 tsk_UTF16toUTF8(fs->endian,
558 (const UTF16 **) &name16,
559 (UTF16 *) & buf[b_offs + sizeof(iso9660_dentry) +
560 dentry->fi_len], &name8,
561 (UTF8 *) ((uintptr_t) & in_node->inode.
562 fn[ISO9660_MAXNAMLEN_STD]),
563 TSKlenientConversion);
564 if (retVal != TSKconversionOK) {
565 if (tsk_verbose)
566 tsk_fprintf(stderr,
567 "iso9660_load_inodes_dir: Error converting Joliet name to UTF8: %d",
568 retVal);
569 in_node->inode.fn[0] = '\0';
570 }
571 *name8 = '\0';
572 }
573
574 else if (ctype == ISO9660_CTYPE_ASCII) {
575 int readlen;
576
577 readlen = dentry->fi_len;
578 if (readlen > ISO9660_MAXNAMLEN_STD)
579 readlen = ISO9660_MAXNAMLEN_STD;
580
581 if (dentry->entry_len < sizeof(iso9660_dentry) + dentry->fi_len) {
582 if (tsk_verbose)
583 tsk_fprintf(stderr,
584 "iso9660_load_inodes_dir: ASCII name length is too large, bailing\n");
585 break;
586 }
587
588
589 memcpy(in_node->inode.fn,
590 &buf[b_offs + sizeof(iso9660_dentry)], readlen);
591 in_node->inode.fn[readlen] = '\0';
592 }
593 else {
594 tsk_error_reset();
595 tsk_error_set_errno(TSK_ERR_FS_ARG);
596 tsk_error_set_errstr
597 ("Invalid ctype in iso9660_load_inodes_dir");
598 return -1;
599 }
600
601 // the version is embedded in the name
602 file_ver = strchr(in_node->inode.fn, ';');
603 if (file_ver) {
604 in_node->inode.version = atoi(file_ver + 1);
605 *file_ver = '\0';
606 file_ver = NULL;
607 }
608
609 // if no extension, remove the final '.'
610 if (in_node->inode.fn[strlen(in_node->inode.fn) - 1] ==
611 '.')
612 in_node->inode.fn[strlen(in_node->inode.fn) - 1] =
613 '\0';
614
615
616 if (strlen(in_node->inode.fn) == 0) {
617 if (tsk_verbose)
618 tsk_fprintf(stderr,
619 "iso9660_load_inodes_dir: length of name after processing is 0. bailing\n");
620 free(in_node);
621 break;
622
623 }
624 }
625
626
627
628 // copy the raw dentry data into the node
629 memcpy(&(in_node->inode.dr), dentry, sizeof(iso9660_dentry));
630
631 in_node->inode.ea = NULL;
632
633 // sanity checks
634 if (tsk_getu32(fs->endian, dentry->ext_loc_m) > fs->last_block) {
635 if (tsk_verbose)
636 tsk_fprintf(stderr,
637 "iso9660_load_inodes_dir: file starts past end of image (%"PRIu32"). bailing\n",
638 tsk_getu32(fs->endian, dentry->ext_loc_m));
639 free(in_node);
640 break;
641 }
642 in_node->offset =
643 tsk_getu32(fs->endian, dentry->ext_loc_m) * fs->block_size;
644
645 if (tsk_getu32(fs->endian, in_node->inode.dr.data_len_m) + in_node->offset > (TSK_OFF_T)(fs->block_count * fs->block_size)) {
646 if (tsk_verbose)
647 tsk_fprintf(stderr,
648 "iso9660_load_inodes_dir: file ends past end of image (%"PRIu32" bytes). bailing\n",
649 tsk_getu32(fs->endian, in_node->inode.dr.data_len_m) + in_node->offset);
650 free(in_node);
651 break;
652 }
653 /* record size to make sure fifos show up as unique files */
654 in_node->size =
655 tsk_getu32(fs->endian, in_node->inode.dr.data_len_m);
656
657
658 in_node->ea_size = dentry->ext_len;
659 in_node->dentry_offset = s_offs + b_offs;
660
661 if (is_first)
662 in_node->inode.is_orphan = 0;
663 else
664 in_node->inode.is_orphan = 1;
665
666 in_node->inum = count++;
667
668 /* RockRidge data is located after the name. See if it is there. */
669 if ((int) (dentry->entry_len - sizeof(iso9660_dentry) -
670 dentry->fi_len) > 1) {
671 int extra_bytes =
672 dentry->entry_len - sizeof(iso9660_dentry) -
673 dentry->fi_len;
674
675 in_node->inode.rr =
676 parse_susp(fs,
677 &buf[b_offs + sizeof(iso9660_dentry) + dentry->fi_len],
678 extra_bytes, NULL);
679 if (in_node->inode.rr == NULL) {
680 if (tsk_verbose)
681 tsk_fprintf(stderr,
682 "iso9660_load_inodes_dir: parse_susp returned error (%s). bailing\n", tsk_error_get());
683 free(in_node);
684 break;
685 }
686
687 in_node->inode.susp_off =
688 b_offs + sizeof(iso9660_dentry) + dentry->fi_len +
689 s_offs;
690 in_node->inode.susp_len = extra_bytes;
691 }
692 else {
693 in_node->inode.rr = NULL;
694 in_node->inode.susp_off = 0;
695 in_node->inode.susp_len = 0;
696 }
697
698 /* add inode to the list */
699 if (iso->in_list) {
700 iso9660_inode_node *tmp, *prev_tmp;
701
702 for (tmp = iso->in_list; tmp; tmp = tmp->next) {
703 /* When processing the "first" volume descriptor, all entries get added to the list.
704 * for the later ones, we skip duplicate ones that have content (blocks) that overlaps
705 * with entries from a previous volume descriptor. */
706 if ((in_node->offset == tmp->offset)
707 && (in_node->size == tmp->size)
708 && (in_node->size) && (is_first == 0)) {
709
710 // if we found rockridge, then update original if needed.
711 if (in_node->inode.rr) {
712 if (tmp->inode.rr == NULL) {
713 tmp->inode.rr = in_node->inode.rr;
714 tmp->inode.susp_off =
715 in_node->inode.susp_off;
716 tmp->inode.susp_len =
717 in_node->inode.susp_len;
718 in_node->inode.rr = NULL;
719 }
720 else {
721 free(in_node->inode.rr);
722 in_node->inode.rr = NULL;
723 }
724 }
725
726 if (tsk_verbose)
727 tsk_fprintf(stderr,
728 "iso9660_load_inodes_dir: Removing duplicate entry for: %s (orig name: %s start: %d size: %d)\n",
729 in_node->inode.fn, tmp->inode.fn, in_node->offset, in_node->size);
730 free(in_node);
731 in_node = NULL;
732 count--;
733 break;
734 }
735 prev_tmp = tmp;
736 }
737
738 // add it to the end (if we didn't get rid of it above)
739 if (in_node) {
740 prev_tmp->next = in_node;
741 in_node->next = NULL;
742 }
743 }
744 else {
745 iso->in_list = in_node;
746 in_node->next = NULL;
747 }
748
749 // skip two entries if this was the root directory (the . and ..).
750 if ((i == 0) && (b_offs == 0) && (count == 1)) {
751 b_offs += dentry->entry_len;
752 dentry = (iso9660_dentry *) & buf[b_offs];
753 }
754 b_offs += dentry->entry_len;
755 }
756 s_offs += cnt1;
757 }
758 return count;
759 }
760
761
762 /**
763 * Process the path table for a joliet secondary volume descriptor
764 * and load all of the files pointed to it.
765 * The path table contains an entry for each directory. This code
766 * then locates each of the directories and processes the contents.
767 *
768 * @param fs File system to process
769 * @param svd Pointer to the secondary volume descriptor
770 * @param count Current count of inodes
771 * @returns updated count of inodes or -1 on error
772 */
773 static int
iso9660_load_inodes_pt_joliet(TSK_FS_INFO * fs,iso9660_svd * svd,int count,uint8_t is_first)774 iso9660_load_inodes_pt_joliet(TSK_FS_INFO * fs, iso9660_svd * svd,
775 int count, uint8_t is_first)
776 {
777 TSK_OFF_T pt_offs; /* offset of where we are in path table */
778 size_t pt_len; /* bytes left in path table */
779
780 // get the location of the path table
781 pt_offs =
782 (TSK_OFF_T) (tsk_getu32(fs->endian,
783 svd->pt_loc_m) * fs->block_size);
784 pt_len = tsk_getu32(fs->endian, svd->pt_size_m);
785
786 while (pt_len > 0) {
787 char utf16_buf[ISO9660_MAXNAMLEN_JOL + 1]; // UTF-16 name from img
788 char utf8buf[2 * ISO9660_MAXNAMLEN_JOL + 1]; // UTF-8 version of name
789 int readlen;
790 TSK_OFF_T extent; /* offset of extent for current directory */
791 path_table_rec dir;
792 int retVal;
793 ssize_t cnt;
794
795 UTF16 *name16;
796 UTF8 *name8;
797
798 // Read the path table entry
799 cnt = tsk_fs_read(fs, pt_offs, (char *) &dir, (int) sizeof(dir));
800 if (cnt != sizeof(dir)) {
801 if (cnt >= 0) {
802 tsk_error_reset();
803 tsk_error_set_errno(TSK_ERR_FS_READ);
804 }
805 tsk_error_set_errstr2("iso9660_load_inodes_pt");
806 return -1;
807 }
808 pt_len -= cnt;
809 pt_offs += (TSK_OFF_T) cnt;
810
811 readlen = dir.len_di;
812 if (dir.len_di > ISO9660_MAXNAMLEN_JOL)
813 readlen = ISO9660_MAXNAMLEN_JOL;
814
815 memset(utf16_buf, 0, ISO9660_MAXNAMLEN_JOL);
816 /* get UCS-2 filename for the entry */
817 cnt = tsk_fs_read(fs, pt_offs, (char *) utf16_buf, readlen);
818 if (cnt != dir.len_di) {
819 if (cnt >= 0) {
820 tsk_error_reset();
821 tsk_error_set_errno(TSK_ERR_FS_READ);
822 }
823 tsk_error_set_errstr2("iso_find_inodes");
824 return -1;
825 }
826 pt_len -= cnt;
827 pt_offs += (TSK_OFF_T) cnt;
828
829 // ISO stores UTF-16 in BE -- convert to local if we need to
830 if (fs->endian & TSK_LIT_ENDIAN) {
831 int i;
832 for (i = 0; i < cnt; i += 2) {
833 char t = utf16_buf[i];
834 utf16_buf[i] = utf16_buf[i + 1];
835 utf16_buf[i] = t;
836 }
837 }
838
839 name16 = (UTF16 *) utf16_buf;
840 name8 = (UTF8 *) utf8buf;
841
842 retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
843 (UTF16 *) ((uintptr_t) & utf16_buf[cnt + 1]), &name8,
844 (UTF8 *) ((uintptr_t) & utf8buf[2 * ISO9660_MAXNAMLEN_JOL]),
845 TSKlenientConversion);
846 if (retVal != TSKconversionOK) {
847 if (tsk_verbose)
848 tsk_fprintf(stderr,
849 "fsstat: Error converting Joliet name to UTF8: %d",
850 retVal);
851 utf8buf[0] = '\0';
852 }
853 *name8 = '\0';
854
855 /* padding byte is there if strlen(file name) is odd */
856 if (dir.len_di % 2) {
857 pt_len--;
858 pt_offs++;
859 }
860
861 extent =
862 (TSK_OFF_T) (tsk_getu32(fs->endian,
863 dir.ext_loc) * fs->block_size);
864
865 // process the directory contents
866 count =
867 iso9660_load_inodes_dir(fs, extent, count,
868 ISO9660_CTYPE_UTF16, utf8buf, is_first);
869
870 if (count == -1) {
871 return -1;
872 }
873 }
874 return count;
875 }
876
877 /**
878 * Proces the path table and the directories that are listed in it.
879 * The files in each directory will be stored in ISO_INFO.
880 *
881 * @param iso File system to analyze and store results in
882 * @returns -1 on error or count of inodes found.
883 */
884 static int
iso9660_load_inodes_pt(ISO_INFO * iso)885 iso9660_load_inodes_pt(ISO_INFO * iso)
886 {
887 TSK_FS_INFO *fs = (TSK_FS_INFO *) & iso->fs_info;
888 int count = 0;
889 iso9660_svd_node *s;
890 iso9660_pvd_node *p;
891 char fn[ISO9660_MAXNAMLEN_STD + 1]; /* store current directory name */
892 path_table_rec dir;
893 TSK_OFF_T pt_offs; /* offset of where we are in path table */
894 TSK_OFF_T extent; /* offset of extent for current directory */
895 ssize_t cnt;
896 uint8_t is_first = 1;
897
898 if (tsk_verbose)
899 tsk_fprintf(stderr, "iso9660_load_inodes_pt\n");
900
901 /* initialize in case repeatedly called */
902 iso9660_inode_list_free(fs);
903 iso->in_list = NULL;
904
905 /* The secondary volume descriptor table will contain the
906 * longer / unicode files, so we process it first to give them
907 * a higher priority */
908 for (s = iso->svd; s != NULL; s = s->next) {
909
910 /* Check if this is Joliet -- there are three possible signatures */
911 if ((s->svd.esc_seq[0] == 0x25) && (s->svd.esc_seq[1] == 0x2F) &&
912 ((s->svd.esc_seq[2] == 0x40) || (s->svd.esc_seq[2] == 0x43)
913 || (s->svd.esc_seq[2] == 0x45))) {
914 count =
915 iso9660_load_inodes_pt_joliet(fs, &(s->svd), count,
916 is_first);
917 if (count == -1) {
918 return -1;
919 }
920 is_first = 0;
921 }
922 }
923
924
925 /* Now look for unique files in the primary descriptors */
926 for (p = iso->pvd; p != NULL; p = p->next) {
927 size_t pt_len; /* bytes left in path table */
928
929 pt_offs =
930 (TSK_OFF_T) (tsk_getu32(fs->endian,
931 p->pvd.pt_loc_m) * fs->block_size);
932 pt_len = tsk_getu32(fs->endian, p->pvd.pt_size_m);
933
934 while (pt_len > 0) {
935 int readlen;
936
937 /* get next path table entry... */
938 cnt = tsk_fs_read(fs, pt_offs, (char *) &dir, sizeof(dir));
939 if (cnt != sizeof(dir)) {
940 if (cnt >= 0) {
941 tsk_error_reset();
942 tsk_error_set_errno(TSK_ERR_FS_READ);
943 }
944 tsk_error_set_errstr2("iso_find_inodes");
945 return -1;
946 }
947 pt_len -= cnt;
948 pt_offs += (TSK_OFF_T) cnt;
949
950 readlen = dir.len_di;
951 if (readlen > ISO9660_MAXNAMLEN_STD)
952 readlen = ISO9660_MAXNAMLEN_STD;
953
954 /* get directory name, this is the only chance */
955 cnt = tsk_fs_read(fs, pt_offs, fn, readlen);
956 if (cnt != readlen) {
957 if (cnt >= 0) {
958 tsk_error_reset();
959 tsk_error_set_errno(TSK_ERR_FS_READ);
960 }
961 tsk_error_set_errstr2("iso_find_inodes");
962 return -1;
963 }
964 fn[cnt] = '\0';
965
966 pt_len -= cnt;
967 pt_offs += (TSK_OFF_T) cnt;
968
969 /* padding byte is there if strlen(file name) is odd */
970 if (dir.len_di % 2) {
971 pt_len--;
972 pt_offs++;
973 }
974
975 extent =
976 (TSK_OFF_T) (tsk_getu32(fs->endian,
977 dir.ext_loc) * fs->block_size);
978
979 // process the directory contents
980 count =
981 iso9660_load_inodes_dir(fs, extent, count,
982 ISO9660_CTYPE_ASCII, fn, is_first);
983
984 if (count == -1) {
985 return -1;
986 }
987 }
988 }
989 return count;
990 }
991
992 /**
993 * Load the raw "inode" into the cached buffer (iso->dinode)
994 *
995 * dinode_load (for now) does not check for extended attribute records...
996 * my issue is I dont have an iso9660 image with extended attr recs, so I
997 * can't test/debug, etc
998 *
999 * @returns 1 if not found and 0 on succuss
1000 */
1001 uint8_t
iso9660_dinode_load(ISO_INFO * iso,TSK_INUM_T inum,iso9660_inode * dinode)1002 iso9660_dinode_load(ISO_INFO * iso, TSK_INUM_T inum,
1003 iso9660_inode * dinode)
1004 {
1005 iso9660_inode_node *n;
1006
1007 n = iso->in_list;
1008 while (n && (n->inum != inum))
1009 n = n->next;
1010
1011 if (n) {
1012 memcpy(dinode, &n->inode, sizeof(iso9660_inode));
1013 return 0;
1014 }
1015 else {
1016 return 1;
1017 }
1018 }
1019
1020
1021 static uint16_t
isomode2tskmode(uint16_t a_mode)1022 isomode2tskmode(uint16_t a_mode)
1023 {
1024 uint16_t mode = 0;
1025
1026 if (a_mode & ISO_EA_IRUSR)
1027 mode |= TSK_FS_META_MODE_IRUSR;
1028 if (a_mode & ISO_EA_IWUSR)
1029 mode |= TSK_FS_META_MODE_IWUSR;
1030 if (a_mode & ISO_EA_IXUSR)
1031 mode |= TSK_FS_META_MODE_IXUSR;
1032
1033 if (a_mode & ISO_EA_IRGRP)
1034 mode |= TSK_FS_META_MODE_IRGRP;
1035 if (a_mode & ISO_EA_IWGRP)
1036 mode |= TSK_FS_META_MODE_IWGRP;
1037 if (a_mode & ISO_EA_IXGRP)
1038 mode |= TSK_FS_META_MODE_IXGRP;
1039
1040 if (a_mode & ISO_EA_IROTH)
1041 mode |= TSK_FS_META_MODE_IROTH;
1042 if (a_mode & ISO_EA_IWOTH)
1043 mode |= TSK_FS_META_MODE_IWOTH;
1044 if (a_mode & ISO_EA_IXOTH)
1045 mode |= TSK_FS_META_MODE_IXOTH;
1046
1047 return mode;
1048 }
1049
1050 /**
1051 * Copies cached disk inode into generic structure.
1052 *
1053 * @returns 1 on error and 0 on success
1054 */
1055 static uint8_t
iso9660_dinode_copy(ISO_INFO * iso,TSK_FS_META * fs_meta,TSK_INUM_T inum,iso9660_inode * dinode)1056 iso9660_dinode_copy(ISO_INFO * iso, TSK_FS_META * fs_meta, TSK_INUM_T inum,
1057 iso9660_inode * dinode)
1058 {
1059 TSK_FS_INFO *fs = (TSK_FS_INFO *) & iso->fs_info;
1060 struct tm t;
1061
1062 if (fs_meta == NULL) {
1063 tsk_error_set_errno(TSK_ERR_FS_ARG);
1064 tsk_error_set_errstr
1065 ("iso9660_dinode_copy: fs_file or meta is NULL");
1066 return 1;
1067 }
1068
1069 fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY;
1070 if (fs_meta->attr) {
1071 tsk_fs_attrlist_markunused(fs_meta->attr);
1072 }
1073
1074 if (fs_meta->content_len < ISO9660_FILE_CONTENT_LEN) {
1075 if ((fs_meta =
1076 tsk_fs_meta_realloc(fs_meta,
1077 ISO9660_FILE_CONTENT_LEN)) == NULL) {
1078 return 1;
1079 }
1080 }
1081
1082 fs_meta->addr = inum;
1083 fs_meta->size = tsk_getu32(fs->endian, dinode->dr.data_len_m);
1084
1085 memset(&t, 0, sizeof(struct tm));
1086 t.tm_sec = dinode->dr.rec_time.sec;
1087 t.tm_min = dinode->dr.rec_time.min;
1088 t.tm_hour = dinode->dr.rec_time.hour;
1089 t.tm_mday = dinode->dr.rec_time.day;
1090 t.tm_mon = dinode->dr.rec_time.month - 1;
1091 t.tm_year = dinode->dr.rec_time.year;
1092 //gmt_hrdiff = iso->dinode->dr.rec_time.gmt_off * 15 / 60;
1093
1094 fs_meta->crtime = mktime(&t);
1095 fs_meta->mtime = fs_meta->atime = fs_meta->ctime = 0;
1096 fs_meta->crtime_nano = fs_meta->mtime_nano = fs_meta->atime_nano =
1097 fs_meta->ctime_nano = 0;
1098
1099 if (dinode->dr.flags & ISO9660_FLAG_DIR)
1100 fs_meta->type = TSK_FS_META_TYPE_DIR;
1101 else
1102 fs_meta->type = TSK_FS_META_TYPE_REG;
1103
1104 if (dinode->ea) {
1105 fs_meta->uid = tsk_getu32(fs->endian, dinode->ea->uid);
1106 fs_meta->gid = tsk_getu32(fs->endian, dinode->ea->gid);
1107 fs_meta->mode =
1108 isomode2tskmode(tsk_getu16(fs->endian, dinode->ea->mode));
1109 fs_meta->nlink = 1;
1110 }
1111 else {
1112 fs_meta->uid = 0;
1113 fs_meta->gid = 0;
1114 fs_meta->mode = 0;
1115 fs_meta->nlink = 1;
1116 }
1117
1118 ((TSK_DADDR_T *) fs_meta->content_ptr)[0] =
1119 (TSK_DADDR_T) tsk_getu32(fs->endian, dinode->dr.ext_loc_m);
1120
1121 // mark files that were found from other volume descriptors as unalloc so that they
1122 // come up as orphan files.
1123 if (dinode->is_orphan)
1124 fs_meta->flags = TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED;
1125 else
1126 fs_meta->flags = TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_USED;
1127 return 0;
1128 }
1129
1130 static void
iso9660_close(TSK_FS_INFO * fs)1131 iso9660_close(TSK_FS_INFO * fs)
1132 {
1133 ISO_INFO *iso = (ISO_INFO *) fs;
1134
1135 fs->tag = 0;
1136
1137 while (iso->pvd != NULL) {
1138 iso9660_pvd_node *p = iso->pvd;
1139 iso->pvd = iso->pvd->next;
1140 free(p);
1141 }
1142
1143 while (iso->svd != NULL) {
1144 iso9660_svd_node *s = iso->svd;
1145 iso->svd = iso->svd->next;
1146 free(s);
1147 }
1148
1149 while (iso->in_list != NULL) {
1150 iso9660_inode_node *in = iso->in_list;
1151 iso->in_list = iso->in_list->next;
1152 if (in->inode.rr != NULL) {
1153 free(in->inode.rr);
1154 }
1155 free(in);
1156 }
1157
1158 tsk_fs_free(fs);
1159 }
1160
1161
1162 static uint8_t
iso9660_inode_lookup(TSK_FS_INFO * fs,TSK_FS_FILE * a_fs_file,TSK_INUM_T inum)1163 iso9660_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
1164 TSK_INUM_T inum)
1165 {
1166 ISO_INFO *iso = (ISO_INFO *) fs;
1167 iso9660_inode *dinode;
1168
1169 if (tsk_verbose)
1170 tsk_fprintf(stderr, "iso9660_inode_lookup: iso:"
1171 " inum: %" PRIuINUM "\n", inum);
1172
1173 if (a_fs_file == NULL) {
1174 tsk_error_set_errno(TSK_ERR_FS_ARG);
1175 tsk_error_set_errstr("iso9660_inode_lookup: fs_file is NULL");
1176 return 1;
1177 }
1178
1179 if (a_fs_file->meta == NULL) {
1180 if ((a_fs_file->meta =
1181 tsk_fs_meta_alloc(ISO9660_FILE_CONTENT_LEN)) == NULL)
1182 return 1;
1183 }
1184 else {
1185 tsk_fs_meta_reset(a_fs_file->meta);
1186 }
1187
1188 // see if they are looking for the special "orphans" directory
1189 if (inum == TSK_FS_ORPHANDIR_INUM(fs)) {
1190 if (tsk_fs_dir_make_orphan_dir_meta(fs, a_fs_file->meta)) {
1191 return 1;
1192 }
1193 else {
1194 return 0;
1195 }
1196 }
1197 else {
1198 /* allocate cache buffers */
1199 /* dinode */
1200 dinode = (iso9660_inode *) tsk_malloc(sizeof(iso9660_inode));
1201 if (dinode == NULL) {
1202 fs->tag = 0;
1203 iso9660_close(fs);
1204 return 1;
1205 }
1206
1207 // load the inode into the ISO buffer
1208 if (iso9660_dinode_load(iso, inum, dinode)) {
1209 free(dinode);
1210 return 1;
1211 }
1212
1213 // copy into the FS_META structure
1214 if (iso9660_dinode_copy(iso, a_fs_file->meta, inum, dinode)) {
1215 free(dinode);
1216 return 1;
1217 }
1218 }
1219
1220 free(dinode);
1221 return 0;
1222 }
1223
1224 static uint8_t
iso9660_inode_walk(TSK_FS_INFO * fs,TSK_INUM_T start,TSK_INUM_T last,TSK_FS_META_FLAG_ENUM flags,TSK_FS_META_WALK_CB action,void * ptr)1225 iso9660_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start, TSK_INUM_T last,
1226 TSK_FS_META_FLAG_ENUM flags, TSK_FS_META_WALK_CB action, void *ptr)
1227 {
1228 char *myname = "iso9660_inode_walk";
1229 ISO_INFO *iso = (ISO_INFO *) fs;
1230 TSK_INUM_T inum, end_inum_tmp;
1231 TSK_FS_FILE *fs_file;
1232 unsigned int myflags;
1233 iso9660_inode *dinode;
1234
1235 // clean up any error messages that are lying around
1236 tsk_error_reset();
1237
1238 if (tsk_verbose)
1239 tsk_fprintf(stderr, "iso9660_inode_walk: "
1240 " start: %" PRIuINUM " last: %" PRIuINUM " flags: %d"
1241 " action: %" PRIu64 " ptr: %" PRIu64 "\n",
1242 start, last, flags, (uint64_t) action, (uint64_t) ptr);
1243
1244 myflags = TSK_FS_META_FLAG_ALLOC;
1245
1246 /*
1247 * Sanity checks.
1248 */
1249 if (start < fs->first_inum || start > fs->last_inum) {
1250 tsk_error_reset();
1251 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1252 tsk_error_set_errstr("%s: Start inode: %" PRIuINUM "", myname,
1253 start);
1254 return 1;
1255 }
1256 if (last < fs->first_inum || last > fs->last_inum || last < start) {
1257 tsk_error_reset();
1258 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1259 tsk_error_set_errstr("%s: End inode: %" PRIuINUM "", myname, last);
1260 return 1;
1261 }
1262
1263 /* If ORPHAN is wanted, then make sure that the flags are correct */
1264 if (flags & TSK_FS_META_FLAG_ORPHAN) {
1265 flags |= TSK_FS_META_FLAG_UNALLOC;
1266 flags &= ~TSK_FS_META_FLAG_ALLOC;
1267 flags |= TSK_FS_META_FLAG_USED;
1268 flags &= ~TSK_FS_META_FLAG_UNUSED;
1269 }
1270 else if (((flags & TSK_FS_META_FLAG_ALLOC) == 0) &&
1271 ((flags & TSK_FS_META_FLAG_UNALLOC) == 0)) {
1272 flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC);
1273 }
1274
1275 /* If neither of the USED or UNUSED flags are set, then set them
1276 * both
1277 */
1278 if (((flags & TSK_FS_META_FLAG_USED) == 0) &&
1279 ((flags & TSK_FS_META_FLAG_UNUSED) == 0)) {
1280 flags |= (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_UNUSED);
1281 }
1282
1283 /* If we are looking for orphan files and have not yet filled
1284 * in the list of unalloc inodes that are pointed to, then fill
1285 * in the list
1286 * */
1287 if ((flags & TSK_FS_META_FLAG_ORPHAN)) {
1288 if (tsk_fs_dir_load_inum_named(fs) != TSK_OK) {
1289 tsk_error_errstr2_concat
1290 ("- iso9660_inode_walk: identifying inodes allocated by file names");
1291 return 1;
1292 }
1293 }
1294
1295
1296 if ((fs_file = tsk_fs_file_alloc(fs)) == NULL)
1297 return 1;
1298
1299 if ((fs_file->meta =
1300 tsk_fs_meta_alloc(ISO9660_FILE_CONTENT_LEN)) == NULL)
1301 return 1;
1302
1303 // we need to handle fs->last_inum specially because it is for the
1304 // virtual ORPHANS directory. Handle it outside of the loop.
1305 if (last == TSK_FS_ORPHANDIR_INUM(fs))
1306 end_inum_tmp = last - 1;
1307 else
1308 end_inum_tmp = last;
1309
1310 /* allocate cache buffers */
1311 /* dinode */
1312 dinode = (iso9660_inode *) tsk_malloc(sizeof(iso9660_inode));
1313 if (dinode == NULL) {
1314 fs->tag = 0;
1315 iso9660_close(fs);
1316 return 1;
1317 }
1318 /*
1319 * Iterate.
1320 */
1321 for (inum = start; inum <= end_inum_tmp; inum++) {
1322 int retval;
1323 if (iso9660_dinode_load(iso, inum, dinode)) {
1324 tsk_fs_file_close(fs_file);
1325 free(dinode);
1326 return 1;
1327 }
1328
1329 if (iso9660_dinode_copy(iso, fs_file->meta, inum, dinode)) {
1330 free(dinode);
1331 return 1;
1332 }
1333 myflags = fs_file->meta->flags;
1334
1335 if ((flags & myflags) != myflags)
1336 continue;
1337
1338 /* If we want only orphans, then check if this
1339 * inode is in the seen list
1340 * */
1341 if ((myflags & TSK_FS_META_FLAG_UNALLOC) &&
1342 (flags & TSK_FS_META_FLAG_ORPHAN) &&
1343 (tsk_fs_dir_find_inum_named(fs, inum))) {
1344 continue;
1345 }
1346
1347 retval = action(fs_file, ptr);
1348 if (retval == TSK_WALK_ERROR) {
1349 tsk_fs_file_close(fs_file);
1350 free(dinode);
1351 return 1;
1352 }
1353 else if (retval == TSK_WALK_STOP) {
1354 break;
1355 }
1356 }
1357
1358 // handle the virtual orphans folder if they asked for it
1359 if ((last == TSK_FS_ORPHANDIR_INUM(fs))
1360 && (flags & TSK_FS_META_FLAG_ALLOC)
1361 && (flags & TSK_FS_META_FLAG_USED)) {
1362 int retval;
1363
1364 if (tsk_fs_dir_make_orphan_dir_meta(fs, fs_file->meta)) {
1365 tsk_fs_file_close(fs_file);
1366 free(dinode);
1367 return 1;
1368 }
1369 /* call action */
1370 retval = action(fs_file, ptr);
1371 if (retval == TSK_WALK_STOP) {
1372 tsk_fs_file_close(fs_file);
1373 free(dinode);
1374 return 0;
1375 }
1376 else if (retval == TSK_WALK_ERROR) {
1377 tsk_fs_file_close(fs_file);
1378 free(dinode);
1379 return 1;
1380 }
1381 }
1382
1383
1384 /*
1385 * Cleanup.
1386 */
1387 tsk_fs_file_close(fs_file);
1388 free(dinode);
1389 return 0;
1390 }
1391
1392 // @@@ Doesn' this seem to ignore interleave?
1393 /* return 1 if block is allocated in a file's extent, return 0 otherwise */
1394 static int
iso9660_is_block_alloc(TSK_FS_INFO * fs,TSK_DADDR_T blk_num)1395 iso9660_is_block_alloc(TSK_FS_INFO * fs, TSK_DADDR_T blk_num)
1396 {
1397 ISO_INFO *iso = (ISO_INFO *) fs;
1398 iso9660_inode_node *in_node;
1399
1400 if (tsk_verbose)
1401 tsk_fprintf(stderr, "iso9660_is_block_alloc: "
1402 " blk_num: %" PRIuDADDR "\n", blk_num);
1403
1404 for (in_node = iso->in_list; in_node; in_node = in_node->next) {
1405 TSK_DADDR_T first_block = in_node->offset / fs->block_size;
1406 TSK_DADDR_T file_size =
1407 tsk_getu32(fs->endian, in_node->inode.dr.data_len_m);
1408 TSK_DADDR_T last_block =
1409 first_block + (file_size / fs->block_size);
1410 if (file_size % fs->block_size)
1411 last_block++;
1412
1413 if ((blk_num >= first_block) && (blk_num <= last_block))
1414 return 1;
1415 }
1416
1417 return 0;
1418 }
1419
1420
1421 static TSK_FS_BLOCK_FLAG_ENUM
iso9660_block_getflags(TSK_FS_INFO * a_fs,TSK_DADDR_T a_addr)1422 iso9660_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr)
1423 {
1424 return (iso9660_is_block_alloc(a_fs, a_addr)) ?
1425 TSK_FS_BLOCK_FLAG_ALLOC : TSK_FS_BLOCK_FLAG_UNALLOC;
1426 }
1427
1428
1429 /* flags: TSK_FS_BLOCK_FLAG_ALLOC and FS_FLAG_UNALLOC
1430 * ISO9660 has a LOT of very sparse meta, so in this function a block is only
1431 * checked to see if it is part of an inode's extent
1432 */
1433 static uint8_t
iso9660_block_walk(TSK_FS_INFO * fs,TSK_DADDR_T start,TSK_DADDR_T last,TSK_FS_BLOCK_WALK_FLAG_ENUM flags,TSK_FS_BLOCK_WALK_CB action,void * ptr)1434 iso9660_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T start, TSK_DADDR_T last,
1435 TSK_FS_BLOCK_WALK_FLAG_ENUM flags, TSK_FS_BLOCK_WALK_CB action,
1436 void *ptr)
1437 {
1438 char *myname = "iso9660_block_walk";
1439 TSK_DADDR_T addr;
1440 TSK_FS_BLOCK *fs_block;
1441
1442 // clean up any error messages that are lying around
1443 tsk_error_reset();
1444
1445 if (tsk_verbose)
1446 tsk_fprintf(stderr, "iso9660_block_walk: "
1447 " start: %" PRIuDADDR " last: %" PRIuDADDR " flags: %d"
1448 " action: %" PRIu64 " ptr: %" PRIu64 "\n",
1449 start, last, flags, (uint64_t) action, (uint64_t) ptr);
1450
1451 /*
1452 * Sanity checks.
1453 */
1454 if (start < fs->first_block || start > fs->last_block) {
1455 tsk_error_reset();
1456 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1457 tsk_error_set_errstr("%s: Start block: %" PRIuDADDR "", myname,
1458 start);
1459 return 1;
1460 }
1461 if (last < fs->first_block || last > fs->last_block) {
1462 tsk_error_reset();
1463 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1464 tsk_error_set_errstr("%s: End block: %" PRIuDADDR "", myname,
1465 last);
1466 return 1;
1467 }
1468
1469 /* Sanity check on flags -- make sure at least one ALLOC is set */
1470 if (((flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) &&
1471 ((flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) {
1472 flags |=
1473 (TSK_FS_BLOCK_WALK_FLAG_ALLOC |
1474 TSK_FS_BLOCK_WALK_FLAG_UNALLOC);
1475 }
1476 if (((flags & TSK_FS_BLOCK_WALK_FLAG_META) == 0) &&
1477 ((flags & TSK_FS_BLOCK_WALK_FLAG_CONT) == 0)) {
1478 flags |=
1479 (TSK_FS_BLOCK_WALK_FLAG_CONT | TSK_FS_BLOCK_WALK_FLAG_META);
1480 }
1481
1482 if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) {
1483 return 1;
1484 }
1485
1486 if (tsk_verbose)
1487 tsk_fprintf(stderr,
1488 "isofs_block_walk: Block Walking %" PRIuDADDR " to %" PRIuDADDR
1489 "\n", start, last);
1490
1491 /* cycle through block addresses */
1492 for (addr = start; addr <= last; addr++) {
1493 int retval;
1494 int myflags = iso9660_block_getflags(fs, addr);
1495
1496 // test if we should call the callback with this one
1497 if ((myflags & TSK_FS_BLOCK_FLAG_ALLOC)
1498 && (!(flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC)))
1499 continue;
1500 else if ((myflags & TSK_FS_BLOCK_FLAG_UNALLOC)
1501 && (!(flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC)))
1502 continue;
1503
1504 if (flags & TSK_FS_BLOCK_WALK_FLAG_AONLY)
1505 myflags |= TSK_FS_BLOCK_FLAG_AONLY;
1506
1507 if (tsk_fs_block_get_flag(fs, fs_block, addr, myflags) == NULL) {
1508 tsk_error_set_errstr2("iso_block_walk");
1509 tsk_fs_block_free(fs_block);
1510 return 1;
1511 }
1512
1513 retval = action(fs_block, ptr);
1514 if (retval == TSK_WALK_ERROR) {
1515 tsk_fs_block_free(fs_block);
1516 return 1;
1517 }
1518 else if (retval == TSK_WALK_STOP) {
1519 break;
1520 }
1521 }
1522
1523 tsk_fs_block_free(fs_block);
1524 return 0;
1525 }
1526
1527
1528
1529 static uint8_t
iso9660_make_data_run(TSK_FS_FILE * a_fs_file)1530 iso9660_make_data_run(TSK_FS_FILE * a_fs_file)
1531 {
1532 ISO_INFO *iso;
1533 iso9660_dentry dd;
1534 TSK_FS_INFO *fs = NULL;
1535 TSK_FS_ATTR *fs_attr = NULL;
1536 TSK_FS_ATTR_RUN *data_run = NULL;
1537 iso9660_inode *dinode;
1538
1539 // clean up any error messages that are lying around
1540 tsk_error_reset();
1541
1542 if ((a_fs_file == NULL) || (a_fs_file->meta == NULL)
1543 || (a_fs_file->fs_info == NULL)) {
1544 tsk_error_set_errno(TSK_ERR_FS_ARG);
1545 tsk_error_set_errstr
1546 ("iso9660_make_data_run: fs_file or meta is NULL");
1547 return 1;
1548 }
1549 fs = a_fs_file->fs_info;
1550 iso = (ISO_INFO *) fs;
1551
1552 // see if we have already loaded the runs
1553 if ((a_fs_file->meta->attr != NULL)
1554 && (a_fs_file->meta->attr_state == TSK_FS_META_ATTR_STUDIED)) {
1555 return 0;
1556 }
1557 else if (a_fs_file->meta->attr_state == TSK_FS_META_ATTR_ERROR) {
1558 return 1;
1559 }
1560
1561 // not sure why this would ever happen, but...
1562 if (a_fs_file->meta->attr != NULL) {
1563 tsk_fs_attrlist_markunused(a_fs_file->meta->attr);
1564 }
1565 else {
1566 a_fs_file->meta->attr = tsk_fs_attrlist_alloc();
1567 }
1568
1569 /* allocate cache buffers */
1570 /* dinode */
1571 if ((dinode =
1572 (iso9660_inode *) tsk_malloc(sizeof(iso9660_inode))) == NULL) {
1573 fs->tag = 0;
1574 iso9660_close(fs);
1575 return 1;
1576 }
1577
1578 // copy the raw data
1579 if (iso9660_dinode_load(iso, a_fs_file->meta->addr, dinode)) {
1580 tsk_error_set_errstr2("iso9660_make_data_run");
1581 a_fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
1582 free(dinode);
1583 return 1;
1584 }
1585 memcpy(&dd, &dinode->dr, sizeof(iso9660_dentry));
1586 free(dinode);
1587 dinode = NULL;
1588
1589 if (dd.gap_sz) {
1590 a_fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
1591 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
1592 tsk_error_set_errstr("file %" PRIuINUM
1593 " has an interleave gap -- not supported",
1594 a_fs_file->meta->addr);
1595 return 1;
1596 }
1597
1598 if ((fs_attr =
1599 tsk_fs_attrlist_getnew(a_fs_file->meta->attr,
1600 TSK_FS_ATTR_NONRES)) == NULL) {
1601 return 1;
1602 }
1603
1604 // make a non-resident run
1605 data_run = tsk_fs_attr_run_alloc();
1606 if (data_run == NULL) {
1607 return -1;
1608 }
1609 data_run->addr = ((TSK_DADDR_T *) a_fs_file->meta->content_ptr)[0];
1610 data_run->len =
1611 (a_fs_file->meta->size + fs->block_size - 1) / fs->block_size;
1612 data_run->offset = 0;
1613
1614 // initialize the data run
1615 if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run, NULL,
1616 TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
1617 a_fs_file->meta->size, a_fs_file->meta->size,
1618 roundup(a_fs_file->meta->size + dd.ext_len,
1619 fs->block_size) - dd.ext_len, 0, 0)) {
1620 return 1;
1621 }
1622
1623 // the first bytes in the run could be allocated for the extended attribute.
1624 fs_attr->nrd.skiplen = dd.ext_len;
1625
1626 a_fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
1627
1628 return 0;
1629 }
1630
1631
1632
1633 static uint8_t
iso9660_fscheck(TSK_FS_INFO * fs,FILE * hFile)1634 iso9660_fscheck(TSK_FS_INFO * fs, FILE * hFile)
1635 {
1636 tsk_error_reset();
1637 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
1638 tsk_error_set_errstr("fscheck not implemented for iso9660 yet");
1639 return 1;
1640 }
1641
1642 /**
1643 * Print details about the file system to a file handle.
1644 *
1645 * @param fs File system to print details on
1646 * @param hFile File handle to print text to
1647 *
1648 * @returns 1 on error and 0 on success
1649 */
1650 static uint8_t
iso9660_fsstat(TSK_FS_INFO * fs,FILE * hFile)1651 iso9660_fsstat(TSK_FS_INFO * fs, FILE * hFile)
1652 {
1653 char str[129]; /* store name of publisher/preparer/etc */
1654 ISO_INFO *iso = (ISO_INFO *) fs;
1655 char *cp;
1656 int i;
1657
1658 iso9660_pvd_node *p = iso->pvd;
1659 iso9660_svd_node *s;
1660
1661 // clean up any error messages that are lying around
1662 tsk_error_reset();
1663
1664 if (tsk_verbose)
1665 tsk_fprintf(stderr, "iso9660_fsstat:\n");
1666
1667 i = 0;
1668
1669 for (p = iso->pvd; p != NULL; p = p->next) {
1670 i++;
1671 tsk_fprintf(hFile, "\n=== PRIMARY VOLUME DESCRIPTOR %d ===\n", i);
1672 tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n");
1673 tsk_fprintf(hFile,
1674 "--------------------------------------------\n");
1675 tsk_fprintf(hFile, "File System Type: ISO9660\n");
1676 tsk_fprintf(hFile, "Volume Name: %s\n", p->pvd.vol_id);
1677 tsk_fprintf(hFile, "Volume Set Size: %d\n",
1678 tsk_getu16(fs->endian, p->pvd.vol_set_m));
1679 tsk_fprintf(hFile, "Volume Set Sequence: %d\n",
1680 tsk_getu16(fs->endian, p->pvd.vol_seq_m));
1681
1682 /* print publisher */
1683 if (p->pvd.pub_id[0] == 0x5f)
1684 /* publisher is in a file. TODO: handle this properly */
1685 snprintf(str, 8, "In file\n");
1686 else
1687 snprintf(str, 128, "%s", p->pvd.pub_id);
1688
1689 cp = &str[127];
1690 /* find last printable non space character */
1691 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1692 cp--;
1693 *++cp = '\0';
1694 tsk_fprintf(hFile, "Publisher: %s\n", str);
1695 memset(str, ' ', 128);
1696
1697
1698 /* print data preparer */
1699 if (p->pvd.prep_id[0] == 0x5f)
1700 /* preparer is in a file. TODO: handle this properly */
1701 snprintf(str, 8, "In file\n");
1702 else
1703 snprintf(str, 128, "%s", p->pvd.prep_id);
1704
1705 cp = &str[127];
1706 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1707 cp--;
1708 *++cp = '\0';
1709 tsk_fprintf(hFile, "Data Preparer: %s\n", str);
1710 memset(str, ' ', 128);
1711
1712
1713 /* print recording application */
1714 if (p->pvd.app_id[0] == 0x5f)
1715 /* application is in a file. TODO: handle this properly */
1716 snprintf(str, 8, "In file\n");
1717 else
1718 snprintf(str, 128, "%s", p->pvd.app_id);
1719 cp = &str[127];
1720 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1721 cp--;
1722 *++cp = '\0';
1723 tsk_fprintf(hFile, "Recording Application: %s\n", str);
1724 memset(str, ' ', 128);
1725
1726
1727 /* print copyright */
1728 if (p->pvd.copy_id[0] == 0x5f)
1729 /* copyright is in a file. TODO: handle this properly */
1730 snprintf(str, 8, "In file\n");
1731 else
1732 snprintf(str, 37, "%s", p->pvd.copy_id);
1733 cp = &str[36];
1734 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1735 cp--;
1736 *++cp = '\0';
1737 tsk_fprintf(hFile, "Copyright: %s\n", str);
1738 memset(str, ' ', 37);
1739
1740 tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
1741 tsk_fprintf(hFile,
1742 "--------------------------------------------\n");
1743 tsk_fprintf(hFile,
1744 "Path Table Location: %" PRIu32 "-%" PRIu32 "\n",
1745 tsk_getu32(fs->endian, p->pvd.pt_loc_m), tsk_getu32(fs->endian,
1746 p->pvd.pt_loc_m) + tsk_getu32(fs->endian,
1747 p->pvd.pt_size_m) / fs->block_size);
1748
1749 tsk_fprintf(hFile, "Inode Range: %" PRIuINUM " - %" PRIuINUM "\n",
1750 fs->first_inum, fs->last_inum);
1751 tsk_fprintf(hFile, "Root Directory Block: %" PRIuDADDR "\n",
1752 tsk_getu32(fs->endian, p->pvd.dir_rec.ext_loc_m));
1753
1754 tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
1755 tsk_fprintf(hFile,
1756 "--------------------------------------------\n");
1757 tsk_fprintf(hFile, "Sector Size: %d\n", ISO9660_SSIZE_B);
1758 tsk_fprintf(hFile, "Block Size: %d\n", tsk_getu16(fs->endian,
1759 p->pvd.blk_sz_m));
1760 if (fs->block_pre_size) {
1761 tsk_fprintf(hFile, "Raw CD pre-block size: %d\n",
1762 fs->block_pre_size);
1763 tsk_fprintf(hFile, "Raw CD post-block size: %d\n",
1764 fs->block_post_size);
1765 }
1766
1767 tsk_fprintf(hFile, "Total Sector Range: 0 - %d\n",
1768 (int) ((fs->block_size / ISO9660_SSIZE_B) *
1769 (fs->block_count - 1)));
1770 /* get image slack, ignore how big the image claims itself to be */
1771 tsk_fprintf(hFile, "Total Block Range: 0 - %d\n",
1772 (int) fs->block_count - 1);
1773 }
1774
1775 i = 0;
1776
1777 for (s = iso->svd; s != NULL; s = s->next) {
1778 i++;
1779 tsk_fprintf(hFile,
1780 "\n=== SUPPLEMENTARY VOLUME DESCRIPTOR %d ===\n", i);
1781 tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n");
1782 tsk_fprintf(hFile,
1783 "--------------------------------------------\n");
1784 tsk_fprintf(hFile, "File System Type: ISO9660\n");
1785 tsk_fprintf(hFile, "Volume Name: %s\n", s->svd.vol_id);
1786 tsk_fprintf(hFile, "Volume Set Size: %d\n",
1787 tsk_getu16(fs->endian, s->svd.vol_set_m));
1788 tsk_fprintf(hFile, "Volume Set Sequence: %d\n",
1789 tsk_getu16(fs->endian, s->svd.vol_seq_m));
1790
1791
1792
1793 /* print publisher */
1794 if (s->svd.pub_id[0] == 0x5f)
1795 /* publisher is in a file. TODO: handle this properly */
1796 snprintf(str, 8, "In file\n");
1797 else
1798 snprintf(str, 128, "%s", s->svd.pub_id);
1799
1800 cp = &str[127];
1801 /* find last printable non space character */
1802 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1803 cp--;
1804 *++cp = '\0';
1805 tsk_fprintf(hFile, "Publisher: %s\n", str);
1806 memset(str, ' ', 128);
1807
1808
1809 /* print data preparer */
1810 if (s->svd.prep_id[0] == 0x5f)
1811 /* preparer is in a file. TODO: handle this properly */
1812 snprintf(str, 8, "In file\n");
1813 else
1814 snprintf(str, 128, "%s", s->svd.prep_id);
1815
1816 cp = &str[127];
1817 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1818 cp--;
1819 *++cp = '\0';
1820 tsk_fprintf(hFile, "Data Preparer: %s\n", str);
1821 memset(str, ' ', 128);
1822
1823
1824 /* print recording application */
1825 if (s->svd.app_id[0] == 0x5f)
1826 /* application is in a file. TODO: handle this properly */
1827 snprintf(str, 8, "In file\n");
1828 else
1829 snprintf(str, 128, "%s", s->svd.app_id);
1830 cp = &str[127];
1831 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1832 cp--;
1833 *++cp = '\0';
1834 tsk_fprintf(hFile, "Recording Application: %s\n", str);
1835 memset(str, ' ', 128);
1836
1837
1838 /* print copyright */
1839 if (s->svd.copy_id[0] == 0x5f)
1840 /* copyright is in a file. TODO: handle this properly */
1841 snprintf(str, 8, "In file\n");
1842 else
1843 snprintf(str, 37, "%s\n", s->svd.copy_id);
1844 cp = &str[36];
1845 while ((!isprint(*cp) || isspace(*cp)) && (cp != str))
1846 cp--;
1847 *++cp = '\0';
1848 tsk_fprintf(hFile, "Copyright: %s\n", str);
1849 memset(str, ' ', 37);
1850
1851 tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
1852 tsk_fprintf(hFile,
1853 "--------------------------------------------\n");
1854 tsk_fprintf(hFile,
1855 "Path Table Location: %" PRIu32 "-%" PRIu32 "\n",
1856 tsk_getu32(fs->endian, s->svd.pt_loc_m), tsk_getu32(fs->endian,
1857 s->svd.pt_loc_m) + tsk_getu32(fs->endian,
1858 s->svd.pt_size_m) / fs->block_size);
1859
1860 tsk_fprintf(hFile, "Root Directory Block: %" PRIuDADDR "\n",
1861 tsk_getu32(fs->endian, s->svd.dir_rec.ext_loc_m));
1862
1863 /* learn joliet level (1-3) */
1864 if (!strncmp((char *) s->svd.esc_seq, "%/E", 3))
1865 tsk_fprintf(hFile, "Joliet Name Encoding: UCS-2 Level 3\n");
1866 if (!strncmp((char *) s->svd.esc_seq, "%/C", 3))
1867 tsk_fprintf(hFile, "Joliet Name Encoding: UCS-2 Level 2\n");
1868 if (!strncmp((char *) s->svd.esc_seq, "%/@", 3))
1869 tsk_fprintf(hFile, "Joliet Name Encoding: UCS-2 Level 1\n");
1870 if (iso->rr_found)
1871 tsk_fprintf(hFile, "RockRidge Extensions present\n");
1872
1873
1874 tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
1875 tsk_fprintf(hFile,
1876 "--------------------------------------------\n");
1877 tsk_fprintf(hFile, "Sector Size: %d\n", ISO9660_SSIZE_B);
1878 tsk_fprintf(hFile, "Block Size: %d\n", fs->block_size);
1879
1880 tsk_fprintf(hFile, "Total Sector Range: 0 - %d\n",
1881 (int) ((fs->block_size / ISO9660_SSIZE_B) *
1882 (fs->block_count - 1)));
1883 /* get image slack, ignore how big the image claims itself to be */
1884 tsk_fprintf(hFile, "Total Block Range: 0 - %d\n",
1885 (int) fs->block_count - 1);
1886 }
1887
1888 return 0;
1889 }
1890
1891
1892 /**
1893 * Make a unix-style permissions string based the flags in dentry and
1894 * the cached inode in fs, storing results in perm. Caller must
1895 * ensure perm can hold 10 chars plus one null char.
1896 */
1897 static char *
make_unix_perm(TSK_FS_INFO * fs,iso9660_dentry * dd,iso9660_inode * dinode,char * perm)1898 make_unix_perm(TSK_FS_INFO * fs, iso9660_dentry * dd,
1899 iso9660_inode * dinode, char *perm)
1900 {
1901 if (tsk_verbose)
1902 tsk_fprintf(stderr, "make_unix_perm: fs: %" PRIu64
1903 " dd: %" PRIu64 "\n", (uint64_t) fs, (uint64_t) dd);
1904
1905 memset(perm, '-', 10);
1906 perm[10] = '\0';
1907
1908 if (dd->flags & ISO9660_FLAG_DIR)
1909 perm[0] = 'd';
1910
1911 if (dinode->ea) {
1912 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_UR)
1913 perm[1] = 'r';
1914
1915 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_UX)
1916 perm[3] = 'x';
1917
1918 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_GR)
1919 perm[4] = 'r';
1920
1921 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_GX)
1922 perm[6] = 'x';
1923
1924 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_AR)
1925 perm[7] = 'r';
1926
1927 if (tsk_getu16(fs->endian, dinode->ea->mode) & ISO9660_BIT_AX)
1928 perm[9] = 'x';
1929 }
1930 else {
1931 strcpy(&perm[1], "r-xr-xr-x");
1932 }
1933
1934 return perm;
1935 }
1936
1937 #if 0
1938 static void
1939 iso9660_print_rockridge(FILE * hFile, rockridge_ext * rr)
1940 {
1941 char mode_buf[11];
1942
1943 tsk_fprintf(hFile, "\nROCKRIDGE EXTENSIONS\n");
1944
1945 tsk_fprintf(hFile, "Owner-ID: ");
1946 tsk_fprintf(hFile, "%d\t", (int) rr->uid);
1947
1948 tsk_fprintf(hFile, "Group-ID: ");
1949 tsk_fprintf(hFile, "%d\n", (int) rr->gid);
1950
1951 tsk_fprintf(hFile, "Mode: ");
1952 memset(mode_buf, '-', 11);
1953 mode_buf[10] = '\0';
1954
1955 /* file type */
1956 /* note: socket and symbolic link are multi bit fields */
1957 if ((rr->mode & MODE_IFSOCK) == MODE_IFSOCK)
1958 mode_buf[0] = 's';
1959 else if ((rr->mode & MODE_IFLNK) == MODE_IFLNK)
1960 mode_buf[0] = 'l';
1961 else if (rr->mode & MODE_IFDIR)
1962 mode_buf[0] = 'd';
1963 else if (rr->mode & MODE_IFIFO)
1964 mode_buf[0] = 'p';
1965 else if (rr->mode & MODE_IFBLK)
1966 mode_buf[0] = 'b';
1967 else if (rr->mode & MODE_IFCHR)
1968 mode_buf[0] = 'c';
1969
1970 /* owner permissions */
1971 if (rr->mode & TSK_FS_META_MODE_IRUSR)
1972 mode_buf[1] = 'r';
1973 if (rr->mode & TSK_FS_META_MODE_IWUSR)
1974 mode_buf[2] = 'w';
1975
1976 if ((rr->mode & TSK_FS_META_MODE_IXUSR)
1977 && (rr->mode & TSK_FS_META_MODE_ISUID))
1978 mode_buf[3] = 's';
1979 else if (rr->mode & TSK_FS_META_MODE_IXUSR)
1980 mode_buf[3] = 'x';
1981 else if (rr->mode & TSK_FS_META_MODE_ISUID)
1982 mode_buf[3] = 'S';
1983
1984 /* group permissions */
1985 if (rr->mode & TSK_FS_META_MODE_IRGRP)
1986 mode_buf[4] = 'r';
1987 if (rr->mode & TSK_FS_META_MODE_IWGRP)
1988 mode_buf[5] = 'w';
1989
1990 if ((rr->mode & TSK_FS_META_MODE_IXGRP)
1991 && (rr->mode & TSK_FS_META_MODE_ISGID))
1992 mode_buf[6] = 's';
1993 else if (rr->mode & TSK_FS_META_MODE_IXGRP)
1994 mode_buf[6] = 'x';
1995 else if (rr->mode & TSK_FS_META_MODE_ISGID)
1996 mode_buf[6] = 'S';
1997
1998 /* other permissions */
1999 if (rr->mode & TSK_FS_META_MODE_IROTH)
2000 mode_buf[7] = 'r';
2001 if (rr->mode & TSK_FS_META_MODE_IWOTH)
2002 mode_buf[8] = 'w';
2003
2004 if ((rr->mode & TSK_FS_META_MODE_IXOTH)
2005 && (rr->mode & TSK_FS_META_MODE_ISVTX))
2006 mode_buf[9] = 't';
2007 else if (rr->mode & TSK_FS_META_MODE_IXOTH)
2008 mode_buf[9] = 'x';
2009 else if (rr->mode & TSK_FS_META_MODE_ISVTX)
2010 mode_buf[9] = 'T';
2011
2012 tsk_fprintf(hFile, "%s\n", mode_buf);
2013 tsk_fprintf(hFile, "Number links: %" PRIu32 "\n", rr->nlink);
2014
2015 tsk_fprintf(hFile, "Alternate name: %s\n", rr->fn);
2016 tsk_fprintf(hFile, "\n");
2017 }
2018 #endif
2019
2020 /**
2021 * Print details on a specific file to a file handle.
2022 *
2023 * @param fs File system file is located in
2024 * @param hFile File handle to print text to
2025 * @param inum Address of file in file system
2026 * @param numblock The number of blocks in file to force print (can go beyond file size)
2027 * @param sec_skew Clock skew in seconds to also print times in
2028 *
2029 * @returns 1 on error and 0 on success
2030 */
2031 static uint8_t
iso9660_istat(TSK_FS_INFO * fs,TSK_FS_ISTAT_FLAG_ENUM istat_flags,FILE * hFile,TSK_INUM_T inum,TSK_DADDR_T numblock,int32_t sec_skew)2032 iso9660_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile, TSK_INUM_T inum,
2033 TSK_DADDR_T numblock, int32_t sec_skew)
2034 {
2035 ISO_INFO *iso = (ISO_INFO *) fs;
2036 TSK_FS_FILE *fs_file;
2037 iso9660_dentry dd;
2038 iso9660_inode *dinode;
2039 char timeBuf[128];
2040
2041 // clean up any error messages that are lying around
2042 tsk_error_reset();
2043
2044 if ((fs_file = tsk_fs_file_open_meta(fs, NULL, inum)) == NULL)
2045 return 1;
2046
2047 tsk_fprintf(hFile, "Entry: %" PRIuINUM "\n", inum);
2048
2049 /* allocate cache buffers */
2050 /* dinode */
2051 dinode = (iso9660_inode *) tsk_malloc(sizeof(iso9660_inode));
2052 if (dinode == NULL) {
2053 fs->tag = 0;
2054 iso9660_close(fs);
2055 return 1;
2056 }
2057
2058 if (iso9660_dinode_load(iso, inum, dinode)) {
2059 tsk_error_set_errstr2("iso9660_istat");
2060 tsk_fs_file_close(fs_file);
2061 free(dinode);
2062 return 1;
2063 }
2064 memcpy(&dd, &dinode->dr, sizeof(iso9660_dentry));
2065
2066 tsk_fprintf(hFile, "Type: ");
2067 if (dd.flags & ISO9660_FLAG_DIR)
2068 tsk_fprintf(hFile, "Directory\n");
2069 else
2070 tsk_fprintf(hFile, "File\n");
2071
2072 tsk_fprintf(hFile, "Links: %d\n", fs_file->meta->nlink);
2073
2074 if (dd.gap_sz > 0) {
2075 tsk_fprintf(hFile, "Interleave Gap Size: %d\n", dd.gap_sz);
2076 tsk_fprintf(hFile, "Interleave File Unit Size: %d\n", dd.unit_sz);
2077 }
2078
2079 tsk_fprintf(hFile, "Flags: ");
2080
2081 if (dd.flags & ISO9660_FLAG_HIDE)
2082 tsk_fprintf(hFile, "Hidden, ");
2083
2084 if (dd.flags & ISO9660_FLAG_ASSOC)
2085 tsk_fprintf(hFile, "Associated, ");
2086
2087 if (dd.flags & ISO9660_FLAG_RECORD)
2088 tsk_fprintf(hFile, "Record Format, ");
2089
2090 if (dd.flags & ISO9660_FLAG_PROT)
2091 tsk_fprintf(hFile, "Protected, ");
2092
2093 /* check if reserved bits are set, be suspicious */
2094 if (dd.flags & ISO9660_FLAG_RES1)
2095 tsk_fprintf(hFile, "Reserved1, ");
2096
2097 if (dd.flags & ISO9660_FLAG_RES2)
2098 tsk_fprintf(hFile, "Reserved2, ");
2099
2100 if (dd.flags & ISO9660_FLAG_MULT)
2101 tsk_fprintf(hFile, "Non-final multi-extent entry");
2102 putchar('\n');
2103
2104 tsk_fprintf(hFile, "Name: %s\n", dinode->fn);
2105 tsk_fprintf(hFile, "Size: %" PRIu32 "\n", tsk_getu32(fs->endian,
2106 dinode->dr.data_len_m));
2107
2108 if (dinode->ea) {
2109 char perm_buf[11];
2110 tsk_fprintf(hFile, "\nEXTENDED ATTRIBUTE INFO\n");
2111 tsk_fprintf(hFile, "Owner-ID: %" PRIu32 "\n",
2112 tsk_getu32(fs->endian, dinode->ea->uid));
2113 tsk_fprintf(hFile, "Group-ID: %" PRIu32 "\n",
2114 tsk_getu32(fs->endian, dinode->ea->gid));
2115 tsk_fprintf(hFile, "Mode: %s\n", make_unix_perm(fs, &dd, dinode,
2116 perm_buf));
2117 }
2118 else if (dinode->susp_off) {
2119 char *buf2 = (char *) tsk_malloc((size_t) dinode->susp_len);
2120 if (buf2 != NULL) {
2121 ssize_t cnt;
2122 fprintf(hFile, "\nRock Ridge Extension Data\n");
2123 cnt =
2124 tsk_fs_read(fs, dinode->susp_off, buf2,
2125 (size_t) dinode->susp_len);
2126 if (cnt == dinode->susp_len) {
2127 parse_susp(fs, buf2, (int) cnt, hFile);
2128 }
2129 else {
2130 fprintf(hFile, "Error reading Rock Ridge Location\n");
2131 if (tsk_verbose) {
2132 fprintf(stderr,
2133 "istat: error reading rock ridge entry\n");
2134 tsk_error_print(stderr);
2135 }
2136 tsk_error_reset();
2137 }
2138 free(buf2);
2139 }
2140 else {
2141 if (tsk_verbose)
2142 fprintf(stderr,
2143 "istat: error allocating memory to process rock ridge entry\n");
2144 tsk_error_reset();
2145 }
2146 }
2147 //else if (iso->dinode->rr) {
2148 // iso9660_print_rockridge(hFile, iso->dinode->rr);
2149 //}
2150 else {
2151 char perm_buf[11];
2152 tsk_fprintf(hFile, "Owner-ID: 0\n");
2153 tsk_fprintf(hFile, "Group-ID: 0\n");
2154 tsk_fprintf(hFile, "Mode: %s\n", make_unix_perm(fs, &dd, dinode,
2155 perm_buf));
2156 }
2157
2158 if (sec_skew != 0) {
2159 tsk_fprintf(hFile, "\nAdjusted File Times:\n");
2160 if (fs_file->meta->mtime)
2161 fs_file->meta->mtime -= sec_skew;
2162 if (fs_file->meta->atime)
2163 fs_file->meta->atime -= sec_skew;
2164 if (fs_file->meta->crtime)
2165 fs_file->meta->crtime -= sec_skew;
2166
2167 tsk_fprintf(hFile, "Written:\t%s\n",
2168 tsk_fs_time_to_str(fs_file->meta->mtime, timeBuf));
2169 tsk_fprintf(hFile, "Accessed:\t%s\n",
2170 tsk_fs_time_to_str(fs_file->meta->atime, timeBuf));
2171 tsk_fprintf(hFile, "Created:\t%s\n",
2172 tsk_fs_time_to_str(fs_file->meta->crtime, timeBuf));
2173
2174 if (fs_file->meta->mtime)
2175 fs_file->meta->mtime += sec_skew;
2176 if (fs_file->meta->atime)
2177 fs_file->meta->atime += sec_skew;
2178 if (fs_file->meta->crtime)
2179 fs_file->meta->crtime += sec_skew;
2180
2181
2182 tsk_fprintf(hFile, "\nOriginal File Times:\n");
2183 }
2184 else {
2185 tsk_fprintf(hFile, "\nFile Times:\n");
2186 }
2187
2188 tsk_fprintf(hFile, "Created:\t%s\n",
2189 tsk_fs_time_to_str(fs_file->meta->crtime, timeBuf));
2190 tsk_fprintf(hFile, "File Modified:\t%s\n",
2191 tsk_fs_time_to_str(fs_file->meta->mtime, timeBuf));
2192 tsk_fprintf(hFile, "Accessed:\t%s\n",
2193 tsk_fs_time_to_str(fs_file->meta->atime, timeBuf));
2194
2195 tsk_fprintf(hFile, "\nSectors:\n");
2196 if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
2197 const TSK_FS_ATTR *fs_attr_default =
2198 tsk_fs_file_attr_get_type(fs_file,
2199 TSK_FS_ATTR_TYPE_DEFAULT, 0, 0);
2200 if (fs_attr_default && (fs_attr_default->flags & TSK_FS_ATTR_NONRES)) {
2201 if (tsk_fs_attr_print(fs_attr_default, hFile)) {
2202 tsk_fprintf(hFile, "\nError creating run lists\n");
2203 tsk_error_print(hFile);
2204 tsk_error_reset();
2205 }
2206 }
2207 }
2208 else {
2209 /* since blocks are all contiguous, print them here to simplify file_walk */
2210
2211 int block = tsk_getu32(fs->endian, dinode->dr.ext_loc_m);
2212 TSK_OFF_T size = fs_file->meta->size;
2213 int rowcount = 0;
2214
2215 while ((int64_t) size > 0) {
2216 tsk_fprintf(hFile, "%d ", block++);
2217 size -= fs->block_size;
2218 rowcount++;
2219 if (rowcount == 8) {
2220 rowcount = 0;
2221 tsk_fprintf(hFile, "\n");
2222 }
2223 }
2224 tsk_fprintf(hFile, "\n");
2225 }
2226
2227 tsk_fs_file_close(fs_file);
2228 free(dinode);
2229 return 0;
2230 }
2231
2232
2233
2234
2235 static uint8_t
iso9660_jopen(TSK_FS_INFO * fs,TSK_INUM_T inum)2236 iso9660_jopen(TSK_FS_INFO * fs, TSK_INUM_T inum)
2237 {
2238 tsk_error_reset();
2239 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
2240 tsk_error_set_errstr("ISO9660 does not have a journal");
2241 return 1;
2242 }
2243
2244 static uint8_t
iso9660_jentry_walk(TSK_FS_INFO * fs,int flags,TSK_FS_JENTRY_WALK_CB action,void * ptr)2245 iso9660_jentry_walk(TSK_FS_INFO * fs, int flags,
2246 TSK_FS_JENTRY_WALK_CB action, void *ptr)
2247 {
2248 tsk_error_reset();
2249 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
2250 tsk_error_set_errstr("ISO9660 does not have a journal");
2251 return 1;
2252 }
2253
2254 static uint8_t
iso9660_jblk_walk(TSK_FS_INFO * fs,TSK_DADDR_T start,TSK_DADDR_T end,int flags,TSK_FS_JBLK_WALK_CB action,void * ptr)2255 iso9660_jblk_walk(TSK_FS_INFO * fs, TSK_DADDR_T start, TSK_DADDR_T end,
2256 int flags, TSK_FS_JBLK_WALK_CB action, void *ptr)
2257 {
2258 tsk_error_reset();
2259 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
2260 tsk_error_set_errstr("ISO9660 does not have a journal");
2261 return 1;
2262 }
2263
2264
2265 static TSK_FS_ATTR_TYPE_ENUM
iso9660_get_default_attr_type(const TSK_FS_FILE * a_file)2266 iso9660_get_default_attr_type(const TSK_FS_FILE * a_file)
2267 {
2268 return TSK_FS_ATTR_TYPE_DEFAULT;
2269 }
2270
2271 /** Load the volume descriptors into save the raw data structures in
2272 * the file system state structure (fs). Also determines the block size.
2273 *
2274 * This is useful for discs which may have 2 volumes on them (no, not
2275 * multisession CD-R/CD-RW).
2276 * Design note: If path table address is the same, then you have the same image.
2277 * Only store unique image info.
2278 * Uses a linked list even though Ecma-119 says there is only 1 primary vol
2279 * desc, consider possibility of more.
2280 *
2281 * Returns -1 on error and 0 on success
2282 */
2283 static int
load_vol_desc(TSK_FS_INFO * fs)2284 load_vol_desc(TSK_FS_INFO * fs)
2285 {
2286 int count = 0;
2287 ISO_INFO *iso = (ISO_INFO *) fs;
2288 TSK_OFF_T offs;
2289 char *myname = "iso_load_vol_desc";
2290 ssize_t cnt;
2291 iso9660_pvd_node *p;
2292 iso9660_svd_node *s;
2293 uint8_t magic_seen = 0;
2294
2295 iso->pvd = NULL;
2296 iso->svd = NULL;
2297 //fs->block_size = 0;
2298 fs->dev_bsize = fs->img_info->sector_size;
2299
2300 #if 0
2301 b = (iso_bootrec *) tsk_malloc(sizeof(iso_bootrec));
2302 if (b == NULL) {
2303 return -1;
2304 }
2305 #endif
2306
2307 // @@@ Technically, we should seek ahea 16 * sector size
2308 for (offs = ISO9660_SBOFF;; offs += sizeof(iso9660_gvd)) {
2309 iso9660_gvd *vd;
2310
2311 // allocate a buffer the size of the nodes in the linked list
2312 // this will be stored in ISO_INFO, so it is not always freed here
2313 if ((vd =
2314 (iso9660_gvd *) tsk_malloc(sizeof(iso9660_pvd_node))) ==
2315 NULL) {
2316 return -1;
2317 }
2318
2319 ISO_RETRY_MAGIC:
2320
2321 // read the full descriptor
2322 cnt = tsk_fs_read(fs, offs, (char *) vd, sizeof(iso9660_gvd));
2323 if (cnt != sizeof(iso9660_gvd)) {
2324 if (cnt >= 0) {
2325 tsk_error_reset();
2326 tsk_error_set_errno(TSK_ERR_FS_READ);
2327 }
2328 tsk_error_set_errstr2("iso_load_vol_desc: Error reading");
2329 free(vd);
2330 return -1;
2331 }
2332
2333 // verify the magic value
2334 if (strncmp(vd->magic, ISO9660_MAGIC, 5)) {
2335 if (tsk_verbose)
2336 tsk_fprintf(stderr,
2337 "%s: Bad volume descriptor: Magic number is not CD001\n",
2338 myname);
2339
2340 // see if we have a RAW image
2341 if (magic_seen == 0) {
2342 if (fs->block_pre_size == 0) {
2343 if (tsk_verbose)
2344 tsk_fprintf(stderr,
2345 "Trying RAW ISO9660 with 16-byte pre-block size\n");
2346 fs->block_pre_size = 16;
2347 fs->block_post_size = 288;
2348 goto ISO_RETRY_MAGIC;
2349 }
2350 else if (fs->block_pre_size == 16) {
2351 if (tsk_verbose)
2352 tsk_fprintf(stderr,
2353 "Trying RAW ISO9660 with 24-byte pre-block size\n");
2354 fs->block_pre_size = 24;
2355 fs->block_post_size = 280;
2356 goto ISO_RETRY_MAGIC;
2357 }
2358 else {
2359 fs->block_pre_size = 0;
2360 fs->block_post_size = 0;
2361 }
2362 }
2363 free(vd);
2364 return -1;
2365 }
2366 magic_seen = 1;
2367
2368 // see if we are done
2369 if (vd->type == ISO9660_VOL_DESC_SET_TERM) {
2370 free(vd);
2371 break;
2372 }
2373
2374 switch (vd->type) {
2375
2376 case ISO9660_PRIM_VOL_DESC:
2377 p = (iso9660_pvd_node *) vd;
2378
2379 /* list not empty */
2380 if (iso->pvd) {
2381 iso9660_pvd_node *ptmp = iso->pvd;
2382 /* append to list if path table address not found in list */
2383 while ((p->pvd.pt_loc_l != ptmp->pvd.pt_loc_l)
2384 && (ptmp->next))
2385 ptmp = ptmp->next;
2386
2387 // we already have it
2388 if (p->pvd.pt_loc_l == ptmp->pvd.pt_loc_l) {
2389 free(vd);
2390 p = NULL;
2391 vd = NULL;
2392 }
2393 else {
2394 ptmp->next = p;
2395 p->next = NULL;
2396 count++;
2397 }
2398 }
2399
2400 /* list empty, insert */
2401 else {
2402 iso->pvd = p;
2403 p->next = NULL;
2404 count++;
2405 }
2406
2407 break;
2408
2409 case ISO9660_SUPP_VOL_DESC:
2410 s = (iso9660_svd_node *) vd;
2411
2412 /* list not empty */
2413 if (iso->svd) {
2414 iso9660_svd_node *stmp = iso->svd;
2415 /* append to list if path table address not found in list */
2416 while ((s->svd.pt_loc_l != stmp->svd.pt_loc_l)
2417 && (stmp->next))
2418 stmp = stmp->next;
2419
2420 // we already have it
2421 if (s->svd.pt_loc_l == stmp->svd.pt_loc_l) {
2422 free(vd);
2423 s = NULL;
2424 vd = NULL;
2425 }
2426 else {
2427 stmp->next = s;
2428 s->next = NULL;
2429 count++;
2430 }
2431 }
2432
2433 /* list empty, insert */
2434 else {
2435 iso->svd = s;
2436 s->next = NULL;
2437 count++;
2438 }
2439
2440 break;
2441
2442 /* boot records are just read and discarded for now... */
2443 case ISO9660_BOOT_RECORD:
2444 free(vd);
2445 #if 0
2446 cnt = tsk_fs_read(fs, offs, (char *) b, sizeof(iso_bootrec));
2447 if (cnt != sizeof(iso_bootrec)) {
2448 if (cnt >= 0) {
2449 tsk_error_reset();
2450 tsk_error_set_errno(TSK_ERR_FS_READ);
2451 }
2452 tsk_error_set_errstr2("iso_load_vol_desc: Error reading");
2453 return -1;
2454 }
2455 offs += sizeof(iso_bootrec);
2456 #endif
2457 break;
2458
2459 default:
2460 free(vd);
2461 break;
2462 }
2463 }
2464
2465
2466 /* now that we have all primary and supplementary volume descs, we should cull the list of */
2467 /* primary that match up with supplems, since supplem has all info primary has plus more. */
2468 /* this will make jobs such as searching all volumes easier later */
2469 for (s = iso->svd; s != NULL; s = s->next) {
2470 for (p = iso->pvd; p != NULL; p = p->next) {
2471 // see if they have the same starting address
2472 if (tsk_getu32(fs->endian,
2473 p->pvd.pt_loc_m) == tsk_getu32(fs->endian,
2474 s->svd.pt_loc_m)) {
2475 // see if it is the head of the list
2476 if (p == iso->pvd) {
2477 iso->pvd = p->next;
2478 }
2479 else {
2480 iso9660_pvd_node *ptmp = iso->pvd;
2481 while (ptmp->next != p)
2482 ptmp = ptmp->next;
2483 ptmp->next = p->next;
2484 }
2485 p->next = NULL;
2486 free(p);
2487 p = NULL;
2488 count--;
2489 break;
2490 }
2491 }
2492 }
2493
2494 if ((iso->pvd == NULL) && (iso->svd == NULL)) {
2495 tsk_error_reset();
2496 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
2497 tsk_error_set_errstr
2498 ("load_vol_desc: primary and secondary volume descriptors null");
2499 return -1;
2500 }
2501
2502
2503 return 0;
2504 }
2505
2506
2507 /* iso9660_open -
2508 * opens an iso9660 filesystem.
2509 * Design note: This function doesn't read a superblock, since iso9660 doesnt
2510 * really have one. Volume info is read in with a call to load_vol_descs().
2511 */
2512 TSK_FS_INFO *
iso9660_open(TSK_IMG_INFO * img_info,TSK_OFF_T offset,TSK_FS_TYPE_ENUM ftype,uint8_t test)2513 iso9660_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
2514 TSK_FS_TYPE_ENUM ftype, uint8_t test)
2515 {
2516 ISO_INFO *iso;
2517 TSK_FS_INFO *fs;
2518 uint8_t tmpguess[4];
2519
2520 if (TSK_FS_TYPE_ISISO9660(ftype) == 0) {
2521 tsk_error_reset();
2522 tsk_error_set_errno(TSK_ERR_FS_ARG);
2523 tsk_error_set_errstr("Invalid FS type in iso9660_open");
2524 return NULL;
2525 }
2526
2527 if (img_info->sector_size == 0) {
2528 tsk_error_reset();
2529 tsk_error_set_errno(TSK_ERR_FS_ARG);
2530 tsk_error_set_errstr("iso9660_open: sector size is 0");
2531 return NULL;
2532 }
2533
2534 if (tsk_verbose) {
2535 tsk_fprintf(stderr, "iso9660_open img_info: %" PRIu64
2536 " ftype: %" PRIu8 " test: %" PRIu8 "\n", (uint64_t) img_info,
2537 ftype, test);
2538 }
2539
2540 if ((iso = (ISO_INFO *) tsk_fs_malloc(sizeof(ISO_INFO))) == NULL) {
2541 return NULL;
2542 }
2543 fs = &(iso->fs_info);
2544
2545 iso->rr_found = 0;
2546 iso->in_list = NULL;
2547
2548 fs->ftype = TSK_FS_TYPE_ISO9660;
2549 fs->duname = "Block";
2550 fs->flags = 0;
2551 fs->tag = TSK_FS_INFO_TAG;
2552 fs->img_info = img_info;
2553 fs->offset = offset;
2554
2555
2556 /* ISO has no magic to calibrate the endian ordering on and it
2557 * stores all numbers in big and small endian. We will use the big
2558 * endian order so load up a 4-byte array and flags. We could hardwire
2559 * the definition, but I would rather use guessu32 in case I later add
2560 * other initialization data to that function (since all other FSs use
2561 * it) */
2562 tmpguess[0] = 0;
2563 tmpguess[1] = 0;
2564 tmpguess[2] = 0;
2565 tmpguess[3] = 1;
2566 tsk_fs_guessu32(fs, tmpguess, 1);
2567
2568 // we need a value here to test for RAW images. So, start with 2048
2569 fs->block_size = 2048;
2570
2571 /* load_vol_descs checks magic value */
2572 if (load_vol_desc(fs) == -1) {
2573 fs->tag = 0;
2574 iso9660_close(fs);
2575 if (tsk_verbose)
2576 fprintf(stderr,
2577 "iso9660_open: Error loading volume descriptor\n");
2578 if (test)
2579 return NULL;
2580 else {
2581 tsk_error_reset();
2582 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
2583 tsk_error_set_errstr("Invalid FS type in iso9660_open");
2584 return NULL;
2585 }
2586 }
2587
2588 if (iso->pvd) {
2589 fs->block_size = tsk_getu16(fs->endian, iso->pvd->pvd.blk_sz_m);
2590 fs->block_count = tsk_getu32(fs->endian, iso->pvd->pvd.vs_sz_m);
2591
2592 /* Volume ID */
2593 for (fs->fs_id_used = 0; fs->fs_id_used < 32; fs->fs_id_used++) {
2594 fs->fs_id[fs->fs_id_used] =
2595 iso->pvd->pvd.vol_id[fs->fs_id_used];
2596 }
2597
2598 }
2599 else {
2600 fs->block_size = tsk_getu16(fs->endian, iso->svd->svd.blk_sz_m);
2601 fs->block_count = tsk_getu32(fs->endian, iso->svd->svd.vs_sz_m);
2602
2603 /* Volume ID */
2604 for (fs->fs_id_used = 0; fs->fs_id_used < 32; fs->fs_id_used++) {
2605 fs->fs_id[fs->fs_id_used] =
2606 iso->svd->svd.vol_id[fs->fs_id_used];
2607 }
2608 }
2609
2610 /* We have seen this case on an image that seemed to be only
2611 * setting blk_siz_l instead of both blk_sz_m and _l. We should
2612 * support both in the future, but this prevents a crash later
2613 * on when we divide by block_size. */
2614 if (fs->block_size == 0) {
2615 fs->tag = 0;
2616 iso9660_close(fs);
2617 if (tsk_verbose)
2618 fprintf(stderr, "iso9660_open: Block size is 0\n");
2619 if (test)
2620 return NULL;
2621 else {
2622 tsk_error_reset();
2623 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
2624 tsk_error_set_errstr("Block size is 0");
2625 return NULL;
2626 }
2627 }
2628
2629 fs->first_block = 0;
2630 fs->last_block = fs->last_block_act = fs->block_count - 1;
2631
2632 // determine the last block we have in this image
2633 if ((TSK_DADDR_T) ((img_info->size - offset) / fs->block_size) <
2634 fs->block_count)
2635 fs->last_block_act =
2636 (img_info->size - offset) / fs->block_size - 1;
2637
2638 fs->inum_count = iso9660_load_inodes_pt(iso);
2639 if ((int) fs->inum_count == -1) {
2640 fs->tag = 0;
2641 iso9660_close(fs);
2642 if (tsk_verbose)
2643 fprintf(stderr, "iso9660_open: Error loading primary table\n");
2644 return NULL;
2645 }
2646 fs->inum_count++; // account for the orphan directory
2647
2648 fs->last_inum = fs->inum_count - 1;
2649 fs->first_inum = ISO9660_FIRSTINO;
2650 fs->root_inum = ISO9660_ROOTINO;
2651
2652
2653 fs->inode_walk = iso9660_inode_walk;
2654 fs->block_walk = iso9660_block_walk;
2655 fs->block_getflags = iso9660_block_getflags;
2656
2657 fs->get_default_attr_type = iso9660_get_default_attr_type;
2658 fs->load_attrs = iso9660_make_data_run;
2659
2660 fs->file_add_meta = iso9660_inode_lookup;
2661 fs->dir_open_meta = iso9660_dir_open_meta;
2662 fs->fsstat = iso9660_fsstat;
2663 fs->fscheck = iso9660_fscheck;
2664 fs->istat = iso9660_istat;
2665 fs->close = iso9660_close;
2666 fs->name_cmp = iso9660_name_cmp;
2667
2668 fs->jblk_walk = iso9660_jblk_walk;
2669 fs->jentry_walk = iso9660_jentry_walk;
2670 fs->jopen = iso9660_jopen;
2671
2672 return fs;
2673 }
2674