1 /*****************************************************************************
2  * Copyright (C) 2002 Szombathelyi György <gyurco@users.sourceforge.net>     *
3  * Copyright (C) 2004-2019 Krusader Krew [https://krusader.org]              *
4  *                                                                           *
5  * This program is free software; you can redistribute it and/or modify      *
6  * it under the terms of the GNU General Public License as published by      *
7  * the Free Software Foundation; either version 2 of the License, or         *
8  * (at your option) any later version.                                       *
9  *                                                                           *
10  * This package is distributed in the hope that it will be useful,           *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
13  * GNU General Public License for more details.                              *
14  *                                                                           *
15  * You should have received a copy of the GNU General Public License         *
16  * along with this package; if not, write to the Free Software               *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA *
18  *****************************************************************************/
19 
20 #include "isofs.h"
21 
22 #include <errno.h>
23 #include <string.h>
24 
25 #include "iso_fs.h"
26 
27 /**************************************************************/
28 
29 
30 /* internal function from the linux kernel (isofs fs) */
getisotime(int year,int month,int day,int hour,int minute,int second,int tz)31 static time_t getisotime(int year, int month, int day, int hour,
32                          int minute, int second, int tz)
33 {
34 
35     int days, i;
36     time_t crtime;
37 
38     year -= 1970;
39 
40     if (year < 0) {
41         crtime = 0;
42     } else {
43         int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
44 
45         days = year * 365;
46         if (year > 2)
47             days += (year + 1) / 4;
48         for (i = 1; i < month; i++)
49             days += monlen[i-1];
50         if (((year + 2) % 4) == 0 && month > 2)
51             days++;
52         days += day - 1;
53         crtime = ((((days * 24) + hour) * 60 + minute) * 60)
54                  + second;
55 
56         /* sign extend */
57         if (tz & 0x80)
58             tz |= (-1 << 8);
59 
60         /*
61          * The timezone offset is unreliable on some disks,
62          * so we make a sanity check.  In no case is it ever
63          * more than 13 hours from GMT, which is 52*15min.
64          * The time is always stored in localtime with the
65          * timezone offset being what get added to GMT to
66          * get to localtime.  Thus we need to subtract the offset
67          * to get to true GMT, which is what we store the time
68          * as internally.  On the local system, the user may set
69          * their timezone any way they wish, of course, so GMT
70          * gets converted back to localtime on the receiving
71          * system.
72          *
73          * NOTE: mkisofs in versions prior to mkisofs-1.10 had
74          * the sign wrong on the timezone offset.  This has now
75          * been corrected there too, but if you are getting screwy
76          * results this may be the explanation.  If enough people
77          * complain, a user configuration option could be added
78          * to add the timezone offset in with the wrong sign
79          * for 'compatibility' with older discs, but I cannot see how
80          * it will matter that much.
81          *
82          * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
83          * for pointing out the sign error.
84          */
85         if (-52 <= tz && tz <= 52)
86             crtime -= tz * 15 * 60;
87     }
88     return crtime;
89 
90 }
91 
92 /**
93  * Returns the Unix from the ISO9660 9.1.5 time format
94  */
isodate_915(char * p,int hs)95 time_t isodate_915(char * p, int hs)
96 {
97 
98     return getisotime(1900 + p[0], p[1], p[2], p[3], p[4], p[5], hs == 0 ? p[6] : 0);
99 }
100 
101 /**
102  * Returns the Unix from the ISO9660 8.4.26.1 time format
103  * BUG: hundredth of seconds are ignored, because Unix time_t has one second
104  * resolution (I think it's no problem at all)
105  */
isodate_84261(char * p,int hs)106 time_t isodate_84261(char * p, int hs)
107 {
108     int year, month, day, hour, minute, second;
109     year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
110     month = (p[4] - '0') * 10 + (p[5] - '0');
111     day = (p[6] - '0') * 10 + (p[7] - '0');
112     hour = (p[8] - '0') * 10 + (p[9] - '0');
113     minute = (p[10] - '0') * 10 + (p[11] - '0');
114     second = (p[12] - '0') * 10 + (p[13] - '0');
115     return getisotime(year, month, day, hour, minute, second, hs == 0 ? p[16] : 0);
116 }
117 
FreeBootTable(boot_head * boot)118 void FreeBootTable(boot_head *boot)
119 {
120     boot_entry *be, *next;
121 
122     be = boot->defentry;
123     while (be) {
124         next = be->next;
125         free(be);
126         be = next;
127     }
128     boot->defentry = NULL;
129 }
130 
BootImageSize(int media,unsigned int len)131 long long BootImageSize(int media, unsigned int len)
132 {
133     long long ret;
134 
135     switch (media & 0xf) {
136     case 0:
137         ret = len; /* No emulation */
138         break;
139     case 1:
140         ret = 80 * 2 * 15; /* 1.2 MB */
141         break;
142     case 2:
143         ret = 80 * 2 * 18; /* 1.44 MB */
144         break;
145     case 3:
146         ret = 80 * 2 * 36; /* 2.88 MB */
147         break;
148     case 4:
149         /* FIXME!!! */
150         ret = len; /* Hard Disk */
151         break;
152     default:
153         ret = len;
154     }
155     return ret;
156 }
157 
CreateBootEntry(char * be)158 static boot_entry *CreateBootEntry(char *be)
159 {
160     boot_entry *entry;
161 
162     entry = (boot_entry*) malloc(sizeof(boot_entry));
163     if (!entry) return NULL;
164     memset(entry, 0, sizeof(boot_entry));
165     memcpy(&(entry->data), be, sizeof(entry->data));
166     return entry;
167 }
168 
ReadBootTable(readfunc * read,unsigned int sector,boot_head * head,void * udata)169 int ReadBootTable(readfunc *read, unsigned int sector, boot_head *head, void *udata)
170 {
171 
172     char buf[2048], *c, *be;
173     int i, end = 0;
174     unsigned short sum;
175     boot_entry *defcur = NULL, *deflast = NULL;
176     register struct validation_entry *ventry = NULL;
177 
178     head->sections = NULL;
179     head->defentry = NULL;
180     while (1) {
181         be = (char*) & buf;
182         if (read(be, sector, 1, udata) != 1) goto err;
183 
184         /* first entry needs to be a validation entry */
185         if (!ventry) {
186             ventry = (struct validation_entry *) be;
187             if (isonum_711(ventry->type) != 1) goto err;
188             sum = 0;
189             c = (char*) ventry;
190             for (i = 0;i < 16;i++) {
191                 sum += isonum_721(c); c += 2;
192             }
193             if (sum) goto err;
194             memcpy(&head->ventry, be, 0x20);
195             be += 0x20;
196         }
197 
198         while (!end && (be < (char *)(&buf + 1))) {
199             switch (isonum_711(be)) {
200             case 0x88:
201                 defcur = CreateBootEntry(be);
202                 if (!defcur) goto err;
203                 if (deflast)
204                     deflast->next = defcur;
205                 else
206                     head->defentry = defcur;
207                 defcur->prev = deflast;
208                 deflast = defcur;
209                 break;
210             case 0x90:
211             case 0x91:
212                 break;
213             default:
214                 end = 1;
215                 break;
216             }
217             be += 0x20;
218         }
219         if (end) break;
220 
221         sector ++;
222     }
223 
224     return 0;
225 
226 err:
227     FreeBootTable(head);
228     return -1;
229 }
230 
231 
232 /**
233  * Creates the linked list of the volume descriptors
234  */
ReadISO9660(readfunc * read,unsigned int sector,void * udata)235 iso_vol_desc *ReadISO9660(readfunc *read, unsigned int sector, void *udata)
236 {
237 
238     int i;
239     struct iso_volume_descriptor buf;
240     iso_vol_desc *first = NULL, *current = NULL, *prev = NULL;
241 
242     for (i = 0;i < 100;i++) {
243         if (read((char*) &buf, sector + i + 16, 1, udata) != 1) {
244             FreeISO9660(first);
245             return NULL;
246         }
247         if (!memcmp(ISO_STANDARD_ID, &buf.id, 5)) {
248             switch (isonum_711(&buf.type[0])) {
249 
250             case ISO_VD_BOOT:
251             case ISO_VD_PRIMARY:
252             case ISO_VD_SUPPLEMENTARY:
253                 current = (iso_vol_desc*) malloc(sizeof(iso_vol_desc));
254                 if (!current) {
255                     FreeISO9660(first);
256                     return NULL;
257                 }
258                 current->prev = prev;
259                 current->next = NULL;
260                 if (prev) prev->next = current;
261                 memcpy(&(current->data), &buf, 2048);
262                 if (!first) first = current;
263                 prev = current;
264                 break;
265 
266             case ISO_VD_END:
267                 return first;
268                 break;
269             }
270         } else if (!memcmp(HS_STANDARD_ID, (struct hs_volume_descriptor*) &buf, 5)) {
271             /* High Sierra format not supported (yet) */
272         }
273     }
274 
275     return first;
276 }
277 
278 /**
279  * Frees the linked list of volume descriptors
280  */
FreeISO9660(iso_vol_desc * data)281 void FreeISO9660(iso_vol_desc *data)
282 {
283 
284     iso_vol_desc *current;
285 
286 
287     while (data) {
288         current = data;
289         data = current->next;
290         free(current);
291     }
292 }
293 
294 /**
295  * Frees the strings in 'rrentry'
296  */
FreeRR(rr_entry * rrentry)297 void FreeRR(rr_entry *rrentry)
298 {
299     if (rrentry->name) {
300         free(rrentry->name);
301         rrentry->name = NULL;
302     }
303     if (rrentry->sl) {
304         free(rrentry->sl);
305         rrentry->name = NULL;
306     }
307 }
308 
str_nappend(char ** d,char * s,int n)309 static int str_nappend(char **d, char *s, int n)
310 {
311     int i = 0;
312     char *c;
313 
314     /* i=strnlen(s,n)+1; */
315     while (i < n && s[i]) i++;
316     i++;
317     if (*d) i += (strlen(*d) + 1);
318     c = (char*) malloc(i);
319     if (!c) return -ENOMEM;
320     if (*d) {
321         strcpy(c, *d);
322         strncat(c, s, n);
323 
324         free(*d);
325     } else
326         strncpy(c, s, n);
327     c[i-1] = 0;
328     *d = c;
329     return 0;
330 }
331 
str_append(char ** d,char * s)332 static int str_append(char **d, char *s)
333 {
334     int i;
335     char *c;
336 
337     i = strlen(s) + 1;
338     if (*d) i += (strlen(*d) + 1);
339     c = (char*) malloc(i);
340     if (!c) return -ENOMEM;
341     if (*d) {
342         strcpy(c, *d);
343         strcat(c, s);
344         free(*d);
345     } else
346         strcpy(c, s);
347     c[i-1] = 0;
348     *d = c;
349     return 0;
350 }
351 
352 #define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
353 #define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
354 /**
355  * Parses the System Use area and fills rr_entry with values
356  */
ParseRR(struct iso_directory_record * idr,rr_entry * rrentry)357 int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry)
358 {
359 
360     int suspoffs, susplen, i, f, ret = 0;
361     char *r, *c;
362     struct rock_ridge *rr;
363 
364     suspoffs = 33 + isonum_711(idr->name_len);
365     if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
366     susplen = isonum_711(idr->length) - suspoffs;
367     r = & (((char*) idr)[suspoffs]);
368     rr = (struct rock_ridge*) r;
369 
370     memset(rrentry, 0, sizeof(rr_entry));
371     rrentry->len = sizeof(rr_entry);
372 
373     while (susplen > 0) {
374         if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
375         if (rr->signature[0] == 'N' && rr->signature[1] == 'M') {
376             if (!(rr->u.NM.flags & 0x26) && rr->len > 5 && !rrentry->name) {
377 
378                 if (str_nappend(&rrentry->name, rr->u.NM.name, isonum_711(&rr->len) - 5)) {
379                     FreeRR(rrentry); return -ENOMEM;
380                 }
381                 ret++;
382             }
383         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'X' &&
384                    (isonum_711(&rr->len) == 44 || isonum_711(&rr->len) == 36)) {
385             rrentry->mode = isonum_733(rr->u.PX.mode);
386             rrentry->nlink = isonum_733(rr->u.PX.n_links);
387             rrentry->uid = isonum_733(rr->u.PX.uid);
388             rrentry->gid = isonum_733(rr->u.PX.gid);
389             if (isonum_711(&rr->len) == 44) rrentry->serno = isonum_733(rr->u.PX.serno);
390             ret++;
391         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'N' &&
392                    isonum_711(&rr->len) == 20) {
393             rrentry->dev_major = isonum_733(rr->u.PN.dev_high);
394             rrentry->dev_minor = isonum_733(rr->u.PN.dev_low);
395             ret++;
396         } else if (rr->signature[0] == 'P' && rr->signature[1] == 'L' &&
397                    isonum_711(&rr->len) == 12) {
398             rrentry->pl = isonum_733(rr->u.PL.location);
399             ret++;
400         } else if (rr->signature[0] == 'C' && rr->signature[1] == 'L' &&
401                    isonum_711(&rr->len) == 12) {
402             rrentry->cl = isonum_733(rr->u.CL.location);
403             ret++;
404         } else if (rr->signature[0] == 'R' && rr->signature[1] == 'E' &&
405                    isonum_711(&rr->len) == 4) {
406             rrentry->re = 1;
407             ret++;
408         } else if (rr->signature[0] == 'S' && rr->signature[1] == 'L' &&
409                    isonum_711(&rr->len) > 7) {
410             i = isonum_711(&rr->len) - 5;
411             c = (char*) rr;
412             c += 5;
413             while (i > 0) {
414                 switch (c[0] & ~1) {
415                 case 0x2:
416                     if (str_append(&rrentry->sl, (char *)".")) {
417                         FreeRR(rrentry); return -ENOMEM;
418                     }
419                     break;
420                 case 0x4:
421                     if (str_append(&rrentry->sl, (char *)"..")) {
422                         FreeRR(rrentry); return -ENOMEM;
423                     }
424                     break;
425                 }
426                 if ((c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
427                                               strlen(rrentry->sl) > 1)) {
428                     if (str_append(&rrentry->sl, (char *) DIR_SEPARATOR)) {
429                         FreeRR(rrentry); return -ENOMEM;
430                     }
431                 }
432 
433                 if ((unsigned char)c[1] > 0) {
434                     if (str_nappend(&rrentry->sl, c + 2, (unsigned char)c[1])) {
435                         FreeRR(rrentry); return -ENOMEM;
436                     }
437                 }
438                 i -= ((unsigned char)c[1] + 2);
439                 c += ((unsigned char)c[1] + 2);
440             }
441             ret++;
442         } else if (rr->signature[0] == 'T' && rr->signature[1] == 'F' &&
443                    isonum_711(&rr->len) > 5) {
444 
445             i = isonum_711(&rr->len) - 5;
446             f = rr->u.TF.flags;
447             c = (char*) rr;
448             c += 5;
449 
450             while (i >= rrtlen(f)) {
451                 if (f & 1) {
452                     rrentry->t_creat = rrctime(f, c);
453                     f &= ~1;
454                 } else if (f & 2) {
455                     rrentry->t_mtime = rrctime(f, c);
456                     f &= ~2;
457                 } else if (f & 4) {
458                     rrentry->t_atime = rrctime(f, c);
459                     f &= ~4;
460                 } else if (f & 8) {
461                     rrentry->t_ctime = rrctime(f, c);
462                     f &= ~8;
463                 } else if (f & 16) {
464                     rrentry->t_backup = rrctime(f, c);
465                     f &= ~16;
466                 } else if (f & 32) {
467                     rrentry->t_expire = rrctime(f, c);
468                     f &= ~32;
469                 } else if (f & 64) {
470                     rrentry->t_effect = rrctime(f, c);
471                     f &= ~64;
472                 }
473 
474                 i -= rrtlen(f);
475                 c += rrtlen(f);
476             }
477             ret++;
478 
479         } else if (rr->signature[0] == 'Z' && rr->signature[1] == 'F' &&
480                    isonum_711(&rr->len) == 16) {
481             /* Linux-specific extension: transparent decompression */
482             rrentry->z_algo[0] = rr->u.ZF.algorithm[0];
483             rrentry->z_algo[1] = rr->u.ZF.algorithm[1];
484             rrentry->z_params[0] = rr->u.ZF.parms[0];
485             rrentry->z_params[1] = rr->u.ZF.parms[1];
486             rrentry->z_size = isonum_733(rr->u.ZF.real_size);
487             ret++;
488         } else {
489             /*   printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */
490         }
491 
492         susplen -= isonum_711(&rr->len);
493         r += isonum_711(&rr->len);
494         rr = (struct rock_ridge*) r;
495     }
496 
497     return ret;
498 }
499 
500 /**
501  * Iterates over the directory entries. The directory is in 'buf',
502  * the size of the directory is 'size'. 'callback' is called for each
503  * directory entry with the parameter 'udata'.
504  */
ProcessDir(readfunc * read,int extent,int size,dircallback * callback,void * udata)505 int ProcessDir(readfunc *read, int extent, int size, dircallback *callback, void *udata)
506 {
507 
508     int pos = 0, ret = 0, siz;
509     char *buf;
510     struct iso_directory_record *idr;
511 
512     if (size & 2047) {
513         siz = ((size >> 11) + 1) << 11;
514     } else {
515         siz = size;
516     }
517 
518     buf = (char*) malloc(siz);
519     if (!buf) return -ENOMEM;
520     if (read(buf, extent, siz >> 11, udata) != siz >> 11) {
521         free(buf);
522         return -EIO;
523     }
524 
525     while (size > 0) {
526         idr = (struct iso_directory_record*) & buf[pos];
527         if (isonum_711(idr->length) == 0) {
528 
529             size -= (2048 - (pos & 0x7ff));
530             if (size <= 2) break;
531             pos += 0x800;
532             pos &= 0xfffff800;
533             idr = (struct iso_directory_record*) & buf[pos];
534         }
535         pos += isonum_711(idr->length);
536         pos += isonum_711(idr->ext_attr_length);
537         size -= isonum_711(idr->length);
538         size -= isonum_711(idr->ext_attr_length);
539         if (size < 0) break;
540 
541         if (isonum_711(idr->length)
542                 < 33 ||
543                 isonum_711(idr->length) < 33 + isonum_711(idr->name_len)) {
544             /* Invalid directory entry */
545             continue;
546         }
547         if ((ret = callback(idr, udata))) break;
548     }
549 
550     free(buf);
551     return ret;
552 }
553 
554 /**
555  * returns the joliet level from the volume descriptor
556  */
JolietLevel(struct iso_volume_descriptor * ivd)557 int JolietLevel(struct iso_volume_descriptor *ivd)
558 {
559     int ret = 0;
560     register struct iso_supplementary_descriptor *isd;
561 
562     isd = (struct iso_supplementary_descriptor *) ivd;
563 
564     if (isonum_711(ivd->type) == ISO_VD_SUPPLEMENTARY) {
565         if (isd->escape[0] == 0x25 &&
566                 isd->escape[1] == 0x2f) {
567 
568             switch (isd->escape[2]) {
569             case 0x40:
570                 ret = 1;
571                 break;
572             case 0x43:
573                 ret = 2;
574                 break;
575             case 0x45:
576                 ret = 3;
577                 break;
578             }
579         }
580     }
581     return ret;
582 }
583 
584 /********************************************************************/
585 #ifdef ISOFS_MAIN
586 
587 #include <time.h>
588 #include <fcntl.h>
589 #include <stdio.h>
590 #include <unistd.h>
591 #include <sys/types.h>
592 #include <sys/stat.h>
593 #include <iconv.h>
594 
595 int level = 0, joliet = 0, dirs, files;
596 iconv_t iconv_d;
597 int fd;
598 
readf(char * buf,unsigned int start,unsigned int len,void * udata)599 int readf(char *buf, unsigned int start, unsigned int len, void *udata)
600 {
601     int ret;
602 
603     if ((ret = lseek64(fd, (long long)start << (long long)11, SEEK_SET)) < 0) return ret;
604     ret = read(fd, buf, len << 11u);
605     if (ret < 0) return ret;
606     return (ret >> 11u);
607 }
608 
dumpchars(char * c,int len)609 void dumpchars(char *c, int len)
610 {
611     while (len > 0) {
612         printf("%c", *c);
613         len--;
614         c++;
615     }
616 }
617 
sp(int num)618 void sp(int num)
619 {
620     int i;
621     for (i = 0;i < num*5;i++) {
622         printf(" ");
623     };
624 }
625 
dumpflags(char flags)626 void dumpflags(char flags)
627 {
628     if (flags & 1) printf("HIDDEN ");
629     if (flags & 2) printf("DIR ");
630     if (flags & 4) printf("ASF ");
631 }
632 
dumpjoliet(char * c,int len)633 void dumpjoliet(char *c, int len)
634 {
635 
636     char outbuf[255];
637     size_t out;
638     int ret;
639     char *outptr;
640 
641     outptr = (char*) & outbuf;
642     out = 255;
643     if ((iconv(iconv_d, &c, &len, &outptr, &out)) < 0) {
644         printf("conversion error=%d", errno);
645         return;
646     }
647     ret = 255 - out;
648     dumpchars((char*) &outbuf, ret);
649 }
650 
dumpchardesc(char * c,int len)651 void dumpchardesc(char *c, int len)
652 {
653 
654     if (joliet)
655         dumpjoliet(c, len);
656     else {
657         dumpchars(c, len);
658     }
659 }
660 
dumpiso915time(char * t,int hs)661 void dumpiso915time(char *t, int hs)
662 {
663 
664     time_t time;
665     char *c;
666 
667     time = isodate_915(t, hs);
668     c = (char*) ctime(&time);
669     if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
670     if (c) printf("%s", c);
671 }
672 
dumpiso84261time(char * t,int hs)673 void dumpiso84261time(char *t, int hs)
674 {
675 
676     time_t time;
677     char *c;
678 
679     time = isodate_84261(t, hs);
680     c = (char*) ctime(&time);
681     if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
682     if (c) printf("%s", c);
683 }
684 
dumpdirrec(struct iso_directory_record * dir)685 void dumpdirrec(struct iso_directory_record *dir)
686 {
687 
688     if (isonum_711(dir->name_len) == 1) {
689         switch (dir->name[0]) {
690         case 0:
691             printf(".");
692             break;
693         case 1:
694             printf("..");
695             break;
696         default:
697             printf("%c", dir->name[0]);
698             break;
699         }
700     }
701     dumpchardesc(dir->name, isonum_711(dir->name_len));
702     printf(" size=%d", isonum_733(dir->size));
703     printf(" extent=%d ", isonum_733(dir->extent));
704     dumpflags(isonum_711(dir->flags));
705     dumpiso915time((char*) &(dir->date), 0);
706 }
707 
dumprrentry(rr_entry * rr)708 void dumprrentry(rr_entry *rr)
709 {
710     printf("  NM=[%s] uid=%d gid=%d nlink=%d mode=%o ",
711            rr->name, rr->uid, rr->gid, rr->nlink, rr->mode);
712     if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode))
713         printf("major=%d minor=%d ", rr->dev_major, rr->dev_minor);
714     if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ", rr->sl);
715     /*
716      printf("\n");
717      if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat));
718      if (rr->st_mtime) printf("st_mtime: %s",ctime(&rr->st_mtime));
719      if (rr->st_atime) printf("st_atime: %s",ctime(&rr->st_atime));
720      if (rr->st_ctime) printf("st_ctime: %s",ctime(&rr->st_ctime));
721      if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup));
722      if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire));
723      if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect));
724     */
725 }
726 
dumpsusp(char * c,int len)727 void dumpsusp(char *c, int len)
728 {
729     dumpchars(c, len);
730 }
731 
dumpboot(struct el_torito_boot_descriptor * ebd)732 void dumpboot(struct el_torito_boot_descriptor *ebd)
733 {
734     printf("version: %d\n", isonum_711(ebd->version));
735     printf("system id: ");dumpchars(ebd->system_id, ISODCL(8, 39));printf("\n");
736     printf("boot catalog start: %d\n", isonum_731(ebd->boot_catalog));
737 }
738 
dumpdefentry(struct default_entry * de)739 void dumpdefentry(struct default_entry *de)
740 {
741     printf("Default entry: \n");
742     printf("  bootid=%x\n", isonum_711(de->bootid));
743     printf("  media emulation=%d (", isonum_711(de->media));
744     switch (isonum_711(de->media) & 0xf) {
745     case 0:
746         printf("No emulation");
747         break;
748     case 1:
749         printf("1.2 Mb floppy");
750         break;
751     case 2:
752         printf("1.44 Mb floppy");
753         break;
754     case 3:
755         printf("2.88 Mb floppy");
756         break;
757     case 4:
758         printf("Hard Disk");
759         break;
760     default:
761         printf("Unknown/Invalid");
762         break;
763     }
764     printf(")\n");
765     printf("  loadseg=%d\n", isonum_721(de->loadseg));
766     printf("  systype=%d\n", isonum_711(de->systype));
767     printf("  start lba=%d count=%d\n", isonum_731(de->start),
768            isonum_721(de->seccount));
769 }
770 
dumpbootcat(boot_head * bh)771 void dumpbootcat(boot_head *bh)
772 {
773     boot_entry *be;
774 
775     printf("System id: ");dumpchars(bh->ventry.id, ISODCL(28, 5));printf("\n");
776     be = bh->defentry;
777     while (be) {
778         dumpdefentry(be->data);
779         be = be->next;
780     }
781 }
782 
dumpdesc(struct iso_primary_descriptor * ipd)783 void dumpdesc(struct iso_primary_descriptor *ipd)
784 {
785 
786     printf("system id: ");dumpchardesc(ipd->system_id, ISODCL(9, 40));printf("\n");
787     printf("volume id: ");dumpchardesc(ipd->volume_id, ISODCL(41, 72));printf("\n");
788     printf("volume space size: %d\n", isonum_733(ipd->volume_space_size));
789     printf("volume set size: %d\n", isonum_723(ipd->volume_set_size));
790     printf("volume seq num: %d\n", isonum_723(ipd->volume_set_size));
791     printf("logical block size: %d\n", isonum_723(ipd->logical_block_size));
792     printf("path table size: %d\n", isonum_733(ipd->path_table_size));
793     printf("location of type_l path table: %d\n", isonum_731(ipd->type_l_path_table));
794     printf("location of optional type_l path table: %d\n", isonum_731(ipd->opt_type_l_path_table));
795     printf("location of type_m path table: %d\n", isonum_732(ipd->type_m_path_table));
796     printf("location of optional type_m path table: %d\n", isonum_732(ipd->opt_type_m_path_table));
797     /*
798      printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record);
799     */
800     printf("Volume set id: ");dumpchardesc(ipd->volume_set_id, ISODCL(191, 318));printf("\n");
801     printf("Publisher id: ");dumpchardesc(ipd->publisher_id, ISODCL(319, 446));printf("\n");
802     printf("Preparer id: ");dumpchardesc(ipd->preparer_id, ISODCL(447, 574));printf("\n");
803     printf("Application id: ");dumpchardesc(ipd->application_id, ISODCL(575, 702));printf("\n");
804     printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id, ISODCL(703, 739));printf("\n");
805     printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id, ISODCL(740, 776));printf("\n");
806     printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id, ISODCL(777, 813));printf("\n");
807     printf("Volume creation date: ");dumpiso84261time(ipd->creation_date, 0);printf("\n");
808     printf("Volume modification date: ");dumpiso84261time(ipd->modification_date, 0);printf("\n");
809     printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date, 0);printf("\n");
810     printf("Volume effective date: ");dumpiso84261time(ipd->effective_date, 0);printf("\n");
811     printf("File structure version: %d\n", isonum_711(ipd->file_structure_version));
812 }
813 
mycallb(struct iso_directory_record * idr,void * udata)814 int mycallb(struct iso_directory_record *idr, void *udata)
815 {
816     rr_entry rrentry;
817 
818     sp(level);dumpdirrec(idr);
819     if (level == 0) printf(" (Root directory) ");
820     printf("\n");
821 
822     if (ParseRR(idr, &rrentry) > 0) {
823         sp(level);printf("  ");dumprrentry(&rrentry);printf("\n");
824     }
825     FreeRR(&rrentry);
826     if (!(idr->flags[0] & 2)) files++;
827     if ((idr->flags[0] & 2) && (level == 0 || isonum_711(idr->name_len) > 1)) {
828         level++;
829         dirs++;
830         ProcessDir(&readf, isonum_733(idr->extent), isonum_733(idr->size), &mycallb, udata);
831         level--;
832     }
833     return 0;
834 }
835 
836 /************************************************/
837 
main(int argc,char * argv[])838 int main(int argc, char *argv[])
839 {
840 
841     int i = 1, sector = 0;
842     iso_vol_desc *desc;
843     boot_head boot;
844 
845     if (argc < 2) {
846         fprintf(stderr, "\nUsage: %s iso-file-name or device [starting sector]\n\n", argv[0]);
847         return 0;
848     }
849     if (argc >= 3) {
850         sector = atoi(argv[2]);
851         printf("Using starting sector number %d\n", sector);
852     }
853     fd = open(argv[1], O_RDONLY);
854     if (fd < 0) {
855         fprintf(stderr, "open error\n");
856         return -1;
857     }
858     iconv_d = iconv_open("ISO8859-2", "UTF16BE");
859     if (iconv_d == 0) {
860         fprintf(stderr, "iconv open error\n");
861         return -1;
862     }
863 
864     desc = ReadISO9660(&readf, sector, NULL);
865     if (!desc) {
866         printf("No volume descriptors\n");
867         return -1;
868     }
869     while (desc) {
870 
871         printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n",
872                i, isonum_711(desc->data.type));
873         switch (isonum_711(desc->data.type)) {
874         case ISO_VD_BOOT: {
875 
876             struct el_torito_boot_descriptor* bootdesc;
877             bootdesc = &(desc->data);
878             dumpboot(bootdesc);
879             if (!memcmp(EL_TORITO_ID, bootdesc->system_id, ISODCL(8, 39))) {
880 
881                 if (ReadBootTable(&readf, isonum_731(bootdesc->boot_catalog), &boot, NULL)) {
882                     printf("Boot Catalog Error\n");
883                 } else {
884                     dumpbootcat(&boot);
885                     FreeBootTable(&boot);
886                 }
887             }
888         }
889         break;
890 
891         case ISO_VD_PRIMARY:
892         case ISO_VD_SUPPLEMENTARY:
893             joliet = 0;
894             joliet = JolietLevel(&desc->data);
895             printf("Joliet level: %d\n", joliet);
896             dumpdesc((struct iso_primary_descriptor*) &desc->data);
897             printf("\n\n--------------- Directory structure: -------------------\n\n");
898             dirs = 0;files = 0;
899             mycallb(&(((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL);
900             printf("\nnumber of directories: %d\n", dirs);
901             printf("\nnumber of files: %d\n", files);
902             break;
903 
904         }
905         desc = desc->next;
906         i++;
907     }
908     iconv_close(iconv_d);
909     close(fd);
910     FreeISO9660(desc);
911     return 0;
912 }
913 
914 #endif /* ISOFS_MAIN */
915