1 /* file.c - file I/O functions */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2006,2007,2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/misc.h>
22 #include <grub/file.h>
26 #include <grub/device.h>
27 #include <grub/i18n.h>
29 void (*EXPORT_VAR (grub_grubnet_fini
)) (void);
31 grub_file_filter_t grub_file_filters
[GRUB_FILE_FILTER_MAX
];
33 /* Get the device part of the filename NAME. It is enclosed by parentheses. */
35 grub_file_get_device_name (const char *name
)
39 char *p
= grub_strchr (name
, ')');
44 grub_error (GRUB_ERR_BAD_FILENAME
, N_("missing `%c' symbol"), ')');
48 ret
= (char *) grub_malloc (p
- name
);
52 grub_memcpy (ret
, name
+ 1, p
- name
- 1);
53 ret
[p
- name
- 1] = '\0';
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:"
65 grub_file_t
grub_memfile_open(const char *name
)
70 file
= (grub_file_t
)grub_zalloc(sizeof(*file
));
76 file
->name
= grub_strdup(name
);
77 file
->data
= (void *)grub_strtoul(name
+ grub_strlen(GRUB_MEMFILE_MEM
), NULL
, 0);
79 size
= grub_strstr(name
, GRUB_MEMFILE_SIZE
);
80 file
->size
= (grub_off_t
)grub_strtoul(size
+ grub_strlen(GRUB_MEMFILE_SIZE
), NULL
, 0);
82 grub_errno
= GRUB_ERR_NONE
;
86 int ventoy_check_file_exist(const char * fmt
, ...)
90 char fullpath
[256] = {0};
93 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
96 file
= grub_file_open(fullpath
, GRUB_FILE_TYPE_NONE
);
104 grub_file_close(file
);
109 typedef struct grub_vlnk
114 struct grub_vlnk
*next
;
117 static grub_vlnk g_vtoy_vlnk
;
118 static grub_vlnk
*g_vlnk_list
;
120 int grub_file_is_vlnk_suffix(const char *name
, int len
)
122 grub_uint32_t suffix
;
126 suffix
= *(grub_uint32_t
*)(name
+ len
- 4);
127 if (grub_strncmp(name
+ len
- 9, ".vlnk.", 6) == 0)
129 /* .iso .wim .img .vhd .efi .dat */
130 if (suffix
== 0x6F73692E || suffix
== 0x6D69772E ||
131 suffix
== 0x676D692E || suffix
== 0x6468762E ||
132 suffix
== 0x6966652E || suffix
== 0x7461642E)
137 else if (len
> 10 && grub_strncmp(name
+ len
- 10, ".vlnk.", 6) == 0)
140 if (suffix
== 0x78646876 || suffix
== 0x796F7476)
150 int grub_file_vtoy_vlnk(const char *src
, const char *dst
)
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);
160 g_vtoy_vlnk
.srclen
= 0;
161 g_vtoy_vlnk
.src
[0] = 0;
162 g_vtoy_vlnk
.dst
[0] = 0;
167 int grub_file_add_vlnk(const char *src
, const char *dst
)
169 grub_vlnk
*node
= NULL
;
173 node
= grub_zalloc(sizeof(grub_vlnk
));
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);
180 node
->next
= g_vlnk_list
;
189 const char *grub_file_get_vlnk(const char *name
, int *vlnk
)
192 grub_vlnk
*node
= g_vlnk_list
;
194 len
= grub_strlen(name
);
196 if (!grub_file_is_vlnk_suffix(name
, len
))
201 if (len
== g_vtoy_vlnk
.srclen
&& grub_strcmp(name
, g_vtoy_vlnk
.src
) == 0)
204 return g_vtoy_vlnk
.dst
;
209 if (node
->srclen
== len
&& grub_strcmp(name
, node
->src
) == 0)
221 grub_file_open (const char *name
, enum grub_file_type type
)
224 grub_device_t device
= 0;
225 grub_file_t file
= 0, last_file
= 0;
227 const char *file_name
;
228 grub_file_filter_id_t filter
;
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
);
235 if ((g_vlnk_list
|| g_vtoy_vlnk
.srclen
) && (type
& GRUB_FILE_TYPE_NO_VLNK
) == 0)
236 name
= grub_file_get_vlnk(name
, &vlnk
);
238 device_name
= grub_file_get_device_name (name
);
242 /* Get the file part of NAME. */
243 file_name
= (name
[0] == '(') ? grub_strchr (name
, ')') : NULL
;
249 device
= grub_device_open (device_name
);
250 grub_free (device_name
);
254 file
= (grub_file_t
) grub_zalloc (sizeof (*file
));
258 file
->device
= device
;
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.
266 if (device
->disk
&& file_name
[0] != '/'
267 #if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU)
268 && grub_strcmp (device
->disk
->name
, "host")
271 /* This is a block list. */
272 file
->fs
= &grub_fs_blocklist
;
275 file
->fs
= grub_fs_probe (device
);
280 if ((file
->fs
->fs_open
) (file
, file_name
) != GRUB_ERR_NONE
)
283 file
->name
= grub_strdup (name
);
284 grub_errno
= GRUB_ERR_NONE
;
286 for (filter
= 0; file
&& filter
< ARRAY_SIZE (grub_file_filters
);
288 if (grub_file_filters
[filter
])
291 file
= grub_file_filters
[filter
] (file
, type
);
292 if (file
&& file
!= last_file
)
294 file
->name
= grub_strdup (name
);
295 grub_errno
= GRUB_ERR_NONE
;
299 grub_file_close (last_file
);
305 grub_device_close (device
);
307 /* if (net) grub_net_close (net); */
314 grub_disk_read_hook_t grub_file_progress_hook
;
317 grub_file_read (grub_file_t file
, void *buf
, grub_size_t len
)
320 grub_disk_read_hook_t read_hook
;
321 void *read_hook_data
;
323 if (file
->offset
> file
->size
)
325 grub_error (GRUB_ERR_OUT_OF_RANGE
,
326 N_("attempt to read past the end of file"));
333 if (len
> file
->size
- file
->offset
)
334 len
= file
->size
- file
->offset
;
336 /* Prevent an overflow. */
337 if ((grub_ssize_t
) len
< 0)
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
);
349 read_hook
= file
->read_hook
;
350 read_hook_data
= file
->read_hook_data
;
351 if (!file
->read_hook
)
353 file
->read_hook
= grub_file_progress_hook
;
354 file
->read_hook_data
= file
;
355 file
->progress_offset
= file
->offset
;
357 res
= (file
->fs
->fs_read
) (file
, buf
, len
);
358 file
->read_hook
= read_hook
;
359 file
->read_hook_data
= read_hook_data
;
367 grub_file_close (grub_file_t file
)
369 if (file
->fs
&& file
->fs
->fs_close
)
370 (file
->fs
->fs_close
) (file
);
373 grub_device_close (file
->device
);
374 grub_free (file
->name
);
380 grub_file_seek (grub_file_t file
, grub_off_t offset
)
384 if (offset
> file
->size
)
386 grub_error (GRUB_ERR_OUT_OF_RANGE
,
387 N_("attempt to seek outside of the file"));
392 file
->offset
= offset
;