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