2009-06-11 Felix Zielcke <fzielcke@z-51.de>
[grub2/phcoder.git] / kern / fs.c
blobc8f4970b961264ad7e40207f6816c604a6177bcd
1 /* fs.c - filesystem manager */
2 /*
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>
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>
30 static grub_fs_t grub_fs_list;
32 grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
34 void
35 grub_fs_register (grub_fs_t fs)
37 fs->next = grub_fs_list;
38 grub_fs_list = fs;
41 void
42 grub_fs_unregister (grub_fs_t fs)
44 grub_fs_t *p, q;
46 for (p = &grub_fs_list, q = *p; q; p = &(q->next), q = q->next)
47 if (q == fs)
49 *p = q->next;
50 break;
54 void
55 grub_fs_iterate (int (*hook) (const grub_fs_t fs))
57 grub_fs_t p;
59 for (p = grub_fs_list; p; p = p->next)
60 if (hook (p))
61 break;
64 grub_fs_t
65 grub_fs_probe (grub_device_t device)
67 grub_fs_t p;
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)))
74 return 1;
77 if (device->disk)
79 /* Make it sure not to have an infinite recursive calls. */
80 static int count = 0;
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)
87 return p;
89 grub_error_push ();
90 grub_dprintf ("fs", "%s detection failed.\n", p->name);
91 grub_error_pop ();
93 if (grub_errno != GRUB_ERR_BAD_FS)
94 return 0;
96 grub_errno = GRUB_ERR_NONE;
99 /* Let's load modules automatically. */
100 if (grub_fs_autoload_hook && count == 0)
102 count++;
104 while (grub_fs_autoload_hook ())
106 p = grub_fs_list;
108 (p->dir) (device, "/", dummy_func);
109 if (grub_errno == GRUB_ERR_NONE)
111 count--;
112 return p;
115 if (grub_errno != GRUB_ERR_BAD_FS)
117 count--;
118 return 0;
121 grub_errno = GRUB_ERR_NONE;
124 count--;
127 else if (device->net->fs)
128 return device->net->fs;
130 grub_error (GRUB_ERR_UNKNOWN_FS, "unknown filesystem");
131 return 0;
136 /* Block list support routines. */
138 struct grub_fs_block
140 grub_disk_addr_t offset;
141 unsigned long length;
144 static grub_err_t
145 grub_fs_blocklist_open (grub_file_t file, const char *name)
147 char *p = (char *) name;
148 unsigned num = 0;
149 unsigned i;
150 grub_disk_t disk = file->device->disk;
151 struct grub_fs_block *blocks;
153 /* First, count the number of blocks. */
156 num++;
157 p = grub_strchr (p, ',');
158 if (p)
159 p++;
161 while (p);
163 /* Allocate a block list. */
164 blocks = grub_malloc (sizeof (struct grub_fs_block) * (num + 1));
165 if (! blocks)
166 return 0;
168 file->size = 0;
169 p = (char *) name;
170 for (i = 0; i < num; i++)
172 if (*p != '+')
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);
179 goto fail;
182 else
183 blocks[i].offset = 0;
185 p++;
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);
193 goto fail;
196 if (disk->total_sectors < blocks[i].offset + blocks[i].length)
198 grub_error (GRUB_ERR_BAD_FILENAME, "beyond the total sectors");
199 goto fail;
202 file->size += (blocks[i].length << GRUB_DISK_SECTOR_BITS);
203 p++;
206 blocks[i].length = 0;
207 file->data = blocks;
209 return GRUB_ERR_NONE;
211 fail:
212 grub_free (blocks);
213 return grub_errno;
216 static grub_ssize_t
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;
221 grub_off_t offset;
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)
233 grub_size_t size;
235 size = len;
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)
242 return -1;
244 ret += size;
245 len -= size;
246 sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS);
247 offset = ((size + offset) & (GRUB_DISK_SECTOR_SIZE - 1));
249 else
250 sector -= p->length;
253 return ret;
256 struct grub_fs grub_fs_blocklist =
258 .name = "blocklist",
259 .dir = 0,
260 .open = grub_fs_blocklist_open,
261 .read = grub_fs_blocklist_read,
262 .close = 0,
263 .next = 0