File indexing completed on 2024-05-19 16:52:41

0001 /*
0002     SPDX-FileCopyrightText: 2002 Szombathelyi György <gyurco@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "isofs.h"
0009 
0010 #include <errno.h>
0011 #include <string.h>
0012 
0013 #include "iso_fs.h"
0014 
0015 /* internal function from the linux kernel (isofs fs) */
0016 static time_t getisotime(int year, int month, int day, int hour,
0017                          int minute, int second, int tz)
0018 {
0019 
0020     int days, i;
0021     time_t crtime;
0022 
0023     year -= 1970;
0024 
0025     if (year < 0) {
0026         crtime = 0;
0027     } else {
0028         int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
0029 
0030         days = year * 365;
0031         if (year > 2)
0032             days += (year + 1) / 4;
0033         for (i = 1; i < month; i++)
0034             days += monlen[i-1];
0035         if (((year + 2) % 4) == 0 && month > 2)
0036             days++;
0037         days += day - 1;
0038         crtime = ((((days * 24) + hour) * 60 + minute) * 60)
0039                  + second;
0040 
0041         /* sign extend */
0042         if (tz & 0x80)
0043             tz |= (-1 << 8);
0044 
0045         /*
0046          * The timezone offset is unreliable on some disks,
0047          * so we make a sanity check.  In no case is it ever
0048          * more than 13 hours from GMT, which is 52*15min.
0049          * The time is always stored in localtime with the
0050          * timezone offset being what get added to GMT to
0051          * get to localtime.  Thus we need to subtract the offset
0052          * to get to true GMT, which is what we store the time
0053          * as internally.  On the local system, the user may set
0054          * their timezone any way they wish, of course, so GMT
0055          * gets converted back to localtime on the receiving
0056          * system.
0057          *
0058          * NOTE: mkisofs in versions prior to mkisofs-1.10 had
0059          * the sign wrong on the timezone offset.  This has now
0060          * been corrected there too, but if you are getting screwy
0061          * results this may be the explanation.  If enough people
0062          * complain, a user configuration option could be added
0063          * to add the timezone offset in with the wrong sign
0064          * for 'compatibility' with older discs, but I cannot see how
0065          * it will matter that much.
0066          *
0067          * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
0068          * for pointing out the sign error.
0069          */
0070         if (-52 <= tz && tz <= 52)
0071             crtime -= tz * 15 * 60;
0072     }
0073     return crtime;
0074 
0075 }
0076 
0077 /**
0078  * Returns the Unix from the ISO9660 9.1.5 time format
0079  */
0080 time_t isodate_915(char * p, int hs)
0081 {
0082 
0083     return getisotime(1900 + p[0], p[1], p[2], p[3], p[4], p[5], hs == 0 ? p[6] : 0);
0084 }
0085 
0086 /**
0087  * Returns the Unix from the ISO9660 8.4.26.1 time format
0088  * BUG: hundredth of seconds are ignored, because Unix time_t has one second
0089  * resolution (I think it's no problem at all)
0090  */
0091 time_t isodate_84261(char * p, int hs)
0092 {
0093     int year, month, day, hour, minute, second;
0094     year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
0095     month = (p[4] - '0') * 10 + (p[5] - '0');
0096     day = (p[6] - '0') * 10 + (p[7] - '0');
0097     hour = (p[8] - '0') * 10 + (p[9] - '0');
0098     minute = (p[10] - '0') * 10 + (p[11] - '0');
0099     second = (p[12] - '0') * 10 + (p[13] - '0');
0100     return getisotime(year, month, day, hour, minute, second, hs == 0 ? p[16] : 0);
0101 }
0102 
0103 void FreeBootTable(boot_head *boot)
0104 {
0105     boot_entry *be, *next;
0106 
0107     be = boot->defentry;
0108     while (be) {
0109         next = be->next;
0110         free(be);
0111         be = next;
0112     }
0113     boot->defentry = NULL;
0114 }
0115 
0116 long long BootImageSize(int media, unsigned int len)
0117 {
0118     long long ret;
0119 
0120     switch (media & 0xf) {
0121     case 0:
0122         ret = len; /* No emulation */
0123         break;
0124     case 1:
0125         ret = 80 * 2 * 15; /* 1.2 MB */
0126         break;
0127     case 2:
0128         ret = 80 * 2 * 18; /* 1.44 MB */
0129         break;
0130     case 3:
0131         ret = 80 * 2 * 36; /* 2.88 MB */
0132         break;
0133     case 4:
0134         /* FIXME!!! */
0135         ret = len; /* Hard Disk */
0136         break;
0137     default:
0138         ret = len;
0139     }
0140     return ret;
0141 }
0142 
0143 static boot_entry *CreateBootEntry(char *be)
0144 {
0145     boot_entry *entry;
0146 
0147     entry = (boot_entry*) malloc(sizeof(boot_entry));
0148     if (!entry) return NULL;
0149     memset(entry, 0, sizeof(boot_entry));
0150     memcpy(&(entry->data), be, sizeof(entry->data));
0151     return entry;
0152 }
0153 
0154 int ReadBootTable(readfunc *read, unsigned int sector, boot_head *head, void *udata)
0155 {
0156 
0157     char buf[2048], *c, *be;
0158     int i, end = 0;
0159     unsigned short sum;
0160     boot_entry *defcur = NULL, *deflast = NULL;
0161     register struct validation_entry *ventry = NULL;
0162 
0163     head->sections = NULL;
0164     head->defentry = NULL;
0165     while (1) {
0166         be = (char*) & buf;
0167         if (read(be, sector, 1, udata) != 1) goto err;
0168 
0169         /* first entry needs to be a validation entry */
0170         if (!ventry) {
0171             ventry = (struct validation_entry *) be;
0172             if (isonum_711(ventry->type) != 1) goto err;
0173             sum = 0;
0174             c = (char*) ventry;
0175             for (i = 0;i < 16;i++) {
0176                 sum += isonum_721(c); c += 2;
0177             }
0178             if (sum) goto err;
0179             memcpy(&head->ventry, be, 0x20);
0180             be += 0x20;
0181         }
0182 
0183         while (!end && (be < (char *)(&buf + 1))) {
0184             switch (isonum_711(be)) {
0185             case 0x88:
0186                 defcur = CreateBootEntry(be);
0187                 if (!defcur) goto err;
0188                 if (deflast)
0189                     deflast->next = defcur;
0190                 else
0191                     head->defentry = defcur;
0192                 defcur->prev = deflast;
0193                 deflast = defcur;
0194                 break;
0195             case 0x90:
0196             case 0x91:
0197                 break;
0198             default:
0199                 end = 1;
0200                 break;
0201             }
0202             be += 0x20;
0203         }
0204         if (end) break;
0205 
0206         sector ++;
0207     }
0208 
0209     return 0;
0210 
0211 err:
0212     FreeBootTable(head);
0213     return -1;
0214 }
0215 
0216 
0217 /**
0218  * Creates the linked list of the volume descriptors
0219  */
0220 iso_vol_desc *ReadISO9660(readfunc *read, unsigned int sector, void *udata)
0221 {
0222 
0223     int i;
0224     struct iso_volume_descriptor buf;
0225     iso_vol_desc *first = NULL, *current = NULL, *prev = NULL;
0226 
0227     for (i = 0;i < 100;i++) {
0228         if (read((char*) &buf, sector + i + 16, 1, udata) != 1) {
0229             FreeISO9660(first);
0230             return NULL;
0231         }
0232         if (!memcmp(ISO_STANDARD_ID, &buf.id, 5)) {
0233             switch (isonum_711(&buf.type[0])) {
0234 
0235             case ISO_VD_BOOT:
0236             case ISO_VD_PRIMARY:
0237             case ISO_VD_SUPPLEMENTARY:
0238                 current = (iso_vol_desc*) malloc(sizeof(iso_vol_desc));
0239                 if (!current) {
0240                     FreeISO9660(first);
0241                     return NULL;
0242                 }
0243                 current->prev = prev;
0244                 current->next = NULL;
0245                 if (prev) prev->next = current;
0246                 memcpy(&(current->data), &buf, 2048);
0247                 if (!first) first = current;
0248                 prev = current;
0249                 break;
0250 
0251             case ISO_VD_END:
0252                 return first;
0253                 break;
0254             }
0255         } else if (!memcmp(HS_STANDARD_ID, (struct hs_volume_descriptor*) &buf, 5)) {
0256             /* High Sierra format not supported (yet) */
0257         }
0258     }
0259 
0260     return first;
0261 }
0262 
0263 /**
0264  * Frees the linked list of volume descriptors
0265  */
0266 void FreeISO9660(iso_vol_desc *data)
0267 {
0268 
0269     iso_vol_desc *current;
0270 
0271 
0272     while (data) {
0273         current = data;
0274         data = current->next;
0275         free(current);
0276     }
0277 }
0278 
0279 /**
0280  * Frees the strings in 'rrentry'
0281  */
0282 void FreeRR(rr_entry *rrentry)
0283 {
0284     if (rrentry->name) {
0285         free(rrentry->name);
0286         rrentry->name = NULL;
0287     }
0288     if (rrentry->sl) {
0289         free(rrentry->sl);
0290         rrentry->sl = NULL;
0291     }
0292 }
0293 
0294 static int str_nappend(char **d, char *s, int n)
0295 {
0296     int i = 0;
0297     char *c;
0298 
0299     /* i=strnlen(s,n)+1; */
0300     while (i < n && s[i]) i++;
0301     i++;
0302     if (*d) i += (strlen(*d) + 1);
0303     c = (char*) malloc(i);
0304     if (!c) return -ENOMEM;
0305     if (*d) {
0306         strcpy(c, *d);
0307         strncat(c, s, n);
0308 
0309         free(*d);
0310     } else
0311         strncpy(c, s, n);
0312     c[i-1] = 0;
0313     *d = c;
0314     return 0;
0315 }
0316 
0317 static int str_append(char **d, char *s)
0318 {
0319     int i;
0320     char *c;
0321 
0322     i = strlen(s) + 1;
0323     if (*d) i += (strlen(*d) + 1);
0324     c = (char*) malloc(i);
0325     if (!c) return -ENOMEM;
0326     if (*d) {
0327         strcpy(c, *d);
0328         strcat(c, s);
0329         free(*d);
0330     } else
0331         strcpy(c, s);
0332     c[i-1] = 0;
0333     *d = c;
0334     return 0;
0335 }
0336 
0337 #define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
0338 #define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
0339 /**
0340  * Parses the System Use area and fills rr_entry with values
0341  */
0342 int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry)
0343 {
0344 
0345     int suspoffs, susplen, i, f, ret = 0;
0346     char *r, *c;
0347     struct rock_ridge *rr;
0348 
0349     suspoffs = 33 + isonum_711(idr->name_len);
0350     if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
0351     susplen = isonum_711(idr->length) - suspoffs;
0352     r = & (((char*) idr)[suspoffs]);
0353     rr = (struct rock_ridge*) r;
0354 
0355     memset(rrentry, 0, sizeof(rr_entry));
0356     rrentry->len = sizeof(rr_entry);
0357 
0358     while (susplen > 0) {
0359         if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
0360         if (rr->signature[0] == 'N' && rr->signature[1] == 'M') {
0361             if (!(rr->u.NM.flags & 0x26) && rr->len > 5 && !rrentry->name) {
0362 
0363                 if (str_nappend(&rrentry->name, rr->u.NM.name, isonum_711(&rr->len) - 5)) {
0364                     FreeRR(rrentry); return -ENOMEM;
0365                 }
0366                 ret++;
0367             }
0368         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'X' &&
0369                    (isonum_711(&rr->len) == 44 || isonum_711(&rr->len) == 36)) {
0370             rrentry->mode = isonum_733(rr->u.PX.mode);
0371             rrentry->nlink = isonum_733(rr->u.PX.n_links);
0372             rrentry->uid = isonum_733(rr->u.PX.uid);
0373             rrentry->gid = isonum_733(rr->u.PX.gid);
0374             if (isonum_711(&rr->len) == 44) rrentry->serno = isonum_733(rr->u.PX.serno);
0375             ret++;
0376         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'N' &&
0377                    isonum_711(&rr->len) == 20) {
0378             rrentry->dev_major = isonum_733(rr->u.PN.dev_high);
0379             rrentry->dev_minor = isonum_733(rr->u.PN.dev_low);
0380             ret++;
0381         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'L' &&
0382                    isonum_711(&rr->len) == 12) {
0383             rrentry->pl = isonum_733(rr->u.PL.location);
0384             ret++;
0385         } else if (rr->signature[0] == 'C' && rr->signature[1] == 'L' &&
0386                    isonum_711(&rr->len) == 12) {
0387             rrentry->cl = isonum_733(rr->u.CL.location);
0388             ret++;
0389         } else if (rr->signature[0] == 'R' && rr->signature[1] == 'E' &&
0390                    isonum_711(&rr->len) == 4) {
0391             rrentry->re = 1;
0392             ret++;
0393         } else if (rr->signature[0] == 'S' && rr->signature[1] == 'L' &&
0394                    isonum_711(&rr->len) > 7) {
0395             i = isonum_711(&rr->len) - 5;
0396             c = (char*) rr;
0397             c += 5;
0398             while (i > 0) {
0399                 switch (c[0] & ~1) {
0400                 case 0x2:
0401                     if (str_append(&rrentry->sl, (char *)".")) {
0402                         FreeRR(rrentry); return -ENOMEM;
0403                     }
0404                     break;
0405                 case 0x4:
0406                     if (str_append(&rrentry->sl, (char *)"..")) {
0407                         FreeRR(rrentry); return -ENOMEM;
0408                     }
0409                     break;
0410                 }
0411                 if ((c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
0412                                               strlen(rrentry->sl) > 1)) {
0413                     if (str_append(&rrentry->sl, (char *) DIR_SEPARATOR)) {
0414                         FreeRR(rrentry); return -ENOMEM;
0415                     }
0416                 }
0417 
0418                 if ((unsigned char)c[1] > 0) {
0419                     if (str_nappend(&rrentry->sl, c + 2, (unsigned char)c[1])) {
0420                         FreeRR(rrentry); return -ENOMEM;
0421                     }
0422                 }
0423                 i -= ((unsigned char)c[1] + 2);
0424                 c += ((unsigned char)c[1] + 2);
0425             }
0426             ret++;
0427         } else if (rr->signature[0] == 'T' && rr->signature[1] == 'F' &&
0428                    isonum_711(&rr->len) > 5) {
0429 
0430             i = isonum_711(&rr->len) - 5;
0431             f = rr->u.TF.flags;
0432             c = (char*) rr;
0433             c += 5;
0434 
0435             while (i >= rrtlen(f)) {
0436                 if (f & 1) {
0437                     rrentry->t_creat = rrctime(f, c);
0438                     f &= ~1;
0439                 } else if (f & 2) {
0440                     rrentry->t_mtime = rrctime(f, c);
0441                     f &= ~2;
0442                 } else if (f & 4) {
0443                     rrentry->t_atime = rrctime(f, c);
0444                     f &= ~4;
0445                 } else if (f & 8) {
0446                     rrentry->t_ctime = rrctime(f, c);
0447                     f &= ~8;
0448                 } else if (f & 16) {
0449                     rrentry->t_backup = rrctime(f, c);
0450                     f &= ~16;
0451                 } else if (f & 32) {
0452                     rrentry->t_expire = rrctime(f, c);
0453                     f &= ~32;
0454                 } else if (f & 64) {
0455                     rrentry->t_effect = rrctime(f, c);
0456                     f &= ~64;
0457                 }
0458 
0459                 i -= rrtlen(f);
0460                 c += rrtlen(f);
0461             }
0462             ret++;
0463 
0464         } else if (rr->signature[0] == 'Z' && rr->signature[1] == 'F' &&
0465                    isonum_711(&rr->len) == 16) {
0466             /* Linux-specific extension: transparent decompression */
0467             rrentry->z_algo[0] = rr->u.ZF.algorithm[0];
0468             rrentry->z_algo[1] = rr->u.ZF.algorithm[1];
0469             rrentry->z_params[0] = rr->u.ZF.parms[0];
0470             rrentry->z_params[1] = rr->u.ZF.parms[1];
0471             rrentry->z_size = isonum_733(rr->u.ZF.real_size);
0472             ret++;
0473         } else {
0474             /*   printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */
0475         }
0476 
0477         susplen -= isonum_711(&rr->len);
0478         r += isonum_711(&rr->len);
0479         rr = (struct rock_ridge*) r;
0480     }
0481 
0482     return ret;
0483 }
0484 
0485 /**
0486  * Iterates over the directory entries. The directory is in 'buf',
0487  * the size of the directory is 'size'. 'callback' is called for each
0488  * directory entry with the parameter 'udata'.
0489  */
0490 int ProcessDir(readfunc *read, int extent, int size, dircallback *callback, void *udata)
0491 {
0492 
0493     int pos = 0, ret = 0, siz;
0494     char *buf;
0495     struct iso_directory_record *idr;
0496 
0497     if (size & 2047) {
0498         siz = ((size >> 11) + 1) << 11;
0499     } else {
0500         siz = size;
0501     }
0502 
0503     buf = (char*) malloc(siz);
0504     if (!buf) return -ENOMEM;
0505     if (read(buf, extent, siz >> 11, udata) != siz >> 11) {
0506         free(buf);
0507         return -EIO;
0508     }
0509 
0510     while (size > 0) {
0511         idr = (struct iso_directory_record*) & buf[pos];
0512         if (isonum_711(idr->length) == 0) {
0513 
0514             size -= (2048 - (pos & 0x7ff));
0515             if (size <= 2) break;
0516             pos += 0x800;
0517             pos &= 0xfffff800;
0518             idr = (struct iso_directory_record*) & buf[pos];
0519         }
0520         pos += isonum_711(idr->length);
0521         pos += isonum_711(idr->ext_attr_length);
0522         size -= isonum_711(idr->length);
0523         size -= isonum_711(idr->ext_attr_length);
0524         if (size < 0) break;
0525 
0526         if (isonum_711(idr->length)
0527                 < 33 ||
0528                 isonum_711(idr->length) < 33 + isonum_711(idr->name_len)) {
0529             /* Invalid directory entry */
0530             continue;
0531         }
0532         if ((ret = callback(idr, udata))) break;
0533     }
0534 
0535     free(buf);
0536     return ret;
0537 }
0538 
0539 /**
0540  * returns the joliet level from the volume descriptor
0541  */
0542 int JolietLevel(struct iso_volume_descriptor *ivd)
0543 {
0544     int ret = 0;
0545     register struct iso_supplementary_descriptor *isd;
0546 
0547     isd = (struct iso_supplementary_descriptor *) ivd;
0548 
0549     if (isonum_711(ivd->type) == ISO_VD_SUPPLEMENTARY) {
0550         if (isd->escape[0] == 0x25 &&
0551                 isd->escape[1] == 0x2f) {
0552 
0553             switch (isd->escape[2]) {
0554             case 0x40:
0555                 ret = 1;
0556                 break;
0557             case 0x43:
0558                 ret = 2;
0559                 break;
0560             case 0x45:
0561                 ret = 3;
0562                 break;
0563             }
0564         }
0565     }
0566     return ret;
0567 }
0568 
0569 /********************************************************************/
0570 #ifdef ISOFS_MAIN
0571 
0572 #include <time.h>
0573 #include <fcntl.h>
0574 #include <stdio.h>
0575 #include <unistd.h>
0576 #include <sys/types.h>
0577 #include <sys/stat.h>
0578 #include <iconv.h>
0579 
0580 int level = 0, joliet = 0, dirs, files;
0581 iconv_t iconv_d;
0582 int fd;
0583 
0584 int readf(char *buf, unsigned int start, unsigned int len, void *udata)
0585 {
0586     int ret;
0587 
0588     if ((ret = lseek64(fd, (long long)start << (long long)11, SEEK_SET)) < 0) return ret;
0589     ret = read(fd, buf, len << 11u);
0590     if (ret < 0) return ret;
0591     return (ret >> 11u);
0592 }
0593 
0594 void dumpchars(char *c, int len)
0595 {
0596     while (len > 0) {
0597         printf("%c", *c);
0598         len--;
0599         c++;
0600     }
0601 }
0602 
0603 void sp(int num)
0604 {
0605     int i;
0606     for (i = 0;i < num*5;i++) {
0607         printf(" ");
0608     };
0609 }
0610 
0611 void dumpflags(char flags)
0612 {
0613     if (flags & 1) printf("HIDDEN ");
0614     if (flags & 2) printf("DIR ");
0615     if (flags & 4) printf("ASF ");
0616 }
0617 
0618 void dumpjoliet(char *c, int len)
0619 {
0620 
0621     char outbuf[255];
0622     size_t out;
0623     int ret;
0624     char *outptr;
0625 
0626     outptr = (char*) & outbuf;
0627     out = 255;
0628     if ((iconv(iconv_d, &c, &len, &outptr, &out)) < 0) {
0629         printf("conversion error=%d", errno);
0630         return;
0631     }
0632     ret = 255 - out;
0633     dumpchars((char*) &outbuf, ret);
0634 }
0635 
0636 void dumpchardesc(char *c, int len)
0637 {
0638 
0639     if (joliet)
0640         dumpjoliet(c, len);
0641     else {
0642         dumpchars(c, len);
0643     }
0644 }
0645 
0646 void dumpiso915time(char *t, int hs)
0647 {
0648 
0649     time_t time;
0650     char *c;
0651 
0652     time = isodate_915(t, hs);
0653     c = (char*) ctime(&time);
0654     if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
0655     if (c) printf("%s", c);
0656 }
0657 
0658 void dumpiso84261time(char *t, int hs)
0659 {
0660 
0661     time_t time;
0662     char *c;
0663 
0664     time = isodate_84261(t, hs);
0665     c = (char*) ctime(&time);
0666     if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
0667     if (c) printf("%s", c);
0668 }
0669 
0670 void dumpdirrec(struct iso_directory_record *dir)
0671 {
0672 
0673     if (isonum_711(dir->name_len) == 1) {
0674         switch (dir->name[0]) {
0675         case 0:
0676             printf(".");
0677             break;
0678         case 1:
0679             printf("..");
0680             break;
0681         default:
0682             printf("%c", dir->name[0]);
0683             break;
0684         }
0685     }
0686     dumpchardesc(dir->name, isonum_711(dir->name_len));
0687     printf(" size=%d", isonum_733(dir->size));
0688     printf(" extent=%d ", isonum_733(dir->extent));
0689     dumpflags(isonum_711(dir->flags));
0690     dumpiso915time((char*) &(dir->date), 0);
0691 }
0692 
0693 void dumprrentry(rr_entry *rr)
0694 {
0695     printf("  NM=[%s] uid=%d gid=%d nlink=%d mode=%o ",
0696            rr->name, rr->uid, rr->gid, rr->nlink, rr->mode);
0697     if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode))
0698         printf("major=%d minor=%d ", rr->dev_major, rr->dev_minor);
0699     if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ", rr->sl);
0700     /*
0701      printf("\n");
0702      if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat));
0703      if (rr->st_mtime) printf("st_mtime: %s",ctime(&rr->st_mtime));
0704      if (rr->st_atime) printf("st_atime: %s",ctime(&rr->st_atime));
0705      if (rr->st_ctime) printf("st_ctime: %s",ctime(&rr->st_ctime));
0706      if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup));
0707      if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire));
0708      if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect));
0709     */
0710 }
0711 
0712 void dumpsusp(char *c, int len)
0713 {
0714     dumpchars(c, len);
0715 }
0716 
0717 void dumpboot(struct el_torito_boot_descriptor *ebd)
0718 {
0719     printf("version: %d\n", isonum_711(ebd->version));
0720     printf("system id: ");dumpchars(ebd->system_id, ISODCL(8, 39));printf("\n");
0721     printf("boot catalog start: %d\n", isonum_731(ebd->boot_catalog));
0722 }
0723 
0724 void dumpdefentry(struct default_entry *de)
0725 {
0726     printf("Default entry: \n");
0727     printf("  bootid=%x\n", isonum_711(de->bootid));
0728     printf("  media emulation=%d (", isonum_711(de->media));
0729     switch (isonum_711(de->media) & 0xf) {
0730     case 0:
0731         printf("No emulation");
0732         break;
0733     case 1:
0734         printf("1.2 Mb floppy");
0735         break;
0736     case 2:
0737         printf("1.44 Mb floppy");
0738         break;
0739     case 3:
0740         printf("2.88 Mb floppy");
0741         break;
0742     case 4:
0743         printf("Hard Disk");
0744         break;
0745     default:
0746         printf("Unknown/Invalid");
0747         break;
0748     }
0749     printf(")\n");
0750     printf("  loadseg=%d\n", isonum_721(de->loadseg));
0751     printf("  systype=%d\n", isonum_711(de->systype));
0752     printf("  start lba=%d count=%d\n", isonum_731(de->start),
0753            isonum_721(de->seccount));
0754 }
0755 
0756 void dumpbootcat(boot_head *bh)
0757 {
0758     boot_entry *be;
0759 
0760     printf("System id: ");dumpchars(bh->ventry.id, ISODCL(28, 5));printf("\n");
0761     be = bh->defentry;
0762     while (be) {
0763         dumpdefentry(be->data);
0764         be = be->next;
0765     }
0766 }
0767 
0768 void dumpdesc(struct iso_primary_descriptor *ipd)
0769 {
0770 
0771     printf("system id: ");dumpchardesc(ipd->system_id, ISODCL(9, 40));printf("\n");
0772     printf("volume id: ");dumpchardesc(ipd->volume_id, ISODCL(41, 72));printf("\n");
0773     printf("volume space size: %d\n", isonum_733(ipd->volume_space_size));
0774     printf("volume set size: %d\n", isonum_723(ipd->volume_set_size));
0775     printf("volume seq num: %d\n", isonum_723(ipd->volume_set_size));
0776     printf("logical block size: %d\n", isonum_723(ipd->logical_block_size));
0777     printf("path table size: %d\n", isonum_733(ipd->path_table_size));
0778     printf("location of type_l path table: %d\n", isonum_731(ipd->type_l_path_table));
0779     printf("location of optional type_l path table: %d\n", isonum_731(ipd->opt_type_l_path_table));
0780     printf("location of type_m path table: %d\n", isonum_732(ipd->type_m_path_table));
0781     printf("location of optional type_m path table: %d\n", isonum_732(ipd->opt_type_m_path_table));
0782     /*
0783      printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record);
0784     */
0785     printf("Volume set id: ");dumpchardesc(ipd->volume_set_id, ISODCL(191, 318));printf("\n");
0786     printf("Publisher id: ");dumpchardesc(ipd->publisher_id, ISODCL(319, 446));printf("\n");
0787     printf("Preparer id: ");dumpchardesc(ipd->preparer_id, ISODCL(447, 574));printf("\n");
0788     printf("Application id: ");dumpchardesc(ipd->application_id, ISODCL(575, 702));printf("\n");
0789     printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id, ISODCL(703, 739));printf("\n");
0790     printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id, ISODCL(740, 776));printf("\n");
0791     printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id, ISODCL(777, 813));printf("\n");
0792     printf("Volume creation date: ");dumpiso84261time(ipd->creation_date, 0);printf("\n");
0793     printf("Volume modification date: ");dumpiso84261time(ipd->modification_date, 0);printf("\n");
0794     printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date, 0);printf("\n");
0795     printf("Volume effective date: ");dumpiso84261time(ipd->effective_date, 0);printf("\n");
0796     printf("File structure version: %d\n", isonum_711(ipd->file_structure_version));
0797 }
0798 
0799 int mycallb(struct iso_directory_record *idr, void *udata)
0800 {
0801     rr_entry rrentry;
0802 
0803     sp(level);dumpdirrec(idr);
0804     if (level == 0) printf(" (Root directory) ");
0805     printf("\n");
0806 
0807     if (ParseRR(idr, &rrentry) > 0) {
0808         sp(level);printf("  ");dumprrentry(&rrentry);printf("\n");
0809     }
0810     FreeRR(&rrentry);
0811     if (!(idr->flags[0] & 2)) files++;
0812     if ((idr->flags[0] & 2) && (level == 0 || isonum_711(idr->name_len) > 1)) {
0813         level++;
0814         dirs++;
0815         ProcessDir(&readf, isonum_733(idr->extent), isonum_733(idr->size), &mycallb, udata);
0816         level--;
0817     }
0818     return 0;
0819 }
0820 
0821 /************************************************/
0822 
0823 int main(int argc, char *argv[])
0824 {
0825 
0826     int i = 1, sector = 0;
0827     iso_vol_desc *desc;
0828     boot_head boot;
0829 
0830     if (argc < 2) {
0831         fprintf(stderr, "\nUsage: %s iso-file-name or device [starting sector]\n\n", argv[0]);
0832         return 0;
0833     }
0834     if (argc >= 3) {
0835         sector = atoi(argv[2]);
0836         printf("Using starting sector number %d\n", sector);
0837     }
0838     fd = open(argv[1], O_RDONLY);
0839     if (fd < 0) {
0840         fprintf(stderr, "open error\n");
0841         return -1;
0842     }
0843     iconv_d = iconv_open("ISO8859-2", "UTF16BE");
0844     if (iconv_d == 0) {
0845         fprintf(stderr, "iconv open error\n");
0846         return -1;
0847     }
0848 
0849     desc = ReadISO9660(&readf, sector, NULL);
0850     if (!desc) {
0851         printf("No volume descriptors\n");
0852         return -1;
0853     }
0854     while (desc) {
0855 
0856         printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n",
0857                i, isonum_711(desc->data.type));
0858         switch (isonum_711(desc->data.type)) {
0859         case ISO_VD_BOOT: {
0860 
0861             struct el_torito_boot_descriptor* bootdesc;
0862             bootdesc = &(desc->data);
0863             dumpboot(bootdesc);
0864             if (!memcmp(EL_TORITO_ID, bootdesc->system_id, ISODCL(8, 39))) {
0865 
0866                 if (ReadBootTable(&readf, isonum_731(bootdesc->boot_catalog), &boot, NULL)) {
0867                     printf("Boot Catalog Error\n");
0868                 } else {
0869                     dumpbootcat(&boot);
0870                     FreeBootTable(&boot);
0871                 }
0872             }
0873         }
0874         break;
0875 
0876         case ISO_VD_PRIMARY:
0877         case ISO_VD_SUPPLEMENTARY:
0878             joliet = 0;
0879             joliet = JolietLevel(&desc->data);
0880             printf("Joliet level: %d\n", joliet);
0881             dumpdesc((struct iso_primary_descriptor*) &desc->data);
0882             printf("\n\n--------------- Directory structure: -------------------\n\n");
0883             dirs = 0;files = 0;
0884             mycallb(&(((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL);
0885             printf("\nnumber of directories: %d\n", dirs);
0886             printf("\nnumber of files: %d\n", files);
0887             break;
0888 
0889         }
0890         desc = desc->next;
0891         i++;
0892     }
0893     iconv_close(iconv_d);
0894     close(fd);
0895     FreeISO9660(desc);
0896     return 0;
0897 }
0898 
0899 #endif /* ISOFS_MAIN */