diff options
Diffstat (limited to 'qemu/roms/openbios/fs/grubfs/grubfs_fs.c')
-rw-r--r-- | qemu/roms/openbios/fs/grubfs/grubfs_fs.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/grubfs/grubfs_fs.c b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c new file mode 100644 index 000000000..acd2a6441 --- /dev/null +++ b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c @@ -0,0 +1,398 @@ +/* + * /packages/grubfs-files + * + * grub vfs + * + * Copyright (C) 2004 Stefan Reinauer + * Copyright (C) 2004 Samuel Rydh + * Copyright (C) 2010 Mark Cave-Ayland + * + * inspired by HFS code from Samuel Rydh + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "fs/fs.h" +#include "filesys.h" +#include "glue.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" + +extern void grubfs_init( void ); + +/************************************************************************/ +/* grub GLOBALS (horrible... but difficult to fix) */ +/************************************************************************/ + +/* the grub drivers want these: */ +int filepos; +int filemax; +grub_error_t errnum; +char FSYS_BUF[FSYS_BUFLEN]; + +/* these are not even used by us, instead + * the grub fs drivers want them: + */ +int fsmax; +void (*disk_read_hook) (int, int, int); +void (*disk_read_func) (int, int, int); + + +/************************************************************************/ +/* filsystem table */ +/************************************************************************/ + +typedef struct fsys_entry { + const char *name; + int (*mount_func) (void); + int (*read_func) (char *buf, int len); + int (*dir_func) (char *dirname); + void (*close_func) (void); + int (*embed_func) (int *start_sector, int needed_sectors); +} fsys_entry_t; + +static const struct fsys_entry fsys_table[] = { +# ifdef CONFIG_FSYS_FAT + {"fat", fat_mount, fat_read, fat_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_EXT2FS + {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_MINIX + {"minix", minix_mount, minix_read, minix_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_REISERFS + {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, NULL, reiserfs_embed}, +# endif +# ifdef CONFIG_FSYS_JFS + {"jfs", jfs_mount, jfs_read, jfs_dir, NULL, jfs_embed}, +# endif +# ifdef CONFIG_FSYS_XFS + {"xfs", xfs_mount, xfs_read, xfs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_UFS + {"ufs", ufs_mount, ufs_read, ufs_dir, NULL, ufs_embed}, +# endif +# ifdef CONFIG_FSYS_ISO9660 + {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_NTFS + {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, NULL, NULL}, +# endif +# ifdef CONFIG_FSYS_AFFS + {"affs", affs_mount, affs_read, affs_dir, NULL, NULL}, +# endif +}; + +/* We don't provide a file search mechanism (yet) */ +typedef struct { + unsigned long pos; + unsigned long len; + const char *path; +} grubfile_t; + +typedef struct { + const struct fsys_entry *fsys; + grubfile_t *fd; + int dev_fd; + long long offset; /* Offset added onto each device read; should only ever be non-zero + when probing a partition for a filesystem */ +} grubfs_t; + +typedef struct { + grubfs_t *gfs; +} grubfs_info_t; + +/* Static block and global pointer required for I/O glue */ +static grubfs_t dummy_fs; +static grubfs_t *curfs = &dummy_fs; + +DECLARE_NODE( grubfs, 0, sizeof(grubfs_info_t), "+/packages/grubfs-files" ); + + +/************************************************************************/ +/* I/O glue (called by grub source) */ +/************************************************************************/ + +int +devread( unsigned long sector, unsigned long byte_offset, + unsigned long byte_len, void *buf ) +{ + long long offs = (long long)sector * 512 + byte_offset; + +#ifdef CONFIG_DEBUG_FS + //printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd); +#endif + + if( !curfs ) { +#ifdef CONFIG_DEBUG_FS + printk("devread: fsys == NULL!\n"); +#endif + return -1; + } + + if( seek_io(curfs->dev_fd, offs + curfs->offset) ) { +#ifdef CONFIG_DEBUG_FS + printk("seek failure\n"); +#endif + return -1; + } + return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0; +} + +int +file_read( void *buf, unsigned long len ) +{ + if (filepos < 0 || filepos > filemax) + filepos = filemax; + if (len > filemax-filepos) + len = filemax - filepos; + errnum = 0; + return curfs->fsys->read_func( buf, len ); +} + + +/************************************************************************/ +/* Standard package methods */ +/************************************************************************/ + +/* ( -- success? ) */ +static void +grubfs_files_open( grubfs_info_t *mi ) +{ + int fd, i; + char *path = my_args_copy(); + char *s; + + fd = open_ih( my_parent() ); + if ( fd == -1 ) { + free( path ); + RET( 0 ); + } + + mi->gfs = &dummy_fs; + + for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) { +#ifdef CONFIG_DEBUG_FS + printk("Trying %s\n", fsys_table[i].name); +#endif + if (fsys_table[i].mount_func()) { + const fsys_entry_t *fsys = &fsys_table[i]; +#ifdef CONFIG_DEBUG_FS + printk("Mounted %s\n", fsys->name); +#endif + mi->gfs = malloc(sizeof(grubfs_t)); + mi->gfs->fsys = fsys; + mi->gfs->dev_fd = fd; + mi->gfs->offset = 0; + + s = path; + while (*s) { + if(*s=='\\') *s='/'; + s++; + } +#ifdef CONFIG_DEBUG_FS + printk("Path=%s\n",path); +#endif + if (!mi->gfs->fsys->dir_func((char *) path)) { + forth_printf("File not found\n"); + RET( 0 ); + } + + mi->gfs->fd = malloc(sizeof(grubfile_t)); + mi->gfs->fd->pos = filepos; + mi->gfs->fd->len = filemax; + mi->gfs->fd->path = strdup(path); + + RET( -1 ); + } + } +#ifdef CONFIG_DEBUG_FS + printk("Unknown filesystem type\n"); +#endif + + RET( 0 ); +} + +/* ( -- ) */ +static void +grubfs_files_close( grubfs_info_t *mi ) +{ + grubfile_t *gf = mi->gfs->fd; + + if (gf->path) + free((void *)(gf->path)); + free(gf); + + filepos = 0; + filemax = 0; +} + +/* ( buf len -- actlen ) */ +static void +grubfs_files_read( grubfs_info_t *mi ) +{ + int count = POP(); + char *buf = (char *)cell2pointer(POP()); + + grubfile_t *file = mi->gfs->fd; + int ret; + + filepos = file->pos; + filemax = file->len; + + if (count > filemax - filepos) + count = filemax - filepos; + + ret = mi->gfs->fsys->read_func(buf, count); + + file->pos = filepos; + + RET( ret ); +} + +/* ( pos.d -- status ) */ +static void +grubfs_files_seek( grubfs_info_t *mi ) +{ + long long pos = DPOP(); + int offs = (int)pos; + int whence = SEEK_SET; + + grubfile_t *file = mi->gfs->fd; + unsigned long newpos; + + switch( whence ) { + case SEEK_END: + if (offs < 0 && (unsigned long) -offs > file->len) + newpos = 0; + else + newpos = file->len + offs; + break; + default: + case SEEK_SET: + newpos = (offs < 0) ? 0 : offs; + break; + } + + if (newpos > file->len) + newpos = file->len; + + file->pos = newpos; + + if (newpos) + RET( -1 ); + else + RET( 0 ); +} + +/* ( addr -- size ) */ +static void +grubfs_files_load( grubfs_info_t *mi ) +{ + char *buf = (char *)cell2pointer(POP()); + int count, ret; + + grubfile_t *file = mi->gfs->fd; + count = file->len; + + ret = mi->gfs->fsys->read_func(buf, count); + file->pos = filepos; + + RET( ret ); +} + +/* ( -- cstr ) */ +static void +grubfs_files_get_path( grubfs_info_t *mi ) +{ + grubfile_t *file = mi->gfs->fd; + const char *path = file->path; + + RET( pointer2cell(strdup(path)) ); +} + +/* ( -- cstr ) */ +static void +grubfs_files_get_fstype( grubfs_info_t *mi ) +{ + grubfs_t *gfs = mi->gfs; + + PUSH( pointer2cell(strdup(gfs->fsys->name)) ); +} + + +/* static method, ( pos.d ih -- flag? ) */ +static void +grubfs_files_probe( grubfs_info_t *dummy ) +{ + ihandle_t ih = POP_ih(); + long long offs = DPOP(); + int i; + + curfs->dev_fd = open_ih(ih); + if (curfs->dev_fd == -1) { + RET( -1 ); + } + curfs->offset = offs; + + for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) { +#ifdef CONFIG_DEBUG_FS + printk("Probing for %s\n", fsys_table[i].name); +#endif + if (fsys_table[i].mount_func()) { + RET( -1 ); + } + } + +#ifdef CONFIG_DEBUG_FS + printk("Unknown filesystem type\n"); +#endif + + close_io(curfs->dev_fd); + + RET ( 0 ); +} + +/* static method, ( pathstr len ihandle -- ) */ +static void +grubfs_files_dir( grubfs_info_t *dummy ) +{ + forth_printf("dir method not implemented for grubfs filesystem\n"); + POP(); + POP(); + POP(); +} + +static void +grubfs_initializer( grubfs_info_t *dummy ) +{ + fword("register-fs-package"); +} + +NODE_METHODS( grubfs ) = { + { "probe", grubfs_files_probe }, + { "open", grubfs_files_open }, + { "close", grubfs_files_close }, + { "read", grubfs_files_read }, + { "seek", grubfs_files_seek }, + { "load", grubfs_files_load }, + { "dir", grubfs_files_dir }, + + /* special */ + { "get-path", grubfs_files_get_path }, + { "get-fstype", grubfs_files_get_fstype }, + + { NULL, grubfs_initializer }, +}; + +void +grubfs_init( void ) +{ + REGISTER_NODE( grubfs ); +} |