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>
30 static grub_fs_t grub_fs_list
;
32 grub_fs_autoload_hook_t grub_fs_autoload_hook
= 0;
35 grub_fs_register (grub_fs_t fs
)
37 fs
->next
= grub_fs_list
;
42 grub_fs_unregister (grub_fs_t fs
)
46 for (p
= &grub_fs_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
55 grub_fs_iterate (int (*hook
) (const grub_fs_t fs
))
59 for (p
= grub_fs_list
; p
; p
= p
->next
)
65 grub_fs_probe (grub_device_t device
)
68 auto int dummy_func (const char *filename
,
69 const struct grub_dirhook_info
*info
);
71 int dummy_func (const char *filename
__attribute__ ((unused
)),
72 const struct grub_dirhook_info
*info
__attribute__ ((unused
)))
79 /* Make it sure not to have an infinite recursive calls. */
82 for (p
= grub_fs_list
; p
; p
= p
->next
)
84 grub_dprintf ("fs", "Detecting %s...\n", p
->name
);
85 (p
->dir
) (device
, "/", dummy_func
);
86 if (grub_errno
== GRUB_ERR_NONE
)
90 grub_dprintf ("fs", "%s detection failed.\n", p
->name
);
93 if (grub_errno
!= GRUB_ERR_BAD_FS
)
96 grub_errno
= GRUB_ERR_NONE
;
99 /* Let's load modules automatically. */
100 if (grub_fs_autoload_hook
&& count
== 0)
104 while (grub_fs_autoload_hook ())
108 (p
->dir
) (device
, "/", dummy_func
);
109 if (grub_errno
== GRUB_ERR_NONE
)
115 if (grub_errno
!= GRUB_ERR_BAD_FS
)
121 grub_errno
= GRUB_ERR_NONE
;
127 else if (device
->net
->fs
)
128 return device
->net
->fs
;
130 grub_error (GRUB_ERR_UNKNOWN_FS
, "unknown filesystem");
136 /* Block list support routines. */
140 grub_disk_addr_t offset
;
141 unsigned long length
;
145 grub_fs_blocklist_open (grub_file_t file
, const char *name
)
147 char *p
= (char *) name
;
150 grub_disk_t disk
= file
->device
->disk
;
151 struct grub_fs_block
*blocks
;
153 /* First, count the number of blocks. */
157 p
= grub_strchr (p
, ',');
163 /* Allocate a block list. */
164 blocks
= grub_malloc (sizeof (struct grub_fs_block
) * (num
+ 1));
170 for (i
= 0; i
< num
; i
++)
174 blocks
[i
].offset
= grub_strtoull (p
, &p
, 0);
175 if (grub_errno
!= GRUB_ERR_NONE
|| *p
!= '+')
177 grub_error (GRUB_ERR_BAD_FILENAME
,
178 "invalid file name `%s'", name
);
183 blocks
[i
].offset
= 0;
186 blocks
[i
].length
= grub_strtoul (p
, &p
, 0);
187 if (grub_errno
!= GRUB_ERR_NONE
188 || blocks
[i
].length
== 0
189 || (*p
&& *p
!= ',' && ! grub_isspace (*p
)))
191 grub_error (GRUB_ERR_BAD_FILENAME
,
192 "invalid file name `%s'", name
);
196 if (disk
->total_sectors
< blocks
[i
].offset
+ blocks
[i
].length
)
198 grub_error (GRUB_ERR_BAD_FILENAME
, "beyond the total sectors");
202 file
->size
+= (blocks
[i
].length
<< GRUB_DISK_SECTOR_BITS
);
206 blocks
[i
].length
= 0;
209 return GRUB_ERR_NONE
;
217 grub_fs_blocklist_read (grub_file_t file
, char *buf
, grub_size_t len
)
219 struct grub_fs_block
*p
;
220 grub_disk_addr_t sector
;
222 grub_ssize_t ret
= 0;
224 if (len
> file
->size
- file
->offset
)
225 len
= file
->size
- file
->offset
;
227 sector
= (file
->offset
>> GRUB_DISK_SECTOR_BITS
);
228 offset
= (file
->offset
& (GRUB_DISK_SECTOR_SIZE
- 1));
229 for (p
= file
->data
; p
->length
&& len
> 0; p
++)
231 if (sector
< p
->length
)
236 if (((size
+ offset
+ GRUB_DISK_SECTOR_SIZE
- 1)
237 >> GRUB_DISK_SECTOR_BITS
) > p
->length
- sector
)
238 size
= ((p
->length
- sector
) << GRUB_DISK_SECTOR_BITS
) - offset
;
240 if (grub_disk_read (file
->device
->disk
, p
->offset
+ sector
, offset
,
241 size
, buf
) != GRUB_ERR_NONE
)
246 sector
-= ((size
+ offset
) >> GRUB_DISK_SECTOR_BITS
);
247 offset
= ((size
+ offset
) & (GRUB_DISK_SECTOR_SIZE
- 1));
256 struct grub_fs grub_fs_blocklist
=
260 .open
= grub_fs_blocklist_open
,
261 .read
= grub_fs_blocklist_read
,