]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
1.1.01
[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 if (vlnk)
204 *vlnk = 1;
205 return g_vtoy_vlnk.dst;
206 }
207
208 while (node)
209 {
210 if (node->srclen == len && grub_strcmp(name, node->src) == 0)
211 {
212 if (vlnk)
213 *vlnk = 1;
214 return node->dst;
215 }
216 node = node->next;
217 }
218
219 return name;
220 }
221
222 grub_file_t
223 grub_file_open (const char *name, enum grub_file_type type)
224 {
225 int vlnk = 0;
226 grub_device_t device = 0;
227 grub_file_t file = 0, last_file = 0;
228 char *device_name;
229 const char *file_name;
230 grub_file_filter_id_t filter;
231
232 /* <DESC> : mem:xxx:size:xxx format in chainloader grub_strlen(GRUB_MEMFILE_MEM) */
233 if (grub_strncmp(name, GRUB_MEMFILE_MEM, 4) == 0) {
234 return grub_memfile_open(name);
235 }
236
237 if ((g_vlnk_list || g_vtoy_vlnk.srclen) && (type & GRUB_FILE_TYPE_NO_VLNK) == 0)
238 name = grub_file_get_vlnk(name, &vlnk);
239
240 device_name = grub_file_get_device_name (name);
241 if (grub_errno)
242 goto fail;
243
244 /* Get the file part of NAME. */
245 file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
246 if (file_name)
247 file_name++;
248 else
249 file_name = name;
250
251 device = grub_device_open (device_name);
252 grub_free (device_name);
253 if (! device)
254 goto fail;
255
256 file = (grub_file_t) grub_zalloc (sizeof (*file));
257 if (! file)
258 goto fail;
259
260 file->device = device;
261 file->vlnk = vlnk;
262
263 /* In case of relative pathnames and non-Unix systems (like Windows)
264 * name of host files may not start with `/'. Blocklists for host files
265 * are meaningless as well (for a start, host disk does not allow any direct
266 * access - it is just a marker). So skip host disk in this case.
267 */
268 if (device->disk && file_name[0] != '/'
269 #if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU)
270 && grub_strcmp (device->disk->name, "host")
271 #endif
272 )
273 /* This is a block list. */
274 file->fs = &grub_fs_blocklist;
275 else
276 {
277 file->fs = grub_fs_probe (device);
278 if (! file->fs)
279 goto fail;
280 }
281
282 if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
283 goto fail;
284
285 file->name = grub_strdup (name);
286 grub_errno = GRUB_ERR_NONE;
287
288 for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters);
289 filter++)
290 if (grub_file_filters[filter])
291 {
292 last_file = file;
293 file = grub_file_filters[filter] (file, type);
294 if (file && file != last_file)
295 {
296 file->name = grub_strdup (name);
297 grub_errno = GRUB_ERR_NONE;
298 }
299 }
300 if (!file)
301 grub_file_close (last_file);
302
303 return file;
304
305 fail:
306 if (device)
307 grub_device_close (device);
308
309 /* if (net) grub_net_close (net); */
310
311 grub_free (file);
312
313 return 0;
314 }
315
316 grub_disk_read_hook_t grub_file_progress_hook;
317
318 grub_ssize_t
319 grub_file_read (grub_file_t file, void *buf, grub_size_t len)
320 {
321 grub_ssize_t res;
322 grub_disk_read_hook_t read_hook;
323 void *read_hook_data;
324
325 if (file->offset > file->size)
326 {
327 grub_error (GRUB_ERR_OUT_OF_RANGE,
328 N_("attempt to read past the end of file"));
329 return -1;
330 }
331
332 if (len == 0)
333 return 0;
334
335 if (len > file->size - file->offset)
336 len = file->size - file->offset;
337
338 /* Prevent an overflow. */
339 if ((grub_ssize_t) len < 0)
340 len >>= 1;
341
342 if (len == 0)
343 return 0;
344
345 if (file->name) {
346 if (grub_strncmp(file->name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
347 grub_memcpy(buf, (grub_uint8_t *)(file->data) + file->offset, len);
348 file->offset += len;
349 return len;
350 }
351 }
352
353 read_hook = file->read_hook;
354 read_hook_data = file->read_hook_data;
355 if (!file->read_hook)
356 {
357 file->read_hook = grub_file_progress_hook;
358 file->read_hook_data = file;
359 file->progress_offset = file->offset;
360 }
361 res = (file->fs->fs_read) (file, buf, len);
362 file->read_hook = read_hook;
363 file->read_hook_data = read_hook_data;
364 if (res > 0)
365 file->offset += res;
366
367 return res;
368 }
369
370 grub_err_t
371 grub_file_close (grub_file_t file)
372 {
373 if (file->fs && file->fs->fs_close)
374 (file->fs->fs_close) (file);
375
376 if (file->device)
377 grub_device_close (file->device);
378 grub_free (file->name);
379 grub_free (file);
380 return grub_errno;
381 }
382
383 grub_off_t
384 grub_file_seek (grub_file_t file, grub_off_t offset)
385 {
386 grub_off_t old;
387
388 if (offset > file->size)
389 {
390 grub_error (GRUB_ERR_OUT_OF_RANGE,
391 N_("attempt to seek outside of the file"));
392 return -1;
393 }
394
395 old = file->offset;
396 file->offset = offset;
397
398 return old;
399 }