home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / amicdrom / src / checkcd.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  12KB  |  486 lines

  1. /* Checkcd.c:
  2.  *
  3.  * Performs consistency checks on a ISO 9660 CD.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18.  
  19. #include <dos/var.h>
  20.  
  21. #include <clib/dos_protos.h>
  22. #include <clib/exec_protos.h>
  23. #include <clib/utility_protos.h>
  24.  
  25. #include "cdrom.h"
  26. #include "iso9660.h"
  27. #include "rock.h"
  28.  
  29. #ifdef LATTICE
  30. #include <pragmas/dos_pragmas.h>
  31. #include <pragmas/exec_pragmas.h>
  32. #include <pragmas/utility_pragmas.h>
  33. extern struct Library *SysBase, *DOSBase;
  34. #endif
  35.  
  36. #define STD_BUFFERS 20
  37. #define FILE_BUFFERS 2
  38.  
  39. CDROM *g_cd = NULL;
  40. char g_the_device[80];
  41. int g_the_unit;
  42. t_ulong g_memory_type = MEMF_CHIP;
  43. t_ulong g_check_sector;
  44. char *g_check_name;
  45. prim_vol_desc g_pvd;
  46. int g_path_table_records = 0;
  47.  
  48. struct Library *UtilityBase;
  49.  
  50. #define TU(x,o)  (t_ulong)(((unsigned char *)(x))[o])
  51. #define GET721(x) (TU(x,0) + (TU(x,1) << 8))
  52. #define GET722(x) (TU(x,1) + (TU(x,0) << 8))
  53. #define GET731(x) (TU(x,0) + (TU(x,1) << 8) + (TU(x,2) << 16) + (TU(x,3) << 24))
  54. #define GET732(x) (TU(x,3) + (TU(x,2) << 8) + (TU(x,1) << 16) + (TU(x,0) << 24))
  55.  
  56. /* Check consistency of a 7.2.3 field: */
  57.  
  58. void Check_723 (void *p_buf, int p_offset)
  59. {
  60.   t_uchar *buf = (t_uchar *) (p_buf) + (p_offset - 1);
  61.   t_ulong l = buf[0] + (buf[1] << 8);
  62.   t_ulong m = buf[3] + (buf[2] << 8);
  63.   if (l != m) {
  64.     printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.2.3\n",
  65.             g_check_name, g_check_sector, p_offset);
  66.   }
  67. }
  68.  
  69. /* Check consistency of a 7.3.3 field: */
  70.  
  71. void Check_733 (void *p_buf, int p_offset)
  72. {
  73.   t_uchar *buf = (t_uchar *) p_buf + (p_offset - 1);
  74.   t_ulong l = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
  75.   t_ulong m = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
  76.   if (l != m) {
  77.     printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.3.3\n",
  78.             g_check_name, g_check_sector, p_offset);
  79.   }
  80. }
  81.  
  82. /* Check optional path tables: */
  83.  
  84. void Check_Optional_Path_Tables (void)
  85. {
  86.   t_ulong loc1, loc2;
  87.   t_uchar *buf1;
  88.   t_uchar *buf2;
  89.   int i;
  90.   
  91.   for (i=0; i<=1; i++) {
  92.   
  93.     int remain = g_pvd.path_size_m;
  94.  
  95.     if (i == 0)
  96.       loc1 = GET731((char*) &g_pvd.l_table),
  97.       loc2 = GET731((char *) &g_pvd.opt_l_table);
  98.     else
  99.       loc1 = g_pvd.m_table, loc2 = g_pvd.opt_m_table;
  100.     if (!loc2)
  101.       continue;
  102.  
  103.     for (;;) {
  104.     
  105.       if (!Read_Sector (g_cd, loc1)) {
  106.         printf ("ERROR: illegal sector %lu\n", loc1);
  107.         exit (1);
  108.       }
  109.       buf1 = g_cd->buffer;
  110.     
  111.       if (!Read_Sector (g_cd, loc2)) {
  112.         printf ("ERROR: illegal sector %lu\n", loc2);
  113.         exit (1);
  114.       }
  115.       buf2 = g_cd->buffer;
  116.  
  117.       if (memcmp (buf1, buf2, remain > 2048 ? 2048 : remain) != 0) {
  118.         printf ("ERROR: %c path table and optional %c path table differ"
  119.         " in sectors %lu and %lu\n",
  120.         i ? 'M' : 'L', i ? 'M' : 'L', loc1, loc2);
  121.       }
  122.  
  123.       if (remain > 2048)
  124.         remain -= 2048;
  125.       else
  126.         break;
  127.  
  128.       loc1++, loc2++;
  129.     }
  130.   }
  131. }
  132.  
  133. /* Get the path table record in sector p_loc with offset *p_offset. */
  134.  
  135. void Get_Path_Table_Record (t_uchar *p_buf, t_ulong p_loc, t_ulong *p_offset)
  136. {
  137.   t_ulong sector = p_loc + (*p_offset >> 11);
  138.   int len;
  139.  
  140.   if (!Read_Sector (g_cd, sector)) {
  141.     printf ("ERROR: illegal sector %lu\n", sector);
  142.     exit (1);
  143.   }
  144.   len = g_cd->buffer[*p_offset & 2047] + 8;
  145.   if (len & 1)
  146.     len++;
  147.  
  148.   if (len + (*p_offset & 2047) > 2048) {
  149.     int part1_len = 2048 - (*p_offset & 2047);
  150.     memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), part1_len);
  151.     if (!Read_Sector (g_cd, sector+1)) {
  152.       printf ("ERROR: illegal sector %lu\n", sector+1);
  153.       exit (1);
  154.     }
  155.     memcpy (p_buf + part1_len, g_cd->buffer, len - part1_len);
  156.   } else
  157.     memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), len);
  158.   
  159.   *p_offset += len;
  160. }
  161.  
  162. /* Test whether the L and the M path tables contain the same information: */
  163.  
  164. void Compare_L_And_M_Path_Table (void)
  165. {
  166.   t_ulong loc1 = GET731((char*) &g_pvd.l_table);
  167.   t_ulong loc2 = g_pvd.m_table;
  168.   t_ulong offset1 = 0;
  169.   t_ulong offset2 = 0;
  170.   static t_uchar buf1[256];
  171.   static t_uchar buf2[256];
  172.  
  173.   while (offset1 < g_pvd.path_size_m) {
  174.  
  175.     t_ulong tmp = offset1;
  176.  
  177.     Get_Path_Table_Record (buf1, loc1, &offset1);
  178.     Get_Path_Table_Record (buf2, loc2, &offset2);
  179.  
  180.     if (offset1 != offset2) {
  181.       printf ("ERROR: Length mismatch in L and M path table at offset %lu\n",
  182.                 tmp);
  183.       return;
  184.     }
  185.  
  186.     if (buf1[1] != buf2[1])
  187.       printf ("ERROR: Extended attribute record lengths differ in L and M"
  188.               " path table at offset %lu\n", offset1);
  189.  
  190.     if (memcmp (buf1+8, buf2+8, buf1[0]) != 0)
  191.       printf ("ERROR: directory identifiers differ in L and M path table "
  192.               "at offset %lu\n", offset1);
  193.  
  194.     if (GET731 (buf1+2) != GET732 (buf2+2))
  195.       printf ("ERROR: extent locations differ in L and M path table at"
  196.               " offset %lu\n", offset1);
  197.  
  198.     if (GET721 (buf1+6) != GET722 (buf2+6))
  199.       printf ("ERROR: parent directory numbers differ in L and M path table at"
  200.               " offset %lu\n", offset1);
  201.  
  202.     g_path_table_records++;
  203.   }
  204. }
  205.  
  206. /* Check consistency of path table and directory records: */
  207.  
  208. void Compare_Path_Table_With_Directory_Records (void)
  209. {
  210.   t_ulong loc = g_pvd.m_table;
  211.   t_ulong offset = 0;
  212.   static t_uchar buf[256];
  213.   int rec = 1;
  214.   VOLUME *vol;
  215.   CDROM_OBJ *obj;
  216.   CDROM_INFO info;
  217.   t_ulong pos;
  218.   t_bool warn_case = 0;
  219.  
  220.   vol = Open_Volume (g_cd, 0);
  221.   if (!vol) {
  222.     printf ("ERROR: cannot open volume\n");
  223.     exit (10);
  224.   }
  225.  
  226.   for (; offset < g_pvd.path_size_m; rec++) {
  227.     t_ulong tmp = offset;
  228.  
  229.     if ((rec & 7) == 1) {
  230.       printf ("\r   (%d of %d)",
  231.                 rec, g_path_table_records);
  232.       fflush (stdout);
  233.     }
  234.     Get_Path_Table_Record (buf, loc, &offset);
  235.     /* skip root record: */
  236.     if (rec == 1)
  237.       continue;
  238.     pos = GET732 (buf+2);
  239.     obj = Iso_Create_Directory_Obj (vol, pos);
  240.     if (!obj || !CDROM_Info (obj, &info)) {
  241.       printf ("\nERROR: cannot get information for directory at location %lu\n"
  242.               "(Path table offset = %lu)\n", pos, tmp);
  243.       exit (10);
  244.     }
  245.     if (info.name_length != buf[0] ||
  246.         Strnicmp ((UBYTE*) info.name, (UBYTE*) buf+8, info.name_length) != 0) {
  247.       printf ("\nERROR: names in path table and directory record differ for "
  248.               "directory at location %lu\n", pos);
  249.       printf ("Name in path table = ");
  250.       fwrite (buf+8, 1, info.name_length, stdout);
  251.       printf ("\nName in directory record = ");
  252.       fwrite (info.name, 1, info.name_length, stdout);
  253.       putchar ('\n');
  254.     } else if (!warn_case && memcmp (info.name, buf+8, info.name_length) != 0) {
  255.       printf ("\nWARNING: Directory names in path table and directory records "
  256.               "differ in case.\n");
  257.       warn_case = 1;
  258.     }
  259.     Close_Object (obj);
  260.   }
  261.   printf ("\r%75s\r", "");
  262.   Close_Volume (vol);
  263. }
  264.  
  265. /* Check optional path tables: */
  266.  
  267. void Check_Path_Tables (void)
  268. {
  269.   Check_Optional_Path_Tables ();
  270.   Compare_L_And_M_Path_Table ();
  271. }
  272.  
  273. /* Check primary volume descriptor: */
  274.  
  275. void Check_PVD (void)
  276. {
  277.   int loc = 16;
  278.   int pvd_pos = 0;
  279.   prim_vol_desc *pvd;
  280.  
  281.   do {
  282.     if (!Read_Sector (g_cd, loc)) {
  283.       printf ("ERROR: illegal sector %d\n", loc);
  284.       exit (1);
  285.     }
  286.     pvd = (prim_vol_desc *) g_cd->buffer;
  287.     if (memcmp (pvd->id, "CD001", 5) != 0) {
  288.       printf ("ERROR: missing standard identifier at sector %d\n", loc);
  289.       exit (10);
  290.     }
  291.     if (pvd->type > 4 && pvd->type < 255)
  292.       printf ("WARNING: unknown volume descriptor type at sector %d\n", loc);
  293.     if (pvd->version != 1)
  294.       printf ("WARNING: unknown volume descriptor version at sector %d\n", loc);
  295.     if (pvd->type == 1 && !pvd_pos)
  296.       pvd_pos = loc;
  297.     loc++;
  298.   } while (pvd->type != 255);
  299.  
  300.   if (!Read_Sector (g_cd, pvd_pos)) {
  301.     printf ("ERROR: illegal sector %d\n", loc);
  302.     exit (1);
  303.   }
  304.   pvd = (prim_vol_desc *) g_cd->buffer;
  305.   g_check_name = "primary volume descriptor";
  306.   g_check_sector = pvd_pos;
  307.   Check_733 (pvd, 81);
  308.   Check_723 (pvd, 121);
  309.   Check_723 (pvd, 125);
  310.   Check_723 (pvd, 129);
  311.   Check_733 (pvd, 133);
  312.   memcpy (&g_pvd, pvd, sizeof (g_pvd));
  313. }
  314.  
  315. void Check_Subdirectory (CDROM_OBJ *p_home, char *p_name)
  316. {
  317.   CDROM_OBJ *obj;
  318.   CDROM_INFO info;
  319.   /* VOLUME *vol = p_home->volume; */
  320.  
  321.   printf ("  %s\r", p_name);
  322.   fflush (stdout);
  323.  
  324.   if (obj = Open_Object (p_home, p_name)) {
  325.     unsigned long offset = 0;
  326.  
  327.     while (Examine_Next (obj, &info, &offset)) {
  328.       directory_record *dir = info.suppl_info;
  329.       g_check_name = "directory record";
  330.       g_check_sector = offset;
  331.       Check_733 (dir, 3);
  332.       Check_733 (dir, 11);
  333.       Check_723 (dir, 29);
  334.     }
  335.  
  336.     Close_Object (obj);
  337.   } else {
  338.     printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
  339.     return;
  340.   }
  341.  
  342.   if (obj = Open_Object (p_home, p_name)) {
  343.     unsigned long offset = 0;
  344.  
  345.     while (Examine_Next (obj, &info, &offset)) {
  346.       if (info.directory_f) {
  347.         char *name = malloc (strlen (p_name) + info.name_length + 2);
  348.     int len;
  349.     if (!name) {
  350.       fprintf (stderr, "out of memory\n");
  351.       exit (10);
  352.     }
  353.     if (Is_Top_Level_Object (obj))
  354.       name[0] = 0;
  355.     else
  356.       sprintf (name, "%s/", p_name);
  357.     len = strlen (name) + info.name_length;
  358.     memcpy (name + strlen (name), info.name, info.name_length);
  359.     name[len] = 0;
  360.     Check_Subdirectory (p_home, name);
  361.     free (name);
  362.       }
  363.     }
  364.     Close_Object (obj);
  365.   } else {
  366.     printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
  367.   }
  368.  
  369.   printf ("  %*s\r", strlen (p_name), "");
  370. }
  371.  
  372. void Check_Directories (void)
  373. {
  374.   VOLUME *vol;
  375.   CDROM_OBJ *home;
  376.  
  377.   if (!(vol = Open_Volume (g_cd, 1))) {
  378.     printf ("ERROR: cannot open volume; iso_errno = %d\n", iso_errno);
  379.     exit (10);
  380.   }
  381.  
  382.   if (!(home = Open_Top_Level_Directory (vol))) {
  383.     printf ("ERROR: cannot open top level directory; iso_errno = %d\n", iso_errno);
  384.     Close_Volume (vol);
  385.     exit (1);
  386.   }
  387.  
  388.   Check_Subdirectory (home, ":");
  389.  
  390.   Close_Object (home);
  391.   Close_Volume (vol);
  392. }
  393.  
  394. void Cleanup (void)
  395. {
  396.   if (g_cd)
  397.     Cleanup_CDROM (g_cd);
  398.  
  399.   if (UtilityBase)
  400.     CloseLibrary (UtilityBase);
  401. }
  402.  
  403. int Get_Device_And_Unit (void)
  404. {
  405.   int len;
  406.   char buf[10];
  407.   
  408.   len = GetVar ((UBYTE *) "CDROM_DEVICE", (UBYTE *) g_the_device,
  409.           sizeof (g_the_device), 0);
  410.   if (len < 0)
  411.     return 0;
  412.   if (len >= sizeof (g_the_device)) {
  413.     fprintf (stderr, "CDROM_DEVICE too long\n");
  414.     exit (1);
  415.   }
  416.   g_the_device[len] = 0;
  417.   
  418.   len = GetVar ((UBYTE *) "CDROM_UNIT", (UBYTE *) buf,
  419.           sizeof (buf), 0);
  420.   if (len < 0)
  421.     return 0;
  422.   if (len >= sizeof (buf)) {
  423.     fprintf (stderr, "CDROM_UNIT too long\n");
  424.     exit (1);
  425.   }
  426.   buf[len] = 0;
  427.   g_the_unit = atoi (buf);
  428.   
  429.   if (GetVar ((UBYTE *) "CDROM_FASTMEM", (UBYTE *) buf,
  430.       sizeof (buf), 0) > 0) {
  431.     fprintf (stderr, "using fastmem\n");
  432.     g_memory_type = MEMF_FAST;
  433.   }
  434.  
  435.   return 1;
  436. }
  437.  
  438. void main (int argc, char *argv[])
  439. {
  440.   atexit (Cleanup);
  441.  
  442.   if (!(UtilityBase = (struct Library *)
  443.          OpenLibrary ((UBYTE *) "utility.library", 37))) {
  444.     fprintf (stderr, "cannot open utility.library\n");
  445.     exit (1);
  446.   }
  447.  
  448.   if (!Get_Device_And_Unit ()) {
  449.     fprintf (stderr,
  450.       "Please set the following environment variables:\n"
  451.       "  CDROM_DEVICE    name of SCSI device\n"
  452.       "  CDROM_UNIT      unit number of CDROM drive\n"
  453.       "e.g.\n"
  454.       "  setenv CDROM_DEVICE scsi.device\n"
  455.       "  setenv CDROM_UNIT 2\n"
  456.       "Set the variable CDROM_FASTMEM to any value if you\n"
  457.       "want to use fast memory for SCSI buffers (does not work\n"
  458.       "with all SCSI devices!)\n"
  459.       );
  460.     exit (1);
  461.   }
  462.  
  463.   g_ignore_blocklength = TRUE;
  464.  
  465.   g_cd = Open_CDROM (g_the_device, g_the_unit, 1, g_memory_type,
  466.              STD_BUFFERS, FILE_BUFFERS);
  467.   if (!g_cd) {
  468.     fprintf (stderr, "cannot open CDROM, error code = %d\n", g_cdrom_errno);
  469.     exit (1);
  470.   }
  471.  
  472.   printf ("Checking primary volume descriptor...\n");
  473.   Check_PVD ();
  474.   printf ("Checking path tables...\n");
  475.   Check_Path_Tables ();
  476.   printf ("Comparing path table with directory records...\n");
  477.   Compare_Path_Table_With_Directory_Records ();
  478.  
  479.   printf ("Checking directories...\n");
  480.   Check_Directories ();
  481.  
  482.   printf ("All checks completed.\n");
  483.  
  484.   exit (0);
  485. }
  486.