| /* |
| * /packages/iso9660-files filesystem handler |
| * |
| * (c) 2009 Laurent Vivier <Laurent@vivier.eu> |
| * (c) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk> |
| */ |
| |
| #include "config.h" |
| #include "libopenbios/bindings.h" |
| #include "libiso9660.h" |
| #include "fs/fs.h" |
| #include "libc/vsprintf.h" |
| #include "libc/diskio.h" |
| |
| extern void iso9660_init( void ); |
| |
| typedef struct { |
| enum { FILE, DIR } type; |
| union { |
| iso9660_FILE *file; |
| iso9660_DIR * dir; |
| }; |
| } iso9660_COMMON; |
| |
| typedef struct { |
| iso9660_VOLUME *volume; |
| iso9660_COMMON *common; |
| } iso9660_info_t; |
| |
| DECLARE_NODE( iso9660, 0, sizeof(iso9660_info_t), "+/packages/iso9660-files" ); |
| |
| /* ( -- success? ) */ |
| static void |
| iso9660_files_open( iso9660_info_t *mi ) |
| { |
| int fd; |
| char *path = my_args_copy(); |
| |
| if ( ! path ) |
| RET( 0 ); |
| |
| fd = open_ih( my_parent() ); |
| if ( fd == -1 ) { |
| free( path ); |
| RET( 0 ); |
| } |
| |
| mi->volume = iso9660_mount( fd ); |
| if ( mi->volume == NULL ) { |
| free( path ); |
| close_io( fd ); |
| RET( 0 ); |
| } |
| |
| mi->common->dir = iso9660_opendir( mi->volume, path ); |
| if ( mi->common->dir == NULL ) { |
| mi->common->file = iso9660_open( mi->volume, path ); |
| if (mi->common->file == NULL) { |
| iso9660_umount( mi->volume ); |
| close_io( fd ); |
| free( path ); |
| RET( 0 ); |
| } |
| mi->common->type = FILE; |
| free( path ); |
| RET( -1 ); |
| } |
| mi->common->type = DIR; |
| free( path ); |
| |
| RET( -1 ); |
| } |
| |
| /* ( -- ) */ |
| static void |
| iso9660_files_close( iso9660_info_t *mi ) |
| { |
| int fd = mi->volume->fd; |
| |
| if (mi->common->type == FILE ) |
| iso9660_close( mi->common->file ); |
| else if ( mi->common->type == DIR ) |
| iso9660_closedir( mi->common->dir ); |
| iso9660_umount( mi->volume ); |
| close_io( fd ); |
| } |
| |
| /* ( buf len -- actlen ) */ |
| static void |
| iso9660_files_read( iso9660_info_t *mi ) |
| { |
| int count = POP(); |
| char *buf = (char *)cell2pointer(POP()); |
| int ret; |
| |
| if ( mi->common->type != FILE ) |
| PUSH( 0 ); |
| |
| ret = iso9660_read( mi->common->file, buf, count ); |
| |
| PUSH( ret ); |
| } |
| |
| /* ( pos.d -- status ) */ |
| static void |
| iso9660_files_seek( iso9660_info_t *mi ) |
| { |
| long long pos = DPOP(); |
| cell ret; |
| int offs = (int)pos; |
| int whence = SEEK_SET; |
| |
| if (mi->common->type != FILE) |
| PUSH( -1 ); |
| |
| if( offs == -1 ) { |
| offs = 0; |
| whence = SEEK_END; |
| } |
| |
| ret = iso9660_lseek(mi->common->file, offs, whence); |
| |
| PUSH( (ret < 0)? -1 : 0 ); |
| } |
| |
| /* ( -- filepos.d ) */ |
| static void |
| iso9660_files_offset( iso9660_info_t *mi ) |
| { |
| if ( mi->common->type != FILE ) |
| DPUSH( -1 ); |
| |
| DPUSH( mi->common->file->offset ); |
| } |
| |
| /* ( addr -- size ) */ |
| static void |
| iso9660_files_load( iso9660_info_t *mi) |
| { |
| char *buf = (char*)cell2pointer(POP()); |
| int ret, size; |
| |
| if ( mi->common->type != FILE ) |
| PUSH( 0 ); |
| |
| size = 0; |
| while(1) { |
| ret = iso9660_read( mi->common->file, buf, 512 ); |
| if (ret <= 0) |
| break; |
| buf += ret; |
| size += ret; |
| if (ret != 512) |
| break; |
| } |
| PUSH( size ); |
| } |
| |
| /* static method, ( pathstr len ihandle -- ) */ |
| static void |
| iso9660_files_dir( iso9660_info_t *dummy ) |
| { |
| iso9660_VOLUME *volume; |
| iso9660_COMMON *common; |
| struct iso_directory_record *idr; |
| char name_buf[256]; |
| int fd; |
| |
| ihandle_t ih = POP(); |
| char *path = pop_fstr_copy(); |
| |
| fd = open_ih( ih ); |
| if ( fd == -1 ) { |
| free( path ); |
| return; |
| } |
| |
| volume = iso9660_mount( fd ); |
| if ( volume == NULL ) { |
| free ( path ); |
| close_io( fd ); |
| return; |
| } |
| |
| common = malloc(sizeof(iso9660_COMMON)); |
| common->dir = iso9660_opendir( volume, path ); |
| |
| forth_printf("\n"); |
| while ( (idr = iso9660_readdir(common->dir)) ) { |
| |
| forth_printf("% 10d ", isonum_733(idr->size)); |
| forth_printf("%d-%02d-%02d %02d:%02d:%02d ", |
| idr->date[0] + 1900, /* year */ |
| idr->date[1], /* month */ |
| idr->date[2], /* day */ |
| idr->date[3], idr->date[4], idr->date[5]); |
| iso9660_name(common->dir->volume, idr, name_buf); |
| if (idr->flags[0] & 2) |
| forth_printf("%s\\\n", name_buf); |
| else |
| forth_printf("%s\n", name_buf); |
| } |
| |
| iso9660_closedir( common->dir ); |
| iso9660_umount( volume ); |
| |
| close_io( fd ); |
| |
| free( common ); |
| free( path ); |
| } |
| |
| /* static method, ( pos.d ih -- flag? ) */ |
| static void |
| iso9660_files_probe( iso9660_info_t *dummy ) |
| { |
| ihandle_t ih = POP_ih(); |
| long long offs = DPOP(); |
| int fd, ret = 0; |
| |
| fd = open_ih(ih); |
| if (fd >= 0) { |
| if (iso9660_probe(fd, offs)) { |
| ret = -1; |
| } |
| close_io(fd); |
| } else { |
| ret = -1; |
| } |
| |
| RET (ret); |
| } |
| |
| static void |
| iso9660_files_block_size( iso9660_info_t *dummy ) |
| { |
| PUSH(2048); |
| } |
| |
| static void |
| iso9660_initializer( iso9660_info_t *dummy ) |
| { |
| fword("register-fs-package"); |
| } |
| |
| NODE_METHODS( iso9660 ) = { |
| { "probe", iso9660_files_probe }, |
| { "open", iso9660_files_open }, |
| { "close", iso9660_files_close }, |
| { "read", iso9660_files_read }, |
| { "seek", iso9660_files_seek }, |
| { "offset", iso9660_files_offset }, |
| { "load", iso9660_files_load }, |
| { "dir", iso9660_files_dir }, |
| { "block-size", iso9660_files_block_size }, |
| { NULL, iso9660_initializer }, |
| }; |
| |
| void |
| iso9660_init( void ) |
| { |
| REGISTER_NODE( iso9660 ); |
| } |