/* loadfile.c - file loading module
* Copyright (C) 2011 Pierre-Nicolas Clauss
*
* Loadfile is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* Loadfile is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Loadfile. If not, see .
*/
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2007 Free Software Foundation, Inc.
* Copyright (C) 2003 NIIBE Yutaka
*
* GRUB 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, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
GRUB_MOD_LICENSE("GPLv3");
static struct grub_relocator* rel;
static grub_extcmd_t cmd;
static const struct grub_arg_option options[] = {
{"skip", 's', 0, N_("Skip offset bytes from file."), 0, ARG_TYPE_INT},
{0, 0, 0, 0, 0, 0}
};
static grub_err_t
grub_cmd_loadfile(grub_extcmd_context_t ctxt, int argc, char** argv) {
struct grub_arg_list* state = ctxt->state;
grub_file_t file;
grub_relocator_chunk_t chunk;
char* dest;
grub_off_t skip, size;
grub_ssize_t done;
if(argc != 2) {
return grub_error(GRUB_ERR_BAD_ARGUMENT,
"file name and memory address required");
}
skip = (grub_off_t)(state[0].set ? grub_strtoull(state[0].arg, 0, 0) : 0);
file = grub_file_open(argv[0]);
if(!file) {
return grub_errno;
}
size = grub_file_size(file);
if(size == GRUB_FILE_SIZE_UNKNOWN) {
return grub_error(GRUB_ERR_FILE_READ_ERROR,
"could not determine size of %s", argv[0]);
}
if(skip >= size) {
return grub_error(GRUB_ERR_BAD_ARGUMENT,
"cannot skip %llu bytes, file is only %llu", skip, size);
}
if(grub_relocator_alloc_chunk_addr(rel, &chunk,
(grub_phys_addr_t)grub_strtoull(argv[1], 0, 0), size)) {
return grub_errno;
}
dest = get_virtual_current_address(chunk);
if(skip > 0) {
grub_printf("Skipping %llu bytes from %s...\n", skip, argv[0]);
size -= skip;
if(grub_file_seekable(file)) {
grub_file_seek(file, skip);
} else while(skip > 0 && (done = grub_file_read(file, dest, skip)) > 0) {
skip -= done;
}
}
grub_printf("Loading %llu bytes from %s to %p...\n", size, argv[0], dest);
while(size > 0 && (done = grub_file_read(file, dest, size)) > 0) {
dest += done;
size -= done;
}
grub_file_close(file);
if(size > 0) {
return grub_error(GRUB_ERR_FILE_READ_ERROR,
"early stop while reading %s: %llu bytes missing",
argv[0], size);
}
return 0;
}
GRUB_MOD_INIT(loadfile) {
rel = grub_relocator_new();
cmd = grub_register_extcmd("loadfile", grub_cmd_loadfile, 0,
N_("[OPTIONS] FILE ADDR"),
N_("Load a file to memory."), options);
}
GRUB_MOD_FINI(loadfile) {
grub_unregister_extcmd(cmd);
grub_relocator_unload(rel);
}