]>
Commit | Line | Data |
---|---|---|
6a161fa9 | 1 | /* file.c - file I/O functions */ |
2 | /* | |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
5a79f472 | 4 | * Copyright (C) 2002,2006,2007 Free Software Foundation, Inc. |
6a161fa9 | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
6a161fa9 | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
6a161fa9 | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
6a161fa9 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
6a161fa9 | 18 | */ |
19 | ||
4b13b216 | 20 | #include <grub/misc.h> |
21 | #include <grub/err.h> | |
22 | #include <grub/file.h> | |
23 | #include <grub/mm.h> | |
24 | #include <grub/fs.h> | |
25 | #include <grub/device.h> | |
6a161fa9 | 26 | |
27 | /* Get the device part of the filename NAME. It is enclosed by parentheses. */ | |
28 | char * | |
4b13b216 | 29 | grub_file_get_device_name (const char *name) |
6a161fa9 | 30 | { |
31 | if (name[0] == '(') | |
32 | { | |
4b13b216 | 33 | char *p = grub_strchr (name, ')'); |
6a161fa9 | 34 | char *ret; |
35 | ||
36 | if (! p) | |
37 | { | |
4b13b216 | 38 | grub_error (GRUB_ERR_BAD_FILENAME, "missing `)'"); |
6a161fa9 | 39 | return 0; |
40 | } | |
41 | ||
4b13b216 | 42 | ret = (char *) grub_malloc (p - name); |
6a161fa9 | 43 | if (! ret) |
44 | return 0; | |
45 | ||
4b13b216 | 46 | grub_memcpy (ret, name + 1, p - name - 1); |
6a161fa9 | 47 | ret[p - name - 1] = '\0'; |
48 | return ret; | |
49 | } | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
4b13b216 | 54 | grub_file_t |
55 | grub_file_open (const char *name) | |
6a161fa9 | 56 | { |
4b13b216 | 57 | grub_device_t device; |
58 | grub_file_t file = 0; | |
6a161fa9 | 59 | char *device_name; |
60 | char *file_name; | |
61 | ||
4b13b216 | 62 | device_name = grub_file_get_device_name (name); |
63 | if (grub_errno) | |
6a161fa9 | 64 | return 0; |
65 | ||
66 | /* Get the file part of NAME. */ | |
4b13b216 | 67 | file_name = grub_strchr (name, ')'); |
6a161fa9 | 68 | if (file_name) |
69 | file_name++; | |
70 | else | |
71 | file_name = (char *) name; | |
72 | ||
4b13b216 | 73 | device = grub_device_open (device_name); |
74 | grub_free (device_name); | |
6a161fa9 | 75 | if (! device) |
76 | goto fail; | |
77 | ||
4b13b216 | 78 | file = (grub_file_t) grub_malloc (sizeof (*file)); |
6a161fa9 | 79 | if (! file) |
80 | goto fail; | |
81 | ||
82 | file->device = device; | |
83 | file->offset = 0; | |
84 | file->data = 0; | |
85 | file->read_hook = 0; | |
86 | ||
87 | if (device->disk && file_name[0] != '/') | |
88 | /* This is a block list. */ | |
4b13b216 | 89 | file->fs = &grub_fs_blocklist; |
6a161fa9 | 90 | else |
91 | { | |
4b13b216 | 92 | file->fs = grub_fs_probe (device); |
6a161fa9 | 93 | if (! file->fs) |
94 | goto fail; | |
95 | } | |
96 | ||
4b13b216 | 97 | if ((file->fs->open) (file, file_name) != GRUB_ERR_NONE) |
6a161fa9 | 98 | goto fail; |
99 | ||
100 | return file; | |
101 | ||
102 | fail: | |
103 | if (device) | |
4b13b216 | 104 | grub_device_close (device); |
6a161fa9 | 105 | |
4b13b216 | 106 | /* if (net) grub_net_close (net); */ |
6a161fa9 | 107 | |
4b13b216 | 108 | grub_free (file); |
6a161fa9 | 109 | |
110 | return 0; | |
111 | } | |
112 | ||
4b13b216 | 113 | grub_ssize_t |
524a1e6a | 114 | grub_file_read (grub_file_t file, char *buf, grub_size_t len) |
6a161fa9 | 115 | { |
4b13b216 | 116 | grub_ssize_t res; |
6a161fa9 | 117 | |
118 | if (len == 0 || len > file->size - file->offset) | |
119 | len = file->size - file->offset; | |
120 | ||
524a1e6a | 121 | /* Prevent an overflow. */ |
122 | if ((grub_ssize_t) len < 0) | |
123 | len >>= 1; | |
124 | ||
6a161fa9 | 125 | if (len == 0) |
126 | return 0; | |
127 | ||
128 | res = (file->fs->read) (file, buf, len); | |
129 | if (res > 0) | |
130 | file->offset += res; | |
131 | ||
132 | return res; | |
133 | } | |
134 | ||
4b13b216 | 135 | grub_err_t |
136 | grub_file_close (grub_file_t file) | |
6a161fa9 | 137 | { |
138 | if (file->fs->close) | |
139 | (file->fs->close) (file); | |
140 | ||
d9864ee1 | 141 | if (file->device) |
142 | grub_device_close (file->device); | |
4b13b216 | 143 | grub_free (file); |
144 | return grub_errno; | |
6a161fa9 | 145 | } |
146 | ||
524a1e6a | 147 | grub_off_t |
148 | grub_file_seek (grub_file_t file, grub_off_t offset) | |
6a161fa9 | 149 | { |
524a1e6a | 150 | grub_off_t old; |
6a161fa9 | 151 | |
524a1e6a | 152 | if (offset > file->size) |
6a161fa9 | 153 | { |
4b13b216 | 154 | grub_error (GRUB_ERR_OUT_OF_RANGE, |
6a161fa9 | 155 | "attempt to seek outside of the file"); |
156 | return -1; | |
157 | } | |
158 | ||
159 | old = file->offset; | |
160 | file->offset = offset; | |
161 | return old; | |
162 | } |