comparison packages/redboot/current/src/fs/disk.c @ 174:38892b97b685

Merge from eCos master repository on 2001-07-28-00:17:32-BST
author jlarmour
date Sun, 29 Jul 2001 02:00:07 +0000
parents
children 3902ef905c9c
comparison
equal deleted inserted replaced
173:547dc35af910 174:38892b97b685
1 //==========================================================================
2 //
3 // disk.c
4 //
5 // RedBoot disk support
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //==========================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s): msalter
35 // Contributors: msalter
36 // Date: 2001-07-14
37 // Purpose:
38 // Description:
39 //
40 // This code is part of RedBoot (tm).
41 //
42 //####DESCRIPTIONEND####
43 //
44 //==========================================================================
45
46 #include <redboot.h>
47 #include <fs/disk.h>
48
49 #ifdef CYGSEM_REDBOOT_DISK_EXT2FS
50 #include <fs/e2fs.h>
51 #endif
52
53 static void do_disks(int argc, char *argv[]);
54
55 RedBoot_cmd("disks",
56 "Display disks/partitions.",
57 "",
58 do_disks
59 );
60
61 static disk_t disk_table[CYGNUM_REDBOOT_MAX_DISKS];
62 static int disk_count = 0;
63
64 static int
65 find_dos_partitions(disk_t *d, cyg_uint8 *mbr)
66 {
67 cyg_uint32 s, n, tmp;
68 struct mbr_partition *p;
69 int i, found = 0;
70
71 p = (struct mbr_partition *)(mbr + MBR_PTABLE_OFFSET);
72
73 // Look for primary partitions
74 for (i = 0; i < 4 && i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
75
76 // Have to use memcpy because of alignment
77 memcpy(&tmp, p->start_sect, 4);
78 s = SWAB_LE32(tmp);
79 memcpy(&tmp, p->nr_sects, 4);
80 n = SWAB_LE32(tmp);
81
82 if (s && n) {
83 ++found;
84 d->partitions[i].disk = d;
85 d->partitions[i].start_sector = s;
86 d->partitions[i].nr_sectors = n;
87 d->partitions[i].systype = p->sys_ind;
88 d->partitions[i].bootflag = p->boot_ind;
89 }
90 p++;
91 }
92
93 #if CYGNUM_REDBOOT_MAX_PARTITIONS > 4
94 {
95 cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
96 cyg_uint16 magic;
97 int j, nextp;
98
99 // Go back through and find extended partitions
100 for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
101 if (d->partitions[i].systype == SYSTYPE_EXTENDED) {
102 // read partition boot record (same format as mbr)
103 if (DISK_READ(d, d->partitions[i].start_sector, buf, 1) <= 0)
104 break;
105
106 magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
107 if (SWAB_LE16(magic) != MBR_MAGIC)
108 continue;
109
110 p = (struct mbr_partition *)(buf + MBR_PTABLE_OFFSET);
111
112 for (j = 0; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; j++, nextp++) {
113 // Have to use memcpy because of alignment
114 memcpy(&tmp, p->start_sect, 4);
115 s = SWAB_LE32(tmp);
116 memcpy(&tmp, p->nr_sects, 4);
117 n = SWAB_LE32(tmp);
118
119 if (s && n) {
120 ++found;
121 d->partitions[nextp].disk = d;
122 d->partitions[nextp].start_sector = s + d->partitions[i].start_sector;
123 d->partitions[nextp].nr_sectors = n;
124 d->partitions[nextp].systype = p->sys_ind;
125 d->partitions[nextp].bootflag = p->boot_ind;
126 }
127 ++p;
128 }
129 }
130 }
131 }
132 #endif
133
134 return found;
135 }
136
137
138 // Find partitions on given disk.
139 // Return number of partitions found
140 static int
141 find_partitions(disk_t *d)
142 {
143 cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
144 cyg_uint16 magic;
145 partition_t *p;
146 int i, found = 0;
147
148
149 if (d->kind == DISK_IDE_CDROM) {
150 // no partition table, so fake it
151 p = d->partitions;
152 p->disk = d;
153 p->start_sector = 0;
154 p->nr_sectors = d->nr_sectors;
155 return 1;
156 }
157
158 // read Master Boot Record
159 if (DISK_READ(d, 0, buf, 1) <= 0)
160 return 0;
161
162 // Check for DOS MBR
163 magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
164 if (SWAB_LE16(magic) == MBR_MAGIC) {
165 found = find_dos_partitions(d, (cyg_uint8 *)buf);
166 } else {
167 // Might want to handle other MBR types, here...
168 }
169
170 #ifdef CYGSEM_REDBOOT_DISK_ISO9660
171 if (d->kind == DISK_IDE_CDROM) {
172 p->funs = &redboot_iso9660_funs;
173 return found;
174 }
175 #endif
176
177 // Now go through all partitions and install the correct
178 // funcs for supported filesystems.
179 for (i = 0, p = d->partitions; i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++, p++) {
180 switch (p->systype) {
181 #ifdef CYGSEM_REDBOOT_DISK_EXT2FS
182 case SYSTYPE_LINUX:
183 p->funs = &redboot_e2fs_funs;
184 break;
185 #endif
186 #ifdef CYGSEM_REDBOOT_DISK_FAT16
187 case SYSTYPE_FAT16:
188 p->funs = &redboot_fat16_funs;
189 break;
190 #endif
191 #ifdef CYGSEM_REDBOOT_DISK_FAT32
192 case SYSTYPE_FAT32:
193 p->funs = &redboot_fat32_funs;
194 break;
195 #endif
196 default:
197 break; // ignore unsupported filesystems
198 }
199 }
200
201 return found;
202 }
203
204 // Add a disk to the disk table.
205 // Return zero if no more room in table.
206 externC int
207 disk_register(disk_t *d)
208 {
209 int i;
210
211 // make sure we have room for it
212 if (disk_count >= CYGNUM_REDBOOT_MAX_DISKS)
213 return 0;
214
215 // Set the index
216 d->index = 0;
217 for (i = 0; i < disk_count; i++)
218 if (disk_table[i].kind == d->kind)
219 d->index++;
220
221 // put it in the table
222 disk_table[disk_count] = *d;
223
224 // fill in partition info
225 find_partitions(&disk_table[disk_count++]);
226
227 return 1;
228 }
229
230 // Convert a filename in the form <partition_name>:<filename> into
231 // a partition and path.
232 //
233 static int
234 disk_parse_filename(const char *name, partition_t **part, const char **path)
235 {
236 int i, kind, index, pindex;
237
238 kind = index = pindex = 0;
239
240 if (name[0] == 'h' && name[1] == 'd') {
241 // IDE hard drives
242 kind = DISK_IDE_HD;
243 if (name[2] < 'a' || name[2] > 'z')
244 return 0;
245 index = name[2] - 'a';
246 if (name[3] < '1' || name[3] >= ('1' + CYGNUM_REDBOOT_MAX_PARTITIONS))
247 return 0;
248 pindex = name[3] - '1';
249 if (name[4] != ':')
250 return 0;
251 *path = &name[5];
252 }
253
254 if (kind) {
255 for (i = 0; i < CYGNUM_REDBOOT_MAX_DISKS; i++) {
256 if (disk_table[i].kind == kind && disk_table[i].index == index) {
257 *part = &disk_table[i].partitions[pindex];
258 return 1;
259 }
260 }
261 }
262 return 0;
263 }
264
265 static const struct {
266 int kind;
267 const char *str;
268 } systype_names[] = {
269 { SYSTYPE_FAT12, "FAT12" },
270 { SYSTYPE_FAT16_32M, "FAT16 <32M" },
271 { SYSTYPE_FAT16, "FAT16" },
272 { SYSTYPE_EXTENDED, "Extended" },
273 { SYSTYPE_LINUX_SWAP, "Linux Swap" },
274 { SYSTYPE_LINUX, "Linux" }
275 };
276
277 static const char *
278 systype_name(int systype)
279 {
280 int i;
281
282 for (i = 0; i < sizeof(systype_names)/sizeof(systype_names[0]); i++)
283 if (systype_names[i].kind == systype)
284 return systype_names[i].str;
285 return "Unknown";
286 }
287
288 // List disk partitions
289 static void
290 do_disks(int argc, char *argv[])
291 {
292 int i, j;
293 disk_t *d;
294 partition_t *p;
295 char name[16];
296
297 for (i = 0, d = disk_table; i < disk_count; i++, d++) {
298 switch (d->kind) {
299 case DISK_IDE_HD:
300 for (j = 0, p = d->partitions; j < CYGNUM_REDBOOT_MAX_PARTITIONS; j++, p++) {
301 if (p->systype) {
302 sprintf(name, "hd%c%d", 'a' + d->index, j+1);
303 printf("%-8s %s\n", name, systype_name(p->systype));
304 }
305 }
306 break;
307 case DISK_IDE_CDROM:
308 sprintf(name, "cd%d", d->index);
309 printf("%-8s ISO9660\n", name);
310 break;
311 }
312 }
313 }
314
315 static void *fileptr;
316 static partition_t *file_part;
317
318 externC int
319 disk_stream_open(char *filename, int *err)
320 {
321 const char *filepath;
322
323 // The filename is in <disk>:<path> format.
324 // Convert to a partition and path.
325 if (!disk_parse_filename(filename, &file_part, &filepath)) {
326 *err = diskerr_badname;
327 return -1;
328 }
329
330 if (file_part->systype == 0 || file_part->funs == (fs_funs_t *)0) {
331 *err = diskerr_partition;
332 return -1;
333 }
334
335 fileptr = (file_part->funs->open)(file_part, filepath);
336 if (fileptr == NULL) {
337 *err = diskerr_open;
338 return -1;
339 }
340 return 0;
341 }
342
343 externC int
344 disk_stream_read(char *buf, int size, int *err)
345 {
346 int nread;
347
348 if ((nread = (file_part->funs->read)(fileptr, buf, size)) != size) {
349 *err = diskerr_read;
350 return -1;
351 }
352 return nread;
353 }
354
355 externC void
356 disk_stream_close(int *err)
357 {
358 fileptr = NULL;
359 }
360
361 externC char *
362 disk_error(int err)
363 {
364 switch (err) {
365 case diskerr_badname:
366 return "Bad filename";
367 break;
368 case diskerr_partition:
369 return "Unsupported filesystem";
370 break;
371 case diskerr_open:
372 return "Can't open file";
373 break;
374 case diskerr_read:
375 return "Can't read file";
376 break;
377 default:
378 return "Unknown error";
379 break;
380 }
381 }
382