xref: /openbsd/gnu/usr.sbin/mkhybrid/src/diag/isovfy.c (revision f0d9efc0)
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(&sector[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