home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga GigaPD 3
/
Amiga_GigaPD_v3_2of3.iso
/
amicdrom
/
rock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-15
|
9KB
|
348 lines
/* rock.c:
*
* Support for the Rock Ridge filing system.
*
* ----------------------------------------------------------------------
* This code is (C) Copyright 1993 by Frank Munkert.
* All rights reserved.
* This software may be freely distributed and redistributed for
* non-commercial purposes, provided this notice is included.
*/
#include <stdlib.h>
#include <string.h>
#include <exec/memory.h>
#include <clib/exec_protos.h>
#include "rock.h"
/* Check whether the given volume uses the Rock Ridge Interchange Protocol.
* The protocol is identified by the sequence
* 'S' 'P' 7 1 0xbe 0xef
* in the system use field of the (00) directory in the root directory of
* the volume.
*
* Returns 1 iff the RR protocol is used; 0 otherwise.
* If the RR protocol is used, p_volume->skip will be set to the skip length
* specified in the SP system use field.
*/
int Uses_Rock_Ridge_Protocol (VOLUME *p_volume)
{
unsigned long loc = p_volume->pvd.root.extent_loc_m;
directory_record *dir;
int system_use_pos;
unsigned char *sys;
if (!(dir = Get_Directory_Record (p_volume, loc, 0)))
return 0;
system_use_pos = 33 + dir->file_id_length;
if (system_use_pos & 1)
system_use_pos++;
if (system_use_pos >= dir->length)
return 0;
sys = (unsigned char *) dir + system_use_pos;
if (sys[0] == 'S' && sys[1] == 'P' && sys[2] == 7 &&
sys[3] == 1 && sys[4] == 0xbe && sys[5] == 0xef) {
p_volume->skip = sys[6];
return 1;
} else
return 0;
}
/* Searches for the system use field with name p_name in the directory record
* p_dir and fills the buffer p_buf (with length p_buf_len) with the information
* contained in the system use field.
*
* p_index is the ordinal number of the system use field (if more than one
* system use field with the same name is recorded.) 0=first occurrence,
* 1=second occurrence, and so on.
*
* 1 is returned if the system use field has been found; otherwise 0
* is returned.
*/
int Get_System_Use_Field (VOLUME *p_volume, directory_record *p_dir,
char *p_name, char *p_buf, int p_buf_len,
int p_index)
{
int system_use_pos;
int slen, len;
unsigned long length = p_dir->length;
unsigned char *buf = (unsigned char *) p_dir;
system_use_pos = 33 + p_dir->file_id_length;
if (system_use_pos & 1)
system_use_pos++;
system_use_pos += p_volume->skip;
/* the system use field must be at least 4 bytes long */
while (system_use_pos + 3 < length) {
slen = buf[system_use_pos+2];
if (buf[system_use_pos] == p_name[0] &&
buf[system_use_pos+1] == p_name[1]) {
if (p_index)
p_index--;
else {
len = (slen < p_buf_len) ? slen : p_buf_len;
memcpy (p_buf, buf + system_use_pos, len);
return 1;
}
}
/* look for continuation area: */
if (buf[system_use_pos] == 'C' &&
buf[system_use_pos+1] == 'E') {
unsigned long newloc, offset;
memcpy (&newloc, buf + system_use_pos + 8, 4);
memcpy (&offset, buf + system_use_pos + 16, 4);
memcpy (&length, buf + system_use_pos + 24, 4);
if (!Read_Sector (p_volume->cd, newloc))
return 0;
buf = p_volume->cd->buffer;
system_use_pos = offset;
continue;
}
/* look for system use field terminator: */
if (buf[system_use_pos] == 'S' &&
buf[system_use_pos+1] == 'T')
return 0;
system_use_pos += slen;
}
return 0;
}
/* Determines the Rock Ridge file name of the CDROM object p_obj.
* The file name will be stored in the buffer p_buf (with length p_buf_len).
* The file name will NOT be null-terminated. The number of characters in
* the file name is returned. If there is no Rock Ridge file name for
* p_obj, then -1 is returned.
*/
int Get_RR_File_Name (VOLUME *p_volume, directory_record *p_dir,
char *p_buf, int p_buf_len)
{
struct nm_system_use_field {
char id[2];
unsigned char length;
unsigned char version;
unsigned char flags;
char name[210];
} nm;
int len, slen;
int index = 0;
int total = 0;
for (;;) {
if (!Get_System_Use_Field (p_volume, p_dir, "NM",
(char *) &nm, sizeof (nm), index))
return -1;
slen = nm.length-5;
len = (p_buf_len < slen) ? p_buf_len : slen;
if (len)
memcpy (p_buf, nm.name, len);
total += len;
if (!(nm.flags & 1))
return total;
p_buf += len;
p_buf_len -= len;
index++;
}
}
/* Get parent directory.
*/
unsigned long Get_Parent_Directory_RR (VOLUME *p_volume, unsigned long p_loc)
{
directory_record *dir;
/* skip first directory record: */
if (!(dir = Get_Directory_Record (p_volume, p_loc, 0)))
return 0;
/* get directory record for parent directory: */
if (!(dir = Get_Directory_Record (p_volume, p_loc, dir->length)))
return 0;
return dir->extent_loc_m;
}
/* Open a "CDROM object".
*/
CDROM_OBJ *Open_Object_RR (CDROM_OBJ *p_result,
CDROM_OBJ *p_current_dir, char *p_name)
{
CDROM_OBJ *obj = p_result;
char *cp = p_name;
char name[256];
char *np;
directory_record *dir = 0;
unsigned long location, old_loc;
if (*cp == ':') {
location = p_current_dir->volume->pvd.root.extent_loc_m;
cp++;
} else {
location = p_current_dir->dir_record->extent_loc_m;
while (*cp == '/') {
location = Get_Parent_Directory_RR (p_current_dir->volume, location);
cp++;
}
}
old_loc = location;
while (*cp) {
for (np = name; *cp && *cp != '/'; )
*np++ = *cp++;
*np = 0;
if (name[0] == 0) {
iso_errno = ISOERR_ILLEGAL_NAME;
return NULL;
}
dir = Find_Directory_Entry (p_current_dir->volume, location, name);
if (!dir)
return NULL;
if (!(dir->flags & 2)) {
/* directory entry is a file: */
if (*cp != 0) {
iso_errno = ISOERR_NOT_FOUND;
return NULL;
}
obj->directory_f = FALSE;
obj->parent = location;
obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
if (!obj->dir_record) {
iso_errno = ISOERR_NO_MEMORY;
return NULL;
}
memcpy (obj->dir_record, dir, dir->length);
return obj;
}
old_loc = location;
location = dir->extent_loc_m;
if (*cp == '/')
cp++;
}
if (!dir)
if (!(dir = Get_Directory_Record (p_current_dir->volume, location, 0)))
return NULL;
obj->directory_f = TRUE;
obj->path_table_pos = 0; /* not needed for Rock Ridge */
obj->parent = old_loc;
obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
if (!obj->dir_record) {
iso_errno = ISOERR_NO_MEMORY;
return NULL;
}
memcpy (obj->dir_record, dir, dir->length);
return obj;
}
/* Find parent directory by location.
*/
directory_record *Find_Parent_In_Directory (VOLUME *p_volume,
unsigned long p_dir_location,
unsigned long p_son_location)
{
unsigned long length;
directory_record *dir;
unsigned long offset = 0;
if (!(dir = Get_Directory_Record (p_volume, p_dir_location, 0)))
return NULL;
length = dir->data_length_m;
for (;;) {
offset += dir->length;
for (;;) {
if (offset >= length) {
iso_errno = ISOERR_NOT_FOUND;
return NULL;
}
dir = Get_Directory_Record (p_volume, p_dir_location, offset);
if (!dir)
return NULL;
if (dir->length == 0)
/* goto next logical sector: */
offset = (offset & 0xfffff800) + 2048;
else
break;
}
if (dir->extent_loc_m == p_son_location)
return dir;
}
}
/* Find parent of "CDROM object."
*/
CDROM_OBJ *Find_Parent_RR (CDROM_OBJ *p_object)
{
directory_record *dir;
CDROM_OBJ *obj;
unsigned long loc;
obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC);
if (!obj) {
iso_errno = ISOERR_NO_MEMORY;
return NULL;
}
obj->pos = 0;
obj->volume = p_object->volume;
/* determine location of grandfather of 'p_object': */
loc = p_object->parent;
if (!(dir = Get_Directory_Record (p_object->volume, loc, 0))) {
FreeMem (obj, sizeof (CDROM_OBJ));
return NULL;
}
if (!(dir = Get_Directory_Record (p_object->volume, loc, dir->length))) {
FreeMem (obj, sizeof (CDROM_OBJ));
return NULL;
}
loc = obj->parent = dir->extent_loc_m;
if (!(dir = Find_Parent_In_Directory (p_object->volume, loc,
p_object->parent))) {
FreeMem (obj, sizeof (CDROM_OBJ));
return NULL;
}
obj->directory_f = TRUE;
obj->path_table_pos = 0; /* not needed for Rock Ridge */
obj->dir_record = AllocMem (dir->length, MEMF_PUBLIC);
if (!obj->dir_record) {
FreeMem (obj, sizeof (CDROM_OBJ));
iso_errno = ISOERR_NO_MEMORY;
return NULL;
}
memcpy (obj->dir_record, dir, dir->length);
return obj;
}