1 /****************************************************************************
4 * Copyright (C) 2008-2010
5 * tipoloski, clava, shagkur, Tantric, joedj
6 ****************************************************************************/
9 #include <ogc/lwp_watchdog.h>
15 #include <sys/iosupport.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 '/'
39 unsigned long total_sector_le
, total_sect_be
;
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
;
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
));
57 char name
[ISO_MAXPATHLEN
];
58 }__attribute__((packed
)) PATHTABLE_ENTRY
;
60 typedef struct pentry_s
64 PATHTABLE_ENTRY table_entry
;
65 struct pentry_s
*children
;
68 typedef struct dentry_s
70 char name
[ISO_MAXPATHLEN
];
75 PATH_ENTRY
*path_entry
;
76 struct dentry_s
*children
;
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)));
87 PATH_ENTRY
*iso_rootentry
;
88 PATH_ENTRY
*iso_currententry
;
92 typedef struct filestruct_s
100 typedef struct dstate_s
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
);
129 if (!disc
->readSectors(sector
, BUFFER_SIZE
/ SECTOR_SIZE
, mdescr
->read_buffer
))
131 mdescr
->cache_sectors
= 0;
135 mdescr
->cache_start
= sector
;
136 mdescr
->cache_sectors
= BUFFER_SIZE
/ SECTOR_SIZE
;
137 memcpy(ptr
, mdescr
->read_buffer
+ sector_offset
, len
);
142 static int _read(MOUNT_DESCR
*mdescr
, void *ptr
, u64 offset
, size_t len
)
148 ret
= __read(mdescr
, cptr
+ read
, offset
+ read
, len
- read
);
159 static void stat_entry(DIR_ENTRY
*entry
, struct stat
*st
)
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
);
167 st
->st_rdev
= st
->st_dev
;
168 st
->st_size
= entry
->size
;
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
)
185 for (i
= strlen(path
) - 1; i
>= 0; i
--)
187 if (path
[i
] == DIR_SEPARATOR
)
193 static char* dirname(char *path
)
196 char *result
= strdup(path
);
198 j
= strlen(result
) - 1;
202 for (i
= j
; i
>= 0; i
--)
204 if (result
[i
] == DIR_SEPARATOR
)
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
;
231 entry
->flags
= flags
;
235 DIR_ENTRY
*newChildren
= realloc(entry
->children
, sizeof(DIR_ENTRY
) * (entry
->fileCount
+ 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
;
243 child
->flags
= flags
;
244 char *name
= child
->name
;
246 if (namelen
== 1 && buf
[OFFSET_NAME
] == 1)
251 else if (mdescr
->iso_unicode
)
254 for (i
= 0; i
< (namelen
/ 2); i
++)
255 name
[i
] = buf
[OFFSET_NAME
+ i
* 2 + 1];
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';
271 static bool read_directory(MOUNT_DESCR
*mdescr
, DIR_ENTRY
*dir_entry
, PATH_ENTRY
*path_entry
)
273 u32 sector
= path_entry
->table_entry
.sector
;
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
))
281 int offset
= read_direntry(mdescr
, dir_entry
, mdescr
->cluster_buffer
);
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
;
296 } while (remaining
> 0);
301 static bool path_entry_from_path(MOUNT_DESCR
*mdescr
, PATH_ENTRY
*path_entry
, const char *path
)
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
)
312 if (pathPosition
>= pathEnd
)
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
;
323 dirnameLength
= strlen(pathPosition
);
324 if (dirnameLength
>= ISO_MAXPATHLEN
)
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
))
337 if (childIndex
>= dir
->childCount
)
342 else if (!nextPathPosition
|| nextPathPosition
>= pathEnd
)
349 pathPosition
= nextPathPosition
;
350 while (pathPosition
[0] == DIR_SEPARATOR
)
352 if (pathPosition
>= pathEnd
)
360 memcpy(path_entry
, entry
, sizeof(PATH_ENTRY
));
364 static bool find_in_directory(MOUNT_DESCR
*mdescr
, DIR_ENTRY
*entry
, PATH_ENTRY
*parent
, const char *base
)
367 u32 nl
= strlen(base
);
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
))
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
));
395 static bool entry_from_path(MOUNT_DESCR
*mdescr
, DIR_ENTRY
*entry
, const char *const_path
)
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
);
409 while (len
> 1 && path
[len
- 1] == DIR_SEPARATOR
)
410 path
[--len
] = '\x00';
413 base
= basename(path
);
414 if (!path_entry_from_path(mdescr
, &parent_entry
, dir
))
417 found
= find_in_directory(mdescr
, entry
, &parent_entry
, base
);
418 if (!found
&& entry
->children
)
419 free(entry
->children
);
427 static bool check_dev_name(const char* name
, char *devname
, size_t devname_size
)
435 if (len
== 0 || len
> devname_size
-2)
438 // append ':' if missing
439 strcpy(devname
, name
);
440 if (devname
[len
-1] != ':')
441 strcat(devname
, ":");
446 static int _ISO9660_open_r(struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
)
449 FILE_STRUCT
*file
= (FILE_STRUCT
*) fileStruct
;
452 mdescr
= _ISO9660_getMountDescrFromPath(path
, NULL
);
459 if (!entry_from_path(mdescr
, &entry
, path
))
464 else if (is_dir(&entry
))
467 free(entry
.children
);
472 memcpy(&file
->entry
, &entry
, sizeof(DIR_ENTRY
));
475 file
->mdescr
= mdescr
;
480 static int _ISO9660_close_r(struct _reent
*r
, int fd
)
482 FILE_STRUCT
*file
= (FILE_STRUCT
*) fd
;
494 static ssize_t
_ISO9660_read_r(struct _reent
*r
, int fd
, char *ptr
, size_t len
)
498 FILE_STRUCT
*file
= (FILE_STRUCT
*) fd
;
506 if (file
->offset
>= file
->entry
.size
)
508 r
->_errno
= EOVERFLOW
;
512 if (len
+ file
->offset
> file
->entry
.size
)
514 r
->_errno
= EOVERFLOW
;
515 len
= file
->entry
.size
- file
->offset
;
521 offset
= (u64
) file
->entry
.sector
* SECTOR_SIZE
+ file
->offset
;
522 if ((ret
= _read(file
->mdescr
, ptr
, offset
, len
)) < 0)
533 static off_t
_ISO9660_seek_r(struct _reent
*r
, int fd
, off_t pos
, int dir
)
536 FILE_STRUCT
*file
= (FILE_STRUCT
*) fd
;
550 position
= file
->offset
+ pos
;
553 position
= file
->entry
.size
+ pos
;
560 if (pos
> 0 && position
< 0)
562 r
->_errno
= EOVERFLOW
;
566 if (position
< 0 || position
> file
->entry
.size
)
572 file
->offset
= position
;
576 static int _ISO9660_fstat_r(struct _reent
*r
, int fd
, struct stat
*st
)
578 FILE_STRUCT
*file
= (FILE_STRUCT
*) fd
;
586 stat_entry(&file
->entry
, st
);
590 static int _ISO9660_stat_r(struct _reent
*r
, const char *path
, struct stat
*st
)
595 mdescr
= _ISO9660_getMountDescrFromPath(path
, NULL
);
602 if (!entry_from_path(mdescr
, &entry
, path
))
608 stat_entry(&entry
, st
);
610 free(entry
.children
);
615 static int _ISO9660_chdir_r(struct _reent
*r
, const char *path
)
620 mdescr
= _ISO9660_getMountDescrFromPath(path
, NULL
);
627 if (!entry_from_path(mdescr
, &entry
, path
))
632 else if (!is_dir(&entry
))
638 mdescr
->iso_currententry
= entry
.path_entry
;
640 free(entry
.children
);
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
);
650 mdescr
= _ISO9660_getMountDescrFromPath(path
, NULL
);
657 if (!entry_from_path(mdescr
, &state
->entry
, path
))
662 else if (!is_dir(&state
->entry
))
673 static int _ISO9660_dirreset_r(struct _reent
*r
, DIR_ITER
*dirState
)
675 DIR_STATE_STRUCT
*state
= (DIR_STATE_STRUCT
*) (dirState
->dirStruct
);
687 static int _ISO9660_dirnext_r(struct _reent
*r
, DIR_ITER
*dirState
, char *filename
, struct stat
*st
)
690 DIR_STATE_STRUCT
*state
= (DIR_STATE_STRUCT
*) (dirState
->dirStruct
);
698 if (state
->index
>= state
->entry
.fileCount
)
704 entry
= &state
->entry
.children
[state
->index
++];
705 strncpy(filename
, entry
->name
, ISO_MAXPATHLEN
- 1);
706 stat_entry(entry
, st
);
710 static int _ISO9660_dirclose_r(struct _reent
*r
, DIR_ITER
*dirState
)
712 DIR_STATE_STRUCT
*state
= (DIR_STATE_STRUCT
*) (dirState
->dirStruct
);
720 state
->inUse
= false;
721 if (state
->entry
.children
)
722 free(state
->entry
.children
);
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;
752 static const devoptab_t dotab_iso9660
=
768 sizeof(DIR_STATE_STRUCT
),
774 NULL
, // device ftruncate_r
775 NULL
, // device fsync_r
779 static MOUNT_DESCR
* _ISO9660_getMountDescrFromPath(const char *path
, devoptab_t
**pdevops
)
786 devops
= (devoptab_t
*) GetDeviceOpTab(path
);
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
)
797 return (MOUNT_DESCR
*) devops
->deviceData
;
800 static PATH_ENTRY
* entry_from_index(PATH_ENTRY
*entry
, u16 index
)
804 if (entry
->index
== index
)
807 for (i
= 0; i
< entry
->childCount
; i
++)
809 PATH_ENTRY
*match
= entry_from_index(&entry
->children
[i
], index
);
816 static PATH_ENTRY
* add_child_entry(PATH_ENTRY
*dir
)
819 PATH_ENTRY
*newChildren
= NULL
;
821 newChildren
= realloc(dir
->children
, (dir
->childCount
+ 1) * sizeof(PATH_ENTRY
));
822 if (newChildren
== NULL
)
825 memset(newChildren
+ dir
->childCount
, 0, sizeof(PATH_ENTRY
));
826 dir
->children
= newChildren
;
828 child
= &dir
->children
[dir
->childCount
++];
832 static void cleanup_recursive(PATH_ENTRY
*entry
)
836 for (i
= 0; i
< entry
->childCount
; i
++)
837 cleanup_recursive(&entry
->children
[i
]);
839 free(entry
->children
);
842 static struct pvd_s
* read_volume_descriptor(MOUNT_DESCR
*mdescr
, u8 descriptor
)
845 const DISC_INTERFACE
*disc
= mdescr
->disc_interface
;
847 for (sector
= 16; sector
< 32; sector
++)
849 if (!disc
->readSectors(sector
, 1, mdescr
->read_buffer
))
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)
863 static bool read_directories(MOUNT_DESCR
*mdescr
)
865 struct pvd_s
*volume
= read_volume_descriptor(mdescr
, 2);
867 mdescr
->iso_unicode
= true;
868 else if (!(volume
= read_volume_descriptor(mdescr
, 1)))
871 if (!(mdescr
->iso_rootentry
= malloc(sizeof(PATH_ENTRY
))))
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
;
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
);
899 PATH_ENTRY
*child
= add_child_entry(parent
);
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)
908 if (mdescr
->iso_unicode
)
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
;
918 child
->table_entry
.name
[child
->table_entry
.name_length
] = '\x00';
926 static MOUNT_DESCR
*_ISO9660_mdescr_constructor(const DISC_INTERFACE
*disc_interface
)
928 MOUNT_DESCR
*mdescr
= NULL
;
930 mdescr
= malloc(sizeof(MOUNT_DESCR
));
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
))
949 bool ISO9660_Mount(const char* name
, const DISC_INTERFACE
*disc_interface
)
952 devoptab_t
*devops
= NULL
;
953 MOUNT_DESCR
*mdescr
= NULL
;
956 if (!name
|| strlen(name
) > 8 || !disc_interface
)
959 if (!disc_interface
->startup())
962 if (!disc_interface
->isInserted())
965 sprintf(devname
, "%s:", name
);
966 if (FindDevice(devname
) >= 0)
969 devops
= malloc(sizeof(dotab_iso9660
) + strlen(name
) + 1);
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
);
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)
1000 bool ISO9660_Unmount(const char* name
)
1003 MOUNT_DESCR
*mdescr
;
1006 if (! check_dev_name(name
, devname
, sizeof(devname
)))
1009 mdescr
= _ISO9660_getMountDescrFromPath(devname
, &devops
);
1013 if (RemoveDevice(devname
) == -1)
1016 if (mdescr
->iso_rootentry
)
1018 cleanup_recursive(mdescr
->iso_rootentry
);
1019 free(mdescr
->iso_rootentry
);
1027 const char *ISO9660_GetVolumeLabel(const char *name
)
1029 MOUNT_DESCR
*mdescr
;
1032 if (! check_dev_name(name
, devname
, sizeof(devname
)))
1035 mdescr
= _ISO9660_getMountDescrFromPath(devname
, NULL
);
1039 return mdescr
->volume_id
;