46#define DBG_NOTICE "[iso9660] Notice: "
47#define DBG_ERROR "[iso9660] Error: "
49#define dbglog(sev,prm...) printf(sev prm);
52#define MAX_ISO_FILES 8
55static bool is_mass =
false;
56static bool is_mounted =
false;
59static int init_percd();
67 return dev->
readSectors(sector, numSectors, buffer);
73 sec_t trueSector = sector * 4;
74 sec_t trueNumSectors = numSectors * 4;
77 return dev->
readSectors(trueSector, trueNumSectors, buffer);
85static void utf2ucs(
char * ucs,
const char * utf) {
91 }
else if (
c < 0xc0) {
96 c |= ((*utf++) & 0x3f) << 6;
104static void ucs2utfn(
char * utf,
const char * ucs,
size_t len) {
115 }
else if (
c <= 0x7ff) {
116 *utf++ = 0xc0 | (
c >> 6);
117 *utf++ = 0x80 | (
c & 0x3f);
119 *utf++ = 0xe0 | (
c >> 12);
120 *utf++ = 0x80 | ((
c >> 6) & 0x3f);
121 *utf++ = 0x80 | (
c & 0x3f);
127static int ucscompare(
const char * isofn,
const char * normalfn,
int isosize) {
131 for (i=0; i<isosize; i+=2) {
132 c0 = ((int)isofn[i] << 8) | ((int)isofn[i+1]);
133 c1 = ((int)normalfn[i] << 8) | ((int)normalfn[i+1]);
135 if (c0 ==
';')
break;
138 if (tolower(c0) != tolower(c1))
142 c1 = ((int)normalfn[i] << 8) | (normalfn[i+1]);
145 if (c1 !=
'/' && c1 !=
'\0')
151static int isjoliet(
char * p) {
152 if (p[0] ==
'%' && p[1] ==
'/') {
188static u32 ntohl_32(
const void *
data) {
190 return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | (d[3] << 0);
195static u32 htohl_32(
const void *
data) {
197 return (d[0] << 0) | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
204static u32 iso_733(
const u8 *from) {
return htohl_32(from); }
223#define NUM_CACHE_BLOCKS 16
228static unsigned int * cache_mutex;
236 cache[i]->sector = -1;
251 cache[i] = cache[i+1];
258static void iso_break_all();
267 if (cache[i]->sector == sector) {
268 bgrad_cache(cache, i);
276 if (cache[i]->sector == -1)
break;
283 j = read_iso9660_sectors(iso9660_dev, sector, 1, cache[i]->
data);
290 dbglog(
DBG_ERROR,
"fs_iso9660: can't read_sectors for %d: %d\n", (
unsigned int)sector,
j);
295 cache[i]->
sector = sector;
298 bgrad_cache(cache, i);
308static int bdread(
u32 sector) {
309 return bread_cache(dcache, sector);
313static int biread(
u32 sector) {
314 return bread_cache(icache, sector);
318static void bclear() {
319 bclear_cache(dcache);
320 bclear_cache(icache);
327static u32 session_base = 0;
330static u32 root_extent = 0, root_size = 0;
338static int init_percd() {
348 for (i=1; i<=3; i++) {
349 blk = biread(session_base + i + 16);
351 if (memcmp((
char *)icache[
blk]->
data,
"\02CD001", 6) == 0) {
352 joliet = isjoliet((
char *)icache[
blk]->
data+88);
361 blk = biread(session_base + 16);
362 if (
blk < 0)
return i;
363 if (memcmp((
char*)icache[
blk]->
data,
"\01CD001", 6)) {
371 root_extent = iso_733(root_dirent.
extent);
372 root_size = iso_733(root_dirent.
size);
381static int fncompare(
const char *isofn,
int isosize,
const char *normalfn) {
386 for (i=0; i<isosize; i++) {
388 if (isofn[i] ==
';')
break;
391 if (isofn[i] ==
'.' &&
392 (i == (isosize-1) || isofn[i+1] ==
';'))
396 if (tolower(isofn[i]) != tolower(normalfn[i]))
401 if (normalfn[i] !=
'/' && normalfn[i] !=
'\0')
430 size_left = (int)dir_size;
433 char * ucsname = rrname;
437 utf2ucs(ucsname, fn);
439 while (size_left > 0) {
440 c = biread(dir_extent);
441 if (
c < 0)
return NULL;
443 for (i=0; i<2048 && i<size_left; ) {
466 while ((len >= 4) && ((pnt[3] == 1) || (pnt[3] == 2))) {
467 if (strncmp(pnt,
"NM", 2) == 0) {
468 rrnamelen = pnt[2] - 5;
469 strncpy(rrname, pnt+5, rrnamelen);
470 rrname[rrnamelen] = 0;
478 char *p = strchr(fn,
'/');
486 if (!strncasecmp(rrname, fn, fnlen)) {
525 while ((cur = strchr(fn,
'/'))) {
529 start = find_object(fn, 1, iso_733(start->
extent), iso_733(start->
size));
538 start = find_object(fn,
dir, iso_733(start->
extent), iso_733(start->
size));
564static unsigned int * fh_mutex;
570static void iso_break_all() {
580static int iso_open(
const char *fn,
int mode) {
584 if (memcmp(fn,
"dvd:/", 6))
586 else if (memcmp(fn,
"dvd", 3) && memcmp(fn + 4,
":/", 2))
590 if (mode != O_RDONLY && mode !=
O_DIR)
594 if (!percd_done && init_percd() < 0)
599 de = find_object_path(fn, (mode &
O_DIR)?1:0, &root_dirent);
607 fh[fd].first_extent = -1;
616 fh[fd].first_extent = iso_733(de->
extent);
617 fh[fd].dir = (mode &
O_DIR)?1:0;
619 fh[fd].size = iso_733(de->
size);
626static void iso_close(
int fd) {
630 fh[fd].first_extent = 0;
635static ssize_t iso_read(
int fd,
void *buf,
size_t bytes) {
636 int rv, toread, thissect,
c;
649 toread = (bytes > (fh[fd].size - fh[fd].ptr)) ?
650 fh[fd].size - fh[fd].ptr : bytes;
651 if (toread == 0)
break;
654 thissect = 2048 - (fh[fd].ptr % 2048);
664 if (thissect == 2048 && toread >= 2048) {
666 thissect = toread / 2048;
667 if (thissect>32) thissect=32;
668 toread = thissect * 2048;
674 if (read_iso9660_sectors(iso9660_dev, fh[fd].
first_extent + fh[fd].
ptr/2048, thissect, outbuf) < 0)
677 toread = (toread > thissect) ? thissect : toread;
683 memcpy(outbuf, dcache[
c]->
data + (fh[fd].
ptr%2048), toread);
688 fh[fd].ptr += toread;
697static off_t iso_seek(
int fd, off_t offset,
int whence) {
708 fh[fd].ptr += offset;
711 fh[fd].ptr = fh[fd].size + offset;
718 if (fh[fd].
ptr < 0) fh[fd].ptr = 0;
719 if (fh[fd].
ptr > fh[fd].
size) fh[fd].ptr = fh[fd].size;
725static off_t iso_tell(
int fd) {
733static size_t iso_total(
int fd) {
742static void fn_postprocess(
char *fnin) {
745 while (*fn && *fn !=
';') {
752 if (fn > fnin && fn[-1] ==
'.') {
758static struct dirent *iso_readdir(
int fd) {
772 while(fh[fd].
ptr < fh[fd].
size) {
775 if (
c < 0)
return NULL;
781 fh[fd].ptr += 2048 - (fh[fd].ptr%2048);
799 fh[fd].dirent.d_name[de->
name_len] = 0;
808 while ((len >= 4) && ((pnt[3] == 1) || (pnt[3] == 2))) {
809 if (strncmp(pnt,
"NM", 2) == 0) {
811 fh[fd].dirent.d_name[pnt[2] - 5] = 0;
822 fh[fd].dirent.d_type =
DT_DIR;
825 fh[fd].dirent.d_type =
DT_REG;
830 return &fh[fd].dirent;
845static int iso_last_status;
846static int iso_vblank_hnd;
847static void iso_vblank(
u32 evt) {
852 if (cdrom_get_status(&
status, &disc_type) < 0)
855 if (iso_last_status !=
status) {
856 if (
status == CD_STATUS_OPEN ||
status == CD_STATUS_NO_DISC)
865static int iso_ioctl(
int hnd,
void *
data,
size_t size) {
876 memset(fh, 0,
sizeof(fh));
879 fh[0].first_extent = -1;
882 cache_mutex = malloc(
sizeof(
u32));
883 fh_mutex = malloc(
sizeof(
u32));
898 iso_last_status = -1;
915 if (cache_mutex !=
NULL)
917 if (fh_mutex !=
NULL)
919 cache_mutex = fh_mutex =
NULL;
924static int _ISO9660_open_r(
struct _reent *r,
void *fileStruct,
const char *path,
int flags,
int mode)
927 file->
fd = iso_open(path, flags);
931static int _ISO9660_close_r(
struct _reent *r,
int fd)
938static ssize_t _ISO9660_read_r(
struct _reent *r,
int fd,
char *
ptr,
size_t len)
941 return iso_read(fd,
ptr, len);
944static off_t _ISO9660_seek_r(
struct _reent *r,
int fd, off_t pos,
int dir)
947 return iso_seek(fd, pos,
dir);
950static int _ISO9660_fstat_r(
struct _reent *r,
int fd,
struct stat *st)
953 memset(st, 0,
sizeof(
stat));
954 st->st_size = iso_total(fd);
955 st->st_mode = S_IFREG;
956 st->st_blksize = 65536;
960static int _ISO9660_stat_r(
struct _reent *r,
const char *path,
struct stat *st)
962 int fd = iso_open(path, O_RDONLY);
963 memset(st, 0,
sizeof(
stat));
964 st->st_size = iso_total(fd);
965 st->st_mode = S_IFREG;
966 st->st_blksize = 65536;
971static int _ISO9660_chdir_r(
struct _reent *r,
const char *path)
1001static DIR_ITER* _ISO9660_diropen_r(
struct _reent *r,
DIR_ITER *dirState,
const char *path)
1030static int _ISO9660_dirreset_r(
struct _reent *r,
DIR_ITER *dirState)
1044static int _ISO9660_dirnext_r(
struct _reent *r,
DIR_ITER *dirState,
char *filename,
struct stat *st)
1067static int _ISO9660_dirclose_r(
struct _reent *r,
DIR_ITER *dirState)
1083static int _ISO9660_statvfs_r(
struct _reent *r,
const char *path,
struct statvfs *buf)
1127 _ISO9660_dirreset_r,
1129 _ISO9660_dirclose_r,
1138 char sector_data[2048];
1139 int is_joliet, i,
blk = 0;
1143 for (i=1; i<=3; i++) {
1144 blk = read_iso9660_sectors(di, 16, 1, sector_data);
1146 if (memcmp(sector_data,
"\02CD001", 6) == 0) {
1147 is_joliet = isjoliet(sector_data+88);
1148 if (is_joliet)
break;
1155 blk = read_iso9660_sectors(di, 16, 1, sector_data);
1156 if (
blk < 0)
return i;
1157 if (memcmp(sector_data,
"\01CD001", 6) != 0) {
1175 if (!name || strlen(name) > 8 || !disc_interface)
1178 if (!disc_interface->
startup())
1188 if (verify_iso9660_disc(disc_interface) != 0)
1191 sprintf(devname,
"%s:", name);
1195 devops = malloc(
sizeof(dotab_iso9660) + strlen(name) + 1);
1200 nameCopy = (
char*) (devops + 1);
1202 iso9660_dev = disc_interface;
1206 memcpy(devops, &dotab_iso9660,
sizeof(dotab_iso9660));
1207 strcpy(nameCopy, name);
1208 devops->
name = nameCopy;
1220static bool check_dev_name(
const char* name,
char *devname,
size_t devname_size)
1228 if (len == 0 || len > devname_size-2)
1232 strcpy(devname, name);
1233 if (devname[len-1] !=
':')
1234 strcat(devname,
":");
1242 if (! check_dev_name(name, devname,
sizeof(devname)))
1254 if (!check_dev_name(name, devname,
sizeof(devname)))
void lock(unsigned int *lock)
void unlock(unsigned int *lock)
#define FEATURE_XENON_ATA
#define DISKIO_ERROR_NO_MEDIA
#define FEATURE_XENON_USB
struct filestruct_s FILE_STRUCT
#define dbglog(sev, prm...)
int fs_iso9660_shutdown()
bool ISO9660_Mount(const char *name, const DISC_INTERFACE *disc_interface)
const char * ISO9660_GetVolumeLabel(const char *name)
bool ISO9660_Unmount(const char *name)
int stat(const char *file, struct stat *st)
int RemoveDevice(const char *name)
int AddDevice(const devoptab_t *device)
int FindDevice(const char *name)
FN_MEDIUM_ISINSERTED isInserted
FN_MEDIUM_READSECTORS readSectors
FN_MEDIUM_STARTUP startup
uint8_t u8
8bit unsigned integer
int32_t s32
32bit signed integer
uint32_t u32
32bit unsigned integer