📄 fs_helper.c
字号:
/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2004,2005,2006 Free Software Foundation, Inc. * Copyright 2006 Pawel Kolodziejski - adopted to linux native bootloader * * 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 2 of the License, or * (at your option) any later version. * * This program 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "types.h"#include "fs_types.h"#include "fs_ext2.h"grub_err_t grub_fshelp_find_file(const char *path, grub_fshelp_node_t rootnode, grub_fshelp_node_t *foundnode, int (*iterate_dir) (grub_fshelp_node_t dir, int NESTED_FUNC_ATTR (*hook)(const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node)), char *(*read_symlink)(grub_fshelp_node_t node), enum grub_fshelp_filetype expecttype) { grub_err_t err; enum grub_fshelp_filetype foundtype = GRUB_FSHELP_DIR; int symlinknest = 0; auto grub_err_t NESTED_FUNC_ATTR find_file(const char *currpath, grub_fshelp_node_t currroot, grub_fshelp_node_t *currfound); grub_err_t NESTED_FUNC_ATTR find_file(const char *currpath, grub_fshelp_node_t currroot, grub_fshelp_node_t *currfound) { const char fpath[1024]; const char *name = fpath; char *next; enum grub_fshelp_filetype type = GRUB_FSHELP_DIR; grub_fshelp_node_t currnode = currroot; grub_fshelp_node_t oldnode = currroot; auto int NESTED_FUNC_ATTR iterate(const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node); auto void free_node(grub_fshelp_node_t node); void free_node(grub_fshelp_node_t node) { if (node != rootnode && node != currroot) free(node); } int NESTED_FUNC_ATTR iterate(const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node) { if (type == GRUB_FSHELP_UNKNOWN || strcmp(name, filename)) { free(node); return 0; } /* The node is found, stop iterating over the nodes. */ type = filetype; oldnode = currnode; currnode = node; return 1; } strncpy((char *)fpath, currpath, strlen(currpath) + 1); /* Remove all leading slashes. */ while (*name == '/') name++; if (!*name) { *currfound = currnode; return 0; } for (;;) { int found; /* Extract the actual part from the pathname. */ next = strchr(name, '/'); if (next) { /* Remove all leading slashes. */ while(*next == '/') *(next++) = '\0'; } /* At this point it is expected that the current node is a directory, check if this is true. */ if (type != GRUB_FSHELP_DIR) { if (currnode != rootnode && currnode != currroot) free(currnode); return grub_error(GRUB_ERR_BAD_FILE_TYPE, "not a directory"); } /* Iterate over the directory. */ found = iterate_dir(currnode, iterate); if (!found) { if (grub_errno) return grub_errno; break; } /* Read in the symlink and follow it. */ if (type == GRUB_FSHELP_SYMLINK) { char *symlink; /* Test if the symlink does not loop. */ if (++symlinknest == 8) { if (currnode != rootnode && currnode != currroot) free(currnode); if (oldnode != rootnode && oldnode != currroot) free(oldnode); return grub_error(GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks"); } symlink = read_symlink(currnode); if (currnode != rootnode && currnode != currroot) free(currnode); if (!symlink) { if (oldnode != rootnode && oldnode != currroot) free(oldnode); return grub_errno; } /* The symlink is an absolute path, go back to the root inode. */ if (symlink[0] == '/') { if (oldnode != rootnode && oldnode != currroot) free(oldnode); oldnode = rootnode; } /* Lookup the node the symlink points to. */ find_file(symlink, oldnode, &currnode); type = foundtype; free(symlink); if (grub_errno) { if (oldnode != rootnode && oldnode != currroot) free(oldnode); return grub_errno; } } if (oldnode != rootnode && oldnode != currroot) free(oldnode); /* Found the node! */ if (!next || *next == '\0') { *currfound = currnode; foundtype = type; return 0; } name = next; } return grub_error(GRUB_ERR_FILE_NOT_FOUND, "file not found"); } if (!path || path[0] != '/') { grub_error(GRUB_ERR_BAD_FILENAME, "bad filename"); return grub_errno; } err = find_file(path, rootnode, foundnode); if (err) return err; /* Check if the node that was found was of the expected type. */ if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype) return grub_error(GRUB_ERR_BAD_FILE_TYPE, "not a regular file"); else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype) return grub_error(GRUB_ERR_BAD_FILE_TYPE, "not a directory"); return 0;}grub_ssize_t grub_fshelp_read_file(grub_disk_t disk, grub_fshelp_node_t node, void (*read_hook)(grub_disk_addr_t sector, unsigned offset, unsigned length), int pos, grub_size_t len, char *buf, int (*get_block)(grub_fshelp_node_t node, int block), grub_off_t filesize, int log2blocksize) { int i; int blockcnt; int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); /* Adjust len so it we can't read past the end of the file. */ if (len > filesize) len = (grub_size_t)filesize; blockcnt = ((len + pos) + blocksize - 1) / blocksize; for (i = pos / blocksize; i < blockcnt; i++) { int blknr; int blockoff = pos % blocksize; int blockend = blocksize; int skipfirst = 0; blknr = get_block(node, i); if (grub_errno) return -1; blknr = blknr << log2blocksize; /* Last block. */ if (i == blockcnt - 1) { blockend = (len + pos) % blocksize; /* The last portion is exactly blocksize. */ if (!blockend) blockend = blocksize; } /* First block. */ if (i == pos / blocksize) { skipfirst = blockoff; blockend -= skipfirst; } /* If the block number is 0 this block is not stored on disk but is zero filled instead. */ if (blknr) { disk->read_hook = read_hook; grub_disk_read(disk, blknr, skipfirst, blockend, buf); disk->read_hook = 0; if (grub_errno) return -1; } else memset(buf, blocksize - skipfirst, 0); buf += blocksize - skipfirst; } return len;}grub_file_t grub_file_open(grub_disk_t disk, const char *file_name) { grub_file_t file = (grub_file_t)malloc(sizeof(*file)); if (!file) { return 0; } file->offset = 0; file->data = 0; file->read_hook = 0; file->disk = disk; if (disk->fs_type == 0) { if (grub_ext2_open(file, file_name) != GRUB_ERR_NONE) { free(file); return 0; } } else if (disk->fs_type == 1) { if (grub_fat_open(file, file_name) != GRUB_ERR_NONE) { free(file); return 0; } } return file;}grub_ssize_t grub_file_read(grub_file_t file, char *buf, grub_size_t len) { grub_ssize_t res; if (len == 0 || len > file->size - file->offset) len = (grub_size_t)(file->size - file->offset); /* Prevent an overflow. */ if ((grub_ssize_t)len < 0) len >>= 1; if (len == 0) return 0; if (file->disk->fs_type == 0) { res = grub_ext2_read(file, buf, len); } else if (file->disk->fs_type == 1) { res = grub_fat_read(file, buf, len); } if (res > 0) file->offset += res; return res;}grub_off_t grub_file_seek(grub_file_t file, grub_off_t offset) { grub_off_t old; if (offset > file->size) { grub_error(GRUB_ERR_OUT_OF_RANGE, "attempt to seek outside of the file"); return -1; } old = file->offset; file->offset = offset; return old;}#define err_no 0xA3100300#define grub_errmsg 0xA3100304void grub_set_error(grub_err_t n) { *(unsigned long *)err_no = (unsigned long)n;}grub_err_t grub_error(grub_err_t n, const char *fmt, ...) { va_list ap; char buffer[256]; *(unsigned long *)(err_no) = (unsigned long)n; va_start(ap, fmt); vsprintf((char *)grub_errmsg, fmt, ap); va_end(ap); sprintf(buffer, "Err: %d, %s\n", (int)(*(unsigned long *)err_no), (char *)grub_errmsg); drawText(1, 28, buffer, 0, 0x003f); mdelay(2000); return n;}grub_err_t grub_get_error() { return *(unsigned long *)err_no;}void grub_debug(const char *fmt, ...) { va_list ap; char buffer[256]; va_start(ap, fmt); vsprintf((char *)buffer, fmt, ap); va_end(ap); drawText(1, 27, buffer, 0, 0x003f); mdelay(2000);}/* Convert UTF-16 to UTF-8. */grub_uint8_t *grub_utf16_to_utf8(grub_uint8_t *dest, grub_uint16_t *src, grub_size_t size) { grub_uint32_t code_high = 0; while (size--) { grub_uint32_t code = *src++; if (code_high) { if (code >= 0xDC00 && code <= 0xDFFF) { /* Surrogate pair. */ code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000; *dest++ = (code >> 18) | 0xF0; *dest++ = ((code >> 12) & 0x3F) | 0x80; *dest++ = ((code >> 6) & 0x3F) | 0x80; *dest++ = (code & 0x3F) | 0x80; } else { /* Error... */ *dest++ = '?'; } code_high = 0; } else { if (code <= 0x007F) *dest++ = code; else if (code <= 0x07FF) { *dest++ = (code >> 6) | 0xC0; *dest++ = (code & 0x3F) | 0x80; } else if (code >= 0xD800 && code <= 0xDBFF) { code_high = code; continue; } else if (code >= 0xDC00 && code <= 0xDFFF) { /* Error... */ *dest++ = '?'; } else { *dest++ = (code >> 16) | 0xE0; *dest++ = ((code >> 12) & 0x3F) | 0x80; *dest++ = (code & 0x3F) | 0x80; } } } return dest;}void grub_file_close(grub_file_t file) { if (file->disk->fs_type == 0) { grub_ext2_close(file); } else if (file->disk->fs_type == 1) { grub_fat_close(file); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -