1 /*
2 * File isovfy.c - verify consistency of iso9660 filesystem.
3 *
4
5 Written by Eric Youngdale (1993).
6
7 Copyright 1993 Yggdrasil Computing, Incorporated
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22
23 static char rcsid[] ="$Id: isovfy.c,v 1.1 2000/10/10 20:40:28 beck Exp $";
24
25 #include <stdio.h>
26 #include <signal.h>
27
28 FILE * infile;
29 int blocksize;
30
31 #define PAGE sizeof(buffer)
32
33 #define ISODCL(from, to) (to - from + 1)
34
35 struct iso_primary_descriptor {
36 unsigned char type [ISODCL ( 1, 1)]; /* 711 */
37 unsigned char id [ISODCL ( 2, 6)];
38 unsigned char version [ISODCL ( 7, 7)]; /* 711 */
39 unsigned char unused1 [ISODCL ( 8, 8)];
40 unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */
41 unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */
42 unsigned char unused2 [ISODCL ( 73, 80)];
43 unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
44 unsigned char unused3 [ISODCL ( 89, 120)];
45 unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */
46 unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
47 unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */
48 unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */
49 unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */
50 unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
51 unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */
52 unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
53 unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
54 unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */
55 unsigned char publisher_id [ISODCL (319, 446)]; /* achars */
56 unsigned char preparer_id [ISODCL (447, 574)]; /* achars */
57 unsigned char application_id [ISODCL (575, 702)]; /* achars */
58 unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
59 unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
60 unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
61 unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
62 unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
63 unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
64 unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
65 unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */
66 unsigned char unused4 [ISODCL (883, 883)];
67 unsigned char application_data [ISODCL (884, 1395)];
68 unsigned char unused5 [ISODCL (1396, 2048)];
69 };
70
71 struct iso_directory_record {
72 unsigned char length [ISODCL (1, 1)]; /* 711 */
73 unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */
74 unsigned char extent [ISODCL (3, 10)]; /* 733 */
75 unsigned char size [ISODCL (11, 18)]; /* 733 */
76 unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */
77 unsigned char flags [ISODCL (26, 26)];
78 unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */
79 unsigned char interleave [ISODCL (28, 28)]; /* 711 */
80 unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
81 unsigned char name_len [ISODCL (33, 33)]; /* 711 */
82 unsigned char name [38];
83 };
84
85 int
isonum_723(char * p)86 isonum_723 (char * p)
87 {
88 #if 0
89 if (p[0] != p[3] || p[1] != p[2]) {
90 fprintf (stderr, "invalid format 7.2.3 number\n");
91 exit (1);
92 }
93 #endif
94 return (isonum_721 (p));
95 }
96
97 int
isonum_721(char * p)98 isonum_721 (char * p)
99 {
100 return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
101 }
102
103 int
isonum_711(char * p)104 isonum_711 (char * p)
105 {
106 return (*p & 0xff);
107 }
108
109 int
isonum_731(char * p)110 isonum_731 (char * p)
111 {
112 return ((p[0] & 0xff)
113 | ((p[1] & 0xff) << 8)
114 | ((p[2] & 0xff) << 16)
115 | ((p[3] & 0xff) << 24));
116 }
117
118 int
isonum_722(char * p)119 isonum_722 (char * p)
120 {
121 return ((p[1] & 0xff)
122 | ((p[0] & 0xff) << 8));
123 }
124
125 int
isonum_732(char * p)126 isonum_732 (char * p)
127 {
128 return ((p[3] & 0xff)
129 | ((p[2] & 0xff) << 8)
130 | ((p[1] & 0xff) << 16)
131 | ((p[0] & 0xff) << 24));
132 }
133
134 int
isonum_733(unsigned char * p)135 isonum_733 (unsigned char * p)
136 {
137 return (isonum_731 ((char *)p));
138 }
139
140 char lbuffer[1024];
141 int iline;
142 int rr_goof;
143
144
145 int
dump_rr(struct iso_directory_record * idr)146 dump_rr(struct iso_directory_record * idr){
147 int len;
148 char * pnt;
149
150 len = idr->length[0] & 0xff;
151 len -= (sizeof(struct iso_directory_record) - sizeof(idr->name));
152 len -= idr->name_len[0];
153 pnt = (char *) idr;
154 pnt += (sizeof(struct iso_directory_record) - sizeof(idr->name));
155 pnt += idr->name_len[0];
156
157 if((idr->name_len[0] & 1) == 0){
158 pnt++;
159 len--;
160 };
161
162 rr_goof = 0;
163 parse_rr(pnt, len, 0);
164 return rr_goof;
165 }
166
parse_rr(unsigned char * pnt,int len,int cont_flag)167 int parse_rr(unsigned char * pnt, int len, int cont_flag)
168 {
169 int slen;
170 int ncount;
171 int flag1, flag2;
172 int extent;
173 unsigned char *pnts;
174 int cont_extent, cont_offset, cont_size;
175 char symlink[1024];
176 sprintf(lbuffer+iline," RRlen=%d ", len);
177 iline += strlen(lbuffer+iline);
178
179 cont_extent = cont_offset = cont_size = 0;
180
181 symlink[0] = 0;
182
183 ncount = 0;
184 flag1 = flag2 = 0;
185 while(len >= 4){
186 if(ncount) sprintf(lbuffer+iline,",");
187 else sprintf(lbuffer+iline,"[");
188 iline += strlen(lbuffer + iline);
189 sprintf(lbuffer+iline,"%c%c", pnt[0], pnt[1]);
190 iline += strlen(lbuffer + iline);
191 if(pnt[0] < 'A' || pnt[0] > 'Z' || pnt[1] < 'A' ||
192 pnt[1] > 'Z') {
193 sprintf(lbuffer+iline,"**BAD SUSP %d %d]",
194 pnt[0], pnt[1], rr_goof++);
195 iline += strlen(lbuffer + iline);
196 return flag2;
197 };
198
199 if(pnt[3] != 1) {
200 sprintf(lbuffer+iline,"**BAD RRVERSION", rr_goof++);
201 iline += strlen(lbuffer + iline);
202 return flag2;
203 };
204 ncount++;
205 if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff;
206 if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1;
207 if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2;
208 if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4;
209 if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8;
210 if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16;
211 if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32;
212 if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64;
213 if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128;
214
215 if(strncmp(pnt, "CE", 2) == 0) {
216 cont_extent = isonum_733(pnt+4);
217 cont_offset = isonum_733(pnt+12);
218 cont_size = isonum_733(pnt+20);
219 sprintf(lbuffer+iline, "=[%x,%x,%d]",
220 cont_extent, cont_offset, cont_size);
221 iline += strlen(lbuffer + iline);
222 };
223
224 if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) {
225 extent = isonum_733(pnt+4);
226 sprintf(lbuffer+iline,"=%x", extent);
227 iline += strlen(lbuffer + iline);
228 if(extent == 0) rr_goof++;
229 };
230 if(strncmp(pnt, "SL", 2) == 0) {
231 pnts = pnt+5;
232 slen = pnt[2] - 5;
233 while(slen >= 1){
234 switch(pnts[0] & 0xfe){
235 case 0:
236 strncat(symlink, pnts+2, pnts[1]);
237 break;
238 case 2:
239 strcat (symlink, ".");
240 break;
241 case 4:
242 strcat (symlink, "..");
243 break;
244 case 8:
245 strcat (symlink, "/");
246 break;
247 case 16:
248 strcat(symlink,"/mnt");
249 sprintf(lbuffer+iline,"Warning - mount point requested");
250 iline += strlen(lbuffer + iline);
251 break;
252 case 32:
253 strcat(symlink,"kafka");
254 sprintf(lbuffer+iline,"Warning - host_name requested");
255 iline += strlen(lbuffer + iline);
256 break;
257 default:
258 sprintf(lbuffer+iline,"Reserved bit setting in symlink", rr_goof++);
259 iline += strlen(lbuffer + iline);
260 break;
261 };
262 if((pnts[0] & 0xfe) && pnts[1] != 0) {
263 sprintf(lbuffer+iline,"Incorrect length in symlink component");
264 iline += strlen(lbuffer + iline);
265 };
266 if((pnts[0] & 1) == 0)
267 strcat(symlink,"/");
268 slen -= (pnts[1] + 2);
269 pnts += (pnts[1] + 2);
270
271 };
272 if(symlink[0] != 0) {
273 sprintf(lbuffer+iline,"=%s", symlink);
274 iline += strlen(lbuffer + iline);
275 symlink[0] = 0;
276 }
277 };
278
279 len -= pnt[2];
280 pnt += pnt[2];
281 if(len <= 3 && cont_extent) {
282 unsigned char sector[2048];
283 lseek(fileno(infile), cont_extent * blocksize, 0);
284 read(fileno(infile), sector, sizeof(sector));
285 flag2 |= parse_rr(§or[cont_offset], cont_size, 1);
286 };
287 };
288 if(ncount)
289 {
290 sprintf(lbuffer+iline,"]");
291 iline += strlen(lbuffer + iline);
292 }
293 if (!cont_flag && flag1 && flag1 != flag2)
294 {
295 sprintf(lbuffer+iline,"Flag %x != %x", flag1, flag2, rr_goof++);
296 iline += strlen(lbuffer + iline);
297 }
298 return flag2;
299 }
300
301
302 int dir_count = 0;
303 int dir_size_count = 0;
304 int ngoof = 0;
305
306
check_tree(int file_addr,int file_size,int parent_addr)307 check_tree(int file_addr, int file_size, int parent_addr){
308 unsigned char buffer[2048];
309 unsigned int k;
310 int rflag;
311 int i, i1, j, goof;
312 int extent, size;
313 int line;
314 int orig_file_addr, parent_file_addr;
315 struct iso_directory_record * idr;
316
317 i1 = 0;
318
319 orig_file_addr = file_addr / blocksize; /* Actual extent of this directory */
320 parent_file_addr = parent_addr / blocksize;
321
322 if((dir_count % 100) == 0) printf("[%d %d]\n", dir_count, dir_size_count);
323 #if 0
324 printf("Starting directory %d %d %d\n", file_addr, file_size, parent_addr);
325 #endif
326
327 dir_count++;
328 dir_size_count += file_size / blocksize;
329
330 if(file_size & 0x3ff) printf("********Directory has unusual size\n");
331
332 for(k=0; k < (file_size / sizeof(buffer)); k++){
333 lseek(fileno(infile), file_addr, 0);
334 read(fileno(infile), buffer, sizeof(buffer));
335 i = 0;
336 while(1==1){
337 goof = iline=0;
338 idr = (struct iso_directory_record *) &buffer[i];
339 if(idr->length[0] == 0) break;
340 sprintf(&lbuffer[iline],"%3d ", idr->length[0]);
341 iline += strlen(lbuffer + iline);
342 extent = isonum_733(idr->extent);
343 size = isonum_733(idr->size);
344 sprintf(&lbuffer[iline],"%5x ", extent);
345 iline += strlen(lbuffer + iline);
346 sprintf(&lbuffer[iline],"%8d ", size);
347 iline += strlen(lbuffer + iline);
348 sprintf (&lbuffer[iline], "%c", (idr->flags[0] & 2) ? '*' : ' ');
349 iline += strlen(lbuffer + iline);
350
351 if(idr->name_len[0] > 33)
352 {
353 sprintf(&lbuffer[iline],"File name length=(%d)",
354 idr->name_len[0], goof++);
355 iline += strlen(lbuffer + iline);
356 }
357 else if(idr->name_len[0] == 1 && idr->name[0] == 0) {
358 sprintf(&lbuffer[iline],". ");
359 iline += strlen(lbuffer + iline);
360 rflag = 0;
361 if(orig_file_addr !=isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length))
362 {
363 sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++);
364 iline += strlen(lbuffer + iline);
365 }
366 if(i1)
367 {
368 sprintf(&lbuffer[iline],"***** . not first entry.", rr_goof++);
369 iline += strlen(lbuffer + iline);
370 }
371 } else if(idr->name_len[0] == 1 && idr->name[0] == 1) {
372 sprintf(&lbuffer[iline],".. ");
373 iline += strlen(lbuffer + iline);
374 rflag = 0;
375 if(parent_file_addr !=isonum_733(idr->extent) + isonum_711((char *) idr->ext_attr_length))
376 {
377 sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++);
378 iline += strlen(lbuffer + iline);
379 }
380 if(i1 != 1)
381 {
382 sprintf(&lbuffer[iline],"***** .. not second entry.", rr_goof++);
383 iline += strlen(lbuffer + iline);
384 }
385
386 } else {
387 if(i1 < 2)
388 {
389 sprintf(&lbuffer[iline]," Improper sorting.", rr_goof++);
390 }
391 for(j=0; j<idr->name_len[0]; j++)
392 {
393 sprintf(&lbuffer[iline],"%c", idr->name[j]);
394 }
395 for(j=0; j<14 - (int) idr->name_len[0]; j++)
396 {
397 sprintf(&lbuffer[iline]," ");
398 iline += strlen(lbuffer + iline);
399 }
400 rflag = 1;
401 };
402
403 if(size && extent == 0)
404 {
405 sprintf(&lbuffer[iline],"****Extent==0, size != 0", goof++);
406 iline += strlen(lbuffer + iline);
407 }
408 #if 0
409 /* This is apparently legal. */
410 if(size == 0 && extent)
411 {
412 sprintf(&lbuffer[iline],"****Extent!=0, size == 0", goof++);
413 iline += strlen(lbuffer + iline);
414 }
415 #endif
416
417 if(idr->flags[0] & 0xf5)
418 {
419 sprintf(&lbuffer[iline],"Flags=(%x) ", idr->flags[0], goof++);
420 iline += strlen(lbuffer + iline);
421 }
422 if(idr->interleave[0])
423 {
424 sprintf(&lbuffer[iline],"Interleave=(%d) ", idr->interleave[0], goof++);
425 iline += strlen(lbuffer + iline);
426 }
427
428 if(idr->file_unit_size[0])
429 {
430 sprintf(&lbuffer[iline],"File unit size=(%d) ", idr->file_unit_size[0], goof++);
431 iline += strlen(lbuffer + iline);
432 }
433
434
435 if(idr->volume_sequence_number[0] != 1)
436 {
437 sprintf(&lbuffer[iline],"Volume sequence number=(%d) ", idr->volume_sequence_number[0], goof++);
438 iline += strlen(lbuffer + iline);
439 }
440
441 goof += dump_rr(idr);
442 sprintf(&lbuffer[iline],"\n");
443 iline += strlen(lbuffer + iline);
444
445
446 if(goof){
447 ngoof++;
448 lbuffer[iline++] = 0;
449 printf("%x: %s", orig_file_addr, lbuffer);
450 };
451
452
453
454 if(rflag && (idr->flags[0] & 2)) check_tree((isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length)) * blocksize,
455 isonum_733(idr->size),
456 orig_file_addr * blocksize);
457 i += buffer[i];
458 i1++;
459 if (i > 2048 - sizeof(struct iso_directory_record)) break;
460 };
461 file_addr += sizeof(buffer);
462 };
463 fflush(stdout);
464 }
465
466
467 /* This function simply dumps the contents of the path tables. No
468 consistency checking takes place, although this would proably be a good
469 idea. */
470
471 struct path_table_info{
472 char * name;
473 unsigned int extent;
474 unsigned short index;
475 unsigned short parent;
476 };
477
478
check_path_tables(int typel_extent,int typem_extent,int path_table_size)479 check_path_tables(int typel_extent, int typem_extent, int path_table_size){
480 int file_addr;
481 int count;
482 int j;
483 char * pnt;
484 char * typel, *typem;
485
486 /* Now read in the path tables */
487
488 typel = (char *) malloc(path_table_size);
489 lseek(fileno(infile), typel_extent * blocksize, 0);
490 read(fileno(infile), typel, path_table_size);
491
492 typem = (char *) malloc(path_table_size);
493 lseek(fileno(infile), typem_extent * blocksize, 0);
494 read(fileno(infile), typem, path_table_size);
495
496 j = path_table_size;
497 pnt = typel;
498 count = 1;
499 while(j){
500 int namelen, extent, index;
501 char name[32];
502 namelen = *pnt++; pnt++;
503 extent = isonum_731(pnt); pnt += 4;
504 index = isonum_721(pnt); pnt+= 2;
505 j -= 8+namelen;
506 memset(name, 0, sizeof(name));
507
508 strncpy(name, pnt, namelen);
509 pnt += namelen;
510 if(j & 1) { j--; pnt++;};
511 printf("%4.4d %4.4d %8.8x %s\n",count++, index, extent, name);
512 };
513
514 j = path_table_size;
515 pnt = typem;
516 count = 1;
517 while(j){
518 int namelen, extent, index;
519 char name[32];
520 namelen = *pnt++; pnt++;
521 extent = isonum_732(pnt); pnt += 4;
522 index = isonum_722(pnt); pnt+= 2;
523 j -= 8+namelen;
524 memset(name, 0, sizeof(name));
525
526 strncpy(name, pnt, namelen);
527 pnt += namelen;
528 if(j & 1) { j--; pnt++;};
529 printf("%4.4d %4.4d %8.8x %s\n", count++, index, extent, name);
530 };
531
532 }
533
main(int argc,char * argv[])534 main(int argc, char * argv[]){
535 int file_addr, file_size;
536 char c;
537 int nbyte;
538 struct iso_primary_descriptor ipd;
539 struct iso_directory_record * idr;
540 int typel_extent, typem_extent;
541 int path_table_size;
542 int i,j;
543 if(argc < 2) return 0;
544 infile = fopen(argv[1],"rb");
545
546
547 file_addr = 32768;
548 lseek(fileno(infile), file_addr, 0);
549 read(fileno(infile), &ipd, sizeof(ipd));
550
551 idr = (struct iso_directory_record *) &ipd.root_directory_record;
552
553 blocksize = isonum_723((char *)ipd.logical_block_size);
554 if( blocksize != 512 && blocksize != 1024 && blocksize != 2048 )
555 {
556 blocksize = 2048;
557 }
558
559 file_addr = isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length);
560 file_size = isonum_733(idr->size);
561
562 printf("Root at extent %x, %d bytes\n", file_addr, file_size);
563 file_addr = file_addr * blocksize;
564
565 check_tree(file_addr, file_size, file_addr);
566
567 typel_extent = isonum_731((char *)ipd.type_l_path_table);
568 typem_extent = isonum_732((char *)ipd.type_m_path_table);
569 path_table_size = isonum_733(ipd.path_table_size);
570
571 /* Enable this to get the dump of the path tables */
572 #if 0
573 check_path_tables(typel_extent, typem_extent, path_table_size);
574 #endif
575
576 fclose(infile);
577
578 if(!ngoof) printf("No errors found\n");
579 }
580
581
582
583
584