diff options
Diffstat (limited to 'qemu/roms/openbios/fs/iso9660/iso9660_mount.c')
-rw-r--r-- | qemu/roms/openbios/fs/iso9660/iso9660_mount.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/iso9660/iso9660_mount.c b/qemu/roms/openbios/fs/iso9660/iso9660_mount.c new file mode 100644 index 000000000..a58170408 --- /dev/null +++ b/qemu/roms/openbios/fs/iso9660/iso9660_mount.c @@ -0,0 +1,210 @@ +/* + * + * (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; +} |