Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / genisoimage / diag / isovfy.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)isovfy.c 1.26 05/05/15 joerg */
14 /*
15  * File isovfy.c - verify consistency of iso9660 filesystem.
16  *
17  *
18  * Written by Eric Youngdale (1993).
19  *
20  * Copyright 1993 Yggdrasil Computing, Incorporated
21  * Copyright (c) 1999-2004 J. Schilling
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License version 2
25  * as published by the Free Software Foundation.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License along with
33  * this program; see the file COPYING.  If not, write to the Free Software
34  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35  */
36
37 #include <mconfig.h>
38 #include <stdxlib.h>
39 #include <unixstd.h>
40 #include <strdefs.h>
41 #include <utypes.h>
42
43 #include <stdio.h>
44 #include <standard.h>
45 #include <signal.h>
46 #include <schily.h>
47
48 #include "../scsi.h"
49 #include "../../wodim/defaults.h"
50
51 /*
52  * XXX JS: Some structures have odd lengths!
53  * Some compilers (e.g. on Sun3/mc68020) padd the structures to even length.
54  * For this reason, we cannot use sizeof (struct iso_path_table) or
55  * sizeof (struct iso_directory_record) to compute on disk sizes.
56  * Instead, we use offsetof(..., name) and add the name size.
57  * See iso9660.h
58  */
59 #ifndef offsetof
60 #define offsetof(TYPE, MEMBER)  ((size_t) &((TYPE *)0)->MEMBER)
61 #endif
62
63 /*
64  * Note: always use these macros to avoid problems.
65  *
66  * ISO_ROUND_UP(X)      may cause an integer overflow and thus give
67  *                      incorrect results. So avoid it if possible.
68  *
69  * ISO_BLOCKS(X)        is overflow safe. Prefer this when ever it is possible.
70  */
71 #define SECTOR_SIZE     (2048)
72 #define ISO_ROUND_UP(X) (((X) + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1))
73 #define ISO_BLOCKS(X)   (((X) / SECTOR_SIZE) + (((X)%SECTOR_SIZE)?1:0))
74
75 #define infile  in_image
76 FILE *infile = NULL;
77 int blocksize;
78
79 #define PAGE    sizeof (buffer)
80
81 #define ISODCL(from, to)        (to - from + 1)
82
83 struct iso_primary_descriptor {
84         unsigned char type                      [ISODCL(1,   1)]; /* 711 */
85         unsigned char id                        [ISODCL(2,   6)];
86         unsigned char version                   [ISODCL(7,   7)]; /* 711 */
87         unsigned char unused1                   [ISODCL(8,   8)];
88         unsigned char system_id                 [ISODCL(9,   40)]; /* aunsigned chars */
89         unsigned char volume_id                 [ISODCL(41,  72)]; /* dunsigned chars */
90         unsigned char unused2                   [ISODCL(73,  80)];
91         unsigned char volume_space_size         [ISODCL(81,  88)]; /* 733 */
92         unsigned char unused3                   [ISODCL(89,  120)];
93         unsigned char volume_set_size           [ISODCL(121, 124)]; /* 723 */
94         unsigned char volume_sequence_number    [ISODCL(125, 128)]; /* 723 */
95         unsigned char logical_block_size        [ISODCL(129, 132)]; /* 723 */
96         unsigned char path_table_size           [ISODCL(133, 140)]; /* 733 */
97         unsigned char type_l_path_table         [ISODCL(141, 144)]; /* 731 */
98         unsigned char opt_type_l_path_table     [ISODCL(145, 148)]; /* 731 */
99         unsigned char type_m_path_table         [ISODCL(149, 152)]; /* 732 */
100         unsigned char opt_type_m_path_table     [ISODCL(153, 156)]; /* 732 */
101         unsigned char root_directory_record     [ISODCL(157, 190)]; /* 9.1 */
102         unsigned char volume_set_id             [ISODCL(191, 318)]; /* dunsigned chars */
103         unsigned char publisher_id              [ISODCL(319, 446)]; /* achars */
104         unsigned char preparer_id               [ISODCL(447, 574)]; /* achars */
105         unsigned char application_id            [ISODCL(575, 702)]; /* achars */
106         unsigned char copyright_file_id         [ISODCL(703, 739)]; /* 7.5 dchars */
107         unsigned char abstract_file_id          [ISODCL(740, 776)]; /* 7.5 dchars */
108         unsigned char bibliographic_file_id     [ISODCL(777, 813)]; /* 7.5 dchars */
109         unsigned char creation_date             [ISODCL(814, 830)]; /* 8.4.26.1 */
110         unsigned char modification_date         [ISODCL(831, 847)]; /* 8.4.26.1 */
111         unsigned char expiration_date           [ISODCL(848, 864)]; /* 8.4.26.1 */
112         unsigned char effective_date            [ISODCL(865, 881)]; /* 8.4.26.1 */
113         unsigned char file_structure_version    [ISODCL(882, 882)]; /* 711 */
114         unsigned char unused4                   [ISODCL(883, 883)];
115         unsigned char application_data          [ISODCL(884, 1395)];
116         unsigned char unused5                   [ISODCL(1396, 2048)];
117 };
118
119 struct iso_directory_record {
120         unsigned char length                    [ISODCL(1, 1)]; /* 711 */
121         unsigned char ext_attr_length           [ISODCL(2, 2)]; /* 711 */
122         unsigned char extent                    [ISODCL(3, 10)]; /* 733 */
123         unsigned char size                      [ISODCL(11, 18)]; /* 733 */
124         unsigned char date                      [ISODCL(19, 25)]; /* 7 by 711 */
125         unsigned char flags                     [ISODCL(26, 26)];
126         unsigned char file_unit_size            [ISODCL(27, 27)]; /* 711 */
127         unsigned char interleave                [ISODCL(28, 28)]; /* 711 */
128         unsigned char volume_sequence_number    [ISODCL(29, 32)]; /* 723 */
129         unsigned char name_len                  [ISODCL(33, 33)]; /* 711 */
130         unsigned char name                      [38];
131 };
132
133 static int      isonum_721(char * p);
134 static int      isonum_723(char * p);
135 static int      isonum_711(char * p);
136 static int      isonum_731(char * p);
137 static int      isonum_722(char * p);
138 static int      isonum_732(char * p);
139 static int      isonum_733(unsigned char * p);
140 static int      parse_rr(unsigned char * pnt, int len, int cont_flag);
141 static int      dump_rr(struct iso_directory_record * idr);
142 static void     check_tree(off_t file_addr, int file_size, off_t parent_addr);
143 static void     check_path_tables(int typel_extent, int typem_extent, 
144                                                                                 int path_table_size);
145 static void     usage(int excode);
146
147 static int
148 isonum_721(char *p)
149 {
150         return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
151 }
152
153 static int
154 isonum_723(char *p)
155 {
156 #if 0
157         if (p[0] != p[3] || p[1] != p[2]) {
158 #ifdef  USE_LIBSCHILY
159                 comerrno(EX_BAD, "invalid format 7.2.3 number\n");
160 #else
161                 fprintf(stderr, "invalid format 7.2.3 number\n");
162                 exit(1);
163 #endif
164         }
165 #endif
166         return (isonum_721(p));
167 }
168
169 static int
170 isonum_711(char *p)
171 {
172         return (*p & 0xff);
173 }
174
175 static int
176 isonum_731(char *p)
177 {
178         return ((p[0] & 0xff)
179                 | ((p[1] & 0xff) << 8)
180                 | ((p[2] & 0xff) << 16)
181                 | ((p[3] & 0xff) << 24));
182 }
183
184 static int
185 isonum_722(char *p)
186 {
187         return ((p[1] & 0xff)
188                 | ((p[0] & 0xff) << 8));
189 }
190
191 static int
192 isonum_732(char *p)
193 {
194         return ((p[3] & 0xff)
195                 | ((p[2] & 0xff) << 8)
196                 | ((p[1] & 0xff) << 16)
197                 | ((p[0] & 0xff) << 24));
198 }
199
200 static int
201 isonum_733(unsigned char *p)
202 {
203         return (isonum_731((char *)p));
204 }
205
206 char    lbuffer[1024];
207 int     iline;
208 int     rr_goof;
209
210
211 static int
212 parse_rr(unsigned char *pnt, int len, int cont_flag)
213 {
214         int             slen;
215         int             ncount;
216         int             flag1;
217         int             flag2;
218         int             extent;
219         unsigned char   *pnts;
220         off_t           cont_extent;
221         int             cont_offset;
222         int             cont_size;
223         char            symlinkname[1024];
224
225         sprintf(lbuffer+iline, " RRlen=%d ", len);
226         iline += strlen(lbuffer+iline);
227
228         cont_extent = (off_t)0;
229         cont_offset = cont_size = 0;
230
231         symlinkname[0] = 0;
232
233         ncount = 0;
234         flag1 = flag2 = 0;
235         while (len >= 4) {
236                 if (ncount)
237                         sprintf(lbuffer+iline, ",");
238                 else
239                         sprintf(lbuffer+iline, "[");
240                 iline += strlen(lbuffer + iline);
241                 sprintf(lbuffer+iline, "%c%c", pnt[0], pnt[1]);
242                 iline += strlen(lbuffer + iline);
243                 if (pnt[0] < 'A' || pnt[0] > 'Z' || pnt[1] < 'A' ||
244                     pnt[1] > 'Z') {
245                         sprintf(lbuffer+iline, "**BAD SUSP %d %d]",
246                                         pnt[0], pnt[1]);
247                         rr_goof++;
248                         iline += strlen(lbuffer + iline);
249                         return (flag2);
250                 }
251
252                 if (pnt[3] != 1 && pnt[3] != 2) {
253                         sprintf(lbuffer+iline, "**BAD RRVERSION (%d)\n", pnt[3]);
254                         rr_goof++;
255                         iline += strlen(lbuffer + iline);
256                         return (flag2);
257                 }
258                 ncount++;
259                 if (pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
260                 if (strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1;
261                 if (strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2;
262                 if (strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4;
263                 if (strncmp((char *)pnt, "NM", 2) == 0) flag2 |= 8;
264                 if (strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16;
265                 if (strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32;
266                 if (strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64;
267                 if (strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128;
268
269                 if (strncmp((char *)pnt, "CE", 2) == 0) {
270                         cont_extent = (off_t)isonum_733(pnt+4);
271                         cont_offset = isonum_733(pnt+12);
272                         cont_size = isonum_733(pnt+20);
273                         sprintf(lbuffer+iline, "=[%x,%x,%d]",
274                                         (int)cont_extent, cont_offset, cont_size);
275                         iline += strlen(lbuffer + iline);
276                 }
277
278                 if (strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
279                         extent = isonum_733(pnt+4);
280                         sprintf(lbuffer+iline, "=%x", extent);
281                         iline += strlen(lbuffer + iline);
282                         if (extent == 0)
283                                 rr_goof++;
284                 }
285                 if (strncmp((char *)pnt, "SL", 2) == 0) {
286                         pnts = pnt+5;
287                         slen = pnt[2] - 5;
288                         while (slen >= 1) {
289                                 switch (pnts[0] & 0xfe) {
290                                 case 0:
291                                         strncat(symlinkname, (char *)(pnts+2), pnts[1]);
292                                         break;
293                                 case 2:
294                                         strcat(symlinkname, ".");
295                                         break;
296                                 case 4:
297                                         strcat(symlinkname, "..");
298                                         break;
299                                 case 8:
300                                         strcat(symlinkname, "/");
301                                         break;
302                                 case 16:
303                                         strcat(symlinkname, "/mnt");
304                                         sprintf(lbuffer+iline, "Warning - mount point requested");
305                                         iline += strlen(lbuffer + iline);
306                                         break;
307                                 case 32:
308                                         strcat(symlinkname, "kafka");
309                                         sprintf(lbuffer+iline, "Warning - host_name requested");
310                                         iline += strlen(lbuffer + iline);
311                                         break;
312                                 default:
313                                         sprintf(lbuffer+iline, "Reserved bit setting in symlink");
314                                         rr_goof++;
315                                         iline += strlen(lbuffer + iline);
316                                         break;
317                                 }
318                                 if ((pnts[0] & 0xfe) && pnts[1] != 0) {
319                                         sprintf(lbuffer+iline, "Incorrect length in symlink component");
320                                         iline += strlen(lbuffer + iline);
321                                 }
322                                 if ((pnts[0] & 1) == 0)
323                                         strcat(symlinkname, "/");
324                                 slen -= (pnts[1] + 2);
325                                 pnts += (pnts[1] + 2);
326                         }
327                         if (symlinkname[0] != 0) {
328                                 sprintf(lbuffer+iline, "=%s", symlinkname);
329                                 iline += strlen(lbuffer + iline);
330                                 symlinkname[0] = 0;
331                         }
332                 }
333
334                 len -= pnt[2];
335                 pnt += pnt[2];
336                 if (len <= 3 && cont_extent) {
337                         unsigned char sector[2048];
338 #ifdef  USE_SCG
339                         readsecs(cont_extent * blocksize / 2048, sector, ISO_BLOCKS(sizeof (sector)));
340 #else
341                         lseek(fileno(infile), cont_extent * blocksize, SEEK_SET);
342                         read(fileno(infile), sector, sizeof (sector));
343 #endif
344                         flag2 |= parse_rr(&sector[cont_offset], cont_size, 1);
345                 }
346         }
347         if (ncount) {
348                 sprintf(lbuffer+iline, "]");
349                 iline += strlen(lbuffer + iline);
350         }
351         if (!cont_flag && flag1 && flag1 != flag2) {
352                 sprintf(lbuffer+iline, "Flag %x != %x", flag1, flag2);
353                 rr_goof++;
354                 iline += strlen(lbuffer + iline);
355         }
356         return (flag2);
357 }
358
359 static int
360 dump_rr(struct iso_directory_record *idr)
361 {
362         int len;
363         char * pnt;
364
365         len = idr->length[0] & 0xff;
366         len -= offsetof(struct iso_directory_record, name[0]);
367         len -= idr->name_len[0];
368         pnt = (char *) idr;
369         pnt += offsetof(struct iso_directory_record, name[0]);
370         pnt += idr->name_len[0];
371
372         if ((idr->name_len[0] & 1) == 0) {
373                 pnt++;
374                 len--;
375         }
376
377         rr_goof = 0;
378         parse_rr((unsigned char *)pnt, len, 0);
379         return (rr_goof);
380 }
381
382
383 static int      dir_count = 0;
384 static int      dir_size_count = 0;
385 static int      ngoof = 0;
386
387 static void
388 check_tree(off_t file_addr, int file_size, off_t parent_addr)
389 {
390         unsigned char   buffer[2048];
391         unsigned int    k;
392         int             rflag = 0;
393         int             i;
394         int             i1;
395         int             j;
396         int             goof;
397         int             extent;
398         int             size;
399         off_t           orig_file_addr;
400         off_t           parent_file_addr;
401         struct iso_directory_record     *idr;
402
403         i1 = 0;
404
405         orig_file_addr = file_addr / blocksize;  /* Actual extent of this directory */
406         parent_file_addr = parent_addr / blocksize;
407
408         if ((dir_count % 100) == 0)
409                 printf("[%d %d]\n", dir_count, dir_size_count);
410 #if 0
411         if (sizeof (file_addr) > sizeof (long)) {
412                 printf("Starting directory %ld %d %lld\n",
413                                 file_addr, file_size,
414                                 (Llong)parent_addr);
415         } else {
416                 printf("Starting directory %ld %d %ld\n", file_addr, file_size, parent_addr);
417         }
418 #endif
419
420         dir_count++;
421         dir_size_count += file_size / blocksize;
422
423         if (file_size & 0x3ff)
424                 printf("********Directory has unusual size\n");
425
426         for (k = 0; k < (file_size / sizeof (buffer)); k++) {
427 #ifdef  USE_SCG
428                 readsecs(file_addr / 2048, buffer, ISO_BLOCKS(sizeof (buffer)));
429 #else
430                 lseek(fileno(infile), file_addr, SEEK_SET);
431                 read(fileno(infile), buffer, sizeof (buffer));
432 #endif
433                 i = 0;
434                 while (1 == 1) {
435                         goof = iline = 0;
436                         idr = (struct iso_directory_record *) &buffer[i];
437                         if (idr->length[0] == 0) break;
438                         sprintf(&lbuffer[iline], "%3d ", idr->length[0]);
439                         iline += strlen(lbuffer + iline);
440                         extent = isonum_733(idr->extent);
441                         size = isonum_733(idr->size);
442                         sprintf(&lbuffer[iline], "%5x ", extent);
443                         iline += strlen(lbuffer + iline);
444                         sprintf(&lbuffer[iline], "%8d ", size);
445                         iline += strlen(lbuffer + iline);
446                         sprintf(&lbuffer[iline], "%c", (idr->flags[0] & 2) ? '*' : ' ');
447                         iline += strlen(lbuffer + iline);
448
449                         if (idr->name_len[0] > 33) {
450                                 sprintf(&lbuffer[iline], "File name length=(%d)",
451                                                         idr->name_len[0]);
452                                 goof++;
453                                 iline += strlen(lbuffer + iline);
454                         } else if (idr->name_len[0] == 1 && idr->name[0] == 0) {
455                                 sprintf(&lbuffer[iline], ".             ");
456                                 iline += strlen(lbuffer + iline);
457                                 rflag = 0;
458                                 if (orig_file_addr != (off_t)(isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length))) {
459                                         sprintf(&lbuffer[iline], "***** Directory has null extent.");
460                                         goof++;
461                                         iline += strlen(lbuffer + iline);
462                                 }
463                                 if (i1) {
464                                         sprintf(&lbuffer[iline], "***** . not  first entry.");
465                                         rr_goof++;
466                                         iline += strlen(lbuffer + iline);
467                                 }
468                         } else if (idr->name_len[0] == 1 && idr->name[0] == 1) {
469                                 sprintf(&lbuffer[iline], "..            ");
470                                 iline += strlen(lbuffer + iline);
471                                 rflag = 0;
472                                 if (parent_file_addr != (off_t)(isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length))) {
473                                         sprintf(&lbuffer[iline], "***** Directory has null extent.");
474                                         goof++;
475                                         iline += strlen(lbuffer + iline);
476                                 }
477                                 if (i1 != 1) {
478                                         sprintf(&lbuffer[iline], "***** .. not second entry.");
479                                         rr_goof++;
480                                         iline += strlen(lbuffer + iline);
481                                 }
482                         } else {
483                                 if (i1 < 2) {
484                                         sprintf(&lbuffer[iline], " Improper sorting.");
485                                         rr_goof++;
486                                 }
487                                 for (j = 0; j < (int)idr->name_len[0]; j++) {
488                                         sprintf(&lbuffer[iline], "%c", idr->name[j]);
489                                 }
490                                 for (j = 0; j < (14 - (int) idr->name_len[0]); j++) {
491                                         sprintf(&lbuffer[iline], " ");
492                                         iline += strlen(lbuffer + iline);
493                                 }
494                                 rflag = 1;
495                         }
496
497                         if (size && extent == 0) {
498                                 sprintf(&lbuffer[iline], "****Extent==0, size != 0");
499                                 goof++;
500                                 iline += strlen(lbuffer + iline);
501                         }
502 #if 0
503                         /* This is apparently legal. */
504                         if (size == 0 && extent) {
505                                 sprintf(&lbuffer[iline], "****Extent!=0, size == 0");
506                                 goof++;
507                                 iline += strlen(lbuffer + iline);
508                         }
509 #endif
510
511                         if (idr->flags[0] & 0xf5) {
512                                 sprintf(&lbuffer[iline], "Flags=(%x) ", idr->flags[0]);
513                                 goof++;
514                                 iline += strlen(lbuffer + iline);
515                         }
516                         if (idr->interleave[0]) {
517                                 sprintf(&lbuffer[iline], "Interleave=(%d) ", idr->interleave[0]);
518                                 goof++;
519                                 iline += strlen(lbuffer + iline);
520                         }
521
522                         if (idr->file_unit_size[0]) {
523                                 sprintf(&lbuffer[iline], "File unit size=(%d) ", idr->file_unit_size[0]);
524                                 goof++;
525                                 iline += strlen(lbuffer + iline);
526                         }
527
528                         if (idr->volume_sequence_number[0] != 1) {
529                                 sprintf(&lbuffer[iline], "Volume sequence number=(%d) ", idr->volume_sequence_number[0]);
530                                 goof++;
531                                 iline += strlen(lbuffer + iline);
532                         }
533
534                         goof += dump_rr(idr);
535                         sprintf(&lbuffer[iline], "\n");
536                         iline += strlen(lbuffer + iline);
537
538
539                         if (goof) {
540                                 ngoof++;
541                                 lbuffer[iline++] = 0;
542                                 if (sizeof (orig_file_addr) > sizeof (long)) {
543                                         printf("%llx: %s", (Llong)orig_file_addr, lbuffer);
544                                 } else {
545                                         printf("%lx: %s", (long)orig_file_addr, lbuffer);
546                                 }
547                         }
548
549
550
551                         if (rflag && (idr->flags[0] & 2))
552                                 check_tree((off_t)(isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length)) * blocksize,
553                                                 isonum_733(idr->size),
554                                                 orig_file_addr * blocksize);
555                         i += buffer[i];
556                         i1++;
557                         if (i > 2048 - offsetof(struct iso_directory_record, name[0]))
558                                 break;
559                 }
560                 file_addr += sizeof (buffer);
561         }
562         fflush(stdout);
563 }
564
565
566 /*
567  * This function simply dumps the contents of the path tables.  No
568  * consistency checking takes place, although this would proably be a good
569  * idea.
570  */
571 struct path_table_info {
572         char            *name;
573         unsigned int    extent;
574         unsigned short  index;
575         unsigned short  parent;
576 };
577
578 static void
579 check_path_tables(int typel_extent, int typem_extent, int path_table_size)
580 {
581         int     count;
582         int     j;
583         char    *pnt;
584         char    *typel;
585         char    *typem;
586
587         /* Now read in the path tables */
588
589         typel = (char *) malloc(ISO_ROUND_UP(path_table_size));
590 #ifdef  USE_SCG
591         readsecs(typel_extent * blocksize / 2048, typel, ISO_BLOCKS(path_table_size));
592 #else
593         lseek(fileno(infile), (off_t)((off_t)typel_extent) * blocksize, SEEK_SET);
594         read(fileno(infile), typel, path_table_size); /* FIXME: check return value */
595 #endif
596         typem = (char *) malloc(path_table_size);
597         lseek(fileno(infile), (off_t)((off_t)typem_extent) * blocksize, SEEK_SET);
598         read(fileno(infile), typem, path_table_size); /* FIXME: check return value */
599
600         j = path_table_size;
601         pnt = typel;
602         count = 1;
603         while (j) {
604                 int     namelen;
605                 int     extent;
606                 int     idx;
607                 char    name[32];
608
609                 namelen = *pnt++; pnt++;
610                 extent = isonum_731(pnt);
611                 pnt += 4;
612                 idx = isonum_721(pnt);
613                 pnt += 2;
614                 j -= 8 + namelen;
615                 memset(name, 0, sizeof (name));
616
617                 strncpy(name, pnt, namelen);
618                 pnt += namelen;
619                 if (j & 1) {
620                         j--;
621                         pnt++;
622                 }
623                 printf("%4.4d %4.4d %8.8x %s\n", count++, idx, extent, name);
624         }
625
626         j = path_table_size;
627         pnt = typem;
628         count = 1;
629
630         while (j) {
631                 int     namelen;
632                 int     extent;
633                 int     idx;
634                 char    name[32];
635
636                 namelen = *pnt++; pnt++;
637                 extent = isonum_732(pnt);
638                 pnt += 4;
639                 idx = isonum_722(pnt);
640                 pnt += 2;
641                 j -= 8+namelen;
642                 memset(name, 0, sizeof (name));
643
644                 strncpy(name, pnt, namelen);
645                 pnt += namelen;
646                 if (j & 1) {
647                         j--;
648                         pnt++;
649                 }
650                 printf("%4.4d %4.4d %8.8x %s\n", count++, idx, extent, name);
651         }
652 }
653
654 static void
655 usage(int excode)
656 {
657         errmsgno(EX_BAD, "Usage: %s [options] image\n",
658                                                 get_progname());
659
660         fprintf(stderr, "Options:\n");
661         fprintf(stderr, "\t-help, -h    Print this help\n");
662         fprintf(stderr, "\t-version     Print version info and exit\n");
663         fprintf(stderr, "\t-i filename  Filename to read ISO-9660 image from\n");
664         fprintf(stderr, "\tdev=target   SCSI target to use as CD/DVD-Recorder\n");
665         fprintf(stderr, "\nIf neither -i nor dev= are speficied, <image> is needed.\n");
666         exit(excode);
667 }
668
669 int
670 main(int argc, char *argv[])
671 {
672         int     cac;
673         char    * const *cav;
674         char    *opts = "help,h,version,i*,dev*";
675         BOOL    help = FALSE;
676         BOOL    prvers = FALSE;
677         char    *filename = NULL;
678         char    *devname = NULL;
679         off_t   file_addr;
680         int     file_size;
681         struct iso_primary_descriptor   ipd;
682         struct iso_directory_record     *idr;
683         int     typel_extent;
684         int     typem_extent;
685         int     path_table_size;
686
687         save_args(argc, argv);
688
689         cac = argc - 1;
690         cav = argv + 1;
691         if (getallargs(&cac, &cav, opts, &help, &help, &prvers,
692                         &filename, &devname) < 0) {
693                 errmsgno(EX_BAD, "Bad Option: '%s'\n", cav[0]);
694                 usage(EX_BAD);
695         }
696         if (help)
697                 usage(0);
698         if (prvers) {
699                 printf("isovfy %s (%s)\n", CDRKIT_VERSION, HOST_SYSTEM);
700                 exit(0);
701         }
702         cac = argc - 1;
703         cav = argv + 1;
704         if (filename == NULL && devname == NULL) {
705                 if (getfiles(&cac, &cav, opts) != 0) {
706                         filename = cav[0];
707                         cac--, cav++;
708                 }
709         }
710         if (getfiles(&cac, &cav, opts) != 0) {
711                 errmsgno(EX_BAD, "Bad Argument: '%s'\n", cav[0]);
712                 usage(EX_BAD);
713         }
714         if (filename != NULL && devname != NULL) {
715                 errmsgno(EX_BAD, "Only one of -i or dev= allowed\n");
716                 usage(EX_BAD);
717         }
718 #ifdef  USE_SCG
719         if (filename == NULL && devname == NULL)
720                 cdr_defaults(&devname, NULL, NULL, NULL);
721 #endif
722         if (filename == NULL && devname == NULL) {
723 #ifdef  USE_LIBSCHILY
724                 errmsgno(EX_BAD, "ISO-9660 image not specified\n");
725 #else
726                 fprintf(stderr, "ISO-9660 image not specified\n");
727 #endif
728                 usage(EX_BAD);
729         }
730
731         if (filename != NULL)
732                 infile = fopen(filename, "rb");
733         else
734                 filename = devname;
735
736         if (infile != NULL) {
737                 /* EMPTY */;
738 #ifdef  USE_SCG
739         } else if (scsidev_open(filename) < 0) {
740 #else
741         } else {
742 #endif
743 #ifdef  USE_LIBSCHILY
744                 comerr("Cannot open '%s'\n", filename);
745 #else
746                 fprintf(stderr, "Cannot open '%s'\n", filename);
747                 exit(1);
748 #endif
749         }
750
751
752         file_addr = (off_t)32768;
753 #ifdef  USE_SCG
754         readsecs(file_addr / 2048, &ipd, ISO_BLOCKS(sizeof (ipd)));
755 #else
756         lseek(fileno(infile), file_addr, SEEK_SET);
757         read(fileno(infile), &ipd, sizeof (ipd));
758 #endif
759
760         idr = (struct iso_directory_record *)ipd.root_directory_record;
761
762         blocksize = isonum_723((char *)ipd.logical_block_size);
763         if (blocksize != 512 && blocksize != 1024 && blocksize != 2048) {
764                 blocksize = 2048;
765         }
766
767         file_addr = (off_t)isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length);
768         file_size = isonum_733(idr->size);
769
770         if (sizeof (file_addr) > sizeof (long)) {
771                 printf("Root at extent %llx, %d bytes\n", (Llong)file_addr, file_size);
772         } else {
773                 printf("Root at extent %lx, %d bytes\n", (long)file_addr, file_size);
774         }
775         file_addr = file_addr * blocksize;
776
777         check_tree(file_addr, file_size, file_addr);
778
779         typel_extent = isonum_731((char *)ipd.type_l_path_table);
780         typem_extent = isonum_732((char *)ipd.type_m_path_table);
781         path_table_size = isonum_733(ipd.path_table_size);
782
783         /* Enable this to get the dump of the path tables */
784 #if 0
785         check_path_tables(typel_extent, typem_extent, path_table_size);
786 #endif
787
788         if (infile != NULL)
789                 fclose(infile);
790
791         if (!ngoof)
792                 printf("No errors found\n");
793         return (0);
794 }