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