]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
keep up with 1.0.67 (#1464)
[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 typedef struct grub_vlnk
110 {
111 int srclen;
112 char src[512];
113 char dst[512];
114 struct grub_vlnk *next;
115 }grub_vlnk;
116
117 static grub_vlnk g_vtoy_vlnk;
118 static grub_vlnk *g_vlnk_list;
119
120 int grub_file_is_vlnk_suffix(const char *name, int len)
121 {
122 grub_uint32_t suffix;
123
124 if (len > 9)
125 {
126 suffix = *(grub_uint32_t *)(name + len - 4);
127 if (grub_strncmp(name + len - 9, ".vlnk.", 6) == 0)
128 {
129 /* .iso .wim .img .vhd .efi .dat */
130 if (suffix == 0x6F73692E || suffix == 0x6D69772E ||
131 suffix == 0x676D692E || suffix == 0x6468762E ||
132 suffix == 0x6966652E || suffix == 0x7461642E)
133 {
134 return 1;
135 }
136 }
137 else if (len > 10 && grub_strncmp(name + len - 10, ".vlnk.", 6) == 0)
138 {
139 /* vhdx vtoy */
140 if (suffix == 0x78646876 || suffix == 0x796F7476)
141 {
142 return 1;
143 }
144 }
145 }
146
147 return 0;
148 }
149
150 int grub_file_vtoy_vlnk(const char *src, const char *dst)
151 {
152 if (src)
153 {
154 g_vtoy_vlnk.srclen = (int)grub_strlen(src);
155 grub_strncpy(g_vtoy_vlnk.src, src, sizeof(g_vtoy_vlnk.src) - 1);
156 grub_strncpy(g_vtoy_vlnk.dst, dst, sizeof(g_vtoy_vlnk.dst) - 1);
157 }
158 else
159 {
160 g_vtoy_vlnk.srclen = 0;
161 g_vtoy_vlnk.src[0] = 0;
162 g_vtoy_vlnk.dst[0] = 0;
163 }
164 return 0;
165 }
166
167 int grub_file_add_vlnk(const char *src, const char *dst)
168 {
169 grub_vlnk *node = NULL;
170
171 if (src && dst)
172 {
173 node = grub_zalloc(sizeof(grub_vlnk));
174 if (node)
175 {
176 node->srclen = (int)grub_strlen(src);
177 grub_strncpy(node->src, src, sizeof(node->src) - 1);
178 grub_strncpy(node->dst, dst, sizeof(node->dst) - 1);
179
180 node->next = g_vlnk_list;
181 g_vlnk_list = node;
182 return 0;
183 }
184 }
185
186 return 1;
187 }
188
189 const char *grub_file_get_vlnk(const char *name, int *vlnk)
190 {
191 int len;
192 grub_vlnk *node = g_vlnk_list;
193
194 len = grub_strlen(name);
195
196 if (!grub_file_is_vlnk_suffix(name, len))
197 {
198 return name;
199 }
200
201 if (len == g_vtoy_vlnk.srclen && grub_strcmp(name, g_vtoy_vlnk.src) == 0)
202 {
203 *vlnk = 1;
204 return g_vtoy_vlnk.dst;
205 }
206
207 while (node)
208 {
209 if (node->srclen == len && grub_strcmp(name, node->src) == 0)
210 {
211 *vlnk = 1;
212 return node->dst;
213 }
214 node = node->next;
215 }
216
217 return name;
218 }
219
220 grub_file_t
221 grub_file_open (const char *name, enum grub_file_type type)
222 {
223 int vlnk = 0;
224 grub_device_t device = 0;
225 grub_file_t file = 0, last_file = 0;
226 char *device_name;
227 const char *file_name;
228 grub_file_filter_id_t filter;
229
230 /* <DESC> : mem:xxx:size:xxx format in chainloader grub_strlen(GRUB_MEMFILE_MEM) */
231 if (grub_strncmp(name, GRUB_MEMFILE_MEM, 4) == 0) {
232 return grub_memfile_open(name);
233 }
234
235 if ((g_vlnk_list || g_vtoy_vlnk.srclen) && (type & GRUB_FILE_TYPE_NO_VLNK) == 0)
236 name = grub_file_get_vlnk(name, &vlnk);
237
238 device_name = grub_file_get_device_name (name);
239 if (grub_errno)
240 goto fail;
241
242 /* Get the file part of NAME. */
243 file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
244 if (file_name)
245 file_name++;
246 else
247 file_name = name;
248
249 device = grub_device_open (device_name);
250 grub_free (device_name);
251 if (! device)
252 goto fail;
253
254 file = (grub_file_t) grub_zalloc (sizeof (*file));
255 if (! file)
256 goto fail;
257
258 file->device = device;
259 file->vlnk = vlnk;
260
261 /* In case of relative pathnames and non-Unix systems (like Windows)
262 * name of host files may not start with `/'. Blocklists for host files
263 * are meaningless as well (for a start, host disk does not allow any direct
264 * access - it is just a marker). So skip host disk in this case.
265 */
266 if (device->disk && file_name[0] != '/'
267 #if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU)
268 && grub_strcmp (device->disk->name, "host")
269 #endif
270 )
271 /* This is a block list. */
272 file->fs = &grub_fs_blocklist;
273 else
274 {
275 file->fs = grub_fs_probe (device);
276 if (! file->fs)
277 goto fail;
278 }
279
280 if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
281 goto fail;
282
283 file->name = grub_strdup (name);
284 grub_errno = GRUB_ERR_NONE;
285
286 for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters);
287 filter++)
288 if (grub_file_filters[filter])
289 {
290 last_file = file;
291 file = grub_file_filters[filter] (file, type);
292 if (file && file != last_file)
293 {
294 file->name = grub_strdup (name);
295 grub_errno = GRUB_ERR_NONE;
296 }
297 }
298 if (!file)
299 grub_file_close (last_file);
300
301 return file;
302
303 fail:
304 if (device)
305 grub_device_close (device);
306
307 /* if (net) grub_net_close (net); */
308
309 grub_free (file);
310
311 return 0;
312 }
313
314 grub_disk_read_hook_t grub_file_progress_hook;
315
316 grub_ssize_t
317 grub_file_read (grub_file_t file, void *buf, grub_size_t len)
318 {
319 grub_ssize_t res;
320 grub_disk_read_hook_t read_hook;
321 void *read_hook_data;
322
323 if (file->offset > file->size)
324 {
325 grub_error (GRUB_ERR_OUT_OF_RANGE,
326 N_("attempt to read past the end of file"));
327 return -1;
328 }
329
330 if (len == 0)
331 return 0;
332
333 if (len > file->size - file->offset)
334 len = file->size - file->offset;
335
336 /* Prevent an overflow. */
337 if ((grub_ssize_t) len < 0)
338 len >>= 1;
339
340 if (len == 0)
341 return 0;
342
343 if (grub_strncmp(file->name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
344 grub_memcpy(buf, (grub_uint8_t *)(file->data) + file->offset, len);
345 file->offset += len;
346 return len;
347 }
348
349 read_hook = file->read_hook;
350 read_hook_data = file->read_hook_data;
351 if (!file->read_hook)
352 {
353 file->read_hook = grub_file_progress_hook;
354 file->read_hook_data = file;
355 file->progress_offset = file->offset;
356 }
357 res = (file->fs->fs_read) (file, buf, len);
358 file->read_hook = read_hook;
359 file->read_hook_data = read_hook_data;
360 if (res > 0)
361 file->offset += res;
362
363 return res;
364 }
365
366 grub_err_t
367 grub_file_close (grub_file_t file)
368 {
369 if (file->fs && file->fs->fs_close)
370 (file->fs->fs_close) (file);
371
372 if (file->device)
373 grub_device_close (file->device);
374 grub_free (file->name);
375 grub_free (file);
376 return grub_errno;
377 }
378
379 grub_off_t
380 grub_file_seek (grub_file_t file, grub_off_t offset)
381 {
382 grub_off_t old;
383
384 if (offset > file->size)
385 {
386 grub_error (GRUB_ERR_OUT_OF_RANGE,
387 N_("attempt to seek outside of the file"));
388 return -1;
389 }
390
391 old = file->offset;
392 file->offset = offset;
393
394 return old;
395 }