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

  1. /* main.c:
  2.  *
  3.  * Interactive test program for the ISO- and Rock-Ridge-support
  4.  * routines.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  * 
  14.  * 17-Feb-94   fmu   Fixed typo.
  15.  * 28-Nov-93   fmu   Improved "cdrom d" command.
  16.  * 12-Oct-93   fmu   "Show path table" function removed.
  17.  * 09-Oct-93   fmu   Open utility.library.
  18.  */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23.  
  24. #include <dos/var.h>
  25. #include <devices/trackdisk.h>
  26.  
  27. #include <clib/alib_protos.h>
  28. #include <clib/dos_protos.h>
  29. #include <clib/exec_protos.h>
  30.  
  31. #include "cdrom.h"
  32. #include "iso9660.h"
  33. #include "rock.h"
  34. #include "hfs.h"
  35.  
  36. #ifdef LATTICE
  37. #include <pragmas/dos_pragmas.h>
  38. #include <pragmas/exec_pragmas.h>
  39. extern struct Library *SysBase, *DOSBase;
  40. #endif
  41.  
  42. #define STD_BUFFERS 10
  43. #define FILE_BUFFERS 5
  44.  
  45. #ifdef DEBUG_SECTORS
  46. void dbprintf (char *p_dummy, ...)
  47. {
  48. }
  49. #endif
  50.  
  51. CDROM *cd = NULL;
  52. char g_the_device[80];
  53. int g_the_unit;
  54. int g_trackdisk = 0;
  55. t_ulong g_memory_type = MEMF_CHIP;
  56.  
  57. struct UtilityBase *UtilityBase;
  58.  
  59. void Cleanup (void)
  60. {
  61.   if (cd)
  62.     Cleanup_CDROM (cd);
  63.  
  64.   if (UtilityBase)
  65.     CloseLibrary ((struct Library*) UtilityBase);
  66. }
  67.  
  68. void Usage (void)
  69. {
  70.   fprintf (stderr,
  71.     "Usage: cdrom command [parameters]\n"
  72.     "Commands:\n"
  73.     "  a                Show information on CDROM drive\n"
  74.     "  b                Read table of contents\n"
  75.     "  c name           Show contents of file 'name'\n"
  76.     "  d[rl] dir        Show contents of directory 'dir' (use ISO names)\n"
  77.     "                   r=also show subdirectories, l=show additional information\n"
  78.     "  e[r[l|L]] dir    Show contents of directory 'dir' (use Rock Ridge names)\n"
  79.     "                   r=also show subdirectories, l=show system use field names\n"
  80.     "                   L=show names and contents of system use fields\n"
  81.     "  f dir name       Change to directory 'dir' and try to find object 'name'\n"
  82.     "  i                Check which protocol is used\n"
  83.     "  j [01]           0=start audio, 1=stop motor\n"
  84.     "  l                Find offset of last session\n"
  85.     "  m num            Read catalog node 'num' (MacHFS only)\n"
  86.     "  o name           Try to open object 'name'\n"
  87.     "  r                Read contents of root directory\n"
  88.     "  s num [cnt]      Read 'cnt' sectors, starting at sector 'num'\n"
  89.     "  t name           Try to open parent of object 'name'\n"
  90.     "  v                Read primary volume descriptor\n"
  91.     "  x dens [length]  Select mode: dens=density code,\n"
  92.     "                   length=block length (default: 2048)\n"
  93.     "  z                Send test unit ready command\n"
  94.     "  T                Test trackdisk device\n"
  95.     "Use \":\" as the name of the root directory\n"
  96.     );
  97.   exit (1);
  98. }
  99.  
  100. char *MKSTR (char *p_in, int p_length, char *p_out)
  101. {
  102.   char *res = p_out;
  103.   int len = p_length;
  104.   int i;
  105.   
  106.   while (len && p_in[len-1] == ' ')
  107.     len--;
  108.  
  109.   for (i=0; i<len; i++)
  110.     *p_out++ = *p_in++;
  111.     
  112.   *p_out = 0;
  113.   
  114.   return res;
  115. }
  116.  
  117. void Show_Flags (unsigned char p_flags)
  118. {
  119.   if (p_flags & 1)
  120.     printf ("existence ");
  121.   if (p_flags & 2)
  122.     printf ("directory ");
  123.   if (p_flags & 4)
  124.     printf ("associated ");
  125.   if (p_flags & 8)
  126.     printf ("record ");
  127.   if (p_flags & 16)
  128.     printf ("protection ");
  129.   if (p_flags & 128)
  130.     printf ("multi-extent ");
  131. }
  132.  
  133. void Show_Directory_Record (directory_record *p_dir)
  134. {
  135.   char buf[256];
  136.  
  137.   printf ("Extended Attr Record Length: %d\n", (int) p_dir->ext_attr_length);
  138.   printf ("Location of Extent:          %lu\n", p_dir->extent_loc_m);
  139.   printf ("Data Length:                 %lu\n", p_dir->data_length_m);
  140.   printf ("Recording Date and Time:     %02d.%02d.19%02d %02d:%02d:%02d %+d\n",
  141.         (int) p_dir->day, (int) p_dir->month, (int) p_dir->year,
  142.       (int) p_dir->hour, (int) p_dir->minute, (int) p_dir->second,
  143.       (int) p_dir->tz);
  144.   printf ("Flags:                       %d (", (int) p_dir->flags);
  145.   Show_Flags (p_dir->flags);
  146.   printf (")\n");
  147.   printf ("File Unit Size:              %d\n", (int) p_dir->file_unit_size);
  148.   printf ("Gap Size:                    %d\n", (int) p_dir->gap_size);
  149.   printf ("Volume Sequence Number:      %hu\n", p_dir->sequence_m);
  150.   printf ("File Identifier:             ");
  151.   if (p_dir->file_id[0] == 0)
  152.     printf ("(00)\n");
  153.   else if (p_dir->file_id[0] == 1)
  154.     printf ("(01)\n");
  155.   else
  156.     printf ("%s\n", MKSTR (p_dir->file_id, p_dir->file_id_length, buf));
  157. }
  158.  
  159. void Find_Block_Starting_With (CDROM *p_cd, int p_val)
  160. {
  161.   unsigned long sec = 0;
  162.   int cmp;
  163.   int i;
  164.   
  165.   for (;;) {
  166.     if (!Read_Sector (p_cd, sec)) {
  167.       fprintf (stderr, "cannot read sector 16\n");
  168.       exit (1);
  169.     }
  170.     for (i=0; i<4; i++) {
  171.       cmp = p_cd->buffer[i<<9] * 256 + p_cd->buffer[(i<<9)+1];
  172.       if (cmp == p_val)
  173.         printf ("sector %lu, block %d\n", sec, i);
  174.     }
  175.     sec++;
  176.   }
  177. }
  178.  
  179. void Show_Primary_Volume_Descriptor (CDROM *p_cd)
  180. {
  181.   prim_vol_desc *pvd;
  182.   char buf[129];
  183.   int blk;
  184.   t_mdb mdb;
  185.   t_hdr_node hdr;
  186.   int skip;
  187.   t_ulong offset;
  188.   int protocol;
  189.   t_bool hfs;
  190.   
  191.   hfs = Uses_HFS_Protocol (p_cd, &skip);
  192.   protocol = Which_Protocol (p_cd, TRUE, &skip, &offset);
  193.   
  194.   if (protocol == PRO_UNKNOWN) {
  195.     printf ("Unknown protocol\n");
  196.     return;
  197.   }
  198.   
  199.   if (protocol == PRO_HIGH_SIERRA) {
  200.     printf ("High sierra protocol (not supported)\n");
  201.   }
  202.   
  203.   if ((protocol == PRO_ROCK || protocol == PRO_ISO) && hfs)
  204.     printf ("Multi-platform disk: HFS & ISO\n");
  205.  
  206.   if (protocol == PRO_ROCK)
  207.     printf ("Rock Ridge extensions available, skip size = %d\n", skip);
  208.   
  209.   if (protocol == PRO_ISO)
  210.     printf ("Data track offset = %lu\n", offset);
  211.  
  212.   if (protocol == PRO_ISO || protocol == PRO_ROCK) {
  213.  
  214.     if (!Read_Sector (p_cd, 16 + offset)) {
  215.       fprintf (stderr, "cannot read sector %lu\n", 16 + offset);
  216.       exit (1);
  217.     }
  218.  
  219.     pvd = (prim_vol_desc *) p_cd->buffer;
  220.     printf ("--- ISO-9660: ---\n");
  221.     printf ("Volume Descriptor Type:          %d\n", (int) pvd->type);
  222.     printf ("Standard Identifier:             %s\n", MKSTR (pvd->id,5,buf));
  223.     printf ("Volume Descriptor Version:       %d\n", (int) pvd->version);
  224.     printf ("System Identifier:               %s\n", MKSTR (pvd->system_id,32,buf));
  225.     printf ("Volume Identifier:               %s\n", MKSTR (pvd->volume_id,32,buf));
  226.     printf ("Volume Space Size:               %lu\n", pvd->space_size_m);
  227.     printf ("Volume Set Size:                 %hu\n", pvd->set_size_m);
  228.     printf ("Volume Sequence Number:          %hu\n", pvd->sequence_m);
  229.     printf ("Logical Block Size:              %hu\n", pvd->block_size_m);
  230.     printf ("Path Table Size:                 %lu\n", pvd->path_size_m);
  231.     printf ("Location of Occ of M Path Table: %lu\n", pvd->m_table); 
  232.     printf ("Location of Occ of Opt M Path T: %lu\n", pvd->opt_m_table);
  233.     printf ("Volume Set Identifier:           %s\n",
  234.                       MKSTR (pvd->volume_set_id,128,buf));  
  235.     printf ("Publisher Identifier:            %s\n",
  236.                       MKSTR (pvd->publisher_id,128,buf)); 
  237.     printf ("Data Preparer Identifier:        %s\n",
  238.                       MKSTR (pvd->data_preparer,128,buf));
  239.     printf ("Application Identifier:          %s\n",
  240.                       MKSTR (pvd->application_id,128,buf));
  241.     printf ("Copyright File Identifier:       %s\n",
  242.                       MKSTR (pvd->copyright,37,buf));
  243.     printf ("Abstract File Identifier:        %s\n",
  244.                       MKSTR (pvd->abstract_file_id,37,buf));
  245.     printf ("Bibliographic File Identifier:   %s\n",
  246.                       MKSTR (pvd->bibliographic_id,37,buf));
  247.     printf ("File Structure Version:          %d\n",
  248.                       (int) pvd->file_structure_version);
  249.     printf ("ROOT DIRECTORY RECORD:\n");
  250.     Show_Directory_Record (&pvd->root);
  251.   }
  252.   
  253.   if (hfs) {
  254.     if ((blk = HFS_Find_Master_Directory_Block (p_cd, &mdb)) < 0) {
  255.       printf ("No master directory block found\n");
  256.       exit (1);
  257.     }
  258.     printf ("--- MacHFS: ---\n");
  259.     printf ("Master directory block located at block %d\n", blk);
  260.     printf ("Volume signature:               0x%hx\n", mdb.SigWord);
  261.     printf ("Date/Time of creation:          %lu\n", mdb.CrDate);
  262.     printf ("Date/Time of last modification: %lu\n", mdb.LsMod);
  263.     printf ("Volume attributes:              0x%hx\n", mdb.Atrb);
  264.     printf ("Number of files in root dir:    %u\n", mdb.NmFls);
  265.     printf ("Allocation block size:          %lu bytes\n", mdb.AlBlkSiz);
  266.     printf ("Loc of first allocation block:  %u\n", mdb.AlBlSt);
  267.     printf ("Volume name:                    %s\n",
  268.                     MKSTR ((char *) mdb.VolName, mdb.VolNameLen,buf));
  269.     printf ("Number of files in volume:      %lu\n", mdb.FilCnt);
  270.     printf ("Number of dirs in volume:       %lu\n", mdb.DirCnt);
  271.     printf ("Size of catalog file:           %lu allocation blocks\n",
  272.                             mdb.CTFlSize);
  273.     printf ("Extent record for catalog file:\n");
  274.     printf ("  1. allocation block: %10lu   length: %10lu\n",
  275.                     mdb.CTExtRec[0].StABN, mdb.CTExtRec[0].NumABlks);
  276.     printf ("  2. allocation block: %10lu   length: %10lu\n",
  277.                     mdb.CTExtRec[1].StABN, mdb.CTExtRec[1].NumABlks);
  278.     printf ("  3. allocation block: %10lu   length: %10lu\n",
  279.                     mdb.CTExtRec[2].StABN, mdb.CTExtRec[2].NumABlks);
  280.     if (!HFS_Get_Header_Node (p_cd, blk, &mdb, &hdr))
  281.       printf ("*** Cannot read header node!!!\n");
  282.     printf ("Header node:\n");
  283.     printf ("Depth of tree:                  %u\n", hdr.Depth);
  284.     printf ("Number of root node:            %lu\n", hdr.Root);
  285.     printf ("Number of leaf records in tree: %lu\n", hdr.NRecs);
  286.     printf ("Number of first leaf node:      %lu\n", hdr.FNode);
  287.     printf ("Number of last leaf node:       %lu\n", hdr.LNode);
  288.   }
  289. }
  290.  
  291. void Show_Directory (CDROM *p_cd, unsigned long p_location, unsigned long p_length)
  292. {
  293.   int cnt = 0;
  294.   int pos = 0;
  295.   
  296.   if (!Read_Sector (p_cd, p_location)) {
  297.     fprintf (stderr, "cannot read sector %lu\n", p_location);
  298.     exit (1);
  299.   }
  300.  
  301.   while (cnt < p_length) {
  302.     directory_record *dir = (directory_record *) (p_cd->buffer + pos);
  303.     
  304.     if (dir->length == 0)
  305.       break;
  306.     Show_Directory_Record (dir);
  307.     cnt += dir->length;
  308.     pos += dir->length;
  309.     if (cnt < p_length) {
  310.       printf ("------------------------------------------------------------\n");
  311.       if (pos >= 2048) {
  312.         if (!Read_Sector (p_cd, ++p_location)) {
  313.           fprintf (stderr, "cannot read sector %lu\n", p_location);
  314.           exit (1);
  315.         }
  316.         pos = 0;
  317.       }
  318.     }
  319.   }
  320. }
  321.  
  322. void Show_Root_Directory (CDROM *p_cd)
  323. {
  324.   prim_vol_desc *pvd;
  325.   
  326.   if (!Read_Sector (p_cd, 16)) {
  327.     fprintf (stderr, "cannot read sector 16\n");
  328.     exit (1);
  329.   }
  330.  
  331.   pvd = (prim_vol_desc *) p_cd->buffer;
  332.  
  333.   Show_Directory (p_cd, pvd->root.extent_loc_m, pvd->root.data_length_m);
  334. }
  335.  
  336. void Check_Protocol (CDROM *p_cd)
  337. {
  338.   int skip;
  339.   t_ulong offset;
  340.  
  341.   switch (Which_Protocol (p_cd, TRUE, &skip, &offset)) {
  342.   case PRO_ROCK:
  343.     printf ("Rock Ridge protocol, skip length = %d\n", skip);
  344.     break;
  345.   case PRO_ISO:
  346.     printf ("ISO-9660 protocol, offset = %lu\n", offset);
  347.     break;
  348.   case PRO_HFS:
  349.     printf ("Macintosh HFS protocol\n");
  350.     break;
  351.   case PRO_HIGH_SIERRA:
  352.     printf ("High Sierra protocol\n");
  353.     break;
  354.   default:
  355.     printf ("Unknown protocol, iso_errno = %d\n", iso_errno);
  356.     break;
  357.   }
  358. }
  359.  
  360. void Try_To_Open (CDROM *p_cd, char *p_directory, char *p_name)
  361. {
  362.   VOLUME *vol;
  363.   CDROM_OBJ *top = NULL;
  364.   CDROM_OBJ *home;
  365.   CDROM_OBJ *obj;
  366.   CDROM_OBJ *parent;
  367.   char pathname[256];
  368.  
  369.   if (!(vol = Open_Volume (p_cd, 1))) {
  370.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  371.     exit (1);
  372.   }
  373.  
  374.   if (p_directory && p_directory != (char *) -1) {
  375.     if (!(top = Open_Top_Level_Directory (vol))) {
  376.       fprintf (stderr, "cannot open top level directory\n");
  377.       Close_Volume (vol);
  378.       exit (1);
  379.     }
  380.     
  381.     if (!(home = Open_Object (top, p_directory))) {
  382.       fprintf (stderr, "cannot open top level directory\n");
  383.       Close_Object (top);
  384.       Close_Volume (vol);
  385.       exit (1);
  386.     }
  387.   } else {
  388.     if (!(home = Open_Top_Level_Directory (vol))) {
  389.       fprintf (stderr, "cannot open home directory;"
  390.                        " iso_errno = %d\n", iso_errno);
  391.       Close_Volume (vol);
  392.       exit (1);
  393.     }
  394.   }
  395.  
  396.   if (obj = Open_Object (home, p_name)) {
  397.     CDROM_INFO info;
  398.     printf ("%s '%s' found, location = %lu\n",
  399.             obj->symlink_f ? "Symbolic link" :
  400.             obj->directory_f ? "Directory" : "File",
  401.             p_name, Location (obj));
  402.     if (obj->symlink_f) {
  403.       char linkname[256];
  404.       printf ("Link to ");
  405.       if (Get_Link_Name (obj, linkname, sizeof (linkname)))
  406.         printf ("'%s'\n", linkname);
  407.       else
  408.         printf ("unknown file or directory\n");
  409.     }
  410.     if (Full_Path_Name (obj, pathname, sizeof (pathname)))
  411.       printf ("Full path name: %s\n", pathname);
  412.     else
  413.       printf ("Full path name unknown\n");
  414.     if (CDROM_Info (obj, &info)) {
  415.       printf ("INFO Name = ");
  416.       fwrite (info.name, info.name_length, 1, stdout);
  417.       printf ("\n");
  418.     } else
  419.       printf ("CANNOT FIND INFO FOR OBJECT!\n");
  420.     if (p_directory == (char *) -1) {
  421.       parent = Find_Parent (obj);
  422.       if (parent) {
  423.         printf ("parent found, location = %lu\n",
  424.             Location (parent));
  425.         Close_Object (parent);
  426.       } else
  427.         printf ("parent not found, iso_errno = %d\n", iso_errno);
  428.     }
  429.     Close_Object (obj);
  430.   } else {
  431.     if (iso_errno == ISOERR_NOT_FOUND)
  432.       printf ("Object '%s' not found\n", p_name);
  433.     else
  434.       printf ("Object '%s': iso_errno = %d\n", p_name, iso_errno);
  435.   }
  436.  
  437.   if (top)
  438.     Close_Object (top);
  439.   Close_Object (home);
  440.   Close_Volume (vol);
  441. }
  442.  
  443. void Show_File_Contents (CDROM *p_cd, char *p_name)
  444. {
  445.   VOLUME *vol;
  446.   CDROM_OBJ *home;
  447.   CDROM_OBJ *obj;
  448. #define THEBUFSIZE 99
  449.   char buffer[THEBUFSIZE];
  450.   int cnt;
  451.  
  452.   if (!(vol = Open_Volume (p_cd, 1))) {
  453.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  454.     exit (1);
  455.   }
  456.  
  457.   if (!(home = Open_Top_Level_Directory (vol))) {
  458.     fprintf (stderr, "cannot open top level directory;"
  459.                      " iso_errno = %d\n", iso_errno);
  460.     Close_Volume (vol);
  461.     exit (1);
  462.   }
  463.  
  464.   if (obj = Open_Object (home, p_name)) {
  465.     for (;;) {
  466.       cnt = Read_From_File (obj, buffer, THEBUFSIZE);
  467.       if (cnt == -1) {
  468.         fprintf (stderr, "cannot read from file!\n");
  469.     break;
  470.       }
  471.       if (cnt == 0)
  472.         break;
  473.       fwrite (buffer, cnt, 1, stdout);
  474.     }
  475.  
  476.     Close_Object (obj);
  477.   } else {
  478.     fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  479.   }
  480.  
  481.   Close_Object (home);
  482.   Close_Volume (vol);
  483.   
  484. }
  485.  
  486. void Print_System_Use_Fields (CDROM *p_cd, directory_record *p_dir,
  487.                   int p_skip_size, int p_long)
  488. {
  489.   int system_use_pos;
  490.   int slen;
  491.   unsigned long length = p_dir->length;
  492.   unsigned char *buf = (unsigned char *) p_dir;
  493.  
  494.   printf ("   system use fields: ");
  495.   if (p_long)
  496.     putchar ('\n');
  497.  
  498.   system_use_pos = 33 + p_dir->file_id_length;
  499.   if (system_use_pos & 1)
  500.     system_use_pos++;
  501.   system_use_pos += p_skip_size;
  502.  
  503.   /* the system use field must be at least 4 bytes long */
  504.   while (system_use_pos + 3 < length) {
  505.     slen = buf[system_use_pos+2];
  506.     /* look for continuation area: */
  507.     if (buf[system_use_pos] == 'C' &&
  508.         buf[system_use_pos+1] == 'E') {
  509.       unsigned long newloc, offset;
  510.       printf ("/ ");
  511.       memcpy (&newloc, buf + system_use_pos + 8, 4);
  512.       memcpy (&offset, buf + system_use_pos + 16, 4);
  513.       memcpy (&length, buf + system_use_pos + 24, 4);
  514.       if (!Read_Sector (p_cd, newloc))
  515.         return;
  516.       buf = p_cd->buffer;
  517.       system_use_pos = offset;
  518.       continue;
  519.     /* look for system use field terminator: */
  520.     } else if (buf[system_use_pos] == 'S' &&
  521.         buf[system_use_pos+1] == 'T') {
  522.       printf ("ST");
  523.       break;
  524.     } else if  (buf[system_use_pos] == 'S' &&
  525.       /* special handling for SL field: */
  526.       buf[system_use_pos+1] == 'L') {
  527.       printf ("SL(%s%d,", (buf[system_use_pos+4] & 1)? "cont " : "",
  528.                     (int) buf[system_use_pos+5]);
  529.       fwrite (buf + system_use_pos + 7, buf[system_use_pos+6], 1, stdout);
  530.       printf (") ");
  531.     } else {
  532.       if (p_long)
  533.         printf ("   ");
  534.       putchar (buf[system_use_pos]);
  535.       putchar (buf[system_use_pos+1]);
  536.       putchar (' ');
  537.       if (p_long) {
  538.         int i;
  539.     for (i=0; i < slen-2; i++) {
  540.       if (i && (i & 15) == 0)
  541.         printf ("\n      ");
  542.       printf ("%2.2x ", (int) buf[system_use_pos+i+2]);
  543.     }
  544.       }
  545.     }
  546.  
  547.     if (p_long)
  548.       putchar ('\n');
  549.  
  550.     system_use_pos += slen;
  551.   }
  552.   
  553.   putchar ('\n');
  554. }
  555.  
  556. void Show_Subdirectory (CDROM_OBJ *p_home, char *p_name, int p_long_info,
  557.             int p_recursive)
  558. {
  559.   CDROM_OBJ *obj;
  560.   CDROM_INFO info;
  561.   VOLUME *vol = p_home->volume;
  562.  
  563.   if (obj = Open_Object (p_home, p_name)) {
  564.     unsigned long offset = 0;
  565.     
  566.     while (Examine_Next (obj, &info, &offset)) {
  567.       directory_record *dir = info.suppl_info;
  568.       fwrite (info.name, info.name_length, 1, stdout);
  569.       if (info.symlink_f)
  570.         printf (" (symbolic link)");
  571.       else if (info.directory_f)
  572.         printf (" (dir)");
  573.       printf ("\n");
  574.       if (p_long_info && dir) {
  575.         printf ("   %02d.%02d.%02d %02d:%02d:%02d  ",
  576.         (int) dir->day,
  577.         (int) dir->month,
  578.         (int) dir->year,
  579.         (int) dir->hour,
  580.         (int) dir->minute,
  581.         (int) dir->second);
  582.     printf ("%lu  ", dir->data_length_m);
  583.     printf ("loc=%lu  ", dir->extent_loc_m);
  584.     Show_Flags (dir->flags);
  585.     putchar ('\n');
  586.         if (dir->ext_attr_length)
  587.       printf ("   contains extended attribute record\n");
  588.     if (dir->gap_size)
  589.       printf ("   is recorded in interleaved mode\n");
  590.     if (vol->protocol == PRO_ROCK)
  591.           Print_System_Use_Fields (vol->cd, dir,
  592.                      ((t_iso_vol_info *) vol->vol_info)->skip,
  593.                    p_long_info == 2);
  594.       }
  595.     }
  596.  
  597.     Close_Object (obj);
  598.   } else {
  599.     fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  600.     return;
  601.   }
  602.  
  603.   if (p_recursive) {
  604.     if (obj = Open_Object (p_home, p_name)) {
  605.       unsigned long offset = 0;
  606.     
  607.       while (Examine_Next (obj, &info, &offset)) {
  608.         if (info.directory_f) {
  609.       char *name = malloc (strlen (p_name) + info.name_length + 2);
  610.       int len;
  611.       if (!name) {
  612.         fprintf (stderr, "out of memory\n");
  613.         exit (1);
  614.       }
  615.       if (Is_Top_Level_Object (obj))
  616.         name[0] = 0;
  617.       else
  618.         sprintf (name, "%s/", p_name);
  619.       len = strlen (name) + info.name_length;
  620.       memcpy (name + strlen (name), info.name, info.name_length);
  621.       name[len] = 0;
  622.       printf ("\n%s:\n", name);
  623.       Show_Subdirectory (p_home, name, p_long_info, TRUE);
  624.       free (name);
  625.         }
  626.       }
  627.       Close_Object (obj);
  628.     } else {
  629.       fprintf (stderr, "Object '%s': iso_errno = %d\n", p_name, iso_errno);
  630.     }
  631.   }
  632.  
  633. }
  634.  
  635. void Show_Dir_Contents (CDROM *p_cd, char *p_name, int p_rock_ridge,
  636.             char *p_options)
  637. {
  638.   VOLUME *vol;
  639.   CDROM_OBJ *home;
  640.   int long_info = strchr (p_options, 'l') ? 1 :
  641.             strchr (p_options, 'L') ? 2 : 0;
  642.   t_bool recursive = (strchr (p_options, 'r') != NULL);
  643.  
  644.   if (!(vol = Open_Volume (p_cd, p_rock_ridge))) {
  645.     fprintf (stderr, "cannot open volume; iso_errno = %d\n", iso_errno);
  646.     exit (1);
  647.   }
  648.  
  649.   if (!(home = Open_Top_Level_Directory (vol))) {
  650.     fprintf (stderr, "cannot open top level directory;"
  651.                      " iso_errno = %d\n", iso_errno);
  652.     Close_Volume (vol);
  653.     exit (1);
  654.   }
  655.  
  656.   Show_Subdirectory (home, p_name, long_info, recursive);
  657.  
  658.   Close_Object (home);
  659.   Close_Volume (vol);
  660. }
  661.  
  662. void Send_Test_Unit_Ready (CDROM *p_cd)
  663. {
  664.   printf ("result = %d\n", Test_Unit_Ready (p_cd));
  665. }
  666.  
  667. void Show_Sectors (CDROM *p_cd, int p_sector, int p_cnt)
  668. {
  669.   int i, j, s;
  670.   int off;
  671.   
  672.   if (p_sector < 0)
  673.     return;
  674.   
  675.   for (s=0; s<p_cnt; s++) {
  676.     if (!Read_Sector (p_cd, p_sector + s)) {
  677.       fprintf (stderr, "cannot read sector %d\n", p_sector + s);
  678.       exit (1);
  679.     }
  680.     for (off=0, i=0; i<128; i++) {
  681.       printf ("%02x:%03x0: ", s, i);
  682.       for (j=0; j<16; j++)
  683.         printf ("%02x ", (int) p_cd->buffer[off++]);
  684.       off -= 16;
  685.       putchar (' ');
  686.       for (j=0; j<16; j++) {
  687.         unsigned char c = p_cd->buffer[off++];
  688.         if (32<=c && c<=127)
  689.           putchar (c);
  690.         else
  691.           putchar ('.');
  692.       }
  693.       putchar ('\n');
  694.     }
  695.   }
  696. }
  697.  
  698. int Get_Device_And_Unit (void)
  699. {
  700.   int len;
  701.   char buf[10];
  702.   
  703.   len = GetVar ((UBYTE *) "CDROM_DEVICE", (UBYTE *) g_the_device,
  704.           sizeof (g_the_device), 0);
  705.   if (len < 0)
  706.     return 0;
  707.   if (len >= sizeof (g_the_device)) {
  708.     fprintf (stderr, "CDROM_DEVICE too long\n");
  709.     exit (1);
  710.   }
  711.   g_the_device[len] = 0;
  712.   
  713.   len = GetVar ((UBYTE *) "CDROM_UNIT", (UBYTE *) buf,
  714.           sizeof (buf), 0);
  715.   if (len < 0)
  716.     return 0;
  717.   if (len >= sizeof (buf)) {
  718.     fprintf (stderr, "CDROM_UNIT too long\n");
  719.     exit (1);
  720.   }
  721.   buf[len] = 0;
  722.   g_the_unit = atoi (buf);
  723.   
  724.   if (GetVar ((UBYTE *) "CDROM_TRACKDISK", (UBYTE *) buf,
  725.       sizeof (buf), 0) > 0) {
  726.     fprintf (stderr, "using trackdisk\n");
  727.     g_trackdisk = 1;
  728.   }
  729.  
  730.   if (GetVar ((UBYTE *) "CDROM_FASTMEM", (UBYTE *) buf,
  731.       sizeof (buf), 0) > 0) {
  732.     fprintf (stderr, "using fastmem\n");
  733.     g_memory_type = MEMF_FAST;
  734.   }
  735.  
  736.   return 1;
  737. }
  738.  
  739. void Select_Mode (CDROM *p_cd, int p_mode, int p_block_length)
  740. {
  741.   if (!Mode_Select (p_cd, p_mode, p_block_length))
  742.     fprintf (stderr, "mode select command failed!\n");
  743. }
  744.  
  745. void Show_Drive_Information (CDROM *p_cd)
  746. {
  747.   t_inquiry_data data;
  748.   int block_length;
  749.   
  750.   if (!Inquire (p_cd, &data)) {
  751.     fprintf (stderr, "cannot access CDROM drive\n");
  752.     return;
  753.   }
  754.  
  755.   if ((data.peripheral_type & 0x1f) != 5) {
  756.     if ((data.peripheral_type & 0x1f) == 8)
  757.       printf ("Drive type: medium changer\n");
  758.     else
  759.       printf ("WARNING: this is not a CDROM drive!\n");
  760.   }
  761.  
  762.   printf ("Vendor      : ");
  763.   fwrite (data.vendor, sizeof (data.vendor), 1, stdout);
  764.   printf ("\nProduct     : ");
  765.   fwrite (data.product, sizeof (data.product), 1, stdout);
  766.   printf ("\nRevision    : ");
  767.   fwrite (data.revision, sizeof (data.revision), 1, stdout);
  768.   putchar ('\n');
  769.   printf ("Conforms to : SCSI-%d\n", (int) (data.version & 0x7));
  770.   block_length = Block_Length (p_cd);
  771.   printf ("Block length: ");
  772.   if (block_length)
  773.     printf ("%d\n", block_length);
  774.   else
  775.     printf ("unknown\n");
  776. }
  777.  
  778. void Show_Table_Of_Contents (CDROM *p_cd)
  779. {
  780.   t_toc_header hdr;
  781.   t_toc_data *toc;
  782.   short i, len;
  783.   
  784.   if (!(toc = Read_TOC (p_cd, &hdr))) {
  785.     fprintf (stderr, "cannot read table of contents\n");
  786.     return;
  787.   }
  788.   
  789.   len = hdr.length / 8;
  790.   for (i=0; i<len; i++) {
  791.     if (toc[i].track_number == 0xAA)
  792.       printf ("Lead-out track at address %lu\n", toc[i].address);
  793.     else
  794.       printf ("Track %d: %s track, start address %lu\n",
  795.               (int) toc[i].track_number,
  796.           (toc[i].flags & 4) ? "data" : "audio",
  797.           toc[i].address);
  798.   }
  799. }
  800.  
  801. void Show_Catalog_Node (CDROM *p_cd, t_ulong p_node)
  802. {
  803.   t_mdb mdb;
  804.   t_node_descr *node;
  805.   t_hdr_node *hdr;
  806.   t_idx_record *idx;
  807.   t_leaf_record *leaf;
  808.   t_file_record *file;
  809.   t_dir_thread_record *thread;
  810.   char *cp;
  811.   int blk;
  812.   int i;
  813.   char buf[100];
  814.  
  815.   blk = HFS_Find_Master_Directory_Block (p_cd, &mdb);
  816.   if (blk < 0) {
  817.     fprintf (stderr, "cannot find master directory block\n");
  818.     return;
  819.   }
  820.  
  821.   node = HFS_Get_Node (p_cd, blk, &mdb, p_node);
  822.   if (!node) {
  823.     fprintf (stderr, "cannot find node %d\n", p_node);
  824.     return;
  825.   }
  826.   
  827.   switch (node->Type) {
  828.   case 0:
  829.     printf ("Index node:\n");
  830.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  831.             (int) node->NHeight);
  832.     idx = (t_idx_record *) ((char *) node + 0xe);
  833.     for (i=0; i<node->NRecs; i++, idx++) {
  834.       printf ("Parent ID = 0x%08lx, '", idx->parent_id);
  835.       fwrite (idx->name, idx->name_length, 1, stdout);
  836.       printf ("', pointer = %lu\n", idx->pointer);
  837.     }
  838.     break;
  839.   case 1:
  840.     printf ("Header node:\n");
  841.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  842.             (int) node->NHeight);
  843.     hdr = (t_hdr_node *) node;
  844.     printf ("Depth of tree:                  %u\n", hdr->Depth);
  845.     printf ("Number of root node:            %lu\n", hdr->Root);
  846.     printf ("Number of leaf records in tree: %lu\n", hdr->NRecs);
  847.     printf ("Number of first leaf node:      %lu\n", hdr->FNode);
  848.     printf ("Number of last leaf node:       %lu\n", hdr->LNode);
  849.     break;
  850.   case 2:
  851.     printf ("Map node:\n");
  852.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  853.             (int) node->NHeight);
  854.     break;
  855.   case 0xff:
  856.     printf ("Leaf node:\n");
  857.     printf ("Fwd=%lu Bwd=%lu Level=%d\n", node->FLink, node->BLink,
  858.             (int) node->NHeight);
  859.     for (i=0; i<node->NRecs; i++) {
  860.       leaf = (t_leaf_record *) ((char *) node + ((short *) node)[255-i]);
  861.       cp = (char *) leaf + leaf->length + 1;
  862.       if ((leaf->length & 1) == 0)
  863.         cp++;
  864.       printf ("Parent ID = 0x%08lx, '", leaf->parent_id);
  865.       memcpy (buf, leaf->name, leaf->name_length);
  866.       Convert_Mac_Characters (buf, leaf->name_length);
  867.       fwrite (buf, leaf->name_length, 1, stdout);
  868.       printf ("'  (");
  869.       switch (*cp) {
  870.       case 1:
  871.         printf ("directory 0x%08lx)\n", *(t_ulong *)(cp+6));
  872.     break;
  873.       case 2:
  874.         file = (t_file_record *) cp;
  875.         printf ("file 0x%08lx)\n\tdata length %lu, "
  876.         "data extents %u-%u/%u-%u/%u-%u\n",
  877.         file->FlNum,
  878.         file->LgLen,
  879.         file->ExtRec[0].StABN, file->ExtRec[0].NumABlks,
  880.         file->ExtRec[1].StABN, file->ExtRec[1].NumABlks,
  881.         file->ExtRec[2].StABN, file->ExtRec[2].NumABlks);
  882.     printf ("\tresource length %lu, resource extents %u-%u/%u-%u/%u-%u\n",
  883.         file->RLgLen,
  884.         file->RExtRec[0].StABN, file->RExtRec[0].NumABlks,
  885.         file->RExtRec[1].StABN, file->RExtRec[1].NumABlks,
  886.         file->RExtRec[2].StABN, file->RExtRec[2].NumABlks);
  887.     printf ("\tfirst alloc blk for data fork: %u\n", file->StBlk);
  888.     printf ("\tfirst alloc blk for resource fork: %u\n", file->RStBlk);
  889.     break;
  890.       case 3:
  891.         thread = (t_dir_thread_record *) cp;
  892.         printf ("directory thread 0x%08lu '", thread->ParID);
  893.     fwrite (thread->CName, thread->CNameLen, 1, stdout);
  894.     printf ("')\n");
  895.     break;
  896.       case 4:
  897.         printf ("file thread)\n");
  898.     break;
  899.       default:
  900.         printf ("unknown)\n");
  901.     break;
  902.       }
  903.     }
  904.     break;
  905.   default:
  906.     printf ("unknown node type\n");
  907.     return;
  908.   }
  909.  
  910. }
  911.  
  912. void Play_Audio (CDROM *p_cd, int p_stop)
  913. {
  914.   int result;
  915.  
  916.   if (p_stop)
  917.     result = Stop_Play_Audio (p_cd);
  918.   else
  919.     result = Start_Play_Audio (p_cd);
  920.   
  921.   if (!result)
  922.     fprintf (stderr, "cannot perform operation\n");
  923. }
  924.  
  925. void Find_Offset_Of_Last_Session (CDROM *p_cd)
  926. {
  927.   unsigned long last;
  928.   
  929.   if (!Find_Last_Session (p_cd, &last)) {
  930.     fprintf (stderr, "cannot determine offset of last session\n");
  931.   } else {
  932.     printf ("offset of last session: %lu\n", last);
  933.   }
  934. }
  935.  
  936. void Test_Trackdisk_Device (CDROM *p_cd)
  937. {
  938.   int state, num;
  939.   
  940.   for (;;) {
  941.     p_cd->scsireq->io_Flags = IOF_QUICK;
  942.     p_cd->scsireq->io_Command = TD_CHANGESTATE;
  943.     BeginIO ((struct IORequest*) p_cd->scsireq);
  944.     state = p_cd->scsireq->io_Actual;
  945.     p_cd->scsireq->io_Flags = IOF_QUICK;
  946.     p_cd->scsireq->io_Command = TD_CHANGENUM;
  947.     BeginIO ((struct IORequest*) p_cd->scsireq);
  948.     num = p_cd->scsireq->io_Actual;
  949.     printf ("%s, changenum = %d\n", state ? "no disk present" : "disk present",
  950.             num);
  951.     Delay (50);
  952.   }
  953. }
  954.  
  955. void main (int argc, char *argv[])
  956. {
  957.   atexit (Cleanup);
  958.  
  959.   if (argc < 2)
  960.     Usage ();
  961.  
  962.   if (!(UtilityBase = (struct UtilityBase *)
  963.          OpenLibrary ((UBYTE *) "utility.library", 37))) {
  964.     fprintf (stderr, "cannot open utility.library\n");
  965.     exit (1);
  966.   }
  967.  
  968.   if (!Get_Device_And_Unit ()) {
  969.     fprintf (stderr,
  970.       "Please set the following environment variables:\n"
  971.       "  CDROM_DEVICE    name of SCSI device\n"
  972.       "  CDROM_UNIT      unit number of CDROM drive\n"
  973.       "e.g.\n"
  974.       "  setenv CDROM_DEVICE scsi.device\n"
  975.       "  setenv CDROM_UNIT 2\n"
  976.       "Set the variable CDROM_TRACKDISK to any value if you\n"
  977.       "want to use trackdisk calls instead of SCSI-direct calls\n"
  978.       "Set the variable CDROM_FASTMEM to any value if you\n"
  979.       "want to use fast memory for SCSI buffers (does not work\n"
  980.       "with all SCSI devices!)\n"
  981.       );
  982.     exit (1);
  983.   }
  984.  
  985.   /* the following commands do not depend on the block length of
  986.    * the CDROM drive:
  987.    */
  988.   switch (argv[1][0]) {
  989.   case 'a':
  990.   case 'b':
  991.   case 'j':
  992.   case 'x':
  993.   case 'z':
  994.     g_ignore_blocklength = TRUE;
  995.   }
  996.  
  997.   cd = Open_CDROM (g_the_device, g_the_unit, g_trackdisk, g_memory_type,
  998.              STD_BUFFERS, FILE_BUFFERS);
  999.   if (!cd) {
  1000.     fprintf (stderr, "cannot open CDROM, error code = %d\n", g_cdrom_errno);
  1001.     exit (1);
  1002.   }
  1003.  
  1004.   if (argv[1][0] == 'a' && argc == 2)
  1005.     Show_Drive_Information (cd);
  1006.   else if (argv[1][0] == 'b' && argc == 2)
  1007.     Show_Table_Of_Contents (cd);
  1008.   else if (argv[1][0] == 'c' && argc == 3)
  1009.     Show_File_Contents (cd, argv[2]);
  1010.   else if (argv[1][0] == 'd' && argc == 3)
  1011.     Show_Dir_Contents (cd, argv[2], 0, argv[1]+1);
  1012.   else if (argv[1][0] == 'e' && argc == 3)
  1013.     Show_Dir_Contents (cd, argv[2], 1, argv[1]+1);
  1014.   else if (argv[1][0] == 'f' && argc == 4)
  1015.     Try_To_Open (cd, argv[2], argv[3]);
  1016.   else if (argv[1][0] == 'i')
  1017.     Check_Protocol (cd);
  1018.   else if (argv[1][0] == 'j' && argc == 3)
  1019.     Play_Audio (cd, atoi (argv[2]));
  1020.   else if (argv[1][0] == 'l' && argc == 2)
  1021.     Find_Offset_Of_Last_Session (cd);
  1022.   else if (argv[1][0] == 'm' && argc == 3)
  1023.     Show_Catalog_Node (cd, atoi (argv[2]));
  1024.   else if (argv[1][0] == 'o' && argc == 3)
  1025.     Try_To_Open (cd, NULL, argv[2]);
  1026.   else if (argv[1][0] == 'r')
  1027.     Show_Root_Directory (cd);
  1028.   else if (argv[1][0] == 's' && argc == 3)
  1029.     Show_Sectors (cd, atoi (argv[2]), 1);
  1030.   else if (argv[1][0] == 's' && argc == 4)
  1031.     Show_Sectors (cd, atoi (argv[2]), atoi (argv[3]));
  1032.   else if (argv[1][0] == 't' && argc == 3)
  1033.     Try_To_Open (cd, (char *) -1, argv[2]);
  1034.   else if (argv[1][0] == 'v')
  1035.     Show_Primary_Volume_Descriptor (cd);
  1036.   else if (argv[1][0] == 'x' && argc == 3)
  1037.     Select_Mode (cd, atoi (argv[2]), 2048);
  1038.   else if (argv[1][0] == 'x' && argc == 4)
  1039.     Select_Mode (cd, atoi (argv[2]), atoi (argv[3]));
  1040.   else if (argv[1][0] == 'y' && argc == 3)
  1041.     Find_Block_Starting_With (cd, atoi (argv[2]));
  1042.   else if (argv[1][0] == 'z')
  1043.     Send_Test_Unit_Ready (cd);
  1044.   else if (argv[1][0] == 'T')
  1045.     Test_Trackdisk_Device (cd);
  1046.   else
  1047.     Usage ();
  1048.  
  1049.   exit (0);
  1050. }
  1051.