]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c
keep up with 1.0.67 (#1464)
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / kern / fs.c
1 /* fs.c - filesystem manager */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2005,2007 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/disk.h>
21 #include <grub/net.h>
22 #include <grub/fs.h>
23 #include <grub/file.h>
24 #include <grub/err.h>
25 #include <grub/misc.h>
26 #include <grub/types.h>
27 #include <grub/mm.h>
28 #include <grub/term.h>
29 #include <grub/i18n.h>
30 #include <grub/env.h>
31
32 grub_fs_t grub_fs_list = 0;
33
34 grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
35
36 /* Helper for grub_fs_probe. */
37 static int
38 probe_dummy_iter (const char *filename __attribute__ ((unused)),
39 const struct grub_dirhook_info *info __attribute__ ((unused)),
40 void *data __attribute__ ((unused)))
41 {
42 return 1;
43 }
44
45 grub_fs_t grub_fs_list_probe(grub_device_t device, const char **list)
46 {
47 int i;
48 grub_fs_t p;
49
50 if (!device->disk)
51 return 0;
52
53 for (p = grub_fs_list; p; p = p->next)
54 {
55 for (i = 0; list[i]; i++)
56 {
57 if (grub_strcmp(p->name, list[i]) == 0)
58 break;
59 }
60
61 if (list[i] == NULL)
62 continue;
63
64 grub_dprintf("fs", "Detecting %s...\n", p->name);
65
66 (p->fs_dir) (device, "/", probe_dummy_iter, NULL);
67 if (grub_errno == GRUB_ERR_NONE)
68 return p;
69
70 grub_error_push ();
71 grub_dprintf ("fs", "%s detection failed.\n", p->name);
72 grub_error_pop ();
73
74 if (grub_errno != GRUB_ERR_BAD_FS && grub_errno != GRUB_ERR_OUT_OF_RANGE) {
75 return 0;
76 }
77 grub_errno = GRUB_ERR_NONE;
78 }
79
80 return 0;
81 }
82
83 grub_fs_t
84 grub_fs_probe (grub_device_t device)
85 {
86 grub_fs_t p;
87 const char *first_probe;
88 grub_size_t len;
89
90 if (device->disk)
91 {
92 /* Make it sure not to have an infinite recursive calls. */
93 static int count = 0;
94
95 first_probe = grub_env_get("ventoy_fs_probe");
96 if (!first_probe)
97 {
98 first_probe = "iso9660";
99 }
100 len = grub_strlen(first_probe);
101
102 /* use iso9660 first */
103 for (p = grub_fs_list; p; p = p->next)
104 {
105 if (grub_strncmp(p->name, first_probe, len) == 0)
106 {
107 break;
108 }
109 }
110
111 if (p)
112 {
113 grub_dprintf ("fs", "Detecting %s...\n", p->name);
114
115 /* This is evil: newly-created just mounted BtrFS after copying all
116 GRUB files has a very peculiar unrecoverable corruption which
117 will be fixed at sync but we'd rather not do a global sync and
118 syncing just files doesn't seem to help. Relax the check for
119 this time. */
120 #ifdef GRUB_UTIL
121 if (grub_strcmp (p->name, "btrfs") == 0)
122 {
123 char *label = 0;
124 p->fs_uuid (device, &label);
125 if (label)
126 grub_free (label);
127 }
128 else
129 #endif
130 (p->fs_dir) (device, "/", probe_dummy_iter, NULL);
131 if (grub_errno == GRUB_ERR_NONE)
132 return p;
133
134 grub_error_push ();
135 grub_dprintf ("fs", "%s detection failed.\n", p->name);
136 grub_error_pop ();
137
138 if (grub_errno != GRUB_ERR_BAD_FS
139 && grub_errno != GRUB_ERR_OUT_OF_RANGE)
140 return 0;
141
142 grub_errno = GRUB_ERR_NONE;
143 }
144
145 for (p = grub_fs_list; p; p = p->next)
146 {
147 grub_dprintf ("fs", "Detecting %s...\n", p->name);
148
149 /* This is evil: newly-created just mounted BtrFS after copying all
150 GRUB files has a very peculiar unrecoverable corruption which
151 will be fixed at sync but we'd rather not do a global sync and
152 syncing just files doesn't seem to help. Relax the check for
153 this time. */
154 #ifdef GRUB_UTIL
155 if (grub_strcmp (p->name, "btrfs") == 0)
156 {
157 char *label = 0;
158 p->fs_uuid (device, &label);
159 if (label)
160 grub_free (label);
161 }
162 else
163 #endif
164 (p->fs_dir) (device, "/", probe_dummy_iter, NULL);
165 if (grub_errno == GRUB_ERR_NONE)
166 return p;
167
168 grub_error_push ();
169 grub_dprintf ("fs", "%s detection failed.\n", p->name);
170 grub_error_pop ();
171
172 if (grub_errno != GRUB_ERR_BAD_FS
173 && grub_errno != GRUB_ERR_OUT_OF_RANGE)
174 return 0;
175
176 grub_errno = GRUB_ERR_NONE;
177 }
178
179 /* Let's load modules automatically. */
180 if (grub_fs_autoload_hook && count == 0)
181 {
182 count++;
183
184 while (grub_fs_autoload_hook ())
185 {
186 p = grub_fs_list;
187
188 (p->fs_dir) (device, "/", probe_dummy_iter, NULL);
189 if (grub_errno == GRUB_ERR_NONE)
190 {
191 count--;
192 return p;
193 }
194
195 if (grub_errno != GRUB_ERR_BAD_FS
196 && grub_errno != GRUB_ERR_OUT_OF_RANGE)
197 {
198 count--;
199 return 0;
200 }
201
202 grub_errno = GRUB_ERR_NONE;
203 }
204
205 count--;
206 }
207 }
208 else if (device->net && device->net->fs)
209 return device->net->fs;
210
211 grub_error (GRUB_ERR_UNKNOWN_FS, N_("unknown filesystem"));
212 return 0;
213 }
214
215 \f
216
217 /* Block list support routines. */
218
219 struct grub_fs_block
220 {
221 grub_disk_addr_t offset;
222 unsigned long length;
223 };
224
225 static grub_err_t
226 grub_fs_blocklist_open (grub_file_t file, const char *name)
227 {
228 char *p = (char *) name;
229 unsigned num = 0;
230 unsigned i;
231 grub_disk_t disk = file->device->disk;
232 struct grub_fs_block *blocks;
233
234 /* First, count the number of blocks. */
235 do
236 {
237 num++;
238 p = grub_strchr (p, ',');
239 if (p)
240 p++;
241 }
242 while (p);
243
244 /* Allocate a block list. */
245 blocks = grub_zalloc (sizeof (struct grub_fs_block) * (num + 1));
246 if (! blocks)
247 return 0;
248
249 file->size = 0;
250 p = (char *) name;
251 for (i = 0; i < num; i++)
252 {
253 if (*p != '+')
254 {
255 blocks[i].offset = grub_strtoull (p, &p, 0);
256 if (grub_errno != GRUB_ERR_NONE || *p != '+')
257 {
258 grub_error (GRUB_ERR_BAD_FILENAME,
259 N_("invalid file name `%s'"), name);
260 goto fail;
261 }
262 }
263
264 p++;
265 blocks[i].length = grub_strtoul (p, &p, 0);
266 if (grub_errno != GRUB_ERR_NONE
267 || blocks[i].length == 0
268 || (*p && *p != ',' && ! grub_isspace (*p)))
269 {
270 grub_error (GRUB_ERR_BAD_FILENAME,
271 N_("invalid file name `%s'"), name);
272 goto fail;
273 }
274
275 if (disk->total_sectors < blocks[i].offset + blocks[i].length)
276 {
277 grub_error (GRUB_ERR_BAD_FILENAME, "beyond the total sectors");
278 goto fail;
279 }
280
281 file->size += (blocks[i].length << GRUB_DISK_SECTOR_BITS);
282 p++;
283 }
284
285 file->data = blocks;
286
287 return GRUB_ERR_NONE;
288
289 fail:
290 grub_free (blocks);
291 return grub_errno;
292 }
293
294 static grub_ssize_t
295 grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
296 {
297 struct grub_fs_block *p;
298 grub_disk_addr_t sector;
299 grub_off_t offset;
300 grub_ssize_t ret = 0;
301
302 if (len > file->size - file->offset)
303 len = file->size - file->offset;
304
305 sector = (file->offset >> GRUB_DISK_SECTOR_BITS);
306 offset = (file->offset & (GRUB_DISK_SECTOR_SIZE - 1));
307 for (p = file->data; p->length && len > 0; p++)
308 {
309 if (sector < p->length)
310 {
311 grub_size_t size;
312
313 size = len;
314 if (((size + offset + GRUB_DISK_SECTOR_SIZE - 1)
315 >> GRUB_DISK_SECTOR_BITS) > p->length - sector)
316 size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset;
317
318 if (grub_disk_read (file->device->disk, p->offset + sector, offset,
319 size, buf) != GRUB_ERR_NONE)
320 return -1;
321
322 ret += size;
323 len -= size;
324 sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS);
325 offset = ((size + offset) & (GRUB_DISK_SECTOR_SIZE - 1));
326 }
327 else
328 sector -= p->length;
329 }
330
331 return ret;
332 }
333
334 struct grub_fs grub_fs_blocklist =
335 {
336 .name = "blocklist",
337 .fs_dir = 0,
338 .fs_open = grub_fs_blocklist_open,
339 .fs_read = grub_fs_blocklist_read,
340 .fs_close = 0,
341 .next = 0
342 };