2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)isoinfo.c 1.50 05/05/15 joerg */
14 /* Parts from @(#)isoinfo.c 1.63 08/08/25 joerg */
16 * File isodump.c - dump iso9660 directory information.
19 * Written by Eric Youngdale (1993).
21 * Copyright 1993 Yggdrasil Computing, Incorporated
22 * Copyright (c) 1999-2004 J. Schilling
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License version 2
26 * as published by the Free Software Foundation.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License along with
34 * this program; see the file COPYING. If not, write to the Free Software
35 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 * Simple program to dump contents of iso9660 image in more usable format.
42 * To list contents of image (with or without RR):
43 * isoinfo -l [-R] -i imagefile
44 * To extract file from image:
45 * isoinfo -i imagefile -x xtractfile > outfile
46 * To generate a "find" like list of files:
47 * isoinfo -f -i imagefile
64 #include "../iso9660.h"
66 #include "../../wodim/defaults.h"
70 #if defined(__CYGWIN32__) || defined(__EMX__) || defined(__DJGPP__)
71 #include <io.h> /* for setmode() prototype */
75 * Make sure we have a definition for this. If not, take a very conservative
77 * POSIX requires the max pathname component lenght to be defined in limits.h
78 * If variable, it may be undefined. If undefined, there should be
79 * a definition for _POSIX_NAME_MAX in limits.h or in unistd.h
80 * As _POSIX_NAME_MAX is defined to 14, we cannot use it.
81 * XXX Eric's wrong comment:
82 * XXX From what I can tell SunOS is the only one with this trouble.
89 #define NAME_MAX FILENAME_MAX
97 #define PATH_MAX FILENAME_MAX
104 * XXX JS: Some structures have odd lengths!
105 * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
106 * For this reason, we cannot use sizeof (struct iso_path_table) or
107 * sizeof (struct iso_directory_record) to compute on disk sizes.
108 * Instead, we use offsetof(..., name) and add the name size.
112 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
116 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
120 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
122 # define S_ISSOCK(m) (0)
127 * Note: always use these macros to avoid problems.
129 * ISO_ROUND_UP(X) may cause an integer overflow and thus give
130 * incorrect results. So avoid it if possible.
132 * ISO_BLOCKS(X) is overflow safe. Prefer this when ever it is possible.
134 #define SECTOR_SIZE (2048)
135 #define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
136 #define ISO_BLOCKS(X) (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
138 #define infile in_image
153 struct stat fstat_buf;
157 unsigned char date_buf[9];
159 * Use sector_offset != 0 (-N #) if we have an image file
160 * of a single session and we need to list the directory contents.
161 * This is the session block (sector) number of the start
162 * of the session when it would be on disk.
164 unsigned int sector_offset = 0;
166 unsigned char buffer[2048];
168 struct unls_table *unls;
170 #define PAGE sizeof (buffer)
172 #define ISODCL(from, to) (to - from + 1)
175 int isonum_721(char * p);
176 int isonum_723(char * p);
177 int isonum_731(char * p);
178 int isonum_732(char * p);
179 int isonum_733(unsigned char * p);
180 void printchars(char *s, int n);
181 char *sdate(char *dp);
182 void dump_pathtab(int block, int size);
183 int parse_rr(unsigned char * pnt, int len, int cont_flag);
184 void find_rr(struct iso_directory_record * idr, Uchar **pntp, int *lenp);
185 int dump_rr(struct iso_directory_record * idr);
186 void dump_stat(struct iso_directory_record * idr, int extent);
187 void extract_file(struct iso_directory_record * idr);
188 void parse_dir(char * rootname, int extent, int len);
189 void usage(int excode);
191 static void printf_bootinfo(FILE *f, int bootcat_offset);
192 static char *arch_name(int val);
193 static char *boot_name(int val);
194 static char *bootmedia_name(int val);
200 return ((p[0] & 0xff)
201 | ((p[1] & 0xff) << 8));
208 if (p[0] != p[3] || p[1] != p[2]) {
210 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
212 fprintf(stderr, "invalid format 7.2.3 number\n");
217 return (isonum_721(p));
223 return ((p[0] & 0xff)
224 | ((p[1] & 0xff) << 8)
225 | ((p[2] & 0xff) << 16)
226 | ((p[3] & 0xff) << 24));
232 return ((p[3] & 0xff)
233 | ((p[2] & 0xff) << 8)
234 | ((p[1] & 0xff) << 16)
235 | ((p[0] & 0xff) << 24));
239 isonum_733(unsigned char *p)
241 return (isonum_731((char *)p));
245 printchars(char *s, int n)
250 for (; n > 0 && *s; n--) {
254 while (--i >= 0 && *p++ == ' ')
264 * Print date info from PVD
271 sprintf(d, "%4.4s %2.2s %2.2s %2.2s:%2.2s:%2.2s.%2.2s",
274 &dp[6], /* Monthday */
276 &dp[10], /* Minute */
277 &dp[12], /* Seconds */
278 &dp[14]); /* Hunreds of a Seconds */
281 * dp[16] contains minute offset from Greenwich
282 * Positive values are to the east of Greenwich.
288 dump_pathtab(int block, int size)
299 unsigned char uh, ul, uc, *up;
302 printf("Path table starts at block %d, size %d\n", block, size);
304 buf = (unsigned char *) malloc(ISO_ROUND_UP(size));
307 readsecs(block - sector_offset, buf, ISO_BLOCKS(size));
309 lseek(fileno(infile), ((off_t)(block - sector_offset)) << 11, SEEK_SET);
310 read(fileno(infile), buf, size);
315 while (offset < size) {
317 extent = isonum_731((char *)buf + offset + 2);
318 pindex = isonum_721((char *)buf + offset + 6);
325 for (j = 0; j < jlen; j++) {
326 uh = buf[offset + 8 + j*2];
327 ul = buf[offset + 8 + j*2+1];
329 up = unls->unls_uni2cs[uh];
336 namebuf[j] = uc ? uc : '_';
338 printf("%4d: %4d %x %.*s\n",
339 idx, pindex, extent, jlen, namebuf);
342 printf("%4d: %4d %x %.*s\n",
343 idx, pindex, extent, len, buf + offset + 8);
356 parse_rr(unsigned char *pnt, int len, int cont_flag)
362 int cont_extent, cont_offset, cont_size;
365 char symlinkname[1024];
370 cont_extent = cont_offset = cont_size = 0;
375 if (pnt[3] != 1 && pnt[3] != 2) {
376 printf("**BAD RRVERSION (%d)\n", pnt[3]);
377 return (0); /* JS ??? Is this right ??? */
380 if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
381 if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1; /* POSIX attributes */
382 if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2; /* POSIX device number */
383 if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4; /* Symlink */
384 if (strncmp((char *)pnt, "NM", 2) == 0) flag2 |= 8; /* Alternate Name */
385 if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16; /* Child link */
386 if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32; /* Parent link */
387 if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64; /* Relocated Direcotry */
388 if (strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128; /* Time stamp */
389 if (strncmp((char *)pnt, "SP", 2) == 0) {
390 flag2 |= 1024; /* SUSP record */
391 su_version = pnt[3] & 0xff;
393 if (strncmp((char *)pnt, "AA", 2) == 0) {
394 flag2 |= 2048; /* Apple Signature record */
395 aa_version = pnt[3] & 0xff;
398 if (strncmp((char *)pnt, "PX", 2) == 0) { /* POSIX attributes */
399 fstat_buf.st_mode = isonum_733(pnt+4);
400 fstat_buf.st_nlink = isonum_733(pnt+12);
401 fstat_buf.st_uid = isonum_733(pnt+20);
402 fstat_buf.st_gid = isonum_733(pnt+28);
405 if (strncmp((char *)pnt, "NM", 2) == 0) { /* Alternate Name */
406 int l = strlen(name_buf);
410 strncpy(&name_buf[l], (char *)(pnt+5), pnt[2] - 5);
411 name_buf[l + pnt[2] - 5] = 0;
415 if (strncmp((char *)pnt, "CE", 2) == 0) { /* Continuation Area */
416 cont_extent = isonum_733(pnt+4);
417 cont_offset = isonum_733(pnt+12);
418 cont_size = isonum_733(pnt+20);
421 if (strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
422 extent = isonum_733(pnt+4);
425 if (strncmp((char *)pnt, "SL", 2) == 0) { /* Symlink */
432 switch (pnts[0] & 0xfe) {
434 strncat(symlinkname, (char *)(pnts+2), pnts[1]);
435 symlinkname[pnts[1]] = 0;
438 strcat(symlinkname, ".");
441 strcat(symlinkname, "..");
444 strcat(symlinkname, "/");
447 strcat(symlinkname, "/mnt");
448 printf("Warning - mount point requested");
451 strcat(symlinkname, "kafka");
452 printf("Warning - host_name requested");
455 printf("Reserved bit setting in symlink");
459 if ((pnts[0] & 0xfe) && pnts[1] != 0) {
460 printf("Incorrect length in symlink component");
462 if (xname[0] == 0) strcpy(xname, "-> ");
463 strcat(xname, symlinkname);
465 xlen = strlen(xname);
466 if ((pnts[0] & 1) == 0 && xname[xlen-1] != '/') strcat(xname, "/");
468 slen -= (pnts[1] + 2);
469 pnts += (pnts[1] + 2);
476 if (len <= 3 && cont_extent) {
477 unsigned char sector[2048];
480 readsecs(cont_extent - sector_offset, sector, ISO_BLOCKS(sizeof (sector)));
482 lseek(fileno(infile), ((off_t)(cont_extent - sector_offset)) << 11, SEEK_SET);
483 read(fileno(infile), sector, sizeof (sector));
485 flag2 |= parse_rr(§or[cont_offset], cont_size, 1);
489 * for symbolic links, strip out the last '/'
491 if (xname[0] != 0 && xname[strlen(xname)-1] == '/') {
492 xname[strlen(xname)-1] = '\0';
498 find_rr(struct iso_directory_record *idr, Uchar **pntp, int *lenp)
500 struct iso_xa_dir_record *xadp;
504 len = idr->length[0] & 0xff;
505 len -= offsetof(struct iso_directory_record, name[0]);
506 len -= idr->name_len[0];
508 pnt = (unsigned char *) idr;
509 pnt += offsetof(struct iso_directory_record, name[0]);
510 pnt += idr->name_len[0];
511 if ((idr->name_len[0] & 1) == 0) {
516 xadp = (struct iso_xa_dir_record *)pnt;
518 if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' &&
519 xadp->reserved[0] == '\0') {
529 dump_rr(struct iso_directory_record *idr)
534 find_rr(idr, &pnt, &len);
535 return (parse_rr(pnt, len, 0));
546 struct todo *todo_idr = NULL;
548 char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
549 "Aug", "Sep", "Oct", "Nov", "Dec"};
552 dump_stat(struct iso_directory_record *idr, int extent)
557 memset(outline, ' ', sizeof (outline));
559 if (S_ISREG(fstat_buf.st_mode))
561 else if (S_ISDIR(fstat_buf.st_mode))
563 else if (S_ISLNK(fstat_buf.st_mode))
565 else if (S_ISCHR(fstat_buf.st_mode))
567 else if (S_ISBLK(fstat_buf.st_mode))
569 else if (S_ISFIFO(fstat_buf.st_mode))
571 else if (S_ISSOCK(fstat_buf.st_mode))
576 memset(outline+1, '-', 9);
577 if (fstat_buf.st_mode & S_IRUSR)
579 if (fstat_buf.st_mode & S_IWUSR)
581 if (fstat_buf.st_mode & S_IXUSR)
584 if (fstat_buf.st_mode & S_IRGRP)
586 if (fstat_buf.st_mode & S_IWGRP)
588 if (fstat_buf.st_mode & S_IXGRP)
591 if (fstat_buf.st_mode & S_IROTH)
593 if (fstat_buf.st_mode & S_IWOTH)
595 if (fstat_buf.st_mode & S_IXOTH)
599 * XXX This is totally ugly code from Eric.
600 * XXX If one field is wider than expected then it is truncated.
602 sprintf(outline+11, "%3ld", (long)fstat_buf.st_nlink);
603 sprintf(outline+15, "%4lo", (unsigned long)fstat_buf.st_uid);
604 sprintf(outline+20, "%4lo", (unsigned long)fstat_buf.st_gid);
605 sprintf(outline+30, "%10lld", (Llong)fstat_buf.st_size);
607 if (do_sectors == 0) {
608 sprintf(outline+30, "%10lld", (Llong)fstat_buf.st_size);
610 sprintf(outline+30, "%10lld", (Llong)((fstat_buf.st_size+PAGE-1)/PAGE));
613 if (date_buf[1] >= 1 && date_buf[1] <= 12) {
614 memcpy(outline+41, months[date_buf[1]-1], 3);
617 sprintf(outline+45, "%2d", date_buf[2]);
619 sprintf(outline+48, "%4d", date_buf[0]+1900);
621 sprintf(outline+53, "[%7d", extent); /* XXX up to 20 GB */
622 sprintf(outline+61, " %02X]", idr->flags[0] & 0xFF);
624 for (i = 0; i < 66; i++) {
625 if (outline[i] == 0) outline[i] = ' ';
628 printf("%s %s %s\n", outline, name_buf, xname);
632 extract_file(struct iso_directory_record *idr)
634 int extent, len, tlen;
635 unsigned char buff[2048];
637 #if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__EMX__) || defined(__DJGPP__)
638 setmode(fileno(stdout), O_BINARY);
641 extent = isonum_733((unsigned char *)idr->extent);
642 len = isonum_733((unsigned char *)idr->size);
646 readsecs(extent - sector_offset, buff, ISO_BLOCKS(sizeof (buff)));
647 tlen = (len > sizeof (buff) ? sizeof (buff) : len);
649 lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
650 tlen = (len > sizeof (buff) ? sizeof (buff) : len);
651 read(fileno(infile), buff, tlen);
655 write(STDOUT_FILENO, buff, tlen); /* FIXME: check return value */
660 parse_dir(char *rootname, int extent, int len)
662 char testname[PATH_MAX+1];
665 struct iso_directory_record * idr;
666 unsigned char uh, ul, uc, *up;
667 unsigned char flags = 0;
673 printf("\nDirectory listing of %s\n", rootname);
677 readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
679 lseek(fileno(infile), ((off_t)(extent - sector_offset)) << 11, SEEK_SET);
680 read(fileno(infile), buffer, sizeof (buffer));
682 len -= sizeof (buffer);
686 idr = (struct iso_directory_record *) &buffer[i];
687 if (idr->length[0] == 0) break;
688 memset(&fstat_buf, 0, sizeof (fstat_buf));
690 name_buf[0] = xname[0] = 0;
691 fstat_buf.st_size = (off_t)(unsigned)isonum_733((unsigned char *)idr->size);
692 if (idr->flags[0] & 2)
693 fstat_buf.st_mode |= S_IFDIR;
695 fstat_buf.st_mode |= S_IFREG;
696 if (idr->name_len[0] == 1 && idr->name[0] == 0)
697 strcpy(name_buf, ".");
698 else if (idr->name_len[0] == 1 && idr->name[0] == 1)
699 strcpy(name_buf, "..");
706 * Unicode name. Convert as best we can.
712 for (j = 0; j < (int)idr->name_len[0] / 2; j++) {
714 ul = idr->name[j*2+1];
716 up = unls->unls_uni2cs[uh];
723 name_buf[j] = uc ? uc : '_';
725 name_buf[idr->name_len[0]/2] = '\0';
730 * Normal non-Unicode name.
732 strncpy(name_buf, idr->name, idr->name_len[0]);
733 name_buf[idr->name_len[0]] = 0;
737 * Don't know how to do these yet. Maybe they are the same
738 * as one of the above.
743 memcpy(date_buf, idr->date, 9);
746 if ((idr->flags[0] & 2) != 0 &&
747 (idr->name_len[0] != 1 ||
748 (idr->name[0] != 0 && idr->name[0] != 1))) {
750 * Add this directory to the todo list.
754 while (td->next != NULL)
756 td->next = (struct todo *) malloc(sizeof (*td));
759 todo_idr = td = (struct todo *) malloc(sizeof (*td));
762 td->extent = isonum_733((unsigned char *)idr->extent);
763 td->length = isonum_733((unsigned char *)idr->size);
764 td->name = (char *) malloc(strlen(rootname)
765 + strlen(name_buf) + 2);
766 strcpy(td->name, rootname);
767 strcat(td->name, name_buf);
768 strcat(td->name, "/");
770 strcpy(testname, rootname);
771 strcat(testname, name_buf);
772 if (xtract && strcmp(xtract, testname) == 0) {
777 (idr->name_len[0] != 1 ||
778 (idr->name[0] != 0 && idr->name[0] != 1))) {
779 strcpy(testname, rootname);
780 strcat(testname, name_buf);
781 printf("%s\n", testname);
784 if ((idr->flags[0] & ISO_MULTIEXTENT) && size == 0)
785 sextent = isonum_733((unsigned char *)idr->extent);
787 ((idr->flags[0] & ISO_MULTIEXTENT) == 0 && size == 0)) {
788 dump_stat(idr, isonum_733((unsigned char *)idr->extent));
790 size += fstat_buf.st_size;
791 if ((flags & ISO_MULTIEXTENT) &&
792 (idr->flags[0] & ISO_MULTIEXTENT) == 0) {
793 fstat_buf.st_size = size;
795 idr->flags[0] |= ISO_MULTIEXTENT;
796 dump_stat(idr, sextent);
798 idr->flags[0] &= ~ISO_MULTIEXTENT;
800 flags = idr->flags[0];
801 if ((idr->flags[0] & ISO_MULTIEXTENT) == 0)
805 if (i > 2048 - offsetof(struct iso_directory_record, name[0])) break;
813 errmsgno(EX_BAD, "Usage: %s [options] -i filename\n", get_progname());
815 fprintf(stderr, "Options:\n");
816 fprintf(stderr, "\t-help,-h Print this help\n");
817 fprintf(stderr, "\t-version Print version info and exit\n");
818 fprintf(stderr, "\t-debug Print additional debug info\n");
819 fprintf(stderr, "\t-d Print information from the primary volume descriptor\n");
820 fprintf(stderr, "\t-f Generate output similar to 'find . -print'\n");
821 fprintf(stderr, "\t-J Print information from Joliet extensions\n");
822 fprintf(stderr, "\t-j charset Use charset to display Joliet file names\n");
823 fprintf(stderr, "\t-l Generate output similar to 'ls -lR'\n");
824 fprintf(stderr, "\t-p Print Path Table\n");
825 fprintf(stderr, "\t-R Print information from Rock Ridge extensions\n");
826 fprintf(stderr, "\t-s Print file size infos in multiples of sector size (%ld bytes).\n", (long)PAGE);
827 fprintf(stderr, "\t-N sector Sector number where ISO image should start on CD\n");
828 fprintf(stderr, "\t-T sector Sector number where actual session starts on CD\n");
829 fprintf(stderr, "\t-i filename Filename to read ISO-9660 image from\n");
830 fprintf(stderr, "\tdev=target SCSI target to use as CD/DVD-Recorder\n");
831 fprintf(stderr, "\t-x pathname Extract specified file to stdout\n");
836 main(int argc, char *argv[])
841 char * filename = NULL;
842 char * devname = NULL;
844 * Use toc_offset != 0 (-T #) if we have a complete multi-session
845 * disc that we want/need to play with.
846 * Here we specify the offset where we want to
847 * start searching for the TOC.
852 struct iso_primary_descriptor ipd;
853 struct iso_primary_descriptor jpd;
854 struct eltorito_boot_descriptor bpd;
855 struct iso_directory_record * idr;
856 char *charset = NULL;
857 char *opts = "help,h,version,debug,d,p,i*,dev*,J,R,l,x*,f,s,N#l,T#l,j*";
860 BOOL found_eltorito = FALSE;
861 int bootcat_offset = 0;
864 save_args(argc, argv);
868 if (getallargs(&cac, &cav, opts,
869 &help, &help, &prvers, &debug,
870 &do_pvd, &do_pathtab,
872 &use_joliet, &use_rock,
875 &do_find, &do_sectors,
876 §or_offset, &toc_offset,
878 errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
884 printf("isoinfo %s (%s)\n", CDRKIT_VERSION, HOST_SYSTEM);
889 if (getfiles(&cac, &cav, opts) != 0) {
890 errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
894 init_unls(); /* Initialize UNICODE tables */
895 init_unls_file(charset);
896 if (charset == NULL) {
897 #if (defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__DJGPP__)) && !defined(IS_CYGWIN_1)
898 unls = load_unls("cp437");
900 unls = load_unls("iso8859-1");
903 if (strcmp(charset, "default") == 0)
904 unls = load_unls_default();
906 unls = load_unls(charset);
908 if (unls == NULL) { /* Unknown charset specified */
909 fprintf(stderr, "Unknown charset: %s\nKnown charsets are:\n",
911 list_unls(); /* List all known charset names */
915 if (filename != NULL && devname != NULL) {
916 errmsgno(EX_BAD, "Only one of -i or dev= allowed\n");
920 if (filename == NULL && devname == NULL)
921 cdr_defaults(&devname, NULL, NULL, NULL);
923 if (filename == NULL && devname == NULL) {
925 errmsgno(EX_BAD, "ISO-9660 image not specified\n");
927 fprintf(stderr, "ISO-9660 image not specified\n");
932 if (filename != NULL)
933 infile = fopen(filename, "rb");
937 if (infile != NULL) {
940 } else if (scsidev_open(filename) < 0) {
945 comerr("Unable to open %s\n", filename);
947 fprintf(stderr, "Unable to open %s\n", filename);
953 * Absolute sector offset, so don't subtract sector_offset here.
956 readsecs(16 + toc_offset, &ipd, ISO_BLOCKS(sizeof (ipd)));
958 lseek(fileno(infile), ((off_t)(16 + toc_offset)) <<11, SEEK_SET);
959 read(fileno(infile), &ipd, sizeof (ipd));
961 idr = (struct iso_directory_record *)ipd.root_directory_record;
966 * DESC TYPE == 1 (VD_SFS) offset 8 len 1
967 * STR ID == "CDROM" offset 9 len 5
968 * STD_VER == 1 offset 14 len 1
970 if ((((char *)&ipd)[8] == 1) &&
971 (strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) &&
972 (((char *)&ipd)[14] == 1)) {
973 printf("CD-ROM is in High Sierra format\n");
979 * DESC TYPE == 1 (VD_PVD) offset 0 len 1
980 * STR ID == "CD001" offset 1 len 5
981 * STD_VER == 1 offset 6 len 1
983 if ((ipd.type[0] != ISO_VD_PRIMARY) ||
984 (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
985 (ipd.version[0] != 1)) {
986 printf("CD-ROM is NOT in ISO 9660 format\n");
990 printf("CD-ROM is in ISO 9660 format\n");
991 printf("System id: ");
992 printchars(ipd.system_id, 32);
994 printf("Volume id: ");
995 printchars(ipd.volume_id, 32);
998 printf("Volume set id: ");
999 printchars(ipd.volume_set_id, 128);
1001 printf("Publisher id: ");
1002 printchars(ipd.publisher_id, 128);
1004 printf("Data preparer id: ");
1005 printchars(ipd.preparer_id, 128);
1007 printf("Application id: ");
1008 printchars(ipd.application_id, 128);
1011 printf("Copyright File id: ");
1012 printchars(ipd.copyright_file_id, 37);
1014 printf("Abstract File id: ");
1015 printchars(ipd.abstract_file_id, 37);
1017 printf("Bibliographic File id: ");
1018 printchars(ipd.bibliographic_file_id, 37);
1021 printf("Volume set size is: %d\n", isonum_723(ipd.volume_set_size));
1022 printf("Volume set sequence number is: %d\n", isonum_723(ipd.volume_sequence_number));
1023 printf("Logical block size is: %d\n", isonum_723(ipd.logical_block_size));
1024 printf("Volume size is: %d\n", isonum_733((unsigned char *)ipd.volume_space_size));
1029 dextent = isonum_733((unsigned char *)idr->extent);
1030 dlen = isonum_733((unsigned char *)idr->size);
1031 printf("Root directory extent: %d size: %d\n",
1033 printf("Path table size is: %d\n",
1034 isonum_733((unsigned char *)ipd.path_table_size));
1035 printf("L Path table start: %d\n",
1036 isonum_731(ipd.type_l_path_table));
1037 printf("L Path opt table start: %d\n",
1038 isonum_731(ipd.opt_type_l_path_table));
1039 printf("M Path table start: %d\n",
1040 isonum_732(ipd.type_m_path_table));
1041 printf("M Path opt table start: %d\n",
1042 isonum_732(ipd.opt_type_m_path_table));
1043 printf("Creation Date: %s\n",
1044 sdate(ipd.creation_date));
1045 printf("Modification Date: %s\n",
1046 sdate(ipd.modification_date));
1047 printf("Expiration Date: %s\n",
1048 sdate(ipd.expiration_date));
1049 printf("Effective Date: %s\n",
1050 sdate(ipd.effective_date));
1051 printf("File structure version: %d\n",
1052 ipd.file_structure_version[0]);
1056 movebytes(&ipd, &jpd, sizeof (ipd));
1057 while ((Uchar)jpd.type[0] != ISO_VD_END) {
1059 if (debug && (Uchar) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
1060 fprintf(stderr, "Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n",
1061 jpd.escape_sequences[0],
1062 jpd.escape_sequences[1],
1063 jpd.escape_sequences[2],
1064 jpd.escape_sequences[3]);
1066 * If Joliet UCS escape sequence found, we may be wrong
1068 if (jpd.escape_sequences[0] == '%' &&
1069 jpd.escape_sequences[1] == '/' &&
1070 (jpd.escape_sequences[3] == '\0' ||
1071 jpd.escape_sequences[3] == ' ') &&
1072 (jpd.escape_sequences[2] == '@' ||
1073 jpd.escape_sequences[2] == 'C' ||
1074 jpd.escape_sequences[2] == 'E')) {
1076 if (jpd.version[0] == 1)
1079 if (jpd.type[0] == 0) {
1080 movebytes(&jpd, &bpd, sizeof (bpd));
1081 if (strncmp(bpd.system_id, EL_TORITO_ID, sizeof (EL_TORITO_ID)) == 0) {
1082 bootcat_offset = (Uchar)bpd.bootcat_ptr[0] +
1083 (Uchar)bpd.bootcat_ptr[1] * 256 +
1084 (Uchar)bpd.bootcat_ptr[2] * 65536 +
1085 (Uchar)bpd.bootcat_ptr[3] * 16777216;
1086 found_eltorito = TRUE;
1087 printf("El Torito VD version %d found, boot catalog is in sector %d\n",
1092 if (jpd.version[0] == 2) {
1093 printf("CD-ROM uses ISO 9660:1999 relaxed format\n");
1100 readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
1102 lseek(fileno(infile), ((off_t)(block + toc_offset)) <<11, SEEK_SET);
1103 read(fileno(infile), &jpd, sizeof (jpd));
1111 * DESC TYPE == 1 (VD_PVD) offset 0 len 1
1112 * STR ID == "CD001" offset 1 len 5
1113 * STD_VER == 1 offset 6 len 1
1115 if ((ipd.type[0] != ISO_VD_PRIMARY) ||
1116 (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
1117 (ipd.version[0] != 1)) {
1118 printf("CD-ROM is NOT in ISO 9660 format\n");
1122 if (use_joliet || do_pvd) {
1124 movebytes(&ipd, &jpd, sizeof (ipd));
1125 while ((unsigned char) jpd.type[0] != ISO_VD_END) {
1126 if (debug && (unsigned char) jpd.type[0] == ISO_VD_SUPPLEMENTARY)
1127 fprintf(stderr, "Joliet escape sequence 0: '%c' 1: '%c' 2: '%c' 3: '%c'\n",
1128 jpd.escape_sequences[0],
1129 jpd.escape_sequences[1],
1130 jpd.escape_sequences[2],
1131 jpd.escape_sequences[3]);
1133 * Find the UCS escape sequence.
1135 if (jpd.escape_sequences[0] == '%' &&
1136 jpd.escape_sequences[1] == '/' &&
1137 (jpd.escape_sequences[3] == '\0' ||
1138 jpd.escape_sequences[3] == ' ') &&
1139 (jpd.escape_sequences[2] == '@' ||
1140 jpd.escape_sequences[2] == 'C' ||
1141 jpd.escape_sequences[2] == 'E')) {
1147 readsecs(block + toc_offset, &jpd, ISO_BLOCKS(sizeof (jpd)));
1149 lseek(fileno(infile),
1150 ((off_t)(block + toc_offset)) <<11, SEEK_SET);
1151 read(fileno(infile), &jpd, sizeof (jpd));
1155 if (use_joliet && ((unsigned char) jpd.type[0] == ISO_VD_END)) {
1156 #ifdef USE_LIBSCHILY
1157 comerrno(EX_BAD, "Unable to find Joliet SVD\n");
1159 fprintf(stderr, "Unable to find Joliet SVD\n");
1164 switch (jpd.escape_sequences[2]) {
1176 if (ucs_level > 3) {
1177 #ifdef USE_LIBSCHILY
1179 "Don't know what ucs_level == %d means\n",
1183 "Don't know what ucs_level == %d means\n",
1188 if (jpd.escape_sequences[3] == ' ')
1190 "Warning: Joliet escape sequence uses illegal space at offset 3\n");
1195 printf("Joliet with UCS level %d found\n", ucs_level);
1197 printf("NO Joliet present\n");
1199 extent = isonum_733((unsigned char *)idr->extent);
1202 readsecs(extent - sector_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
1204 lseek(fileno(infile),
1205 ((off_t)(extent - sector_offset)) <<11, SEEK_SET);
1206 read(fileno(infile), buffer, sizeof (buffer));
1208 idr = (struct iso_directory_record *) buffer;
1209 if ((c = dump_rr(idr)) != 0) {
1210 /* printf("RR %X %d\n", c, c);*/
1213 "Rock Ridge signatures version %d found\n",
1217 "Bad Rock Ridge signatures found (SU record missing)\n");
1220 * This is currently a no op!
1221 * We need to check the first plain file instead of
1222 * the '.' entry in the root directory.
1225 printf("Apple signatures version %d found\n",
1229 printf("NO Rock Ridge present\n");
1232 printf_bootinfo(infile, bootcat_offset);
1237 idr = (struct iso_directory_record *)jpd.root_directory_record;
1241 dump_pathtab(isonum_731(jpd.type_l_path_table),
1242 isonum_733((unsigned char *)jpd.path_table_size));
1244 dump_pathtab(isonum_731(ipd.type_l_path_table),
1245 isonum_733((unsigned char *)ipd.path_table_size));
1249 parse_dir("/", isonum_733((unsigned char *)idr->extent),
1250 isonum_733((unsigned char *)idr->size));
1253 parse_dir(td->name, td->extent, td->length);
1265 printf_bootinfo(FILE *f, int bootcat_offset)
1267 struct eltorito_validation_entry *evp;
1268 struct eltorito_defaultboot_entry *ebe;
1271 readsecs(bootcat_offset, buffer, ISO_BLOCKS(sizeof (buffer)));
1273 lseek(fileno(f), ((off_t)bootcat_offset) <<11, SEEK_SET);
1274 read(fileno(f), buffer, sizeof (buffer));
1277 evp = (struct eltorito_validation_entry *)buffer;
1278 ebe = (struct eltorito_defaultboot_entry *)&buffer[32];
1280 printf("Eltorito validation header:\n");
1281 printf(" Hid %d\n", (Uchar)evp->headerid[0]);
1282 printf(" Arch %d (%s)\n", (Uchar)evp->arch[0], arch_name((Uchar)evp->arch[0]));
1283 printf(" ID '%.23s'\n", evp->id);
1284 printf(" Key %X %X\n", (Uchar)evp->key1[0], (Uchar)evp->key2[0]);
1286 printf(" Eltorito defaultboot header:\n");
1287 printf(" Bootid %X (%s)\n", (Uchar)ebe->boot_id[0], boot_name((Uchar)ebe->boot_id[0]));
1288 printf(" Boot media %X (%s)\n", (Uchar)ebe->boot_media[0], bootmedia_name((Uchar)ebe->boot_media[0]));
1289 printf(" Load segment %X\n", la_to_2_byte(ebe->loadseg));
1290 printf(" Sys type %X\n", (Uchar)ebe->sys_type[0]);
1291 printf(" Nsect %X\n", la_to_2_byte(ebe->nsect));
1292 printf(" Bootoff %lX %ld\n", la_to_4_byte(ebe->bootoff), la_to_4_byte(ebe->bootoff));
1301 case EL_TORITO_ARCH_x86:
1303 case EL_TORITO_ARCH_PPC:
1305 case EL_TORITO_ARCH_MAC:
1308 return ("Unknown Arch");
1317 case EL_TORITO_BOOTABLE:
1318 return ("bootable");
1319 case EL_TORITO_NOT_BOOTABLE:
1320 return ("not bootable");
1327 bootmedia_name(int val)
1331 case EL_TORITO_MEDIA_NOEMUL:
1332 return ("No Emulation Boot");
1333 case EL_TORITO_MEDIA_12FLOP:
1334 return ("1200 Floppy");
1335 case EL_TORITO_MEDIA_144FLOP:
1336 return ("1.44MB Floppy");
1337 case EL_TORITO_MEDIA_288FLOP:
1338 return ("2.88MB Floppy");
1339 case EL_TORITO_MEDIA_HD:
1340 return ("Hard Disk Emulation");
1342 return ("Illegal Bootmedia");