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
, int dir
);
70 int dummy_func (const char *filename
__attribute__ ((unused
)),
71 int dir
__attribute__ ((unused
)))
78 /* Make it sure not to have an infinite recursive calls. */
81 for (p
= grub_fs_list
; p
; p
= p
->next
)
83 grub_dprintf ("fs", "Detecting %s...\n", p
->name
);
84 (p
->dir
) (device
, "/", dummy_func
);
85 if (grub_errno
== GRUB_ERR_NONE
)
89 grub_dprintf ("fs", "%s detection failed.\n", p
->name
);
92 if (grub_errno
!= GRUB_ERR_BAD_FS
)
95 grub_errno
= GRUB_ERR_NONE
;
98 /* Let's load modules automatically. */
99 if (grub_fs_autoload_hook
&& count
== 0)
103 while (grub_fs_autoload_hook ())
107 (p
->dir
) (device
, "/", dummy_func
);
108 if (grub_errno
== GRUB_ERR_NONE
)
114 if (grub_errno
!= GRUB_ERR_BAD_FS
)
120 grub_errno
= GRUB_ERR_NONE
;
126 else if (device
->net
->fs
)
127 return device
->net
->fs
;
129 grub_error (GRUB_ERR_UNKNOWN_FS
, "unknown filesystem");
135 /* Block list support routines. */
139 grub_disk_addr_t offset
;
140 unsigned long length
;
144 grub_fs_blocklist_open (grub_file_t file
, const char *name
)
146 char *p
= (char *) name
;
149 grub_disk_t disk
= file
->device
->disk
;
150 struct grub_fs_block
*blocks
;
152 /* First, count the number of blocks. */
156 p
= grub_strchr (p
, ',');
162 /* Allocate a block list. */
163 blocks
= grub_malloc (sizeof (struct grub_fs_block
) * (num
+ 1));
169 for (i
= 0; i
< num
; i
++)
173 blocks
[i
].offset
= grub_strtoull (p
, &p
, 0);
174 if (grub_errno
!= GRUB_ERR_NONE
|| *p
!= '+')
176 grub_error (GRUB_ERR_BAD_FILENAME
,
177 "invalid file name `%s'", name
);
182 blocks
[i
].offset
= 0;
185 blocks
[i
].length
= grub_strtoul (p
, &p
, 0);
186 if (grub_errno
!= GRUB_ERR_NONE
187 || blocks
[i
].length
== 0
188 || (*p
&& *p
!= ',' && ! grub_isspace (*p
)))
190 grub_error (GRUB_ERR_BAD_FILENAME
,
191 "invalid file name `%s'", name
);
195 if (disk
->total_sectors
< blocks
[i
].offset
+ blocks
[i
].length
)
197 grub_error (GRUB_ERR_BAD_FILENAME
, "beyond the total sectors");
201 file
->size
+= (blocks
[i
].length
<< GRUB_DISK_SECTOR_BITS
);
205 blocks
[i
].length
= 0;
208 return GRUB_ERR_NONE
;
216 grub_fs_blocklist_read (grub_file_t file
, char *buf
, grub_size_t len
)
218 struct grub_fs_block
*p
;
219 grub_disk_addr_t sector
;
221 grub_ssize_t ret
= 0;
223 if (len
> file
->size
- file
->offset
)
224 len
= file
->size
- file
->offset
;
226 sector
= (file
->offset
>> GRUB_DISK_SECTOR_BITS
);
227 offset
= (file
->offset
& (GRUB_DISK_SECTOR_SIZE
- 1));
228 for (p
= file
->data
; p
->length
&& len
> 0; p
++)
230 if (sector
< p
->length
)
235 if (((size
+ offset
+ GRUB_DISK_SECTOR_SIZE
- 1)
236 >> GRUB_DISK_SECTOR_BITS
) > p
->length
- sector
)
237 size
= ((p
->length
- sector
) << GRUB_DISK_SECTOR_BITS
) - offset
;
239 if (grub_disk_read (file
->device
->disk
, p
->offset
+ sector
, offset
,
240 size
, buf
) != GRUB_ERR_NONE
)
245 sector
-= ((size
+ offset
) >> GRUB_DISK_SECTOR_BITS
);
246 offset
= ((size
+ offset
) & (GRUB_DISK_SECTOR_SIZE
- 1));
255 struct grub_fs grub_fs_blocklist
=
259 .open
= grub_fs_blocklist_open
,
260 .read
= grub_fs_blocklist_read
,