1 /* fs.c - filesystem manager */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2005,2007 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/disk.h>
23 #include <grub/file.h>
25 #include <grub/misc.h>
26 #include <grub/types.h>
28 #include <grub/term.h>
29 #include <grub/i18n.h>
32 grub_fs_t grub_fs_list
= 0;
34 grub_fs_autoload_hook_t grub_fs_autoload_hook
= 0;
36 /* Helper for grub_fs_probe. */
38 probe_dummy_iter (const char *filename
__attribute__ ((unused
)),
39 const struct grub_dirhook_info
*info
__attribute__ ((unused
)),
40 void *data
__attribute__ ((unused
)))
45 grub_fs_t
grub_fs_list_probe(grub_device_t device
, const char **list
)
53 for (p
= grub_fs_list
; p
; p
= p
->next
)
55 for (i
= 0; list
[i
]; i
++)
57 if (grub_strcmp(p
->name
, list
[i
]) == 0)
64 grub_dprintf("fs", "Detecting %s...\n", p
->name
);
66 (p
->fs_dir
) (device
, "/", probe_dummy_iter
, NULL
);
67 if (grub_errno
== GRUB_ERR_NONE
)
71 grub_dprintf ("fs", "%s detection failed.\n", p
->name
);
74 if (grub_errno
!= GRUB_ERR_BAD_FS
&& grub_errno
!= GRUB_ERR_OUT_OF_RANGE
) {
77 grub_errno
= GRUB_ERR_NONE
;
84 grub_fs_probe (grub_device_t device
)
87 const char *first_probe
;
92 /* Make it sure not to have an infinite recursive calls. */
95 first_probe
= grub_env_get("ventoy_fs_probe");
98 first_probe
= "iso9660";
100 len
= grub_strlen(first_probe
);
102 /* use iso9660 first */
103 for (p
= grub_fs_list
; p
; p
= p
->next
)
105 if (grub_strncmp(p
->name
, first_probe
, len
) == 0)
113 grub_dprintf ("fs", "Detecting %s...\n", p
->name
);
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
121 if (grub_strcmp (p
->name
, "btrfs") == 0)
124 p
->fs_uuid (device
, &label
);
130 (p
->fs_dir
) (device
, "/", probe_dummy_iter
, NULL
);
131 if (grub_errno
== GRUB_ERR_NONE
)
135 grub_dprintf ("fs", "%s detection failed.\n", p
->name
);
138 if (grub_errno
!= GRUB_ERR_BAD_FS
139 && grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
142 grub_errno
= GRUB_ERR_NONE
;
145 for (p
= grub_fs_list
; p
; p
= p
->next
)
147 grub_dprintf ("fs", "Detecting %s...\n", p
->name
);
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
155 if (grub_strcmp (p
->name
, "btrfs") == 0)
158 p
->fs_uuid (device
, &label
);
164 (p
->fs_dir
) (device
, "/", probe_dummy_iter
, NULL
);
165 if (grub_errno
== GRUB_ERR_NONE
)
169 grub_dprintf ("fs", "%s detection failed.\n", p
->name
);
172 if (grub_errno
!= GRUB_ERR_BAD_FS
173 && grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
176 grub_errno
= GRUB_ERR_NONE
;
179 /* Let's load modules automatically. */
180 if (grub_fs_autoload_hook
&& count
== 0)
184 while (grub_fs_autoload_hook ())
188 (p
->fs_dir
) (device
, "/", probe_dummy_iter
, NULL
);
189 if (grub_errno
== GRUB_ERR_NONE
)
195 if (grub_errno
!= GRUB_ERR_BAD_FS
196 && grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
202 grub_errno
= GRUB_ERR_NONE
;
208 else if (device
->net
&& device
->net
->fs
)
209 return device
->net
->fs
;
211 grub_error (GRUB_ERR_UNKNOWN_FS
, N_("unknown filesystem"));
217 /* Block list support routines. */
221 grub_disk_addr_t offset
;
222 unsigned long length
;
226 grub_fs_blocklist_open (grub_file_t file
, const char *name
)
228 char *p
= (char *) name
;
231 grub_disk_t disk
= file
->device
->disk
;
232 struct grub_fs_block
*blocks
;
234 /* First, count the number of blocks. */
238 p
= grub_strchr (p
, ',');
244 /* Allocate a block list. */
245 blocks
= grub_zalloc (sizeof (struct grub_fs_block
) * (num
+ 1));
251 for (i
= 0; i
< num
; i
++)
255 blocks
[i
].offset
= grub_strtoull (p
, &p
, 0);
256 if (grub_errno
!= GRUB_ERR_NONE
|| *p
!= '+')
258 grub_error (GRUB_ERR_BAD_FILENAME
,
259 N_("invalid file name `%s'"), name
);
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
)))
270 grub_error (GRUB_ERR_BAD_FILENAME
,
271 N_("invalid file name `%s'"), name
);
275 if (disk
->total_sectors
< blocks
[i
].offset
+ blocks
[i
].length
)
277 grub_error (GRUB_ERR_BAD_FILENAME
, "beyond the total sectors");
281 file
->size
+= (blocks
[i
].length
<< GRUB_DISK_SECTOR_BITS
);
287 return GRUB_ERR_NONE
;
295 grub_fs_blocklist_read (grub_file_t file
, char *buf
, grub_size_t len
)
297 struct grub_fs_block
*p
;
298 grub_disk_addr_t sector
;
300 grub_ssize_t ret
= 0;
302 if (len
> file
->size
- file
->offset
)
303 len
= file
->size
- file
->offset
;
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
++)
309 if (sector
< p
->length
)
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
;
318 if (grub_disk_read (file
->device
->disk
, p
->offset
+ sector
, offset
,
319 size
, buf
) != GRUB_ERR_NONE
)
324 sector
-= ((size
+ offset
) >> GRUB_DISK_SECTOR_BITS
);
325 offset
= ((size
+ offset
) & (GRUB_DISK_SECTOR_SIZE
- 1));
334 struct grub_fs grub_fs_blocklist
=
338 .fs_open
= grub_fs_blocklist_open
,
339 .fs_read
= grub_fs_blocklist_read
,