home *** CD-ROM | disk | FTP | other *** search
/ Amiga GigaPD 3 / Amiga_GigaPD_v3_2of3.iso / amicdrom / rock.c < prev    next >
C/C++ Source or Header  |  1994-03-15  |  9KB  |  348 lines

  1. /* rock.c:
  2.  *
  3.  * Support for the Rock Ridge 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.  
  12. #include <stdlib.h>
  13. #include <string.h>
  14.  
  15. #include <exec/memory.h>
  16. #include <clib/exec_protos.h>
  17.  
  18. #include "rock.h"
  19.  
  20. /* Check whether the given volume uses the Rock Ridge Interchange Protocol.
  21.  * The protocol is identified by the sequence
  22.  *            'S' 'P' 7 1 0xbe 0xef
  23.  * in the system use field of the (00) directory in the root directory of
  24.  * the volume.
  25.  *
  26.  * Returns 1 iff the RR protocol is used; 0 otherwise.
  27.  * If the RR protocol is used, p_volume->skip will be set to the skip length
  28.  * specified in the SP system use field.
  29.  */
  30.  
  31. int Uses_Rock_Ridge_Protocol (VOLUME *p_volume)
  32. {
  33.   unsigned long loc = p_volume->pvd.root.extent_loc_m;
  34.   directory_record *dir;
  35.   int system_use_pos;
  36.   unsigned char *sys;
  37.  
  38.   if (!(dir = Get_Directory_Record (p_volume, loc, 0)))
  39.     return 0;
  40.   
  41.   system_use_pos = 33 + dir->file_id_length;
  42.   if (system_use_pos & 1)
  43.     system_use_pos++;
  44.  
  45.   if (system_use_pos >= dir->length)
  46.     return 0;
  47.  
  48.   sys = (unsigned char *) dir + system_use_pos;
  49.   if (sys[0] == 'S' && sys[1] == 'P' && sys[2] == 7 &&
  50.       sys[3] == 1 && sys[4] == 0xbe && sys[5] == 0xef) {
  51.     p_volume->skip = sys[6];
  52.     return 1;
  53.   } else
  54.     return 0;
  55. }
  56.  
  57. /* Searches for the system use field with name p_name in the directory record
  58.  * p_dir and fills the buffer p_buf (with length p_buf_len) with the information
  59.  * contained in the system use field.
  60.  *
  61.  * p_index is the ordinal number of the system use field (if more than one
  62.  * system use field with the same name is recorded.) 0=first occurrence,
  63.  * 1=second occurrence, and so on.
  64.  *
  65.  * 1 is returned if the system use field has been found; otherwise 0
  66.  * is returned.
  67.  */
  68.  
  69. int Get_System_Use_Field (VOLUME *p_volume, directory_record *p_dir,
  70.               char *p_name, char *p_buf, int p_buf_len,
  71.               int p_index)
  72. {
  73.   int system_use_pos;
  74.   int slen, len;
  75.   unsigned long length = p_dir->length;
  76.   unsigned char *buf = (unsigned char *) p_dir;
  77.  
  78.   system_use_pos = 33 + p_dir->file_id_length;
  79.   if (system_use_pos & 1)
  80.     system_use_pos++;
  81.   system_use_pos += p_volume->skip;
  82.  
  83.   /* the system use field must be at least 4 bytes long */
  84.   while (system_use_pos + 3 < length) {
  85.     slen = buf[system_use_pos+2];
  86.     if (buf[system_use_pos] == p_name[0] &&
  87.         buf[system_use_pos+1] == p_name[1]) {
  88.       if (p_index)
  89.         p_index--;
  90.       else {
  91.         len = (slen < p_buf_len) ? slen : p_buf_len;
  92.         memcpy (p_buf, buf + system_use_pos, len);
  93.         return 1;
  94.       }
  95.     }
  96.     /* look for continuation area: */
  97.     if (buf[system_use_pos] == 'C' &&
  98.         buf[system_use_pos+1] == 'E') {
  99.       unsigned long newloc, offset;
  100.       memcpy (&newloc, buf + system_use_pos + 8, 4);
  101.       memcpy (&offset, buf + system_use_pos + 16, 4);
  102.       memcpy (&length, buf + system_use_pos + 24, 4);
  103.       if (!Read_Sector (p_volume->cd, newloc))
  104.         return 0;
  105.       buf = p_volume->cd->buffer;
  106.       system_use_pos = offset;
  107.       continue;
  108.     }
  109.     
  110.     /* look for system use field terminator: */
  111.     if (buf[system_use_pos] == 'S' &&
  112.         buf[system_use_pos+1] == 'T')
  113.       return 0;
  114.  
  115.     system_use_pos += slen;
  116.   }
  117.   return 0;
  118. }
  119.  
  120. /* Determines the Rock Ridge file name of the CDROM object p_obj.
  121.  * The file name will be stored in the buffer p_buf (with length p_buf_len).
  122.  * The file name will NOT be null-terminated. The number of characters in
  123.  * the file name is returned. If there is no Rock Ridge file name for
  124.  * p_obj, then -1 is returned.
  125.  */
  126.  
  127. int Get_RR_File_Name (VOLUME *p_volume, directory_record *p_dir,
  128.               char *p_buf, int p_buf_len)
  129. {
  130.   struct nm_system_use_field {
  131.     char      id[2];
  132.     unsigned char length;
  133.     unsigned char version;
  134.     unsigned char flags;
  135.     char          name[210];
  136.   } nm;
  137.   int len, slen;
  138.   int index = 0;
  139.   int total = 0;
  140.  
  141.   for (;;) {
  142.     if (!Get_System_Use_Field (p_volume, p_dir, "NM",
  143.                      (char *) &nm, sizeof (nm), index))
  144.       return -1;
  145.  
  146.     slen = nm.length-5;
  147.     len = (p_buf_len < slen) ? p_buf_len : slen;
  148.     if (len)
  149.       memcpy (p_buf, nm.name, len);
  150.  
  151.     total += len;
  152.     if (!(nm.flags & 1))
  153.       return total;
  154.  
  155.     p_buf += len;
  156.     p_buf_len -= len;
  157.     index++;
  158.   }
  159. }
  160.  
  161. /* Get parent directory.
  162.  */
  163.  
  164. unsigned long Get_Parent_Directory_RR (VOLUME *p_volume, unsigned long p_loc)
  165. {
  166.   directory_record *dir;
  167.   
  168.   /* skip first directory record: */
  169.   if (!(dir = Get_Directory_Record (p_volume, p_loc, 0)))
  170.     return 0;
  171.   
  172.   /* get directory record for parent directory: */
  173.   if (!(dir = Get_Directory_Record (p_volume, p_loc, dir->length)))
  174.     return 0;
  175.   
  176.   return dir->extent_loc_m;
  177. }
  178.  
  179. /* Open a "CDROM object".
  180.  */
  181.  
  182. CDROM_OBJ *Open_Object_RR (CDROM_OBJ *p_result,
  183.                CDROM_OBJ *p_current_dir, char *p_name)
  184. {
  185.   CDROM_OBJ *obj = p_result;
  186.   char *cp = p_name;
  187.   char name[256];
  188.   char *np;
  189.   directory_record *dir = 0;
  190.   unsigned long location, old_loc;
  191.  
  192.   if (*cp == ':') {
  193.     location = p_current_dir->volume->pvd.root.extent_loc_m;
  194.     cp++;
  195.   } else {
  196.     location = p_current_dir->dir_record->extent_loc_m;
  197.     while (*cp == '/') {    
  198.       location = Get_Parent_Directory_RR (p_current_dir->volume, location);
  199.       cp++;
  200.     }
  201.   }
  202.  
  203.   old_loc = location;
  204.  
  205.   while (*cp) {
  206.     for (np = name; *cp && *cp != '/'; )
  207.       *np++ = *cp++;
  208.     *np = 0;
  209.     
  210.     if (name[0] == 0) {
  211.       iso_errno = ISOERR_ILLEGAL_NAME;
  212.       return NULL;
  213.     }
  214.  
  215.     dir = Find_Directory_Entry (p_current_dir->volume, location, name);
  216.     if (!dir)
  217.     return NULL;
  218.  
  219.     if (!(dir->flags & 2)) {
  220.       /* directory entry is a file: */
  221.       if (*cp != 0) {
  222.         iso_errno = ISOERR_NOT_FOUND;
  223.     return NULL;
  224.       }
  225.       obj->directory_f = FALSE;
  226.       obj->parent = location;
  227.       obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  228.       if (!obj->dir_record) {
  229.         iso_errno = ISOERR_NO_MEMORY;
  230.         return NULL;    
  231.       }
  232.       memcpy (obj->dir_record, dir, dir->length);
  233.  
  234.       return obj;
  235.     }
  236.  
  237.     old_loc = location;
  238.     location = dir->extent_loc_m;
  239.  
  240.     if (*cp == '/')
  241.       cp++;
  242.   }
  243.  
  244.   if (!dir)
  245.     if (!(dir = Get_Directory_Record (p_current_dir->volume, location, 0)))
  246.       return NULL;    
  247.  
  248.   obj->directory_f = TRUE;
  249.   obj->path_table_pos = 0; /* not needed for Rock Ridge */
  250.   obj->parent = old_loc;
  251.   obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  252.   if (!obj->dir_record) {
  253.     iso_errno = ISOERR_NO_MEMORY;
  254.     return NULL;
  255.   }
  256.   memcpy (obj->dir_record, dir, dir->length);
  257.  
  258.   return obj;
  259. }
  260.  
  261. /* Find parent directory by location.
  262.  */
  263.  
  264. directory_record *Find_Parent_In_Directory (VOLUME *p_volume,
  265.                         unsigned long p_dir_location,
  266.                                 unsigned long p_son_location)
  267. {
  268.   unsigned long length;
  269.   directory_record *dir;
  270.   unsigned long offset = 0;
  271.  
  272.   if (!(dir = Get_Directory_Record (p_volume, p_dir_location, 0)))
  273.     return NULL;
  274.  
  275.   length = dir->data_length_m;
  276.   
  277.   for (;;) {
  278.     offset += dir->length;
  279.     for (;;) {
  280.       if (offset >= length) {
  281.         iso_errno = ISOERR_NOT_FOUND;
  282.         return NULL;
  283.       }
  284.       dir = Get_Directory_Record (p_volume, p_dir_location, offset);
  285.       if (!dir)
  286.         return NULL;
  287.  
  288.       if (dir->length == 0)
  289.         /* goto next logical sector: */
  290.         offset = (offset & 0xfffff800) + 2048;
  291.       else
  292.         break;
  293.     }
  294.     
  295.     if (dir->extent_loc_m == p_son_location)
  296.       return dir;
  297.   }
  298. }
  299.  
  300. /* Find parent of "CDROM object."
  301.  */
  302.  
  303. CDROM_OBJ *Find_Parent_RR (CDROM_OBJ *p_object)
  304. {
  305.   directory_record *dir;
  306.   CDROM_OBJ *obj;
  307.   unsigned long loc;
  308.  
  309.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
  310.   if (!obj) {
  311.     iso_errno = ISOERR_NO_MEMORY;
  312.     return NULL;
  313.   }
  314.  
  315.   obj->pos = 0;
  316.   obj->volume = p_object->volume;
  317.  
  318.   /* determine location of grandfather of 'p_object': */
  319.   loc = p_object->parent;
  320.   if (!(dir = Get_Directory_Record (p_object->volume, loc, 0))) {  
  321.     FreeMem (obj, sizeof (CDROM_OBJ));
  322.     return NULL;
  323.   }
  324.   if (!(dir = Get_Directory_Record (p_object->volume, loc, dir->length))) {  
  325.     FreeMem (obj, sizeof (CDROM_OBJ));
  326.     return NULL;
  327.   }
  328.   loc = obj->parent = dir->extent_loc_m;
  329.  
  330.   if (!(dir = Find_Parent_In_Directory (p_object->volume, loc,
  331.                       p_object->parent))) {
  332.     FreeMem (obj, sizeof (CDROM_OBJ));
  333.     return NULL;
  334.   }
  335.  
  336.   obj->directory_f = TRUE;
  337.   obj->path_table_pos = 0; /* not needed for Rock Ridge */
  338.   obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
  339.   if (!obj->dir_record) {
  340.     FreeMem (obj, sizeof (CDROM_OBJ));
  341.     iso_errno = ISOERR_NO_MEMORY;
  342.     return NULL;
  343.   }
  344.   memcpy (obj->dir_record, dir, dir->length);
  345.  
  346.   return obj;
  347. }
  348.