/* * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef __sun__ #define _XOPEN_SOURCE 500 #endif #include #include #include #include "fsimage_grub.h" #include "fsimage_priv.h" static char *disk_read_junk; typedef struct fsig_data { char fd_buf[FSYS_BUFLEN]; } fsig_data_t; typedef struct fsig_file_data { char ffd_buf[FSYS_BUFLEN]; uint64_t ffd_curpos; uint64_t ffd_filepos; uint64_t ffd_filemax; int ffd_int1; int ffd_int2; int ffd_errnum; } fsig_file_data_t; fsi_file_t * fsig_file_alloc(fsi_t *fsi) { fsi_file_t *ffi; fsig_file_data_t *data = malloc(sizeof (fsig_file_data_t)); if (data == NULL) return (NULL); bzero(data, sizeof (fsig_file_data_t)); bcopy(fsig_fs_buf(fsi), data->ffd_buf, FSYS_BUFLEN); if ((ffi = fsip_file_alloc(fsi, data)) == NULL) { free(data); return (NULL); } return (ffi); } void * fsig_fs_buf(fsi_t *fsi) { fsig_data_t *data = fsip_fs_data(fsi); return ((void *)data->fd_buf); } void * fsig_file_buf(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return ((void *)data->ffd_buf); } uint64_t * fsig_filepos(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return (&data->ffd_filepos); } uint64_t * fsig_filemax(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return (&data->ffd_filemax); } int * fsig_int1(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return (&data->ffd_int1); } int * fsig_int2(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return (&data->ffd_int2); } int * fsig_errnum(fsi_file_t *ffi) { fsig_file_data_t *data = fsip_file_data(ffi); return (&data->ffd_errnum); } char ** fsig_disk_read_junk(void) { return (&disk_read_junk); } int fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset, unsigned int bufsize, char *buf) { uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)sector * 512) + offset; ssize_t bytes_read = 0; while (bufsize) { ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read, bufsize, (off_t)off); if (ret == -1) return (0); if (ret == 0) return (0); bytes_read += ret; bufsize -= ret; } return (1); } int fsig_substring(const char *s1, const char *s2) { while (*s1 == *s2) { if (*s1 == '\0') return (0); s1++; s2++; } if (*s1 == '\0') return (-1); return (1); } static int fsig_mount(fsi_t *fsi, const char *path) { fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data; fsi_file_t *ffi; fsi->f_data = malloc(sizeof (fsig_data_t)); if (fsi->f_data == NULL) return (-1); if ((ffi = fsig_file_alloc(fsi)) == NULL) { free(fsi->f_data); fsi->f_data = NULL; return (-1); } bzero(fsi->f_data, sizeof (fsig_data_t)); if (!ops->fpo_mount(ffi)) { fsip_file_free(ffi); free(fsi->f_data); fsi->f_data = NULL; return (-1); } bcopy(fsig_file_buf(ffi), fsig_fs_buf(fsi), FSYS_BUFLEN); fsip_file_free(ffi); return (0); } static int fsig_umount(fsi_t *fsi) { return (0); } static fsi_file_t * fsig_open(fsi_t *fsi, const char *name) { fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data; char *path = strdup(name); fsi_file_t *ffi = NULL; if (path == NULL || (ffi = fsig_file_alloc(fsi)) == NULL) goto out; if (ops->fpo_dir(ffi, path) == 0) { fsip_file_free(ffi); ffi = NULL; errno = ENOENT; } out: free(path); return (ffi); } static ssize_t fsig_pread(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off) { fsig_plugin_ops_t *ops = ffi->ff_fsi->f_plugin->fp_data; fsig_file_data_t *data = fsip_file_data(ffi); data->ffd_filepos = off; if (data->ffd_filepos >= data->ffd_filemax) return (0); /* FIXME: check */ if (data->ffd_filepos + nbytes > data->ffd_filemax) nbytes = data->ffd_filemax - data->ffd_filepos; errnum = 0; return (ops->fpo_read(ffi, buf, nbytes)); } static ssize_t fsig_read(fsi_file_t *ffi, void *buf, size_t nbytes) { fsig_file_data_t *data = fsip_file_data(ffi); ssize_t ret; ret = fsig_pread(ffi, buf, nbytes, data->ffd_curpos); data->ffd_curpos = data->ffd_filepos; return (ret); } static int fsig_close(fsi_file_t *ffi) { fsip_file_free(ffi); return (0); } static fsi_plugin_ops_t fsig_grub_ops = { .fpo_version = FSIMAGE_PLUGIN_VERSION, .fpo_mount = fsig_mount, .fpo_umount = fsig_umount, .fpo_open = fsig_open, .fpo_read = fsig_read, .fpo_pread = fsig_pread, .fpo_close = fsig_close }; fsi_plugin_ops_t * fsig_init(fsi_plugin_t *plugin, fsig_plugin_ops_t *ops) { if (ops->fpo_version > FSIMAGE_PLUGIN_VERSION) return (NULL); plugin->fp_data = ops; return (&fsig_grub_ops); }