home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / disk / amicdrom-1.11.lha / AmiCDROM-1.11 / iso9660.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-22  |  21.2 KB  |  853 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,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.  * 17-May-94   fmu   New option MAYBELOWERCASE (=ML).
  14.  * 25-Apr-94   fmu   The extented attribute record length has to be
  15.  *                   considered when reading file sections.
  16.  * 17-Feb-94   fmu   Volume ID must not be longer than 30 characters.
  17.  * 05-Feb-94   fmu   Added support for relocated directories.
  18.  * 07-Jan-94   fmu   Support for drives which don't support the SCSI-2
  19.  *                   READ TOC command.
  20.  * 01-Jan-94   fmu   Added multisession support.
  21.  * 11-Dec-93   fmu   Fixed bug in Iso_Find_Parent().
  22.  * 02-Dec-93   fmu   Bugfix: a logical block of a file extent must not
  23.  *                   necessarily start at a logical sector border.
  24.  * 29-Nov-93   fmu   - New function Iso_Block_Size().
  25.  *                   - Support for variable logical block sizes.
  26.  * 15-Nov-93   fmu   Uses_High_Sierra_Protocol added.
  27.  * 13-Nov-93   fmu   Bad iso_errno return value in Iso_Open_Obj_In_Directory
  28.  *                   corrected.
  29.  * 12-Oct-93   fmu   Adapted to new VOLUME and CDROM_OBJ structures.
  30.  * 24-Sep-93   fmu   Two further bugs in Seek_Position fixed.
  31.  * 16-Sep-93   fmu   Fixed bug in Seek_Position.
  32.  * 16-Sep-93   fmu   Bugfix: Top level object recognition in CDROM_Info
  33.  *                   had to be changed for Rock Ridge disks.
  34.  */
  35.  
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <ctype.h>
  39.  
  40. #include <exec/types.h>
  41. #include <exec/memory.h>
  42. #include <clib/exec_protos.h>
  43. #include <clib/utility_protos.h>
  44. #ifdef AZTEC_C
  45. #include <pragmas/exec_lib.h>
  46. #include <pragmas/utility_lib.h>
  47. #endif
  48. #ifdef LATTICE
  49. #include <pragmas/exec_pragmas.h>
  50. #include <pragmas/utility_pragmas.h>
  51. #endif
  52. #if defined(_DCC) && defined(REGISTERED)
  53. #include <pragmas/exec_pragmas.h>
  54. #include <pragmas/utility_pragmas.h>
  55. extern struct Library *SysBase;
  56. #endif
  57.  
  58. #include "cdrom.h"
  59. #include "iso9660.h"
  60. #include "rock.h"
  61.  
  62. extern struct Library *UtilityBase;
  63.  
  64. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *);
  65.  
  66. int iso_errno;
  67.  
  68. #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
  69. #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
  70.  
  71. /* Check whether the given volume uses the ISO 9660 Protocol.
  72.  * The protocol is identified by the sequence
  73.  *            'C' 'D' '0' '0' '1'
  74.  * in the 2nd..6th byte of sector 16 of a track.
  75.  *
  76.  * All data tracks on the disk are examined.
  77.  *
  78.  * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
  79.  */
  80.  
  81. t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
  82. {
  83.   int i, len;
  84.   t_ulong *buf;
  85.  
  86.   /* If Data_Tracks() returns -1, then the drive probably doesn't support
  87.    * the SCSI-2 READ TOC command.
  88.    */
  89.   if (p_cdrom->use_trackdisk ||
  90.       (len = Data_Tracks (p_cdrom, &buf)) < 0) {
  91.     *p_offset = 0;
  92.     if (!Read_Sector (p_cdrom, 16))
  93.       return FALSE;  
  94.     return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
  95.   }
  96.  
  97.   if (len == 0)
  98.     return FALSE;
  99.  
  100.   for (i=len-1; i>=0; i--) {
  101.     *p_offset = buf[i];
  102.     if (!Read_Sector (p_cdrom, 16 + *p_offset))
  103.       continue;
  104.     if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  105.       FreeVec (buf);
  106.       return TRUE;
  107.     }
  108.   }
  109.  
  110.   FreeVec (buf);
  111.   return FALSE;
  112. }
  113.  
  114. /* Check whether the given volume uses the High Sierra Protocol.
  115.  * The protocol is identified by the sequence
  116.  *            'C' 'D' 'R' 'O' 'M'
  117.  * in the 10th..14th byte of sector 16.
  118.  *
  119.  * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
  120.  */
  121.  
  122. t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
  123. {
  124.   if (!Read_Sector (p_cdrom, 16))
  125.     return FALSE;
  126.   
  127.   return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
  128. }
  129.  
  130. t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset)
  131. {
  132.   long loc = 16 + p_offset;
  133.   extern t_handler g_iso_handler, g_rr_handler;
  134.  
  135.   if (p_volume->protocol == PRO_ISO)
  136.     p_volume->handler = &g_iso_handler;
  137.   else
  138.     p_volume->handler = &g_rr_handler;
  139.  
  140.   p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC);
  141.   if (!p_volume->vol_info) {
  142.     iso_errno = ISOERR_NO_MEMORY;
  143.     return FALSE;
  144.   }
  145.  
  146.   for (;;) {
  147.     if (!Read_Sector (p_volume->cd, loc)) {
  148.       iso_errno = ISOERR_SCSI_ERROR;
  149.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  150.       return FALSE;
  151.     }
  152.  
  153.     if (p_volume->cd->buffer[0] == 1) {
  154.       memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
  155.       break;
  156.     }
  157.     
  158.     if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
  159.       iso_errno = ISOERR_NO_PVD;
  160.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  161.       return FALSE;
  162.     }
  163.     
  164.     loc++;
  165.   }
  166.   
  167.   VOL(p_volume,skip) = p_skip;
  168.  
  169.   switch (VOL(p_volume,pvd).block_size_m) {
  170.   case 512:
  171.     VOL(p_volume,blockshift) = 2;
  172.     break;
  173.   case 1024:
  174.     VOL(p_volume,blockshift) = 1;
  175.     break;
  176.   case 2048:
  177.   default:
  178.     VOL(p_volume,blockshift) = 0;
  179.     break;
  180.   }
  181.  
  182.   /* Look at the system ID to find out if the CD is supposed
  183.    * to feature proper file names. These are CDs made for use
  184.    * with the CDTV and the CD³² (both share the "CDTV" system ID)
  185.    * and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
  186.    * created by Mkisofs. If any of these IDs is found the
  187.    * file name to lower case conversion is temporarily
  188.    * disabled if the "ML=MAYBELOWERCASE" option has been selected.
  189.    */
  190.  
  191.   if (p_volume->protocol == PRO_ROCK ||
  192.       !strncmp(VOL(p_volume,pvd).system_id,"CDTV",4) ||
  193.       !strncmp(VOL(p_volume,pvd).system_id,"AMIGA",5))
  194.     p_volume->mixed_char_filenames = TRUE;
  195.   else
  196.     p_volume->mixed_char_filenames = FALSE;
  197.  
  198.   return TRUE;
  199. }
  200.  
  201. void Iso_Close_Vol_Info (VOLUME *p_volume)
  202. {
  203.   FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  204. }
  205.  
  206. CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
  207. {
  208.   CDROM_OBJ *obj;
  209.  
  210.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
  211.   if (!obj) {
  212.     iso_errno = ISOERR_NO_MEMORY;
  213.     return NULL;
  214.   }
  215.  
  216.   obj->obj_info = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  217.   if (!obj->obj_info) {
  218.     FreeMem (obj, sizeof (CDROM_OBJ));
  219.     return NULL;
  220.   }
  221.  
  222.   OBJ(obj,dir) = AllocMem (p_length_of_dir_record, MEMF_PUBLIC);
  223.   if (!OBJ(obj,dir)) {
  224.     iso_errno = ISOERR_NO_MEMORY;
  225.     FreeMem (obj->obj_info, sizeof (t_iso_obj_info));
  226.     FreeMem (obj, sizeof (CDROM_OBJ));
  227.     return NULL;
  228.   }
  229.  
  230.   return obj;
  231. }
  232.  
  233. /* Get the "CDROM object" for the root directory of the volume.
  234.  */
  235.  
  236. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
  237. {
  238.   CDROM_OBJ *obj;
  239.  
  240.   obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
  241.   if (!obj)
  242.     return NULL;
  243.  
  244.   obj->directory_f = TRUE;
  245.   obj->volume = p_volume;
  246.   obj->pos = 0;
  247.   memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
  248.  
  249.   return obj;
  250. }
  251.  
  252. /* Test on equality of directory names (ignoring case).
  253.  */
  254.  
  255. int Directory_Names_Equal (char *p_iso_name, int p_length, char *p_name)
  256. {
  257.   return Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  258.        p_name[p_length] == 0;
  259. }
  260.  
  261. /* Compare the name of the directory entry p_iso_name (with length p_length)
  262.  * with the C string p_name, and return 1 iff both strings are equal.
  263.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  264.  *       name (without version number).
  265.  */
  266.  
  267. int Names_Equal (char *p_iso_name, int p_length, char *p_name)
  268. {
  269.   int pos;
  270.  
  271.   if (Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  272.       p_name[p_length] == 0)
  273.     return TRUE;
  274.   
  275.   /* compare without version number: */
  276.   
  277.   for (pos=p_length-1; pos>=0; pos--)
  278.     if (p_iso_name[pos] == ';')
  279.       break;
  280.  
  281.   if (pos>=0)
  282.     return (Strncasecmp (p_iso_name, p_name, pos) == 0 &&
  283.             p_name[pos] == 0);
  284.   else
  285.     return FALSE;
  286. }
  287.  
  288. /* Get a record from a directory.
  289.  * p_location is a LOGICAL BLOCK number.
  290.  */
  291.  
  292. directory_record *Get_Directory_Record (VOLUME *p_volume,
  293.                     unsigned long p_location,
  294.                     unsigned long p_offset)
  295. {
  296.   static unsigned char result[256];
  297.   int len;
  298.   int loc;
  299.   
  300.   loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
  301.   if (!Read_Sector (p_volume->cd, loc)) {
  302.     iso_errno = ISOERR_SCSI_ERROR;
  303.     return NULL;
  304.   }
  305.  
  306.   len = p_volume->cd->buffer[p_offset & 2047];
  307.   if (len)
  308.     memcpy (result, p_volume->cd->buffer + (p_offset & 2047), len);
  309.   else
  310.     result[0] = 0;  /* mark as last record */
  311.   
  312.   return (directory_record *) result;
  313. }
  314.  
  315. /* Create a "CDROM object" for the directory which is located
  316.  * at sector p_location.
  317.  */
  318.  
  319. CDROM_OBJ *Iso_Create_Directory_Obj (VOLUME *p_volume, unsigned long p_location)
  320. {
  321.   directory_record *dir;
  322.   unsigned long loc;
  323.   int offset = 0;
  324.   CDROM_OBJ *obj;
  325.   unsigned long len;
  326.  
  327.   if (p_location == VOL(p_volume,pvd).root.extent_loc_m)
  328.     return Iso_Open_Top_Level_Directory (p_volume);
  329.  
  330.   dir = Get_Directory_Record (p_volume, p_location, 0);
  331.   if (!dir)
  332.     return NULL;
  333.   
  334.   dir = Get_Directory_Record (p_volume, p_location, dir->length);
  335.   if (!dir)
  336.     return NULL;
  337.   
  338.   loc = dir->extent_loc_m;
  339.   len = dir->data_length_m;
  340.   for (;;) {
  341.     if (offset >= len)
  342.       return NULL;
  343.     dir = Get_Directory_Record (p_volume, loc, offset);
  344.     if (!dir)
  345.       return NULL;
  346.     if (!dir->length) {
  347.       /* go to next logical sector: */
  348.       offset = (offset & 0xfffff800) + 2048;
  349.       continue;
  350.     }
  351.     if (dir->extent_loc_m == p_location)
  352.       break;
  353.     offset += dir->length;
  354.   }
  355.  
  356.   obj = Iso_Alloc_Obj (dir->length);
  357.   if (!obj)
  358.     return NULL;
  359.  
  360.   obj->directory_f = TRUE;
  361.   obj->volume = p_volume;
  362.   obj->pos = 0;
  363.   memcpy (OBJ(obj,dir), dir, dir->length);
  364.  
  365.   return obj;
  366. }
  367.  
  368.  
  369. /* Open the object with name p_name in the directory p_dir.
  370.  * p_name must not contain '/' or ':' characters.
  371.  */
  372.  
  373. CDROM_OBJ *Iso_Open_Obj_In_Directory (CDROM_OBJ *p_dir, char *p_name)
  374. {
  375.   unsigned long loc = OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length;
  376.   unsigned long len = OBJ(p_dir,dir)->data_length_m;
  377.   directory_record *dir;
  378.   int offset;
  379.   CDROM_OBJ *obj;
  380.   long cl;
  381.  
  382.   /* skip first two entries: */
  383.  
  384.   dir = Get_Directory_Record (p_dir->volume, loc, 0);
  385.   if (!dir)
  386.     return NULL;
  387.   
  388.   offset = dir->length;
  389.   dir = Get_Directory_Record (p_dir->volume, loc, offset);
  390.   if (!dir)
  391.     return NULL;
  392.  
  393.   offset += dir->length;
  394.   for (;;) {
  395.     if (offset >= len) {
  396.       iso_errno = ISOERR_NOT_FOUND;
  397.       return NULL;
  398.     }
  399.     dir = Get_Directory_Record (p_dir->volume, loc, offset);
  400.     if (!dir)
  401.       return NULL;
  402.     if (!dir->length) {
  403.       /* go to next logical sector: */
  404.       offset = (offset & 0xfffff800) + 2048;
  405.       continue;
  406.     }
  407.     if (p_dir->volume->protocol == PRO_ROCK) {
  408.       char buf[256];
  409.       int len;
  410.  
  411.       if ((len = Get_RR_File_Name (p_dir->volume, dir, buf, sizeof (buf))) > 0 &&
  412.           Strncasecmp (buf, p_name, len) == 0 &&
  413.       p_name[len] == 0)
  414.     break;
  415.     }
  416.  
  417.     if (Names_Equal (dir->file_id, dir->file_id_length, p_name))
  418.       break;
  419.     offset += dir->length;
  420.   }
  421.  
  422.   if (p_dir->volume->protocol == PRO_ROCK &&
  423.       (cl = RR_Child_Link (p_dir->volume, dir)) >= 0)
  424.     return Iso_Create_Directory_Obj (p_dir->volume, cl);
  425.  
  426.   obj = Iso_Alloc_Obj (dir->length);
  427.   if (!obj)
  428.     return NULL;
  429.  
  430.   obj->directory_f = (dir->flags & 2);
  431.   if (p_dir->volume->protocol == PRO_ROCK &&
  432.       Is_A_Symbolic_Link (p_dir->volume, dir)) {
  433.     obj->symlink_f = 1;
  434.     obj->directory_f = 0;
  435.   }
  436.   memcpy (OBJ(obj,dir), dir, dir->length);
  437.   obj->volume = p_dir->volume;
  438.   obj->pos = 0;
  439.   if (!obj->directory_f)
  440.     OBJ(obj,parent_loc) = loc;
  441.  
  442.   return obj;
  443. }
  444.  
  445. /* Close a "CDROM object" and deallocate all associated resources.
  446.  */
  447.  
  448. void Iso_Close_Obj (CDROM_OBJ *p_object)
  449. {
  450.   FreeMem (OBJ(p_object,dir), OBJ(p_object,dir)->length);
  451.   FreeMem (p_object->obj_info, sizeof (t_iso_obj_info));
  452.   FreeMem (p_object, sizeof (CDROM_OBJ));
  453. }
  454.  
  455. /* Read bytes from a file.
  456.  */
  457.  
  458. int Iso_Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  459. {
  460.   unsigned long loc;
  461.   int remain_block, remain_file, remain;
  462.   int len;
  463.   VOLUME *vol = p_file->volume;
  464.   CDROM *cd = vol->cd;
  465.   int buf_pos = 0;
  466.   int todo;
  467.   unsigned long last_loc, ext_loc;
  468.   short blockshift;
  469.   int offset;
  470.   unsigned long firstblock;
  471.  
  472.   if (p_file->pos == OBJ(p_file,dir)->data_length_m)
  473.     /* at end of file: */
  474.     return 0;
  475.  
  476.   blockshift = VOL(vol,blockshift);
  477.   /* 'firstblock' is the first logical block of the file section: */
  478.   firstblock = OBJ(p_file,dir)->extent_loc_m + OBJ(p_file,dir)->ext_attr_length;
  479.   /*
  480.    * 'offset' is the offset of the first logical block of the file
  481.    * extent from the first logical (2048-byte-)sector.
  482.    */
  483.   if (blockshift)
  484.     offset = ((firstblock & ((1<<blockshift)-1))
  485.               << (11-blockshift));
  486.   else
  487.     offset = 0;
  488.   /*
  489.    * 'ext_loc' is the first logical sector of the file extent.
  490.    * 'loc' is the first logical sector to be read.
  491.    * 'last_loc' is the last logical sector of the file extent.
  492.    */
  493.   ext_loc = firstblock >> blockshift;
  494.   loc = ext_loc + ((p_file->pos + offset) >> 11);
  495.   last_loc = ext_loc + ((OBJ(p_file,dir)->data_length_m + offset - 1) >> 11);
  496.   todo = p_buffer_length;
  497.  
  498.   offset += p_file->pos;
  499.   offset &= 2047;
  500.   remain_block = 2048 - offset;
  501.  
  502.   while (todo) {
  503.     if (!Read_Contiguous_Sectors (cd, loc, last_loc)) {
  504.       iso_errno = ISOERR_SCSI_ERROR;
  505.       return -1;
  506.     }
  507.  
  508.     remain_file = OBJ(p_file,dir)->data_length_m - p_file->pos;
  509.     /* 
  510.      * 'todo' is the number of bytes in p_buffer which haven't been filled yet.
  511.      * 'remain' is remaining number of bytes in cd->buffer.
  512.      */
  513.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  514.     len = (todo < remain) ? todo : remain;
  515.     CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
  516.     buf_pos += len;
  517.     p_file->pos += len;
  518.     todo -= len;
  519.  
  520.     if (p_file->pos >= OBJ(p_file,dir)->data_length_m)
  521.       break;
  522.  
  523.     remain_block = 2048;
  524.     offset = 0;
  525.  
  526.     loc++;
  527.   }
  528.  
  529.   return buf_pos;
  530. }
  531.  
  532. t_ulong Extract_Date (directory_record *p_dir_record)
  533. {
  534.   struct ClockData ClockData;
  535.  
  536.   ClockData.sec   = p_dir_record->second;
  537.   ClockData.min      = p_dir_record->minute;
  538.   ClockData.hour  = p_dir_record->hour;
  539.   ClockData.mday  = p_dir_record->day;
  540.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  541.   ClockData.month = p_dir_record->month;
  542.   ClockData.year  = p_dir_record->year + 1900;
  543.  
  544.   if (CheckDate (&ClockData))
  545.     return Date2Amiga (&ClockData);
  546.   else
  547.     return 0;
  548. }
  549.  
  550. /* Return information on a "CDROM object."
  551.  */
  552.  
  553. int Iso_CDROM_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  554. {
  555.   int len;
  556.  
  557.   if (Iso_Is_Top_Level_Object (p_obj)) {
  558.     p_info->name_length = 1;
  559.     p_info->name[0] = ':';
  560.     p_info->directory_f = TRUE;
  561.     p_info->file_length = 0;
  562.     p_info->date = Volume_Creation_Date (p_obj->volume);
  563.   } else {
  564.     if (p_obj->volume->protocol == PRO_ROCK &&
  565.         (len = Get_RR_File_Name (p_obj->volume, OBJ(p_obj,dir),
  566.                        p_info->name, sizeof (p_info->name))) > 0) {
  567.       p_info->name_length = len;
  568.     } else {
  569.       p_info->name_length = OBJ(p_obj,dir)->file_id_length;
  570.       memcpy (p_info->name, OBJ(p_obj,dir)->file_id, p_info->name_length);
  571.     }
  572.     p_info->directory_f = p_obj->directory_f;
  573.     p_info->symlink_f = p_obj->symlink_f;
  574.     p_info->file_length = OBJ(p_obj,dir)->data_length_m;
  575.     p_info->date = Extract_Date (OBJ(p_obj,dir));
  576.   }
  577.  
  578.   return 1;
  579. }
  580.  
  581. /* Browse all entries in a directory.
  582.  */
  583.  
  584. int Iso_Examine_Next (CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  585.               unsigned long *p_offset)
  586. {
  587.   unsigned long offset;
  588.   directory_record *rec;
  589.   int len;
  590.  
  591.   if (!p_dir->directory_f || p_dir->symlink_f) {
  592.     iso_errno = ISOERR_BAD_ARGUMENTS;
  593.     return 0;
  594.   }
  595.  
  596.   if (*p_offset == 0) {
  597.     /* skip first two directory entries: */
  598.   
  599.     rec = Get_Directory_Record
  600.       (p_dir->volume,
  601.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  602.        0);
  603.     if (!rec)
  604.       return 0;
  605.   
  606.     offset = rec->length;
  607.   
  608.     rec = Get_Directory_Record
  609.       (p_dir->volume,
  610.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  611.        offset);
  612.     if (!rec)
  613.       return 0;
  614.   
  615.     *p_offset = offset + rec->length;
  616.   }
  617.  
  618.   for (;;) {
  619.     if (OBJ(p_dir,dir)->data_length_m <= *p_offset)
  620.       return 0;
  621.  
  622.     rec = Get_Directory_Record
  623.         (p_dir->volume,
  624.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  625.      *p_offset);
  626.     if (!rec)
  627.       return 0;
  628.   
  629.     if (rec->length == 0)
  630.       /* go to next logical sector: */
  631.       *p_offset = (*p_offset & 0xfffff800) + 2048;
  632.     else
  633.       break;
  634.   }
  635.  
  636.   *p_offset += rec->length;
  637.  
  638.   if (p_dir->volume->protocol == PRO_ROCK &&
  639.       (len = Get_RR_File_Name (p_dir->volume, rec,
  640.                          p_info->name, sizeof (p_info->name))) > 0) {
  641.       p_info->name_length = len;
  642.   } else {
  643.     p_info->name_length = rec->file_id_length;
  644.     memcpy (p_info->name, rec->file_id, rec->file_id_length);
  645.   }
  646.   if (p_dir->volume->protocol == PRO_ROCK &&
  647.       Is_A_Symbolic_Link (p_dir->volume, rec)) {
  648.     p_info->symlink_f = 1;
  649.     p_info->directory_f = 0;
  650.   } else if (p_dir->volume->protocol == PRO_ROCK &&
  651.              Has_System_Use_Field (p_dir->volume, rec, "CL")) {
  652.     p_info->symlink_f = 0;
  653.     p_info->directory_f = 1;
  654.   } else {
  655.     p_info->symlink_f = 0;
  656.     p_info->directory_f = rec->flags & 2;
  657.   }
  658.   p_info->file_length = rec->data_length_m;
  659.   p_info->date = Extract_Date (rec);
  660.   p_info->suppl_info = rec;
  661.  
  662.   return 1;
  663. }
  664.  
  665. /* Clone a "CDROM object info."
  666.  */
  667.  
  668. void *Iso_Clone_Obj_Info (void *p_info)
  669. {
  670.   t_iso_obj_info *info = (t_iso_obj_info *) p_info;
  671.   t_iso_obj_info *new;
  672.   
  673.   new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  674.   if (!new)
  675.     return NULL;
  676.  
  677.   memcpy (new, info, sizeof (t_iso_obj_info));
  678.  
  679.   new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
  680.   if (!new->dir) {
  681.     FreeMem (new, sizeof (t_iso_obj_info));
  682.     return NULL;
  683.   }
  684.   memcpy (new->dir, info->dir, info->dir->length);
  685.  
  686.   return new;
  687. }
  688.  
  689. /* Find parent directory.
  690.  */
  691.  
  692. CDROM_OBJ *Iso_Find_Parent (CDROM_OBJ *p_object)
  693. {
  694.   directory_record *dir;
  695.   unsigned long dir_loc;
  696.   long pl;
  697.  
  698.   if (p_object->directory_f)
  699.     dir_loc = OBJ(p_object,dir)->extent_loc_m + OBJ(p_object,dir)->ext_attr_length;
  700.   else
  701.     dir_loc = OBJ(p_object,parent_loc);
  702.  
  703.   dir = Get_Directory_Record (p_object->volume, dir_loc, 0);
  704.   if (!dir)
  705.     return NULL;
  706.   
  707.   if (p_object->directory_f) {
  708.     dir = Get_Directory_Record (p_object->volume, dir_loc, dir->length);
  709.     if (!dir)
  710.       return NULL;
  711.     if (p_object->volume->protocol == PRO_ROCK &&
  712.         (pl = RR_Parent_Link (p_object->volume, dir)) >= 0)
  713.       return Iso_Create_Directory_Obj (p_object->volume, pl);
  714.   }
  715.  
  716.   return Iso_Create_Directory_Obj (p_object->volume, dir->extent_loc_m);
  717. }
  718.  
  719. /* Test if p_object is the root directory.
  720.  */
  721.  
  722. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *p_object)
  723. {
  724.   return p_object->directory_f &&
  725.          OBJ(p_object,dir)->extent_loc_m ==
  726.      VOL(p_object->volume,pvd).root.extent_loc_m;
  727. }
  728.  
  729. /* Test if two objects are equal.
  730.  */
  731.  
  732. t_bool Iso_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
  733. {
  734.   return (OBJ(p_obj1,dir)->extent_loc_m ==
  735.       OBJ(p_obj2,dir)->extent_loc_m);
  736. }
  737.  
  738. /*
  739.  * Convert p_num digits into an integer value:
  740.  */
  741.  
  742. int Digs_To_Int (char *p_digits, int p_num)
  743. {
  744.   int result = 0;
  745.   int i;
  746.   
  747.   for (i=0; i<p_num; i++)
  748.     result = result * 10 + p_digits[i] - '0';
  749.     
  750.   return result;
  751. }
  752.  
  753. /*
  754.  * Return volume creation date as number of seconds since 1-Jan-1978:
  755.  */
  756.  
  757. t_ulong Iso_Creation_Date (VOLUME *p_volume)
  758. {
  759.   struct ClockData ClockData;
  760.   char *dt = VOL(p_volume,pvd).vol_creation;
  761.  
  762.   ClockData.sec   = Digs_To_Int (dt+12, 2);
  763.   ClockData.min      = Digs_To_Int (dt+10, 2);
  764.   ClockData.hour  = Digs_To_Int (dt+8, 2);
  765.   ClockData.mday  = Digs_To_Int (dt+6, 2);
  766.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  767.   ClockData.month = Digs_To_Int (dt+4, 2);
  768.   ClockData.year  = Digs_To_Int (dt, 4);
  769.  
  770.   if (CheckDate (&ClockData))
  771.     return Date2Amiga (&ClockData);
  772.   else
  773.     return 0;
  774. }
  775.  
  776. t_ulong Iso_Volume_Size (VOLUME *p_volume)
  777. {
  778.   return VOL(p_volume,pvd).space_size_m;
  779. }
  780.  
  781. t_ulong Iso_Block_Size (VOLUME *p_volume)
  782. {
  783.   return VOL(p_volume,pvd).block_size_m;
  784. }
  785.  
  786. void Iso_Volume_ID (VOLUME *p_volume, char *p_buffer, int p_buf_length)
  787. {
  788.   char *iso_name = VOL(p_volume,pvd).volume_id;
  789.   int iso_len;
  790.   int len;
  791.  
  792.   for (iso_len = 30; iso_len; iso_len--) {
  793.     if (iso_name[iso_len-1] != ' ')
  794.       break;
  795.   }
  796.  
  797.   len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
  798.   if (len > 0)
  799.     memcpy (p_buffer, iso_name, len);
  800.   p_buffer[len] = 0;
  801. }
  802.  
  803. t_ulong Iso_Location (CDROM_OBJ *p_object)
  804. {
  805.   return OBJ(p_object,dir)->extent_loc_m;
  806. }
  807.  
  808. t_ulong Iso_File_Length (CDROM_OBJ *p_obj)
  809. {
  810.   return OBJ(p_obj,dir)->data_length_m;
  811. }
  812.  
  813. t_handler g_iso_handler = {
  814.   Iso_Close_Vol_Info,
  815.   Iso_Open_Top_Level_Directory,
  816.   Iso_Open_Obj_In_Directory,
  817.   Iso_Find_Parent,
  818.   Iso_Close_Obj,
  819.   Iso_Read_From_File,
  820.   Iso_CDROM_Info,
  821.   Iso_Examine_Next,
  822.   Iso_Clone_Obj_Info,
  823.   Iso_Is_Top_Level_Object,
  824.   Iso_Same_Objects,
  825.   Iso_Creation_Date,
  826.   Iso_Volume_Size,
  827.   Iso_Volume_ID,
  828.   Iso_Location,
  829.   Iso_File_Length,
  830.   Iso_Block_Size
  831. };
  832.  
  833. t_handler g_rr_handler = {
  834.   Iso_Close_Vol_Info,
  835.   Iso_Open_Top_Level_Directory,
  836.   Iso_Open_Obj_In_Directory,
  837.   Iso_Find_Parent,
  838.   Iso_Close_Obj,
  839.   Iso_Read_From_File,
  840.   Iso_CDROM_Info,
  841.   Iso_Examine_Next,
  842.   Iso_Clone_Obj_Info,
  843.   Iso_Is_Top_Level_Object,
  844.   Iso_Same_Objects,
  845.   Iso_Creation_Date,
  846.   Iso_Volume_Size,
  847.   Iso_Volume_ID,
  848.   Iso_Location,
  849.   Iso_File_Length,
  850.   Iso_Block_Size
  851. };
  852.  
  853.