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
print_header(TSK_FS_INFO * fs)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
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,
print_header_mac()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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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 *
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