silence some warnings (dhewg)
[libogc.git] / libiso9660 / iso9660.c
blobc3f835fc7ce1f7d852f4a390838b1a8231c91b7d
1 /****************************************************************************
2 * ISO9660 devoptab
3 *
4 * Copyright (C) 2008-2010
5 * tipoloski, clava, shagkur, Tantric, joedj
6 ****************************************************************************/
8 #include <errno.h>
9 #include <ogc/lwp_watchdog.h>
10 #include <ogcsys.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/dir.h>
15 #include <sys/iosupport.h>
17 #include "iso9660.h"
19 #define OFFSET_EXTENDED 1
20 #define OFFSET_SECTOR 6
21 #define OFFSET_SIZE 14
22 #define OFFSET_FLAGS 25
23 #define OFFSET_NAMELEN 32
24 #define OFFSET_NAME 33
26 #define SECTOR_SIZE 0x800
27 #define BUFFER_SIZE 0x8000
29 #define DIR_SEPARATOR '/'
31 #define FLAG_DIR 2
33 struct pvd_s
35 char id[8];
36 char system_id[32];
37 char volume_id[32];
38 char zero[8];
39 unsigned long total_sector_le, total_sect_be;
40 char zero2[32];
41 unsigned long volume_set_size, volume_seq_nr;
42 unsigned short sector_size_le, sector_size_be;
43 unsigned long path_table_len_le, path_table_len_be;
44 unsigned long path_table_le, path_table_2nd_le;
45 unsigned long path_table_be, path_table_2nd_be;
46 u8 root[34];
47 char volume_set_id[128], publisher_id[128], data_preparer_id[128], application_id[128];
48 char copyright_file_id[37], abstract_file_id[37], bibliographical_file_id[37];
49 }__attribute__((packed));
51 typedef struct
53 u8 name_length;
54 u8 extended_sectors;
55 u32 sector;
56 u16 parent;
57 char name[ISO_MAXPATHLEN];
58 }__attribute__((packed)) PATHTABLE_ENTRY;
60 typedef struct pentry_s
62 u16 index;
63 u32 childCount;
64 PATHTABLE_ENTRY table_entry;
65 struct pentry_s *children;
66 } PATH_ENTRY;
68 typedef struct dentry_s
70 char name[ISO_MAXPATHLEN];
71 u32 sector;
72 u32 size;
73 u8 flags;
74 u32 fileCount;
75 PATH_ENTRY *path_entry;
76 struct dentry_s *children;
77 } DIR_ENTRY;
79 typedef struct iso9660mount_s
81 const DISC_INTERFACE *disc_interface;
82 u8 read_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
83 u8 cluster_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
84 u32 cache_start;
85 u32 cache_sectors;
86 bool iso_unicode;
87 PATH_ENTRY *iso_rootentry;
88 PATH_ENTRY *iso_currententry;
89 char volume_id[32];
90 } MOUNT_DESCR;
92 typedef struct filestruct_s
94 DIR_ENTRY entry;
95 off_t offset;
96 bool inUse;
97 MOUNT_DESCR *mdescr;
98 } FILE_STRUCT;
100 typedef struct dstate_s
102 DIR_ENTRY entry;
103 u32 index;
104 bool inUse;
105 } DIR_STATE_STRUCT;
107 static MOUNT_DESCR* _ISO9660_getMountDescrFromPath(const char *path, devoptab_t **pdevops);
109 static __inline__ bool is_dir(DIR_ENTRY *entry)
111 return entry->flags & FLAG_DIR;
114 static int __read(MOUNT_DESCR *mdescr, void *ptr, u64 offset, size_t len)
116 u32 sector = offset / SECTOR_SIZE;
117 u32 end_sector = (offset + len - 1) / SECTOR_SIZE;
118 u32 sectors = MIN(BUFFER_SIZE / SECTOR_SIZE, end_sector - sector + 1);
119 u32 sector_offset = offset % SECTOR_SIZE;
120 const DISC_INTERFACE *disc = mdescr->disc_interface;
122 len = MIN(BUFFER_SIZE - sector_offset, len);
123 if (mdescr->cache_sectors && sector >= mdescr->cache_start && (sector + sectors) <= (mdescr->cache_start + mdescr->cache_sectors))
125 memcpy(ptr, mdescr->read_buffer + (sector - mdescr->cache_start) * SECTOR_SIZE + sector_offset, len);
126 return len;
129 if (!disc->readSectors(sector, BUFFER_SIZE / SECTOR_SIZE, mdescr->read_buffer))
131 mdescr->cache_sectors = 0;
132 return -1;
135 mdescr->cache_start = sector;
136 mdescr->cache_sectors = BUFFER_SIZE / SECTOR_SIZE;
137 memcpy(ptr, mdescr->read_buffer + sector_offset, len);
139 return len;
142 static int _read(MOUNT_DESCR *mdescr, void *ptr, u64 offset, size_t len)
144 int ret, read = 0;
145 char *cptr = ptr;
146 while (read < len)
148 ret = __read(mdescr, cptr + read, offset + read, len - read);
149 if (ret > 0)
150 read += ret;
151 else if (ret == 0)
152 break;
153 else
154 return -1;
156 return read;
159 static void stat_entry(DIR_ENTRY *entry, struct stat *st)
161 st->st_dev = 69;
162 st->st_ino = (ino_t) entry->sector;
163 st->st_mode = (is_dir(entry) ? S_IFDIR : S_IFREG) | (S_IRUSR | S_IRGRP | S_IROTH);
164 st->st_nlink = 1;
165 st->st_uid = 1;
166 st->st_gid = 2;
167 st->st_rdev = st->st_dev;
168 st->st_size = entry->size;
169 st->st_atime = 0;
170 st->st_spare1 = 0;
171 st->st_mtime = 0;
172 st->st_spare2 = 0;
173 st->st_ctime = 0;
174 st->st_spare3 = 0;
175 st->st_blksize = SECTOR_SIZE;
176 st->st_blocks = (entry->size + SECTOR_SIZE - 1) / SECTOR_SIZE;
177 st->st_spare4[0] = 0;
178 st->st_spare4[1] = 0;
181 static char* basename(char *path)
183 s32 i;
185 for (i = strlen(path) - 1; i >= 0; i--)
187 if (path[i] == DIR_SEPARATOR)
188 return path + i + 1;
190 return path;
193 static char* dirname(char *path)
195 size_t i, j;
196 char *result = strdup(path);
198 j = strlen(result) - 1;
199 if (j < 0)
200 return result;
202 for (i = j; i >= 0; i--)
204 if (result[i] == DIR_SEPARATOR)
206 result[i] = '\0';
207 return result;
211 result[0] = '\0';
212 return result;
215 static s32 read_direntry(MOUNT_DESCR *mdescr, DIR_ENTRY *entry, u8 *buf)
217 u8 extended_sectors = buf[OFFSET_EXTENDED];
218 u32 sector = *(u32 *) (buf + OFFSET_SECTOR) + extended_sectors;
219 u32 size = *(u32 *) (buf + OFFSET_SIZE);
220 u8 flags = buf[OFFSET_FLAGS];
221 u8 namelen = buf[OFFSET_NAMELEN];
223 if (namelen == 1 && buf[OFFSET_NAME] == 1 && mdescr->iso_rootentry->table_entry.sector == entry->sector)
225 // .. at root - do not show
227 else if (namelen == 1 && !buf[OFFSET_NAME])
229 entry->sector = sector;
230 entry->size = size;
231 entry->flags = flags;
233 else
235 DIR_ENTRY *newChildren = realloc(entry->children, sizeof(DIR_ENTRY) * (entry->fileCount + 1));
236 if (!newChildren)
237 return -1;
238 memset(newChildren + entry->fileCount, 0, sizeof(DIR_ENTRY));
239 entry->children = newChildren;
240 DIR_ENTRY *child = &entry->children[entry->fileCount++];
241 child->sector = sector;
242 child->size = size;
243 child->flags = flags;
244 char *name = child->name;
246 if (namelen == 1 && buf[OFFSET_NAME] == 1)
248 // ..
249 sprintf(name, "..");
251 else if (mdescr->iso_unicode)
253 u32 i;
254 for (i = 0; i < (namelen / 2); i++)
255 name[i] = buf[OFFSET_NAME + i * 2 + 1];
256 name[i] = '\x00';
257 namelen = i;
259 else
261 memcpy(name, buf + OFFSET_NAME, namelen);
262 name[namelen] = '\x00';
264 if (!(flags & FLAG_DIR) && namelen >= 2 && name[namelen - 2] == ';')
265 name[namelen - 2] = '\x00';
268 return *buf;
271 static bool read_directory(MOUNT_DESCR *mdescr, DIR_ENTRY *dir_entry, PATH_ENTRY *path_entry)
273 u32 sector = path_entry->table_entry.sector;
274 u32 remaining = 0;
275 u32 sector_offset = 0;
279 if (__read(mdescr, mdescr->cluster_buffer, (u64) sector * SECTOR_SIZE + sector_offset, (SECTOR_SIZE - sector_offset)) != (SECTOR_SIZE - sector_offset))
280 return false;
281 int offset = read_direntry(mdescr, dir_entry, mdescr->cluster_buffer);
282 if (offset == -1)
283 return false;
284 if (!remaining)
286 remaining = dir_entry->size;
287 dir_entry->path_entry = path_entry;
289 sector_offset += offset;
290 if (sector_offset >= SECTOR_SIZE || !mdescr->cluster_buffer[offset])
292 remaining -= SECTOR_SIZE;
293 sector_offset = 0;
294 sector++;
296 } while (remaining > 0);
298 return true;
301 static bool path_entry_from_path(MOUNT_DESCR *mdescr, PATH_ENTRY *path_entry, const char *path)
303 bool found = false;
304 bool notFound = false;
306 const char *pathPosition = path;
307 const char *pathEnd = strchr(path, '\0');
309 PATH_ENTRY *entry = mdescr->iso_rootentry;
310 while (pathPosition[0] == DIR_SEPARATOR)
311 pathPosition++;
312 if (pathPosition >= pathEnd)
313 found = true;
315 PATH_ENTRY *dir = entry;
316 while (!found && !notFound)
318 const char *nextPathPosition = strchr(pathPosition, DIR_SEPARATOR);
319 size_t dirnameLength;
320 if (nextPathPosition != NULL)
321 dirnameLength = nextPathPosition - pathPosition;
322 else
323 dirnameLength = strlen(pathPosition);
324 if (dirnameLength >= ISO_MAXPATHLEN)
325 return false;
327 u32 childIndex = 0;
328 while (childIndex < dir->childCount && !found && !notFound)
330 entry = &dir->children[childIndex];
331 if (dirnameLength == strnlen(entry->table_entry.name, ISO_MAXPATHLEN - 1) && !strncasecmp(pathPosition, entry->table_entry.name, dirnameLength))
332 found = true;
333 if (!found)
334 childIndex++;
337 if (childIndex >= dir->childCount)
339 notFound = true;
340 found = false;
342 else if (!nextPathPosition || nextPathPosition >= pathEnd)
344 found = true;
346 else
348 dir = entry;
349 pathPosition = nextPathPosition;
350 while (pathPosition[0] == DIR_SEPARATOR)
351 pathPosition++;
352 if (pathPosition >= pathEnd)
353 found = true;
354 else
355 found = false;
359 if (found)
360 memcpy(path_entry, entry, sizeof(PATH_ENTRY));
361 return found;
364 static bool find_in_directory(MOUNT_DESCR *mdescr, DIR_ENTRY *entry, PATH_ENTRY *parent, const char *base)
366 u32 childIdx;
367 u32 nl = strlen(base);
369 if (!nl)
370 return read_directory(mdescr, entry, parent);
372 for (childIdx = 0; childIdx < parent->childCount; childIdx++)
374 PATH_ENTRY *child = parent->children + childIdx;
375 if (nl == strnlen(child->table_entry.name, ISO_MAXPATHLEN - 1) && !strncasecmp(base, child->table_entry.name, nl))
377 return read_directory(mdescr, entry, child);
381 if (!read_directory(mdescr, entry, parent))
382 return false;
383 for (childIdx = 0; childIdx < entry->fileCount; childIdx++)
385 DIR_ENTRY *child = entry->children + childIdx;
386 if (nl == strnlen(child->name, ISO_MAXPATHLEN - 1) && !strncasecmp(base, child->name, nl))
388 memcpy(entry, child, sizeof(DIR_ENTRY));
389 return true;
392 return false;
395 static bool entry_from_path(MOUNT_DESCR *mdescr, DIR_ENTRY *entry, const char *const_path)
397 u32 len;
398 bool found = false;
399 char *path, *dir, *base;
400 PATH_ENTRY parent_entry;
402 memset(entry, 0, sizeof(DIR_ENTRY));
404 if (strchr(const_path, ':') != NULL)
405 const_path = strchr(const_path, ':') + 1;
407 path = strdup(const_path);
408 len = strlen(path);
409 while (len > 1 && path[len - 1] == DIR_SEPARATOR)
410 path[--len] = '\x00';
412 dir = dirname(path);
413 base = basename(path);
414 if (!path_entry_from_path(mdescr, &parent_entry, dir))
415 goto done;
417 found = find_in_directory(mdescr, entry, &parent_entry, base);
418 if (!found && entry->children)
419 free(entry->children);
421 done:
422 free(path);
423 free(dir);
424 return found;
427 static bool check_dev_name(const char* name, char *devname, size_t devname_size)
429 size_t len;
431 if (!name)
432 return false;
434 len = strlen(name);
435 if (len == 0 || len > devname_size-2)
436 return false;
438 // append ':' if missing
439 strcpy(devname, name);
440 if (devname[len-1] != ':')
441 strcat(devname, ":");
443 return true;
446 static int _ISO9660_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
448 DIR_ENTRY entry;
449 FILE_STRUCT *file = (FILE_STRUCT *) fileStruct;
450 MOUNT_DESCR *mdescr;
452 mdescr = _ISO9660_getMountDescrFromPath(path, NULL);
453 if (mdescr == NULL)
455 r->_errno = ENODEV;
456 return -1;
459 if (!entry_from_path(mdescr, &entry, path))
461 r->_errno = ENOENT;
462 return -1;
464 else if (is_dir(&entry))
466 if (entry.children)
467 free(entry.children);
468 r->_errno = EISDIR;
469 return -1;
472 memcpy(&file->entry, &entry, sizeof(DIR_ENTRY));
473 file->offset = 0;
474 file->inUse = true;
475 file->mdescr = mdescr;
477 return (int) file;
480 static int _ISO9660_close_r(struct _reent *r, int fd)
482 FILE_STRUCT *file = (FILE_STRUCT*) fd;
484 if (!file->inUse)
486 r->_errno = EBADF;
487 return -1;
490 file->inUse = false;
491 return 0;
494 static ssize_t _ISO9660_read_r(struct _reent *r, int fd, char *ptr, size_t len)
496 u64 offset;
497 int ret;
498 FILE_STRUCT *file = (FILE_STRUCT*) fd;
500 if (!file->inUse)
502 r->_errno = EBADF;
503 return -1;
506 if (file->offset >= file->entry.size)
508 r->_errno = EOVERFLOW;
509 return 0;
512 if (len + file->offset > file->entry.size)
514 r->_errno = EOVERFLOW;
515 len = file->entry.size - file->offset;
518 if (len == 0)
519 return 0;
521 offset = (u64) file->entry.sector * SECTOR_SIZE + file->offset;
522 if ((ret = _read(file->mdescr, ptr, offset, len)) < 0)
524 r->_errno = EIO;
525 return -1;
528 len = (size_t)ret;
529 file->offset += len;
530 return len;
533 static off_t _ISO9660_seek_r(struct _reent *r, int fd, off_t pos, int dir)
535 off_t position;
536 FILE_STRUCT *file = (FILE_STRUCT*) fd;
538 if (!file->inUse)
540 r->_errno = EBADF;
541 return -1;
544 switch (dir)
546 case SEEK_SET:
547 position = pos;
548 break;
549 case SEEK_CUR:
550 position = file->offset + pos;
551 break;
552 case SEEK_END:
553 position = file->entry.size + pos;
554 break;
555 default:
556 r->_errno = EINVAL;
557 return -1;
560 if (pos > 0 && position < 0)
562 r->_errno = EOVERFLOW;
563 return -1;
566 if (position < 0 || position > file->entry.size)
568 r->_errno = EINVAL;
569 return -1;
572 file->offset = position;
573 return position;
576 static int _ISO9660_fstat_r(struct _reent *r, int fd, struct stat *st)
578 FILE_STRUCT *file = (FILE_STRUCT*) fd;
580 if (!file->inUse)
582 r->_errno = EBADF;
583 return -1;
586 stat_entry(&file->entry, st);
587 return 0;
590 static int _ISO9660_stat_r(struct _reent *r, const char *path, struct stat *st)
592 DIR_ENTRY entry;
593 MOUNT_DESCR *mdescr;
595 mdescr = _ISO9660_getMountDescrFromPath(path, NULL);
596 if (mdescr == NULL)
598 r->_errno = ENODEV;
599 return -1;
602 if (!entry_from_path(mdescr, &entry, path))
604 r->_errno = ENOENT;
605 return -1;
608 stat_entry(&entry, st);
609 if (entry.children)
610 free(entry.children);
612 return 0;
615 static int _ISO9660_chdir_r(struct _reent *r, const char *path)
617 DIR_ENTRY entry;
618 MOUNT_DESCR *mdescr;
620 mdescr = _ISO9660_getMountDescrFromPath(path, NULL);
621 if (mdescr == NULL)
623 r->_errno = ENODEV;
624 return -1;
627 if (!entry_from_path(mdescr, &entry, path))
629 r->_errno = ENOENT;
630 return -1;
632 else if (!is_dir(&entry))
634 r->_errno = ENOTDIR;
635 return -1;
638 mdescr->iso_currententry = entry.path_entry;
639 if (entry.children)
640 free(entry.children);
642 return 0;
645 static DIR_ITER* _ISO9660_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
647 DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
648 MOUNT_DESCR *mdescr;
650 mdescr = _ISO9660_getMountDescrFromPath(path, NULL);
651 if (mdescr == NULL)
653 r->_errno = ENODEV;
654 return NULL;
657 if (!entry_from_path(mdescr, &state->entry, path))
659 r->_errno = ENOENT;
660 return NULL;
662 else if (!is_dir(&state->entry))
664 r->_errno = ENOTDIR;
665 return NULL;
668 state->index = 0;
669 state->inUse = true;
670 return dirState;
673 static int _ISO9660_dirreset_r(struct _reent *r, DIR_ITER *dirState)
675 DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
677 if (!state->inUse)
679 r->_errno = EBADF;
680 return -1;
683 state->index = 0;
684 return 0;
687 static int _ISO9660_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st)
689 DIR_ENTRY *entry;
690 DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
692 if (!state->inUse)
694 r->_errno = EBADF;
695 return -1;
698 if (state->index >= state->entry.fileCount)
700 r->_errno = ENOENT;
701 return -1;
704 entry = &state->entry.children[state->index++];
705 strncpy(filename, entry->name, ISO_MAXPATHLEN - 1);
706 stat_entry(entry, st);
707 return 0;
710 static int _ISO9660_dirclose_r(struct _reent *r, DIR_ITER *dirState)
712 DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
714 if (!state->inUse)
716 r->_errno = EBADF;
717 return -1;
720 state->inUse = false;
721 if (state->entry.children)
722 free(state->entry.children);
723 return 0;
726 static int _ISO9660_statvfs_r(struct _reent *r, const char *path, struct statvfs *buf)
728 // FAT clusters = POSIX blocks
729 buf->f_bsize = 0x800; // File system block size.
730 buf->f_frsize = 0x800; // Fundamental file system block size.
732 //buf->f_blocks = totalsectors; // Total number of blocks on file system in units of f_frsize.
733 buf->f_bfree = 0; // Total number of free blocks.
734 buf->f_bavail = 0; // Number of free blocks available to non-privileged process.
736 // Treat requests for info on inodes as clusters
737 //buf->f_files = totalentries; // Total number of file serial numbers.
738 buf->f_ffree = 0; // Total number of free file serial numbers.
739 buf->f_favail = 0; // Number of file serial numbers available to non-privileged process.
741 // File system ID. 32bit ioType value
742 buf->f_fsid = 0; //??!!?
744 // Bit mask of f_flag values.
745 buf->f_flag = ST_NOSUID // No support for ST_ISUID and ST_ISGID file mode bits
746 | ST_RDONLY; // Read only file system
747 // Maximum filename length.
748 buf->f_namemax = 208;
749 return 0;
752 static const devoptab_t dotab_iso9660 =
754 NULL,
755 sizeof(FILE_STRUCT),
756 _ISO9660_open_r,
757 _ISO9660_close_r,
758 NULL,
759 _ISO9660_read_r,
760 _ISO9660_seek_r,
761 _ISO9660_fstat_r,
762 _ISO9660_stat_r,
763 NULL,
764 NULL,
765 _ISO9660_chdir_r,
766 NULL,
767 NULL,
768 sizeof(DIR_STATE_STRUCT),
769 _ISO9660_diropen_r,
770 _ISO9660_dirreset_r,
771 _ISO9660_dirnext_r,
772 _ISO9660_dirclose_r,
773 _ISO9660_statvfs_r,
774 NULL, // device ftruncate_r
775 NULL, // device fsync_r
776 NULL // device data
779 static MOUNT_DESCR* _ISO9660_getMountDescrFromPath(const char *path, devoptab_t **pdevops)
781 devoptab_t *devops;
783 if (!path)
784 return NULL;
786 devops = (devoptab_t *) GetDeviceOpTab(path);
787 if (!devops)
788 return NULL;
790 // Perform a quick check to make sure we're dealing with a libiso9660 controlled device
791 if (devops->open_r != dotab_iso9660.open_r)
792 return NULL;
794 if (pdevops)
795 *pdevops = devops;
797 return (MOUNT_DESCR*) devops->deviceData;
800 static PATH_ENTRY* entry_from_index(PATH_ENTRY *entry, u16 index)
802 u32 i;
804 if (entry->index == index)
805 return entry;
807 for (i = 0; i < entry->childCount; i++)
809 PATH_ENTRY *match = entry_from_index(&entry->children[i], index);
810 if (match)
811 return match;
813 return NULL;
816 static PATH_ENTRY* add_child_entry(PATH_ENTRY *dir)
818 PATH_ENTRY *child;
819 PATH_ENTRY *newChildren = NULL;
821 newChildren = realloc(dir->children, (dir->childCount + 1) * sizeof(PATH_ENTRY));
822 if (newChildren == NULL)
823 return NULL;
825 memset(newChildren + dir->childCount, 0, sizeof(PATH_ENTRY));
826 dir->children = newChildren;
828 child = &dir->children[dir->childCount++];
829 return child;
832 static void cleanup_recursive(PATH_ENTRY *entry)
834 u32 i;
836 for (i = 0; i < entry->childCount; i++)
837 cleanup_recursive(&entry->children[i]);
838 if (entry->children)
839 free(entry->children);
842 static struct pvd_s* read_volume_descriptor(MOUNT_DESCR *mdescr, u8 descriptor)
844 u8 sector;
845 const DISC_INTERFACE *disc = mdescr->disc_interface;
847 for (sector = 16; sector < 32; sector++)
849 if (!disc->readSectors(sector, 1, mdescr->read_buffer))
850 return NULL;
851 if (!memcmp(mdescr->read_buffer + 1, "CD001\1", 6))
853 if (*mdescr->read_buffer == descriptor)
854 return (struct pvd_s*) mdescr->read_buffer;
855 else if (*mdescr->read_buffer == 0xff)
856 return NULL;
860 return NULL;
863 static bool read_directories(MOUNT_DESCR *mdescr)
865 struct pvd_s *volume = read_volume_descriptor(mdescr, 2);
866 if (volume)
867 mdescr->iso_unicode = true;
868 else if (!(volume = read_volume_descriptor(mdescr, 1)))
869 return false;
871 if (!(mdescr->iso_rootentry = malloc(sizeof(PATH_ENTRY))))
872 return false;
873 memset(mdescr->iso_rootentry, 0, sizeof(PATH_ENTRY));
874 mdescr->iso_rootentry->table_entry.name_length = 1;
875 mdescr->iso_rootentry->table_entry.extended_sectors = volume->root[OFFSET_EXTENDED];
876 mdescr->iso_rootentry->table_entry.sector = *(u32 *) (volume->root + OFFSET_SECTOR);
877 mdescr->iso_rootentry->table_entry.parent = 0;
878 mdescr->iso_rootentry->table_entry.name[0] = '\x00';
879 mdescr->iso_rootentry->index = 1;
880 mdescr->iso_currententry = mdescr->iso_rootentry;
882 strncpy(mdescr->volume_id, volume->volume_id, 32);
883 mdescr->volume_id[31] = '\0';
885 u32 path_table = volume->path_table_be;
886 u32 path_table_len = volume->path_table_len_be;
887 u16 i = 1;
888 u64 offset = sizeof(PATHTABLE_ENTRY) - ISO_MAXPATHLEN + 2;
889 PATH_ENTRY *parent = mdescr->iso_rootentry;
890 while (i < 0xffff && offset < path_table_len)
892 PATHTABLE_ENTRY entry;
893 if (__read(mdescr, &entry, (u64) path_table * SECTOR_SIZE + offset, sizeof(PATHTABLE_ENTRY)) != sizeof(PATHTABLE_ENTRY))
894 return false; // kinda dodgy - could be reading too far
895 if (parent->index != entry.parent)
896 parent = entry_from_index(mdescr->iso_rootentry, entry.parent);
897 if (!parent)
898 return false;
899 PATH_ENTRY *child = add_child_entry(parent);
900 if (!child)
901 return false;
902 memcpy(&child->table_entry, &entry, sizeof(PATHTABLE_ENTRY));
903 offset += sizeof(PATHTABLE_ENTRY) - ISO_MAXPATHLEN + child->table_entry.name_length;
904 if (child->table_entry.name_length % 2)
905 offset++;
906 child->index = ++i;
908 if (mdescr->iso_unicode)
910 u32 i;
911 for (i = 0; i < (child->table_entry.name_length / 2); i++)
912 child->table_entry.name[i] = entry.name[i * 2 + 1];
913 child->table_entry.name[i] = '\x00';
914 child->table_entry.name_length = i;
916 else
918 child->table_entry.name[child->table_entry.name_length] = '\x00';
923 return true;
926 static MOUNT_DESCR *_ISO9660_mdescr_constructor(const DISC_INTERFACE *disc_interface)
928 MOUNT_DESCR *mdescr = NULL;
930 mdescr = malloc(sizeof(MOUNT_DESCR));
931 if (!mdescr)
932 return NULL;
934 mdescr->disc_interface = disc_interface;
935 mdescr->cache_start = 0;
936 mdescr->cache_sectors = 0;
937 mdescr->iso_unicode = false;
938 mdescr->iso_rootentry = NULL;
939 mdescr->iso_currententry = NULL;
941 if (!read_directories(mdescr))
943 free(mdescr);
944 return NULL;
946 return mdescr;
949 bool ISO9660_Mount(const char* name, const DISC_INTERFACE *disc_interface)
951 char *nameCopy;
952 devoptab_t *devops = NULL;
953 MOUNT_DESCR *mdescr = NULL;
954 char devname[10];
956 if (!name || strlen(name) > 8 || !disc_interface)
957 return false;
959 if (!disc_interface->startup())
960 return false;
962 if (!disc_interface->isInserted())
963 return false;
965 sprintf(devname, "%s:", name);
966 if (FindDevice(devname) >= 0)
967 return false;
969 devops = malloc(sizeof(dotab_iso9660) + strlen(name) + 1);
970 if (!devops)
971 return false;
973 // Use the space allocated at the end of the devoptab struct for storing the name
974 nameCopy = (char*) (devops + 1);
976 // Initialize the file system
977 mdescr = _ISO9660_mdescr_constructor(disc_interface);
978 if (!mdescr)
980 free(devops);
981 return false;
984 // Add an entry for this device to the devoptab table
985 memcpy(devops, &dotab_iso9660, sizeof(dotab_iso9660));
986 strcpy(nameCopy, name);
987 devops->name = nameCopy;
988 devops->deviceData = mdescr;
990 if (AddDevice(devops) < 0)
992 free(mdescr);
993 free(devops);
994 return false;
996 return true;
1000 bool ISO9660_Unmount(const char* name)
1002 devoptab_t *devops;
1003 MOUNT_DESCR *mdescr;
1004 char devname[11];
1006 if (! check_dev_name(name, devname, sizeof(devname)))
1007 return false;
1009 mdescr = _ISO9660_getMountDescrFromPath(devname, &devops);
1010 if (!mdescr)
1011 return false;
1013 if (RemoveDevice(devname) == -1)
1014 return false;
1016 if (mdescr->iso_rootentry)
1018 cleanup_recursive(mdescr->iso_rootentry);
1019 free(mdescr->iso_rootentry);
1022 free(mdescr);
1023 free(devops);
1024 return true;
1027 const char *ISO9660_GetVolumeLabel(const char *name)
1029 MOUNT_DESCR *mdescr;
1030 char devname[11];
1032 if (! check_dev_name(name, devname, sizeof(devname)))
1033 return NULL;
1035 mdescr = _ISO9660_getMountDescrFromPath(devname, NULL);
1036 if (!mdescr)
1037 return NULL;
1039 return mdescr->volume_id;