home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
new
/
disk
/
cdrom
/
amicdfs
/
src
/
iso9660.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-03
|
20KB
|
836 lines
/* iso9660.c:
*
* Support for the ISO-9660 filing system.
*
* Modified by Nicola Salmoria.
*
* ----------------------------------------------------------------------
* This code is (C) Copyright 1993,1994 by Frank Munkert.
* All rights reserved.
* This software may be freely distributed and redistributed for
* non-commercial purposes, provided this notice is included.
* ----------------------------------------------------------------------
* [History removed]
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include "cdrom.h"
#include "iso9660.h"
#include "rock.h"
t_bool Iso_Is_Top_Level_Object (VOLUME *,CDROM_OBJ *);
CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume);
LONG Iso_Examine_Next (VOLUME *p_volume,CDROM_OBJ *p_dir, CDROM_INFO *p_info,
unsigned long *p_offset);
void Iso_Close_Obj (CDROM_OBJ *p_object);
#define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
#define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
/* Check whether the given volume uses the ISO 9660 Protocol.
* The protocol is identified by the sequence
* 'C' 'D' '0' '0' '1'
* in the 2nd..6th byte of sector 16 of a track.
*
* All data tracks on the disk are examined.
*
* Returns TRUE iff the ISO protocol is used; FALSE otherwise.
*/
t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
{
int i, len;
t_ulong *buf;
SetIoErr(ERROR_NOT_A_DOS_DISK); /* initialize error code (Read_Sector() */
/* will change it if needed) */
/* If Data_Tracks() returns -1, then the drive probably doesn't support
* the SCSI-2 READ TOC command.
*/
if (p_cdrom->use_trackdisk ||
(len = Data_Tracks (p_cdrom, &buf)) < 0) {
*p_offset = 0;
if (!Read_Sector (p_cdrom, 16))
return FALSE;
return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
}
if (len == 0)
return FALSE;
/* Use a vendor-specific command to find the offset of the last
* session:
*/
if (Find_Last_Session (p_cdrom, p_offset) &&
Read_Sector (p_cdrom, 16 + *p_offset) &&
strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
FreeVec (buf);
return TRUE;
}
/* Search all data tracks for valid primary volume descriptors: */
for (i=len-1; i>=0; i--) {
*p_offset = buf[i];
if (!Read_Sector (p_cdrom, 16 + *p_offset))
continue;
if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
FreeVec (buf);
return TRUE;
}
}
FreeVec (buf);
/* On some disks, the information in the TOC may not be valid. Therefore
* also check sector 16:
*/
if (!Read_Sector (p_cdrom, 16))
return FALSE;
if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
*p_offset = 0;
return TRUE;
}
return FALSE;
}
/* Check whether the given volume uses the High Sierra Protocol.
* The protocol is identified by the sequence
* 'C' 'D' 'R' 'O' 'M'
* in the 10th..14th byte of sector 16.
*
* Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
*/
t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
{
SetIoErr(ERROR_NOT_A_DOS_DISK); /* initialize error code (Read_Sector() */
/* will change it if needed) */
if (!Read_Sector (p_cdrom, 16))
return FALSE;
return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
}
t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset,
t_bool lowercase)
{
long loc = 16 + p_offset;
extern t_handler g_iso_handler;
p_volume->handler = &g_iso_handler;
p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC | MEMF_CLEAR);
if (!p_volume->vol_info) {
SetIoErr(ERROR_NO_FREE_STORE);
return FALSE;
}
for (;;) {
if (!Read_Sector (p_volume->cd, loc)) {
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
return FALSE;
}
if (p_volume->cd->buffer[0] == 1) {
memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
break;
}
if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
SetIoErr(ISOERR_NO_PVD);
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
return FALSE;
}
loc++;
}
VOL(p_volume,skip) = p_skip;
switch (VOL(p_volume,pvd).block_size_m) {
case 512:
VOL(p_volume,blockshift) = 2;
break;
case 1024:
VOL(p_volume,blockshift) = 1;
break;
case 2048:
default:
VOL(p_volume,blockshift) = 0;
break;
}
if (lowercase)
{
/* Look at the system ID to find out if the CD is supposed
* to feature proper file names. These are CDs made for use
* with the CDTV and the CD³² (both share the "CDTV" system ID)
* and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
* created by Mkisofs. If any of these IDs is found the
* file name to lower case conversion is disabled.
*/
if (!strncmp(VOL(p_volume,pvd).system_id,"CDTV",4) ||
!strncmp(VOL(p_volume,pvd).system_id,"AMIGA",5))
{
lowercase = 0;
}
}
VOL(p_volume,lowercase) = lowercase;
return TRUE;
}
void Iso_Close_Vol_Info (VOLUME *p_volume)
{
FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
}
CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
{
CDROM_OBJ *obj;
if (obj = AllocMem(sizeof(CDROM_OBJ),MEMF_PUBLIC | MEMF_CLEAR))
{
if (obj->obj_info = AllocMem(sizeof (t_iso_obj_info),MEMF_PUBLIC))
{
if (OBJ(obj,dir) = AllocMem(p_length_of_dir_record,MEMF_PUBLIC))
return(obj);
FreeMem(obj->obj_info, sizeof (t_iso_obj_info));
}
FreeMem(obj,sizeof(CDROM_OBJ));
}
SetIoErr(ERROR_NO_FREE_STORE);
return(NULL);
}
/* Get the "CDROM object" for the root directory of the volume.
*/
CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
{
CDROM_OBJ *obj;
obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
if (!obj)
return NULL;
obj->directory_f = TRUE;
obj->handler = p_volume->handler;
obj->pos = 0;
memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
return obj;
}
/* Compare the name of the directory entry p_iso_name
* with the C string p_name, and return 1 iff strings are equal.
* NOTE: p_iso_name may be a file name (with version number) or a directory
* name (without version number).
* NOTE: may *TRASH* p_iso_name
*/
int Names_Equal (char *p_iso_name, char *p_name)
{
int pos;
if (!Stricmp(p_iso_name, p_name))
return TRUE;
/* compare without version number: */
for (pos=strlen(p_iso_name)-1; pos>=0; pos--)
if (p_iso_name[pos] == ';')
break;
if (pos>=0)
{
p_iso_name[pos] = 0;
return(!Stricmp(p_iso_name,p_name));
}
else
return FALSE;
}
/* Get a record from a directory.
* p_location is a LOGICAL BLOCK number.
* the record will be stored in buffer, which must be 256 bytes long.
*/
directory_record *Get_Directory_Record (VOLUME *p_volume,struct directory_record *p_dir,
unsigned long p_location,
unsigned long p_offset)
{
int len;
int loc;
loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
if (!Read_Sector (p_volume->cd, loc)) {
return NULL;
}
len = p_volume->cd->buffer[p_offset & 2047];
if (len)
memcpy (p_dir, p_volume->cd->buffer + (p_offset & 2047), len);
else
p_dir->length = 0; /* mark as last record */
return(p_dir);
}
/* store the name of an object into buffer, which must be 32 bytes long */
VOID Convert_Iso_Name(VOLUME *p_volume,struct directory_record *p_dir,UBYTE *buffer)
{
int len;
len = -1;
if (p_volume->protocol == PRO_ROCK)
len = Get_RR_File_Name(p_volume,p_dir,buffer,30);
if (len < 0)
{
len = p_dir->file_id_length;
/* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
if (len > 30) len = 30;
memcpy(buffer,p_dir->file_id,len);
if (VOL(p_volume,lowercase))
{
/* convert file name to lowercase if the user requested it */
WORD i;
for (i = 0;i < len;i++)
buffer[i] = ToLower(buffer[i]);
}
}
/* NULL terminate the string */
buffer[len] = 0;
}
/* Create a "CDROM object" for the directory which is located
* at s