1
/* @(#)isovfy.c 1.15 00/12/09 joerg */
4
"@(#)isovfy.c 1.15 00/12/09 joerg";
7
* File isovfy.c - verify consistency of iso9660 filesystem.
10
Written by Eric Youngdale (1993).
12
Copyright 1993 Yggdrasil Computing, Incorporated
14
This program is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License as published by
16
the Free Software Foundation; either version 2, or (at your option)
19
This program is distributed in the hope that it will be useful,
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
GNU General Public License for more details.
24
You should have received a copy of the GNU General Public License
25
along with this program; if not, write to the Free Software
26
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
42
#define PAGE sizeof(buffer)
44
#define ISODCL(from, to) (to - from + 1)
46
struct iso_primary_descriptor {
47
unsigned char type [ISODCL ( 1, 1)]; /* 711 */
48
unsigned char id [ISODCL ( 2, 6)];
49
unsigned char version [ISODCL ( 7, 7)]; /* 711 */
50
unsigned char unused1 [ISODCL ( 8, 8)];
51
unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */
52
unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */
53
unsigned char unused2 [ISODCL ( 73, 80)];
54
unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
55
unsigned char unused3 [ISODCL ( 89, 120)];
56
unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */
57
unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
58
unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */
59
unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */
60
unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */
61
unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
62
unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */
63
unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
64
unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
65
unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */
66
unsigned char publisher_id [ISODCL (319, 446)]; /* achars */
67
unsigned char preparer_id [ISODCL (447, 574)]; /* achars */
68
unsigned char application_id [ISODCL (575, 702)]; /* achars */
69
unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
70
unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
71
unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
72
unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
73
unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
74
unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
75
unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
76
unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */
77
unsigned char unused4 [ISODCL (883, 883)];
78
unsigned char application_data [ISODCL (884, 1395)];
79
unsigned char unused5 [ISODCL (1396, 2048)];
82
struct iso_directory_record {
83
unsigned char length [ISODCL (1, 1)]; /* 711 */
84
unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */
85
unsigned char extent [ISODCL (3, 10)]; /* 733 */
86
unsigned char size [ISODCL (11, 18)]; /* 733 */
87
unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */
88
unsigned char flags [ISODCL (26, 26)];
89
unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */
90
unsigned char interleave [ISODCL (28, 28)]; /* 711 */
91
unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
92
unsigned char name_len [ISODCL (33, 33)]; /* 711 */
93
unsigned char name [38];
96
int isonum_721 __PR((char * p));
97
int isonum_723 __PR((char * p));
98
int isonum_711 __PR((char * p));
99
int isonum_731 __PR((char * p));
100
int isonum_722 __PR((char * p));
101
int isonum_732 __PR((char * p));
102
int isonum_733 __PR((unsigned char * p));
103
int parse_rr __PR((unsigned char * pnt, int len, int cont_flag));
104
int dump_rr __PR((struct iso_directory_record * idr));
105
void check_tree __PR((off_t file_addr, int file_size, off_t parent_addr));
106
void check_path_tables __PR((int typel_extent, int typem_extent, int path_table_size));
107
void usage __PR((int excode));
108
int main __PR((int argc, char *argv[]));
114
return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
122
if (p[0] != p[3] || p[1] != p[2]) {
124
comerrno(EX_BAD, "invalid format 7.2.3 number\n");
126
fprintf (stderr, "invalid format 7.2.3 number\n");
131
return (isonum_721 (p));
145
return ((p[0] & 0xff)
146
| ((p[1] & 0xff) << 8)
147
| ((p[2] & 0xff) << 16)
148
| ((p[3] & 0xff) << 24));
155
return ((p[1] & 0xff)
156
| ((p[0] & 0xff) << 8));
163
return ((p[3] & 0xff)
164
| ((p[2] & 0xff) << 8)
165
| ((p[1] & 0xff) << 16)
166
| ((p[0] & 0xff) << 24));
173
return (isonum_731 ((char *)p));
181
int parse_rr(pnt, len, cont_flag)
192
int cont_offset, cont_size;
193
char symlinkname[1024];
194
sprintf(lbuffer+iline," RRlen=%d ", len);
195
iline += strlen(lbuffer+iline);
197
cont_extent = (off_t)0;
198
cont_offset = cont_size = 0;
205
if(ncount) sprintf(lbuffer+iline,",");
206
else sprintf(lbuffer+iline,"[");
207
iline += strlen(lbuffer + iline);
208
sprintf(lbuffer+iline,"%c%c", pnt[0], pnt[1]);
209
iline += strlen(lbuffer + iline);
210
if(pnt[0] < 'A' || pnt[0] > 'Z' || pnt[1] < 'A' ||
212
sprintf(lbuffer+iline,"**BAD SUSP %d %d]",
215
iline += strlen(lbuffer + iline);
219
if(pnt[3] != 1 && pnt[3] != 2) {
220
sprintf(lbuffer+iline, "**BAD RRVERSION (%d)\n", pnt[3]);
222
iline += strlen(lbuffer + iline);
226
if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
227
if(strncmp((char *)pnt, "PX", 2) == 0) flag2 |= 1;
228
if(strncmp((char *)pnt, "PN", 2) == 0) flag2 |= 2;
229
if(strncmp((char *)pnt, "SL", 2) == 0) flag2 |= 4;
230
if(strncmp((char *)pnt, "NM", 2) == 0) flag2 |= 8;
231
if(strncmp((char *)pnt, "CL", 2) == 0) flag2 |= 16;
232
if(strncmp((char *)pnt, "PL", 2) == 0) flag2 |= 32;
233
if(strncmp((char *)pnt, "RE", 2) == 0) flag2 |= 64;
234
if(strncmp((char *)pnt, "TF", 2) == 0) flag2 |= 128;
236
if(strncmp((char *)pnt, "CE", 2) == 0) {
237
cont_extent = (off_t)isonum_733(pnt+4);
238
cont_offset = isonum_733(pnt+12);
239
cont_size = isonum_733(pnt+20);
240
sprintf(lbuffer+iline, "=[%x,%x,%d]",
241
(int)cont_extent, cont_offset, cont_size);
242
iline += strlen(lbuffer + iline);
245
if(strncmp((char *)pnt, "PL", 2) == 0 || strncmp((char *)pnt, "CL", 2) == 0) {
246
extent = isonum_733(pnt+4);
247
sprintf(lbuffer+iline,"=%x", extent);
248
iline += strlen(lbuffer + iline);
249
if(extent == 0) rr_goof++;
251
if(strncmp((char *)pnt, "SL", 2) == 0) {
255
switch(pnts[0] & 0xfe){
257
strncat(symlinkname, (char *)(pnts+2), pnts[1]);
260
strcat (symlinkname, ".");
263
strcat (symlinkname, "..");
266
strcat (symlinkname, "/");
269
strcat(symlinkname,"/mnt");
270
sprintf(lbuffer+iline,"Warning - mount point requested");
271
iline += strlen(lbuffer + iline);
274
strcat(symlinkname,"kafka");
275
sprintf(lbuffer+iline,"Warning - host_name requested");
276
iline += strlen(lbuffer + iline);
279
sprintf(lbuffer+iline,"Reserved bit setting in symlink");
281
iline += strlen(lbuffer + iline);
284
if((pnts[0] & 0xfe) && pnts[1] != 0) {
285
sprintf(lbuffer+iline,"Incorrect length in symlink component");
286
iline += strlen(lbuffer + iline);
288
if((pnts[0] & 1) == 0)
289
strcat(symlinkname,"/");
290
slen -= (pnts[1] + 2);
291
pnts += (pnts[1] + 2);
294
if(symlinkname[0] != 0) {
295
sprintf(lbuffer+iline,"=%s", symlinkname);
296
iline += strlen(lbuffer + iline);
303
if(len <= 3 && cont_extent) {
304
unsigned char sector[2048];
305
lseek(fileno(infile), cont_extent * blocksize, SEEK_SET);
306
read(fileno(infile), sector, sizeof(sector));
307
flag2 |= parse_rr(§or[cont_offset], cont_size, 1);
312
sprintf(lbuffer+iline,"]");
313
iline += strlen(lbuffer + iline);
315
if (!cont_flag && flag1 && flag1 != flag2)
317
sprintf(lbuffer+iline,"Flag %x != %x", flag1, flag2);
319
iline += strlen(lbuffer + iline);
326
struct iso_directory_record *idr;
331
len = idr->length[0] & 0xff;
332
len -= (sizeof(struct iso_directory_record) - sizeof(idr->name));
333
len -= idr->name_len[0];
335
pnt += (sizeof(struct iso_directory_record) - sizeof(idr->name));
336
pnt += idr->name_len[0];
338
if((idr->name_len[0] & 1) == 0){
344
parse_rr((unsigned char *)pnt, len, 0);
350
int dir_size_count = 0;
354
check_tree(file_addr, file_size, parent_addr)
359
unsigned char buffer[2048];
364
off_t orig_file_addr, parent_file_addr;
365
struct iso_directory_record * idr;
369
orig_file_addr = file_addr / blocksize; /* Actual extent of this directory */
370
parent_file_addr = parent_addr / blocksize;
372
if((dir_count % 100) == 0) printf("[%d %d]\n", dir_count, dir_size_count);
374
if (sizeof(file_addr) > sizeof(long)) {
375
printf("Starting directory %ld %d %lld\n",
376
file_addr, file_size,
379
printf("Starting directory %ld %d %ld\n", file_addr, file_size, parent_addr);
384
dir_size_count += file_size / blocksize;
386
if(file_size & 0x3ff) printf("********Directory has unusual size\n");
388
for(k=0; k < (file_size / sizeof(buffer)); k++){
389
lseek(fileno(infile), file_addr, SEEK_SET);
390
read(fileno(infile), buffer, sizeof(buffer));
394
idr = (struct iso_directory_record *) &buffer[i];
395
if(idr->length[0] == 0) break;
396
sprintf(&lbuffer[iline],"%3d ", idr->length[0]);
397
iline += strlen(lbuffer + iline);
398
extent = isonum_733(idr->extent);
399
size = isonum_733(idr->size);
400
sprintf(&lbuffer[iline],"%5x ", extent);
401
iline += strlen(lbuffer + iline);
402
sprintf(&lbuffer[iline],"%8d ", size);
403
iline += strlen(lbuffer + iline);
404
sprintf (&lbuffer[iline], "%c", (idr->flags[0] & 2) ? '*' : ' ');
405
iline += strlen(lbuffer + iline);
407
if(idr->name_len[0] > 33)
409
sprintf(&lbuffer[iline],"File name length=(%d)",
412
iline += strlen(lbuffer + iline);
414
else if(idr->name_len[0] == 1 && idr->name[0] == 0) {
415
sprintf(&lbuffer[iline],". ");
416
iline += strlen(lbuffer + iline);
418
if(orig_file_addr !=(off_t)(isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length)))
420
sprintf(&lbuffer[iline],"***** Directory has null extent.");
422
iline += strlen(lbuffer + iline);
426
sprintf(&lbuffer[iline],"***** . not first entry.");
428
iline += strlen(lbuffer + iline);
430
} else if(idr->name_len[0] == 1 && idr->name[0] == 1) {
431
sprintf(&lbuffer[iline],".. ");
432
iline += strlen(lbuffer + iline);
434
if(parent_file_addr != (off_t)(isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length)))
436
sprintf(&lbuffer[iline],"***** Directory has null extent.");
438
iline += strlen(lbuffer + iline);
442
sprintf(&lbuffer[iline],"***** .. not second entry.");
444
iline += strlen(lbuffer + iline);
450
sprintf(&lbuffer[iline]," Improper sorting.");
453
for(j=0; j<idr->name_len[0]; j++)
455
sprintf(&lbuffer[iline],"%c", idr->name[j]);
457
for(j=0; j<14 - (int) idr->name_len[0]; j++)
459
sprintf(&lbuffer[iline]," ");
460
iline += strlen(lbuffer + iline);
465
if(size && extent == 0)
467
sprintf(&lbuffer[iline],"****Extent==0, size != 0");
469
iline += strlen(lbuffer + iline);
472
/* This is apparently legal. */
473
if(size == 0 && extent)
475
sprintf(&lbuffer[iline],"****Extent!=0, size == 0");
477
iline += strlen(lbuffer + iline);
481
if(idr->flags[0] & 0xf5)
483
sprintf(&lbuffer[iline],"Flags=(%x) ", idr->flags[0]);
485
iline += strlen(lbuffer + iline);
487
if(idr->interleave[0])
489
sprintf(&lbuffer[iline],"Interleave=(%d) ", idr->interleave[0]);
491
iline += strlen(lbuffer + iline);
494
if(idr->file_unit_size[0])
496
sprintf(&lbuffer[iline],"File unit size=(%d) ", idr->file_unit_size[0]);
498
iline += strlen(lbuffer + iline);
502
if(idr->volume_sequence_number[0] != 1)
504
sprintf(&lbuffer[iline],"Volume sequence number=(%d) ", idr->volume_sequence_number[0]);
506
iline += strlen(lbuffer + iline);
509
goof += dump_rr(idr);
510
sprintf(&lbuffer[iline],"\n");
511
iline += strlen(lbuffer + iline);
516
lbuffer[iline++] = 0;
517
if (sizeof(orig_file_addr) > sizeof(long)) {
518
printf("%llx: %s", (Llong)orig_file_addr, lbuffer);
520
printf("%lx: %s", (long)orig_file_addr, lbuffer);
526
if(rflag && (idr->flags[0] & 2)) check_tree((off_t)(isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length)) * blocksize,
527
isonum_733(idr->size),
528
orig_file_addr * blocksize);
531
if (i > 2048 - sizeof(struct iso_directory_record)) break;
533
file_addr += sizeof(buffer);
539
/* This function simply dumps the contents of the path tables. No
540
consistency checking takes place, although this would proably be a good
543
struct path_table_info{
546
unsigned short index;
547
unsigned short parent;
551
check_path_tables(typel_extent, typem_extent, path_table_size)
559
char * typel, *typem;
561
/* Now read in the path tables */
563
typel = (char *) malloc(path_table_size);
564
lseek(fileno(infile), (off_t)((off_t)typel_extent) * blocksize, SEEK_SET);
565
read(fileno(infile), typel, path_table_size);
567
typem = (char *) malloc(path_table_size);
568
lseek(fileno(infile), (off_t)((off_t)typem_extent) * blocksize, SEEK_SET);
569
read(fileno(infile), typem, path_table_size);
575
int namelen, extent, idx;
577
namelen = *pnt++; pnt++;
578
extent = isonum_731(pnt); pnt += 4;
579
idx = isonum_721(pnt); pnt+= 2;
581
memset(name, 0, sizeof(name));
583
strncpy(name, pnt, namelen);
585
if(j & 1) { j--; pnt++;};
586
printf("%4.4d %4.4d %8.8x %s\n",count++, idx, extent, name);
593
int namelen, extent, idx;
595
namelen = *pnt++; pnt++;
596
extent = isonum_732(pnt); pnt += 4;
597
idx = isonum_722(pnt); pnt+= 2;
599
memset(name, 0, sizeof(name));
601
strncpy(name, pnt, namelen);
603
if(j & 1) { j--; pnt++;};
604
printf("%4.4d %4.4d %8.8x %s\n", count++, idx, extent, name);
613
errmsgno(EX_BAD, "Usage: %s [options] image\n",
627
struct iso_primary_descriptor ipd;
628
struct iso_directory_record * idr;
629
int typel_extent, typem_extent;
632
save_args(argc, argv);
636
infile = fopen(argv[1],"rb");
637
if (infile == NULL) {
639
comerr("Cannot open '%s'.\n", argv[1]);
641
printf("Cannot open '%s'.\n", argv[1]);
647
file_addr = (off_t)32768;
648
lseek(fileno(infile), file_addr, SEEK_SET);
649
read(fileno(infile), &ipd, sizeof(ipd));
651
idr = (struct iso_directory_record *)ipd.root_directory_record;
653
blocksize = isonum_723((char *)ipd.logical_block_size);
654
if( blocksize != 512 && blocksize != 1024 && blocksize != 2048 )
659
file_addr = (off_t)isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length);
660
file_size = isonum_733(idr->size);
662
if (sizeof(file_addr) > sizeof(long)) {
663
printf("Root at extent %llx, %d bytes\n", (Llong)file_addr, file_size);
665
printf("Root at extent %lx, %d bytes\n", (long)file_addr, file_size);
667
file_addr = file_addr * blocksize;
669
check_tree(file_addr, file_size, file_addr);
671
typel_extent = isonum_731((char *)ipd.type_l_path_table);
672
typem_extent = isonum_732((char *)ipd.type_m_path_table);
673
path_table_size = isonum_733(ipd.path_table_size);
675
/* Enable this to get the dump of the path tables */
677
check_path_tables(typel_extent, typem_extent, path_table_size);
682
if(!ngoof) printf("No errors found\n");