Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / iso9660 / iso9660_fs.c
diff --git a/qemu/roms/openbios/fs/iso9660/iso9660_fs.c b/qemu/roms/openbios/fs/iso9660/iso9660_fs.c
new file mode 100644 (file)
index 0000000..d6f547b
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * /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 );
+}