home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / useful / dist / other / amicdrom / iso9660.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-27  |  17.9 KB  |  784 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993 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.  * 24-Sep-93   fmu   Two further bugs in Seek_Position fixed.
  14.  * 16-Sep-93   fmu   Fixed bug in Seek_Position.
  15.  * 16-Sep-93   fmu   Bugfix: Top level object recognition in CDROM_Info
  16.  *                   had to be changed for Rock Ridge disks.
  17.  */
  18.  
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22.  
  23. #include <exec/types.h>
  24. #include <exec/memory.h>
  25. #include <clib/exec_protos.h>
  26.  
  27. #include "cdrom.h"
  28. #include "iso9660.h"
  29. #include "rock.h"
  30.  
  31. int iso_errno;
  32.  
  33. /* A "volume" is the basic handle that we'll use for CDROM access.
  34.  * A volume contains all necessary information for finding files on
  35.  * a CDROM.
  36.  */
  37.  
  38. VOLUME *Open_Volume (CDROM *p_cdrom, int p_use_rock_ridge)
  39. {
  40.   VOLUME *res;
  41.   long loc = 16;
  42.   
  43.   res = AllocMem (sizeof (VOLUME), MEMF_PUBLIC);
  44.   if (!res) {
  45.     iso_errno = ISOERR_NO_MEMORY;
  46.     return NULL;
  47.   }
  48.  
  49.   res->cd = p_cdrom;
  50.   
  51.   for (;;) {
  52.     if (!Read_Sector (res->cd, loc)) {
  53.       iso_errno = ISOERR_SCSI_ERROR;
  54.       FreeMem (res, sizeof (VOLUME));
  55.       return NULL;
  56.     }
  57.  
  58.     if (res->cd->buffer[0] == 1) {
  59.       memcpy (&res->pvd, res->cd->buffer, sizeof (prim_vol_desc));
  60.       break;
  61.     }
  62.     
  63.     if (res->cd->buffer[0] == 255 || loc > 1000) {
  64.       iso_errno = ISOERR_NO_PVD;
  65.       FreeMem (res, sizeof (VOLUME));
  66.       return NULL;
  67.     }
  68.     
  69.     loc++;
  70.   }
  71.   
  72.   res->use_rock_ridge = p_use_rock_ridge && Uses_Rock_Ridge_Protocol (res);
  73.   
  74.   res->valid = 1;  /* may be modified by application program */
  75.   res->locks = 0;  /* may be modified by application program */
  76.  
  77.   return res;
  78. }
  79.  
  80. /* Close a volume; deallocate all associated resources.
  81.  */
  82.  
  83. void Close_Volume (VOLUME *p_volume)
  84. {
  85.   FreeMem (p_volume, sizeof (VOLUME));
  86. }
  87.  
  88. /* Get the "CDROM object" for the root directory of the volume.
  89.  */
  90.  
  91. CDROM_OBJ *Open_Top_Level_Directory (VOLUME *p_volume)
  92. {
  93.   CDROM_OBJ *obj;
  94.   
  95.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
  96.   if (!obj) {
  97.     iso_errno = ISOERR_NO_MEMORY;
  98.     return NULL;
  99.   }
  100.  
  101.   obj->directory_f = TRUE;
  102.   obj->volume = p_volume;
  103.   obj->path_table_pos = 1;
  104.   if (obj->volume->use_rock_ridge)
  105.     obj->parent = p_volume->pvd.root.extent_loc_m;
  106.   else
  107.     obj->parent = 1;
  108.   obj->pos = 0;
  109.   
  110.   obj->dir_record = AllocMem (p_volume->pvd.root.length, MEMF_PUBLIC);
  111.   if (!obj->dir_record) {
  112.     iso_errno = ISOERR_NO_MEMORY;
  113.     FreeMem (obj, sizeof (CDROM_OBJ));
  114.     return NULL;
  115.   }
  116.   memcpy (obj->dir_record, &p_volume->pvd.root, p_volume->pvd.root.length);
  117.  
  118.   return obj;
  119. }
  120.  
  121. /* Read a record from the path table.
  122.  */
  123.  
  124. path_table_record *Get_Path_Table_Record (VOLUME *p_volume, unsigned long p_dir,
  125.                       unsigned long *p_offset)
  126. {
  127.   static unsigned char result[256];
  128.   unsigned long loc = p_volume->pvd.m_table;
  129.   unsigned long size = 0;
  130.   int pos = 0;
  131.   int cnt = 1;
  132.   int len;
  133.  
  134.   if (p_dir) {
  135.     if (!Read_Sector (p_volume->cd, loc)) {
  136.       iso_errno = ISOERR_SCSI_ERROR;
  137.       return NULL;
  138.     }
  139.  
  140.     while (cnt < p_dir) {
  141.       if (size >= p_volume->pvd.path_size_m) {
  142.         iso_errno = ISOERR_NO_SUCH_RECORD;
  143.         return NULL;
  144.       }
  145.   
  146.       len = 8 + p_volume->cd->buffer[pos];
  147.       if (len & 1)
  148.         len++;
  149.       pos += len;
  150.       size += len;
  151.     
  152.       if (pos >= 2048) {
  153.         if (!Read_Sector (p_volume->cd, ++loc)) {
  154.           iso_errno = ISOERR_SCSI_ERROR;
  155.           return NULL;
  156.         }
  157.         pos -= 2048;
  158.       }
  159.     
  160.       cnt++;
  161.     }
  162.   } else {
  163.     loc += (*p_offset >> 11);
  164.     if (!Read_Sector (p_volume->cd, loc)) {
  165.       iso_errno = ISOERR_SCSI_ERROR;
  166.       return NULL;
  167.     }
  168.     pos = *p_offset & 2047;
  169.     size = *p_offset;
  170.   }
  171.  
  172.   len = 8 + p_volume->cd->buffer[pos];
  173.   if (len & 1)
  174.     len++;
  175.  
  176.   if (pos + len <= 2048)
  177.     memcpy (result, p_volume->cd->buffer + pos, len);
  178.   else {
  179.     memcpy (result, p_volume->cd->buffer + pos, 2048 - pos);
  180.     if (!Read_Sector (p_volume->cd, ++loc)) {
  181.       iso_errno = ISOERR_SCSI_ERROR;
  182.       return NULL;
  183.     }
  184.     memcpy (result + (2048 - pos), p_volume->cd->buffer, len - (2048 - pos));
  185.   }
  186.  
  187.   if (p_offset)
  188.     *p_offset = size + len;
  189.  
  190.   return (path_table_record *) result;
  191. }
  192.  
  193. /* Find parent directory.
  194.  */
  195.  
  196. unsigned long Get_Parent_Directory_ISO (VOLUME *p_volume, unsigned long p_dir)
  197. {
  198.   path_table_record *ptr;
  199.  
  200.   ptr = Get_Path_Table_Record (p_volume, p_dir, NULL);
  201.   if (!ptr)
  202.     return 1;
  203.  
  204.   return ptr->parent;
  205. }
  206.  
  207. /* Strncasecmp works like 'strncmp' but ignores case differences.
  208.  */
  209.  
  210. int Strncasecmp (char *p_str1, char *p_str2, int p_length)
  211. {
  212.   int i;
  213.   int len = 0;
  214.   
  215.   while (len < p_length && *p_str1 && *p_str2) {
  216.     if (i = tolower (*p_str1++) - tolower (*p_str2++))
  217.       return i;
  218.     len++;
  219.   }
  220.   return (len == p_length) ? 0 : tolower (*p_str1) - tolower (*p_str2);
  221. }
  222.  
  223. /* Test on equality of directory names (ignoring case).
  224.  */
  225.  
  226. int Directory_Names_Equal (char *p_iso_name, int p_length, char *p_name)
  227. {
  228.   return Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  229.        p_name[p_length] == 0;
  230. }
  231.  
  232. /* Compare the name of the directory entry p_iso_name (with length p_length)
  233.  * with the C string p_name, and return 1 iff both strings are equal.
  234.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  235.  *       name (without version number).
  236.  */
  237.  
  238. int Names_Equal (char *p_iso_name, int p_length, char *p_name)
  239. {
  240.   if (!strchr (p_name, ';')) {
  241.     /* compare without version number: */
  242.     int pos = p_length-1;
  243.  
  244.     for (; pos>=0; pos--)
  245.       if (p_iso_name[pos] == ';')
  246.         break;
  247.     
  248.     if (pos>=0)
  249.       p_length = pos;
  250.       
  251.   }
  252.   return (Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  253.         p_name[p_length] == 0);
  254. }
  255.  
  256. /* Get a record from a directory.
  257.  */
  258.  
  259. directory_record *Get_Directory_Record (VOLUME *p_volume,
  260.                     unsigned long p_location,
  261.                     unsigned long p_offset)
  262. {
  263.   static unsigned char result[256];
  264.   int len;
  265.   int loc;
  266.   
  267.   loc = p_location + (p_offset >> 11);
  268.   if (!Read_Sector (p_volume->cd, loc)) {
  269.     iso_errno = ISOERR_SCSI_ERROR;
  270.     return NULL;
  271.   }
  272.  
  273.   len = p_volume->cd->buffer[p_offset & 2047];
  274.   if (len)
  275.     memcpy (result, p_volume->cd->buffer + (p_offset & 2047), len);
  276.   else
  277.     result[0] = 0;  /* mark as last record */
  278.   
  279.   return (directory_record *) result;
  280. }
  281.  
  282. /* Find directory in path table.
  283.  */
  284.  
  285. unsigned long Find_Directory_ISO (VOLUME *p_volume, unsigned long p_parent,
  286.                       char *p_name)
  287. {
  288.   path_table_record *ptr;
  289.   unsigned long rec = p_parent + 1;
  290.   unsigned long offset;
  291.   directory_record *dir;
  292.  
  293.   ptr = Get_Path_Table_Record (p_volume, rec, &offset);
  294.   for (;;) {
  295.     if (!ptr)
  296.       return 0;
  297.  
  298.     if (ptr->parent == p_parent &&
  299.         Directory_Names_Equal (ptr->id, ptr->id_length, p_name))
  300.       return rec;
  301.  
  302.     if (ptr->parent > p_parent) {
  303.       iso_errno = ISOERR_NOT_FOUND;
  304.       return 0;
  305.     }
  306.  
  307.     rec++;
  308.     /* get next record: */
  309.     ptr = Get_Path_Table_Record (p_volume, 0, &offset);
  310.   }
  311. }
  312.  
  313. /* Find an entry (directory or file) in a directory.
  314.  */
  315.  
  316. directory_record *Find_Directory_Entry (VOLUME *p_volume, unsigned long p_location,
  317.                             char *p_name)
  318. {
  319.   unsigned long length;
  320.   directory_record *dir;
  321.   unsigned long offset = 0;
  322.   int rr_len;
  323.   char rr_buf[256];
  324.  
  325.   if (!(dir = Get_Directory_Record (p_volume, p_location, 0)))
  326.     return NULL;
  327.  
  328.   length = dir->data_length_m;
  329.   
  330.   for (;;) {
  331.     offset += dir->length;
  332.     for (;;) {
  333.       if (offset >= length) {
  334.         iso_errno = ISOERR_NOT_FOUND;
  335.         return NULL;
  336.       }
  337.       dir = Get_Directory_Record (p_volume, p_location, offset);
  338.       if (!dir)
  339.         return NULL;
  340.  
  341.       if (dir->length == 0)
  342.         /* goto next logical sector: */
  343.         offset = (offset & 0xfffff800) + 2048;
  344.       else
  345.         break;
  346.     }
  347.     
  348.     if (p_volume->use_rock_ridge) {
  349.       rr_len = Get_RR_File_Name (p_volume, dir, rr_buf, sizeof (rr_buf));
  350.       if (rr_len != -1) {
  351.         if (Strncasecmp (rr_buf, p_name, rr_len) == 0 &&
  352.         p_name[rr_len] == 0)
  353.       return dir;
  354.     else
  355.       continue;
  356.       }
  357.     }
  358.  
  359.     if (Names_Equal (dir->file_id, dir->file_id_length, p_name))
  360.       return dir;
  361.   }
  362. }
  363.  
  364. /* Open a "CDROM object" on an ISO-9660 disk.
  365.  */
  366.  
  367. CDROM_OBJ *Open_Object_ISO (CDROM_OBJ *p_result,
  368.                 CDROM_OBJ *p_current_dir, char *p_name)
  369. {
  370.   CDROM_OBJ *obj = p_result;
  371.   unsigned long path_table_pos = p_current_dir->path_table_pos;
  372.   unsigned long child_pos;
  373.   char *cp = p_name;
  374.   char name[256];
  375.   char *np;
  376.   path_table_record *ptr;
  377.   directory_record *dir;
  378.  
  379.   if (*cp == ':') {
  380.     path_table_pos = 1;
  381.     cp++;
  382.   } else while (*cp == '/') {
  383.     path_table_pos = Get_Parent_Directory_ISO (p_current_dir->volume, path_table_pos);
  384.     cp++;
  385.   }
  386.  
  387.   while (*cp) {
  388.     for (np = name; *cp && *cp != '/'; )
  389.       *np++ = *cp++;
  390.     *np = 0;
  391.     
  392.     if (name[0] == 0) {
  393.       iso_errno = ISOERR_ILLEGAL_NAME;
  394.       return NULL;
  395.     }
  396.  
  397.     child_pos = Find_Directory_ISO (p_current_dir->volume, path_table_pos, name);
  398.     if (!child_pos) {
  399.       if (iso_errno != ISOERR_NOT_FOUND) {
  400.     return NULL;
  401.       }
  402.     
  403.       if (*cp != 0) {
  404.     return NULL;
  405.       }
  406.  
  407.       ptr = Get_Path_Table_Record (p_current_dir->volume, path_table_pos, NULL);
  408.       if (!ptr)
  409.         return NULL;
  410.  
  411.       dir = Find_Directory_Entry (p_current_dir->volume, ptr->location, name);
  412.       if (!dir)
  413.     return NULL;
  414.  
  415.       obj->directory_f = FALSE;
  416.       obj->parent = path_table_pos;
  417.       obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  418.       if (!obj->dir_record) {
  419.         iso_errno = ISOERR_NO_MEMORY;
  420.         return NULL;    
  421.       }
  422.       memcpy (obj->dir_record, dir, dir->length);
  423.  
  424.       return obj;
  425.     }
  426.  
  427.     path_table_pos = child_pos;
  428.  
  429.     if (*cp == '/')
  430.       cp++;
  431.   }
  432.  
  433.   if (!(ptr = Get_Path_Table_Record (p_current_dir->volume, path_table_pos,
  434.                        NULL))) {
  435.     return NULL;
  436.   }
  437.   
  438.   if (!(dir = Get_Directory_Record (p_current_dir->volume, ptr->location, 0))) {
  439.     return NULL;    
  440.   }
  441.  
  442.   obj->directory_f = TRUE;
  443.   obj->path_table_pos = path_table_pos;
  444.   obj->parent = ptr->parent;
  445.   obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  446.   if (!obj->dir_record) {
  447.     iso_errno = ISOERR_NO_MEMORY;
  448.     return NULL;    
  449.   }
  450.   memcpy (obj->dir_record, dir, dir->length);
  451.  
  452.   return obj;
  453. }
  454.  
  455. /* Open an object on an ISO or Rock Ridge disk.
  456.  */
  457.  
  458. CDROM_OBJ *Open_Object (CDROM_OBJ *p_current_dir, char *p_name)
  459. {
  460.   CDROM_OBJ *obj, *res;
  461.  
  462.   if (*p_name == 0) {
  463.     obj = Clone_Object (p_current_dir);
  464.     if (!obj)
  465.       iso_errno = ISOERR_NO_MEMORY;
  466.     return obj;
  467.   }
  468.  
  469.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
  470.   if (!obj) {
  471.     iso_errno = ISOERR_NO_MEMORY;
  472.     return NULL;
  473.   }
  474.   
  475.   obj->pos = 0;
  476.   obj->volume = p_current_dir->volume;
  477.  
  478.   if (p_current_dir->volume->use_rock_ridge)
  479.     res = Open_Object_RR (obj, p_current_dir, p_name);
  480.   else
  481.     res = Open_Object_ISO (obj, p_current_dir, p_name);
  482.   
  483.   if (!res)
  484.     FreeMem (obj, sizeof (CDROM_OBJ));
  485.  
  486.   return res;
  487. }
  488.  
  489. /* Close a "CDROM object" and deallocate all associated resources.
  490.  */
  491.  
  492. void Close_Object (CDROM_OBJ *p_object)
  493. {
  494.   FreeMem (p_object->dir_record, p_object->dir_record->length);
  495.   FreeMem (p_object, sizeof (CDROM_OBJ));
  496. }
  497.  
  498. /* Read bytes from a file.
  499.  */
  500.  
  501. int Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  502. {
  503.   unsigned long loc;
  504.   int remain_block, remain_file, remain;
  505.   int len;
  506.   CDROM *cd;
  507.   int pos;
  508.   int buf_pos = 0;
  509.   int todo;
  510.   unsigned long last_loc;
  511.  
  512.   if (p_file->pos == p_file->dir_record->data_length_m)
  513.     /* at end of file: */
  514.     return 0;
  515.  
  516.   cd = p_file->volume->cd;
  517.   loc = p_file->dir_record->extent_loc_m + (p_file->pos >> 11);
  518.   last_loc = p_file->dir_record->extent_loc_m +
  519.            ((p_file->dir_record->data_length_m-1) >> 11);
  520.   todo = p_buffer_length;
  521.  
  522.   while (todo) {
  523.     if (!Read_Sector_With_Lookahead (cd, loc, last_loc)) {
  524.       iso_errno = ISOERR_SCSI_ERROR;
  525.       return -1;
  526.     }
  527.  
  528.     remain_block = 2048 - (pos = (p_file->pos & 2047));
  529.     remain_file = p_file->dir_record->data_length_m - p_file->pos;
  530.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  531.     len = (todo < remain) ? todo : remain;
  532.     memcpy (p_buffer + buf_pos, cd->buffer + pos, len);
  533.     buf_pos += len;
  534.     p_file->pos += len;
  535.     todo -= len;
  536.     
  537.     if (p_file->pos >= p_file->dir_record->data_length_m)
  538.       break;
  539.  
  540.     loc++;
  541.   }
  542.  
  543.   return buf_pos;
  544. }
  545.  
  546. /* Return information on a "CDROM object."
  547.  */
  548.  
  549. int CDROM_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  550. {
  551.   memcpy (&p_info->dir_record, p_obj->dir_record, p_obj->dir_record->length);
  552.  
  553.   if (p_obj->volume->use_rock_ridge) {
  554.     p_info->name_length = Get_RR_File_Name (p_obj->volume, &p_info->dir_record,
  555.                       p_info->name, sizeof (p_info->name));
  556.     if (p_info->name_length != -1)
  557.       return 1;
  558.   }
  559.  
  560.   if (p_obj->directory_f) {
  561.     /* dir_record contains only the short directory name (00 byte).
  562.        we have to find the full directory name from the path table. */
  563.  
  564.     path_table_record *ptr;
  565.     
  566.     if (p_obj->dir_record->extent_loc_m ==
  567.         p_obj->volume->pvd.root.extent_loc_m) {
  568.       /* top level object: */
  569.       p_info->name[0] = ':';
  570.       p_info->name_length = 1;
  571.     } else {
  572.       /* other: */
  573.       if (!(ptr = Get_Path_Table_Record (p_obj->volume, p_obj->path_table_pos,
  574.                             NULL))) {
  575.         return 0;
  576.       }
  577.       p_info->name_length = ptr->id_length;
  578.       memcpy (p_info->name, ptr->id, ptr->id_length);
  579.     }
  580.   } else {
  581.     p_info->name_length = p_info->dir_record.file_id_length;
  582.     memcpy (p_info->name, p_info->dir_record.file_id, p_info->name_length);
  583.   }
  584.   return 1;
  585. }
  586.  
  587. /* Browse all entries in a directory.
  588.  */
  589.  
  590. int Examine_Next (CDROM_OBJ *p_dir, CDROM_INFO *p_info, unsigned long *p_offset)
  591. {
  592.   unsigned long offset;
  593.   directory_record *rec;
  594.  
  595.   if (!p_dir->directory_f) {
  596.     iso_errno = ISOERR_BAD_ARGUMENTS;
  597.     return 0;
  598.   }
  599.  
  600.   if (*p_offset == 0) {
  601.     /* skip first two directory entries: */
  602.   
  603.     rec = Get_Directory_Record (p_dir->volume,
  604.                         p_dir->dir_record->extent_loc_m,
  605.                     0);
  606.     if (!rec)
  607.       return 0;
  608.   
  609.     offset = rec->length;
  610.   
  611.     rec = Get_Directory_Record (p_dir->volume,
  612.                       p_dir->dir_record->extent_loc_m,
  613.                     offset);
  614.     if (!rec)
  615.       return 0;
  616.   
  617.     *p_offset = offset + rec->length;
  618.   }
  619.  
  620.   for (;;) {
  621.     if (p_dir->dir_record->data_length_m <= *p_offset)
  622.       return 0;
  623.  
  624.     rec = Get_Directory_Record (p_dir->volume,
  625.                       p_dir->dir_record->extent_loc_m,
  626.                     *p_offset);
  627.     if (!rec)
  628.       return 0;
  629.   
  630.     if (rec->length == 0)
  631.       /* go to next logical sector: */
  632.       *p_offset = (*p_offset & 0xfffff800) + 2048;
  633.     else
  634.       break;
  635.   }
  636.  
  637.   memcpy (&p_info->dir_record, rec, rec->length);
  638.   *p_offset += rec->length;
  639.  
  640.   if (p_dir->volume->use_rock_ridge) {
  641.     p_info->name_length = Get_RR_File_Name (p_dir->volume, rec,
  642.                       p_info->name, sizeof (p_info->name));
  643.     if (p_info->name_length != -1)
  644.       return 1;
  645.   }
  646.  
  647.   p_info->name_length = rec->file_id_length;
  648.   memcpy (p_info->name, rec->file_id, rec->length);
  649.  
  650.  
  651.   return 1;
  652. }
  653.  
  654. /* Clone a "CDROM object."
  655.  */
  656.  
  657. CDROM_OBJ *Clone_Object (CDROM_OBJ *p_object)
  658. {
  659.   CDROM_OBJ *new = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
  660.   
  661.   if (!new)
  662.     return NULL;
  663.   memcpy (new, p_object, sizeof (CDROM_OBJ));
  664.  
  665.   new->dir_record = AllocMem (p_object->dir_record->length, MEMF_PUBLIC);
  666.   if (!new->dir_record) {
  667.     FreeMem (new, sizeof (CDROM_OBJ));
  668.     return NULL;
  669.   }
  670.   memcpy (new->dir_record, p_object->dir_record, p_object->dir_record->length);
  671.  
  672.   return new;
  673. }
  674.  
  675. /* Find parent directory.
  676.  */
  677.  
  678. CDROM_OBJ *Find_Parent_ISO (CDROM_OBJ *p_object)
  679. {
  680.   path_table_record *ptr;
  681.   directory_record *dir;
  682.   CDROM_OBJ *obj;
  683.  
  684.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
  685.   if (!obj) {
  686.     iso_errno = ISOERR_NO_MEMORY;
  687.     return NULL;
  688.   }
  689.  
  690.   obj->pos = 0;
  691.   obj->volume = p_object->volume;
  692.  
  693.   if (!(ptr = Get_Path_Table_Record (p_object->volume, p_object->parent,
  694.                        NULL))) {
  695.     FreeMem (obj, sizeof (CDROM_OBJ));
  696.     iso_errno = ISOERR_NO_MEMORY;
  697.     return NULL;
  698.   }
  699.   
  700.   if (!(dir = Get_Directory_Record (p_object->volume, ptr->location, 0))) {
  701.     FreeMem (obj, sizeof (CDROM_OBJ));
  702.     iso_errno = ISOERR_NO_MEMORY;
  703.     return NULL;
  704.   }
  705.  
  706.   obj->directory_f = TRUE;
  707.   obj->path_table_pos = p_object->parent;
  708.   obj->parent = Get_Parent_Directory_ISO (p_object->volume, p_object->parent);
  709.   obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  710.   if (!obj->dir_record) {
  711.     FreeMem (obj, sizeof (CDROM_OBJ));
  712.     iso_errno = ISOERR_NO_MEMORY;
  713.     return NULL;    
  714.   }
  715.   memcpy (obj->dir_record, dir, dir->length);
  716.  
  717.   return obj;
  718. }
  719.  
  720. /* Find parent directory on an ISO or Rock Ridge disk.
  721.  */
  722.  
  723. CDROM_OBJ *Find_Parent (CDROM_OBJ *p_object)
  724. {
  725.   if (p_object->volume->use_rock_ridge)
  726.     return Find_Parent_RR (p_object);
  727.   else
  728.     return Find_Parent_ISO (p_object);
  729. }
  730.  
  731. /* Test if p_object is the root directory.
  732.  */
  733.  
  734. int Is_Top_Level_Object (CDROM_OBJ *p_object)
  735. {
  736.   return p_object->directory_f &&
  737.          p_object->dir_record->extent_loc_m ==
  738.      p_object->volume->pvd.root.extent_loc_m;
  739. }
  740.  
  741. /* Find a position in a file.
  742.  */
  743.  
  744. int Seek_Position (CDROM_OBJ *p_object, long p_offset, int p_mode)
  745. {
  746.   unsigned long new_pos;
  747.   unsigned long max_len = p_object->dir_record->data_length_m;
  748.   
  749.   if (p_object->directory_f) {
  750.     iso_errno = ISOERR_BAD_ARGUMENTS;
  751.     return 0;
  752.   }
  753.   
  754.   switch (p_mode) {
  755.   case SEEK_FROM_START:
  756.     if (p_offset < 0 || p_offset > max_len) {
  757.       iso_errno = ISOERR_OFF_BOUNDS;
  758.       return 0;
  759.     }
  760.     new_pos = p_offset;
  761.     break;
  762.   case SEEK_FROM_CURRENT_POS:
  763.     if ((p_offset < 0 && -p_offset > p_object->pos) ||
  764.         (p_offset > 0 && p_object->pos + p_offset > max_len)) {
  765.       iso_errno = ISOERR_OFF_BOUNDS;
  766.       return 0;
  767.     }
  768.     new_pos = p_object->pos + p_offset;
  769.     break;
  770.   case SEEK_FROM_END:
  771.     if (p_offset > 0 || -p_offset > max_len) {
  772.       iso_errno = ISOERR_OFF_BOUNDS;
  773.       return 0;
  774.     }
  775.     new_pos = max_len + p_offset;
  776.     break;
  777.   default:
  778.     iso_errno = ISOERR_BAD_ARGUMENTS;
  779.     return 0;    
  780.   }
  781.   p_object->pos = new_pos;
  782.   return 1;
  783. }
  784.