]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
add support for UnionTechOS fuyu (#864)
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / kern / file.c
1 /* file.c - file I/O functions */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2006,2007,2009 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
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
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/misc.h>
21 #include <grub/err.h>
22 #include <grub/file.h>
23 #include <grub/net.h>
24 #include <grub/mm.h>
25 #include <grub/fs.h>
26 #include <grub/device.h>
27 #include <grub/i18n.h>
28
29 void (*EXPORT_VAR (grub_grubnet_fini)) (void);
30
31 grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX];
32
33 /* Get the device part of the filename NAME. It is enclosed by parentheses. */
34 char *
35 grub_file_get_device_name (const char *name)
36 {
37 if (name[0] == '(')
38 {
39 char *p = grub_strchr (name, ')');
40 char *ret;
41
42 if (! p)
43 {
44 grub_error (GRUB_ERR_BAD_FILENAME, N_("missing `%c' symbol"), ')');
45 return 0;
46 }
47
48 ret = (char *) grub_malloc (p - name);
49 if (! ret)
50 return 0;
51
52 grub_memcpy (ret, name + 1, p - name - 1);
53 ret[p - name - 1] = '\0';
54 return ret;
55 }
56
57 return 0;
58 }
59
60 /* Support mem:xxx:size:xxx format in chainloader */
61 grub_file_t grub_memfile_open(const char *name);
62 #define GRUB_MEMFILE_MEM "mem:"
63 #define GRUB_MEMFILE_SIZE "size:"
64
65 grub_file_t grub_memfile_open(const char *name)
66 {
67 char *size = NULL;
68 grub_file_t file = 0;
69
70 file = (grub_file_t)grub_zalloc(sizeof(*file));
71 if (NULL == file)
72 {
73 return 0;
74 }
75
76 file->name = grub_strdup(name);
77 file->data = (void *)grub_strtoul(name + grub_strlen(GRUB_MEMFILE_MEM), NULL, 0);
78
79 size = grub_strstr(name, GRUB_MEMFILE_SIZE);
80 file->size = (grub_off_t)grub_strtoul(size + grub_strlen(GRUB_MEMFILE_SIZE), NULL, 0);
81
82 grub_errno = GRUB_ERR_NONE;
83 return file;
84 }
85
86 int ventoy_check_file_exist(const char * fmt, ...)
87 {
88 va_list ap;
89 grub_file_t file;
90 char fullpath[256] = {0};
91
92 va_start (ap, fmt);
93 grub_vsnprintf(fullpath, 255, fmt, ap);
94 va_end (ap);
95
96 file = grub_file_open(fullpath, GRUB_FILE_TYPE_NONE);
97 if (!file)
98 {
99 grub_errno = 0;
100 return 0;
101 }
102 else
103 {
104 grub_file_close(file);
105 return 1;
106 }
107 }
108
109 grub_file_t
110 grub_file_open (const char *name, enum grub_file_type type)
111 {
112 grub_device_t device = 0;
113 grub_file_t file = 0, last_file = 0;
114 char *device_name;
115 const char *file_name;
116 grub_file_filter_id_t filter;
117
118 /* <DESC> : mem:xxx:size:xxx format in chainloader */
119 if (grub_strncmp(name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
120 return grub_memfile_open(name);
121 }
122
123 device_name = grub_file_get_device_name (name);
124 if (grub_errno)
125 goto fail;
126
127 /* Get the file part of NAME. */
128 file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
129 if (file_name)
130 file_name++;
131 else
132 file_name = name;
133
134 device = grub_device_open (device_name);
135 grub_free (device_name);
136 if (! device)
137 goto fail;
138
139 file = (grub_file_t) grub_zalloc (sizeof (*file));
140 if (! file)
141 goto fail;
142
143 file->device = device;
144
145 /* In case of relative pathnames and non-Unix systems (like Windows)
146 * name of host files may not start with `/'. Blocklists for host files
147 * are meaningless as well (for a start, host disk does not allow any direct
148 * access - it is just a marker). So skip host disk in this case.
149 */
150 if (device->disk && file_name[0] != '/'
151 #if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU)
152 && grub_strcmp (device->disk->name, "host")
153 #endif
154 )
155 /* This is a block list. */
156 file->fs = &grub_fs_blocklist;
157 else
158 {
159 file->fs = grub_fs_probe (device);
160 if (! file->fs)
161 goto fail;
162 }
163
164 if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
165 goto fail;
166
167 file->name = grub_strdup (name);
168 grub_errno = GRUB_ERR_NONE;
169
170 for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters);
171 filter++)
172 if (grub_file_filters[filter])
173 {
174 last_file = file;
175 file = grub_file_filters[filter] (file, type);
176 if (file && file != last_file)
177 {
178 file->name = grub_strdup (name);
179 grub_errno = GRUB_ERR_NONE;
180 }
181 }
182 if (!file)
183 grub_file_close (last_file);
184
185 return file;
186
187 fail:
188 if (device)
189 grub_device_close (device);
190
191 /* if (net) grub_net_close (net); */
192
193 grub_free (file);
194
195 return 0;
196 }
197
198 grub_disk_read_hook_t grub_file_progress_hook;
199
200 grub_ssize_t
201 grub_file_read (grub_file_t file, void *buf, grub_size_t len)
202 {
203 grub_ssize_t res;
204 grub_disk_read_hook_t read_hook;
205 void *read_hook_data;
206
207 if (file->offset > file->size)
208 {
209 grub_error (GRUB_ERR_OUT_OF_RANGE,
210 N_("attempt to read past the end of file"));
211 return -1;
212 }
213
214 if (len == 0)
215 return 0;
216
217 if (len > file->size - file->offset)
218 len = file->size - file->offset;
219
220 /* Prevent an overflow. */
221 if ((grub_ssize_t) len < 0)
222 len >>= 1;
223
224 if (len == 0)
225 return 0;
226
227 if (grub_strncmp(file->name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
228 grub_memcpy(buf, (grub_uint8_t *)(file->data) + file->offset, len);
229 file->offset += len;
230 return len;
231 }
232
233 read_hook = file->read_hook;
234 read_hook_data = file->read_hook_data;
235 if (!file->read_hook)
236 {
237 file->read_hook = grub_file_progress_hook;
238 file->read_hook_data = file;
239 file->progress_offset = file->offset;
240 }
241 res = (file->fs->fs_read) (file, buf, len);
242 file->read_hook = read_hook;
243 file->read_hook_data = read_hook_data;
244 if (res > 0)
245 file->offset += res;
246
247 return res;
248 }
249
250 grub_err_t
251 grub_file_close (grub_file_t file)
252 {
253 if (file->fs && file->fs->fs_close)
254 (file->fs->fs_close) (file);
255
256 if (file->device)
257 grub_device_close (file->device);
258 grub_free (file->name);
259 grub_free (file);
260 return grub_errno;
261 }
262
263 grub_off_t
264 grub_file_seek (grub_file_t file, grub_off_t offset)
265 {
266 grub_off_t old;
267
268 if (offset > file->size)
269 {
270 grub_error (GRUB_ERR_OUT_OF_RANGE,
271 N_("attempt to seek outside of the file"));
272 return -1;
273 }
274
275 old = file->offset;
276 file->offset = offset;
277
278 return old;
279 }