blob: a58170408f0389496c809ff4c1dc5c6e1bba9811 [file] [log] [blame]
/*
*
* (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu>
*
* This file has been copied from EMILE, http://emile.sf.net
*
* some parts from mkisofs (c) J. Schilling
*
*/
#include "libiso9660.h"
#include "libopenbios/bindings.h"
#include "libc/diskio.h"
void iso9660_name(iso9660_VOLUME *volume, struct iso_directory_record *idr, char *buffer)
{
int j;
unsigned char ul, uc;
buffer[0] = 0;
if (idr->name_len[0] == 1 && idr->name[0] == 0)
strcpy(buffer, ".");
else if (idr->name_len[0] == 1 && idr->name[0] == 1)
strcpy(buffer, "..");
else {
switch (volume->ucs_level) {
case 3:
case 2:
case 1:
/*
* Unicode name.
*/
for (j = 0; j < (int)idr->name_len[0] / 2; j++) {
ul = idr->name[j*2+1];
/*
* unicode convertion
* up = unls->unls_uni2cs[uh];
*
* if (up == NULL)
* uc = '\0';
* else
* uc = up[ul];
*
* we use only low byte
*/
uc = ul;
buffer[j] = uc ? uc : '_';
}
buffer[idr->name_len[0]/2] = '\0';
break;
case 0:
/*
* Normal non-Unicode name.
*/
strncpy(buffer, idr->name, idr->name_len[0]);
buffer[idr->name_len[0]] = 0;
break;
default:
/*
* Don't know how to do these yet. Maybe they are the same
* as one of the above.
*/
break;
}
}
}
iso9660_VOLUME *iso9660_mount(int fd)
{
iso9660_VOLUME* volume;
struct iso_primary_descriptor *jpd;
struct iso_primary_descriptor ipd;
int block;
int ucs_level = 0;
/* read filesystem descriptor */
seek_io(fd, 16 * ISOFS_BLOCK_SIZE);
read_io(fd, &ipd, sizeof (ipd));
/*
* High sierra:
*
* DESC TYPE == 1 (VD_SFS) offset 8 len 1
* STR ID == "CDROM" offset 9 len 5
* STD_VER == 1 offset 14 len 1
*/
/* High Sierra format ? */
if ((((char *)&ipd)[8] == 1) &&
(strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) &&
(((char *)&ipd)[14] == 1)) {
printk("Incompatible format: High Sierra format\n");
return NULL;
}
/*
* ISO 9660:
*
* DESC TYPE == 1 (VD_PVD) offset 0 len 1
* STR ID == "CD001" offset 1 len 5
* STD_VER == 1 offset 6 len 1
*/
/* NOT ISO 9660 format ? */
if ((ipd.type[0] != ISO_VD_PRIMARY) ||
(strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
(ipd.version[0] != 1)) {
return NULL;
}
/* UCS info */
block = 16;
jpd = (struct iso_primary_descriptor *)
malloc(sizeof(struct iso_primary_descriptor));
if (jpd == NULL)
return NULL;
memcpy(jpd, &ipd, sizeof (ipd));
while ((uint8_t)jpd->type[0] != ISO_VD_END) {
/*
* If Joliet UCS escape sequence found, we may be wrong
*/
if (jpd->unused3[0] == '%' &&
jpd->unused3[1] == '/' &&
(jpd->unused3[3] == '\0' ||
jpd->unused3[3] == ' ') &&
(jpd->unused3[2] == '@' ||
jpd->unused3[2] == 'C' ||
jpd->unused3[2] == 'E')) {
if (jpd->version[0] != 1)
break;
}
block++;
seek_io(fd, block * ISOFS_BLOCK_SIZE);
read_io(fd, jpd, sizeof (*jpd));
}
ucs_level = 0;
if (((unsigned char) jpd->type[0] == ISO_VD_END)) {
memcpy(jpd, &ipd, sizeof (ipd));
} else {
switch (jpd->unused3[2]) {
case '@':
ucs_level = 1;
break;
case 'C':
ucs_level = 2;
break;
case 'E':
ucs_level = 3;
break;
}
if (ucs_level && jpd->unused3[3] == ' ')
printk("Warning: Joliet escape sequence uses illegal space at offset 3\n");
}
volume = (iso9660_VOLUME*)malloc(sizeof(iso9660_VOLUME));
if (volume == NULL)
return NULL;
volume->descriptor = jpd;
volume->ucs_level = ucs_level;
volume->fd = fd;
return volume;
}
int iso9660_umount(iso9660_VOLUME* volume)
{
if (volume == NULL)
return -1;
free(volume->descriptor);
free(volume);
return 0;
}
int iso9660_probe(int fd, long long offset)
{
struct iso_primary_descriptor ipd;
seek_io(fd, 16 * ISOFS_BLOCK_SIZE + offset);
read_io(fd, &ipd, sizeof (ipd));
if ((ipd.type[0] != ISO_VD_PRIMARY) ||
(strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
(ipd.version[0] != 1)) {
return 0;
}
return -1;
}
struct iso_directory_record *iso9660_get_root_node(iso9660_VOLUME* volume)
{
return (struct iso_directory_record *)volume->descriptor->root_directory_record;
}