1 /* disk_io.c - implement abstract BIOS disk input and output */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
5 *
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include <shared.h>
23 #include <filesys.h>
24
25 #ifdef SUPPORT_NETBOOT
26 # define GRUB 1
27 # include <etherboot.h>
28 #endif
29
30 #ifdef GRUB_UTIL
31 # include <device.h>
32 #endif
33
34 /* instrumentation variables */
35 void (*disk_read_hook) (int, int, int) = NULL;
36 void (*disk_read_func) (int, int, int) = NULL;
37
38 #ifndef STAGE1_5
39 int print_possibilities;
40
41 static int do_completion;
42 static int unique;
43 static char *unique_string;
44
45 #endif
46
47 int fsmax;
48 struct fsys_entry fsys_table[NUM_FSYS + 1] =
49 {
50 /* TFTP should come first because others don't handle net device. */
51 # ifdef FSYS_TFTP
52 {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
53 # endif
54 # ifdef FSYS_FAT
55 {"fat", fat_mount, fat_read, fat_dir, 0, 0},
56 # endif
57 # ifdef FSYS_EXT2FS
58 {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
59 # endif
60 # ifdef FSYS_MINIX
61 {"minix", minix_mount, minix_read, minix_dir, 0, 0},
62 # endif
63 # ifdef FSYS_REISERFS
64 {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0, reiserfs_embed},
65 # endif
66 # ifdef FSYS_VSTAFS
67 {"vstafs", vstafs_mount, vstafs_read, vstafs_dir, 0, 0},
68 # endif
69 # ifdef FSYS_JFS
70 {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
71 # endif
72 # ifdef FSYS_XFS
73 {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
74 # endif
75 # ifdef FSYS_UFS2
76 {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},
77 # endif
78 # ifdef FSYS_ISO9660
79 {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
80 # endif
81 /* XX FFS should come last as it's superblock is commonly crossing tracks
82 on floppies from track 1 to 2, while others only use 1. */
83 # ifdef FSYS_FFS
84 {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed},
85 # endif
86 {0, 0, 0, 0, 0, 0}
87 };
88
89
90 /* These have the same format as "boot_drive" and "install_partition", but
91 are meant to be working values. */
92 unsigned long current_drive = GRUB_INVALID_DRIVE;
93 unsigned long current_partition;
94
95 #ifndef STAGE1_5
96 /* The register ESI should contain the address of the partition to be
97 used for loading a chain-loader when chain-loading the loader. */
98 unsigned long boot_part_addr = 0;
99 #endif
100
101 /*
102 * Global variables describing details of the filesystem
103 */
104
105 /* FIXME: BSD evil hack */
106 #include "freebsd.h"
107 int bsd_evil_hack;
108
109 /* filesystem type */
110 int fsys_type = NUM_FSYS;
111 #ifndef NO_BLOCK_FILES
112 static int block_file = 0;
113 #endif /* NO_BLOCK_FILES */
114
115 /* these are the translated numbers for the open partition */
116 unsigned long part_start;
117 unsigned long part_length;
118
119 int current_slice;
120
121 /* disk buffer parameters */
122 int buf_drive = -1;
123 int buf_track;
124 struct geometry buf_geom;
125
126 /* filesystem common variables */
127 int filepos;
128 int filemax;
129
130 static inline unsigned long
log2(unsigned long word)131 log2 (unsigned long word)
132 {
133 asm volatile ("bsfl %1,%0"
134 : "=r" (word)
135 : "r" (word));
136 return word;
137 }
138
139 int
rawread(int drive,int sector,int byte_offset,int byte_len,char * buf)140 rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
141 {
142 int slen, sectors_per_vtrack;
143 int sector_size_bits = log2 (buf_geom.sector_size);
144
145 if (byte_len <= 0)
146 return 1;
147
148 while (byte_len > 0 && !errnum)
149 {
150 int soff, num_sect, track, size = byte_len;
151 char *bufaddr;
152
153 /*
154 * Check track buffer. If it isn't valid or it is from the
155 * wrong disk, then reset the disk geometry.
156 */
157 if (buf_drive != drive)
158 {
159 if (get_diskinfo (drive, &buf_geom))
160 {
161 errnum = ERR_NO_DISK;
162 return 0;
163 }
164 buf_drive = drive;
165 buf_track = -1;
166 sector_size_bits = log2 (buf_geom.sector_size);
167 }
168
169 /* Make sure that SECTOR is valid. */
170 if (sector < 0 || sector >= buf_geom.total_sectors)
171 {
172 errnum = ERR_GEOM;
173 return 0;
174 }
175
176 slen = ((byte_offset + byte_len + buf_geom.sector_size - 1)
177 >> sector_size_bits);
178
179 /* Eliminate a buffer overflow. */
180 if ((buf_geom.sectors << sector_size_bits) > BUFFERLEN)
181 sectors_per_vtrack = (BUFFERLEN >> sector_size_bits);
182 else
183 sectors_per_vtrack = buf_geom.sectors;
184
185 /* Get the first sector of track. */
186 soff = sector % sectors_per_vtrack;
187 track = sector - soff;
188 num_sect = sectors_per_vtrack - soff;
189 bufaddr = ((char *) BUFFERADDR
190 + (soff << sector_size_bits) + byte_offset);
191
192 if (track != buf_track)
193 {
194 int bios_err, read_start = track, read_len = sectors_per_vtrack;
195
196 /*
197 * If there's more than one read in this entire loop, then
198 * only make the earlier reads for the portion needed. This
199 * saves filling the buffer with data that won't be used!
200 */
201 if (slen > num_sect)
202 {
203 read_start = sector;
204 read_len = num_sect;
205 bufaddr = (char *) BUFFERADDR + byte_offset;
206 }
207
208 bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom,
209 read_start, read_len, BUFFERSEG);
210 if (bios_err)
211 {
212 buf_track = -1;
213
214 if (bios_err == BIOSDISK_ERROR_GEOMETRY)
215 errnum = ERR_GEOM;
216 else
217 {
218 /*
219 * If there was an error, try to load only the
220 * required sector(s) rather than failing completely.
221 */
222 if (slen > num_sect
223 || biosdisk (BIOSDISK_READ, drive, &buf_geom,
224 sector, slen, BUFFERSEG))
225 errnum = ERR_READ;
226
227 bufaddr = (char *) BUFFERADDR + byte_offset;
228 }
229 }
230 else
231 buf_track = track;
232
233 if ((buf_track == 0 || sector == 0)
234 && (PC_SLICE_TYPE (BUFFERADDR, 0) == PC_SLICE_TYPE_EZD
235 || PC_SLICE_TYPE (BUFFERADDR, 1) == PC_SLICE_TYPE_EZD
236 || PC_SLICE_TYPE (BUFFERADDR, 2) == PC_SLICE_TYPE_EZD
237 || PC_SLICE_TYPE (BUFFERADDR, 3) == PC_SLICE_TYPE_EZD))
238 {
239 /* This is a EZD disk map sector 0 to sector 1 */
240 if (buf_track == 0 || slen >= 2)
241 {
242 /* We already read the sector 1, copy it to sector 0 */
243 memmove ((char *) BUFFERADDR,
244 (char *) BUFFERADDR + buf_geom.sector_size,
245 buf_geom.sector_size);
246 }
247 else
248 {
249 if (biosdisk (BIOSDISK_READ, drive, &buf_geom,
250 1, 1, BUFFERSEG))
251 errnum = ERR_READ;
252 }
253 }
254 }
255
256 if (size > ((num_sect << sector_size_bits) - byte_offset))
257 size = (num_sect << sector_size_bits) - byte_offset;
258
259 /*
260 * Instrumentation to tell which sectors were read and used.
261 */
262 if (disk_read_func)
263 {
264 int sector_num = sector;
265 int length = buf_geom.sector_size - byte_offset;
266 if (length > size)
267 length = size;
268 (*disk_read_func) (sector_num++, byte_offset, length);
269 length = size - length;
270 if (length > 0)
271 {
272 while (length > buf_geom.sector_size)
273 {
274 (*disk_read_func) (sector_num++, 0, buf_geom.sector_size);
275 length -= buf_geom.sector_size;
276 }
277 (*disk_read_func) (sector_num, 0, length);
278 }
279 }
280
281 grub_memmove (buf, bufaddr, size);
282
283 buf += size;
284 byte_len -= size;
285 sector += num_sect;
286 byte_offset = 0;
287 }
288
289 return (!errnum);
290 }
291
292
293 int
devread(int sector,int byte_offset,int byte_len,char * buf)294 devread (int sector, int byte_offset, int byte_len, char *buf)
295 {
296 /*
297 * Check partition boundaries
298 */
299 if (sector < 0
300 || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
301 >= part_length))
302 {
303 errnum = ERR_OUTSIDE_PART;
304 return 0;
305 }
306
307 /*
308 * Get the read to the beginning of a partition.
309 */
310 sector += byte_offset >> SECTOR_BITS;
311 byte_offset &= SECTOR_SIZE - 1;
312
313 #if !defined(STAGE1_5)
314 if (disk_read_hook && debug)
315 printf ("<%d, %d, %d>", sector, byte_offset, byte_len);
316 #endif /* !STAGE1_5 */
317
318 /*
319 * Call RAWREAD, which is very similar, but:
320 *
321 * -- It takes an extra parameter, the drive number.
322 * -- It requires that "sector" is relative to the beginning
323 * of the disk.
324 * -- It doesn't handle offsets of more than 511 bytes into the
325 * sector.
326 */
327 return rawread (current_drive, part_start + sector, byte_offset,
328 byte_len, buf);
329 }
330
331 #ifndef STAGE1_5
332 int
rawwrite(int drive,int sector,char * buf)333 rawwrite (int drive, int sector, char *buf)
334 {
335 if (sector == 0)
336 {
337 if (biosdisk (BIOSDISK_READ, drive, &buf_geom, 0, 1, SCRATCHSEG))
338 {
339 errnum = ERR_WRITE;
340 return 0;
341 }
342
343 if (PC_SLICE_TYPE (SCRATCHADDR, 0) == PC_SLICE_TYPE_EZD
344 || PC_SLICE_TYPE (SCRATCHADDR, 1) == PC_SLICE_TYPE_EZD
345 || PC_SLICE_TYPE (SCRATCHADDR, 2) == PC_SLICE_TYPE_EZD
346 || PC_SLICE_TYPE (SCRATCHADDR, 3) == PC_SLICE_TYPE_EZD)
347 sector = 1;
348 }
349
350 memmove ((char *) SCRATCHADDR, buf, SECTOR_SIZE);
351 if (biosdisk (BIOSDISK_WRITE, drive, &buf_geom,
352 sector, 1, SCRATCHSEG))
353 {
354 errnum = ERR_WRITE;
355 return 0;
356 }
357
358 if (sector - sector % buf_geom.sectors == buf_track)
359 /* Clear the cache. */
360 buf_track = -1;
361
362 return 1;
363 }
364
365 int
devwrite(int sector,int sector_count,char * buf)366 devwrite (int sector, int sector_count, char *buf)
367 {
368 #if defined(GRUB_UTIL) && defined(__linux__)
369 if (current_partition != 0xFFFFFF
370 && is_disk_device (device_map, current_drive))
371 {
372 /* If the grub shell is running under Linux and the user wants to
373 embed a Stage 1.5 into a partition instead of a MBR, use system
374 calls directly instead of biosdisk, because of the bug in
375 Linux. *sigh* */
376 return write_to_partition (device_map, current_drive, current_partition,
377 sector, sector_count, buf);
378 }
379 else
380 #endif /* GRUB_UTIL && __linux__ */
381 {
382 int i;
383
384 for (i = 0; i < sector_count; i++)
385 {
386 if (! rawwrite (current_drive, part_start + sector + i,
387 buf + (i << SECTOR_BITS)))
388 return 0;
389
390 }
391 return 1;
392 }
393 }
394
395 static int
sane_partition(void)396 sane_partition (void)
397 {
398 /* network drive */
399 if (current_drive == NETWORK_DRIVE)
400 return 1;
401
402 if (!(current_partition & 0xFF000000uL)
403 && ((current_drive & 0xFFFFFF7F) < 8
404 || current_drive == cdrom_drive)
405 && (current_partition & 0xFF) == 0xFF
406 && ((current_partition & 0xFF00) == 0xFF00
407 || (current_partition & 0xFF00) < 0x800)
408 && ((current_partition >> 16) == 0xFF
409 || (current_drive & 0x80)))
410 return 1;
411
412 errnum = ERR_DEV_VALUES;
413 return 0;
414 }
415 #endif /* ! STAGE1_5 */
416
417 static void
attempt_mount(void)418 attempt_mount (void)
419 {
420 #ifndef STAGE1_5
421 for (fsys_type = 0; fsys_type < NUM_FSYS; fsys_type++)
422 if ((fsys_table[fsys_type].mount_func) ())
423 break;
424
425 if (fsys_type == NUM_FSYS && errnum == ERR_NONE)
426 errnum = ERR_FSYS_MOUNT;
427 #else
428 fsys_type = 0;
429 if ((*(fsys_table[fsys_type].mount_func)) () != 1)
430 {
431 fsys_type = NUM_FSYS;
432 errnum = ERR_FSYS_MOUNT;
433 }
434 #endif
435 }
436
437
438 #ifndef STAGE1_5
439 /* Turn on the active flag for the partition SAVED_PARTITION in the
440 drive SAVED_DRIVE. If an error occurs, return zero, otherwise return
441 non-zero. */
442 int
make_saved_active(void)443 make_saved_active (void)
444 {
445 char mbr[512];
446
447 if (saved_drive & 0x80)
448 {
449 /* Hard disk */
450 int part = saved_partition >> 16;
451
452 /* If the partition is not a primary partition, the active flag is
453 meaningless. (XXX: Really?) */
454 if (part > 3)
455 {
456 errnum = ERR_DEV_VALUES;
457 return 0;
458 }
459
460 /* Read the MBR in the scratch space. */
461 if (! rawread (saved_drive, 0, 0, SECTOR_SIZE, mbr))
462 return 0;
463
464 /* If the partition is an extended partition, setting the active
465 flag violates the specification by IBM. */
466 if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (mbr, part)))
467 {
468 errnum = ERR_DEV_VALUES;
469 return 0;
470 }
471
472 /* Check if the active flag is disabled. */
473 if (PC_SLICE_FLAG (mbr, part) != PC_SLICE_FLAG_BOOTABLE)
474 {
475 int i;
476
477 /* Clear all the active flags in this table. */
478 for (i = 0; i < 4; i++)
479 PC_SLICE_FLAG (mbr, i) = 0;
480
481 /* Set the flag. */
482 PC_SLICE_FLAG (mbr, part) = PC_SLICE_FLAG_BOOTABLE;
483
484 /* Write back the MBR. */
485 if (! rawwrite (saved_drive, 0, mbr))
486 return 0;
487 }
488 }
489 else
490 {
491 /* If the drive is not a hard disk drive, you shouldn't call this
492 function. (XXX: Should I just ignore this error?) */
493 errnum = ERR_DEV_VALUES;
494 return 0;
495 }
496
497 return 1;
498 }
499
500 /* Hide/Unhide CURRENT_PARTITION. */
501 int
set_partition_hidden_flag(int hidden)502 set_partition_hidden_flag (int hidden)
503 {
504 unsigned long part = 0xFFFFFF;
505 unsigned long start, len, offset, ext_offset;
506 int entry, type;
507 char mbr[512];
508
509 /* The drive must be a hard disk. */
510 if (! (current_drive & 0x80))
511 {
512 errnum = ERR_BAD_ARGUMENT;
513 return 1;
514 }
515
516 /* The partition must be a PC slice. */
517 if ((current_partition >> 16) == 0xFF
518 || (current_partition & 0xFFFF) != 0xFFFF)
519 {
520 errnum = ERR_BAD_ARGUMENT;
521 return 1;
522 }
523
524 /* Look for the partition. */
525 while (next_partition (current_drive, 0xFFFFFF, &part, &type,
526 &start, &len, &offset, &entry,
527 &ext_offset, mbr))
528 {
529 if (part == current_partition)
530 {
531 /* Found. */
532 if (hidden)
533 PC_SLICE_TYPE (mbr, entry) |= PC_SLICE_TYPE_HIDDEN_FLAG;
534 else
535 PC_SLICE_TYPE (mbr, entry) &= ~PC_SLICE_TYPE_HIDDEN_FLAG;
536
537 /* Write back the MBR to the disk. */
538 buf_track = -1;
539 if (! rawwrite (current_drive, offset, mbr))
540 return 1;
541
542 /* Succeed. */
543 return 0;
544 }
545 }
546
547 return 1;
548 }
549
550
551 static void
check_and_print_mount(void)552 check_and_print_mount (void)
553 {
554 attempt_mount ();
555 if (errnum == ERR_FSYS_MOUNT)
556 errnum = ERR_NONE;
557 if (!errnum)
558 print_fsys_type ();
559 print_error ();
560 }
561 #endif /* STAGE1_5 */
562
563
564 /* Get the information on next partition on the drive DRIVE.
565 The caller must not modify the contents of the arguments when
566 iterating this function. The partition representation in GRUB will
567 be stored in *PARTITION. Likewise, the partition type in *TYPE, the
568 start sector in *START, the length in *LEN, the offset of the
569 partition table in *OFFSET, the entry number in the table in *ENTRY,
570 the offset of the extended partition in *EXT_OFFSET.
571 BUF is used to store a MBR, the boot sector of a partition, or
572 a BSD label sector, and it must be at least 512 bytes length.
573 When calling this function first, *PARTITION must be initialized to
574 0xFFFFFF. The return value is zero if fails, otherwise non-zero. */
575 int
next_partition(unsigned long drive,unsigned long dest,unsigned long * partition,int * type,unsigned long * start,unsigned long * len,unsigned long * offset,int * entry,unsigned long * ext_offset,char * buf)576 next_partition (unsigned long drive, unsigned long dest,
577 unsigned long *partition, int *type,
578 unsigned long *start, unsigned long *len,
579 unsigned long *offset, int *entry,
580 unsigned long *ext_offset, char *buf)
581 {
582 /* Forward declarations. */
583 auto int next_bsd_partition (void);
584 auto int next_pc_slice (void);
585
586 /* Get next BSD partition in current PC slice. */
587 int next_bsd_partition (void)
588 {
589 int i;
590 int bsd_part_no = (*partition & 0xFF00) >> 8;
591
592 /* If this is the first time... */
593 if (bsd_part_no == 0xFF)
594 {
595 /* Check if the BSD label is within current PC slice. */
596 if (*len < BSD_LABEL_SECTOR + 1)
597 {
598 errnum = ERR_BAD_PART_TABLE;
599 return 0;
600 }
601
602 /* Read the BSD label. */
603 if (! rawread (drive, *start + BSD_LABEL_SECTOR,
604 0, SECTOR_SIZE, buf))
605 return 0;
606
607 /* Check if it is valid. */
608 if (! BSD_LABEL_CHECK_MAG (buf))
609 {
610 errnum = ERR_BAD_PART_TABLE;
611 return 0;
612 }
613
614 bsd_part_no = -1;
615 }
616
617 /* Search next valid BSD partition. */
618 for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++)
619 {
620 if (BSD_PART_TYPE (buf, i))
621 {
622 /* Note that *TYPE and *PARTITION were set
623 for current PC slice. */
624 *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF);
625 *start = BSD_PART_START (buf, i);
626 *len = BSD_PART_LENGTH (buf, i);
627 *partition = (*partition & 0xFF00FF) | (i << 8);
628
629 #ifndef STAGE1_5
630 /* XXX */
631 if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI)
632 bsd_evil_hack = 4;
633 #endif /* ! STAGE1_5 */
634
635 return 1;
636 }
637 }
638
639 errnum = ERR_NO_PART;
640 return 0;
641 }
642
643 /* Get next PC slice. Be careful of that this function may return
644 an empty PC slice (i.e. a partition whose type is zero) as well. */
645 int next_pc_slice (void)
646 {
647 int pc_slice_no = (*partition & 0xFF0000) >> 16;
648
649 /* If this is the first time... */
650 if (pc_slice_no == 0xFF)
651 {
652 *offset = 0;
653 *ext_offset = 0;
654 *entry = -1;
655 pc_slice_no = -1;
656 }
657
658 /* Read the MBR or the boot sector of the extended partition. */
659 if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
660 return 0;
661
662 /* Check if it is valid. */
663 if (! PC_MBR_CHECK_SIG (buf))
664 {
665 errnum = ERR_BAD_PART_TABLE;
666 return 0;
667 }
668
669 /* Increase the entry number. */
670 (*entry)++;
671
672 /* If this is out of current partition table... */
673 if (*entry == PC_SLICE_MAX)
674 {
675 int i;
676
677 /* Search the first extended partition in current table. */
678 for (i = 0; i < PC_SLICE_MAX; i++)
679 {
680 if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (buf, i)))
681 {
682 /* Found. Set the new offset and the entry number,
683 and restart this function. */
684 *offset = *ext_offset + PC_SLICE_START (buf, i);
685 if (! *ext_offset)
686 *ext_offset = *offset;
687 *entry = -1;
688 return next_pc_slice ();
689 }
690 }
691
692 errnum = ERR_NO_PART;
693 return 0;
694 }
695
696 *type = PC_SLICE_TYPE (buf, *entry);
697 *start = *offset + PC_SLICE_START (buf, *entry);
698 *len = PC_SLICE_LENGTH (buf, *entry);
699
700 /* The calculation of a PC slice number is complicated, because of
701 the rather odd definition of extended partitions. Even worse,
702 there is no guarantee that this is consistent with every
703 operating systems. Uggh. */
704 if (pc_slice_no < PC_SLICE_MAX
705 || (! IS_PC_SLICE_TYPE_EXTENDED (*type)
706 && *type != PC_SLICE_TYPE_NONE))
707 pc_slice_no++;
708
709 *partition = (pc_slice_no << 16) | 0xFFFF;
710 return 1;
711 }
712
713 /* Start the body of this function. */
714
715 #ifndef STAGE1_5
716 if (current_drive == NETWORK_DRIVE)
717 return 0;
718 #endif
719
720 /* If previous partition is a BSD partition or a PC slice which
721 contains BSD partitions... */
722 if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
723 || ! (drive & 0x80))
724 {
725 if (*type == PC_SLICE_TYPE_NONE)
726 *type = PC_SLICE_TYPE_FREEBSD;
727
728 /* Get next BSD partition, if any. */
729 if (next_bsd_partition ())
730 return 1;
731
732 /* If the destination partition is a BSD partition and current
733 BSD partition has any error, abort the operation. */
734 if ((dest & 0xFF00) != 0xFF00
735 && ((dest & 0xFF0000) == 0xFF0000
736 || (dest & 0xFF0000) == (*partition & 0xFF0000)))
737 return 0;
738
739 /* Ignore the error. */
740 errnum = ERR_NONE;
741 }
742
743 return next_pc_slice ();
744 }
745
746 #ifndef STAGE1_5
747 static unsigned long cur_part_offset;
748 static unsigned long cur_part_addr;
749 #endif
750
751 /* Open a partition. */
752 int
real_open_partition(int flags)753 real_open_partition (int flags)
754 {
755 unsigned long dest_partition = current_partition;
756 unsigned long part_offset;
757 unsigned long ext_offset;
758 int entry;
759 char buf[SECTOR_SIZE];
760 int bsd_part, pc_slice;
761
762 /* For simplicity. */
763 auto int next (void);
764 int next (void)
765 {
766 int ret = next_partition (current_drive, dest_partition,
767 ¤t_partition, ¤t_slice,
768 &part_start, &part_length,
769 &part_offset, &entry, &ext_offset, buf);
770 bsd_part = (current_partition >> 8) & 0xFF;
771 pc_slice = current_partition >> 16;
772 return ret;
773 }
774
775 #ifndef STAGE1_5
776 /* network drive */
777 if (current_drive == NETWORK_DRIVE)
778 return 1;
779
780 if (! sane_partition ())
781 return 0;
782 #endif
783
784 bsd_evil_hack = 0;
785 current_slice = 0;
786 part_start = 0;
787
788 /* Make sure that buf_geom is valid. */
789 if (buf_drive != current_drive)
790 {
791 if (get_diskinfo (current_drive, &buf_geom))
792 {
793 errnum = ERR_NO_DISK;
794 return 0;
795 }
796 buf_drive = current_drive;
797 buf_track = -1;
798 }
799 part_length = buf_geom.total_sectors;
800
801 /* If this is the whole disk, return here. */
802 if (! flags && current_partition == 0xFFFFFF)
803 return 1;
804
805 if (flags)
806 dest_partition = 0xFFFFFF;
807
808 /* Initialize CURRENT_PARTITION for next_partition. */
809 current_partition = 0xFFFFFF;
810
811 while (next ())
812 {
813 #ifndef STAGE1_5
814 loop_start:
815
816 cur_part_offset = part_offset;
817 cur_part_addr = BOOT_PART_TABLE + (entry << 4);
818 #endif /* ! STAGE1_5 */
819
820 /* If this is a valid partition... */
821 if (current_slice)
822 {
823 #ifndef STAGE1_5
824 /* Display partition information. */
825 if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice))
826 {
827 if (! do_completion)
828 {
829 if (current_drive & 0x80)
830 grub_printf (" Partition num: %d, ",
831 current_partition >> 16);
832
833 if (! IS_PC_SLICE_TYPE_BSD (current_slice))
834 check_and_print_mount ();
835 else
836 {
837 int got_part = 0;
838 int saved_slice = current_slice;
839
840 while (next ())
841 {
842 if (bsd_part == 0xFF)
843 break;
844
845 if (! got_part)
846 {
847 grub_printf ("[BSD sub-partitions immediately follow]\n");
848 got_part = 1;
849 }
850
851 grub_printf (" BSD Partition num: \'%c\', ",
852 bsd_part + 'a');
853 check_and_print_mount ();
854 }
855
856 if (! got_part)
857 grub_printf (" No BSD sub-partition found, partition type 0x%x\n",
858 saved_slice);
859
860 if (errnum)
861 {
862 errnum = ERR_NONE;
863 break;
864 }
865
866 goto loop_start;
867 }
868 }
869 else
870 {
871 if (bsd_part != 0xFF)
872 {
873 char str[16];
874
875 if (! (current_drive & 0x80)
876 || (dest_partition >> 16) == pc_slice)
877 grub_sprintf (str, "%c)", bsd_part + 'a');
878 else
879 grub_sprintf (str, "%d,%c)",
880 pc_slice, bsd_part + 'a');
881 print_a_completion (str);
882 }
883 else if (! IS_PC_SLICE_TYPE_BSD (current_slice))
884 {
885 char str[8];
886
887 grub_sprintf (str, "%d)", pc_slice);
888 print_a_completion (str);
889 }
890 }
891 }
892
893 errnum = ERR_NONE;
894 #endif /* ! STAGE1_5 */
895
896 /* Check if this is the destination partition. */
897 if (! flags
898 && (dest_partition == current_partition
899 || ((dest_partition >> 16) == 0xFF
900 && ((dest_partition >> 8) & 0xFF) == bsd_part)))
901 return 1;
902 }
903 }
904
905 #ifndef STAGE1_5
906 if (flags)
907 {
908 if (! (current_drive & 0x80))
909 {
910 current_partition = 0xFFFFFF;
911 check_and_print_mount ();
912 }
913
914 errnum = ERR_NONE;
915 return 1;
916 }
917 #endif /* ! STAGE1_5 */
918
919 return 0;
920 }
921
922
923 int
open_partition(void)924 open_partition (void)
925 {
926 return real_open_partition (0);
927 }
928
929
930 #ifndef STAGE1_5
931 /* XX used for device completion in 'set_device' and 'print_completions' */
932 static int incomplete, disk_choice;
933 static enum
934 {
935 PART_UNSPECIFIED = 0,
936 PART_DISK,
937 PART_CHOSEN,
938 }
939 part_choice;
940 #endif /* ! STAGE1_5 */
941
942 char *
set_device(char * device)943 set_device (char *device)
944 {
945 #ifdef STAGE1_5
946 /* In Stage 1.5, the first 4 bytes of FILENAME has a device number. */
947 unsigned long dev = *((unsigned long *) device);
948 int drive = (dev >> 24) & 0xFF;
949 int partition = dev & 0xFFFFFF;
950
951 /* If DRIVE is disabled, use SAVED_DRIVE instead. */
952 if (drive == GRUB_INVALID_DRIVE)
953 current_drive = saved_drive;
954 else
955 current_drive = drive;
956
957 /* The `partition' part must always have a valid number. */
958 current_partition = partition;
959
960 return device + sizeof (unsigned long);
961
962 #else /* ! STAGE1_5 */
963
964 int result = 0;
965
966 incomplete = 0;
967 disk_choice = 1;
968 part_choice = PART_UNSPECIFIED;
969 current_drive = saved_drive;
970 current_partition = 0xFFFFFF;
971
972 if (*device == '(' && !*(device + 1))
973 /* user has given '(' only, let disk_choice handle what disks we have */
974 return device + 1;
975
976 if (*device == '(' && *(++device))
977 {
978 if (*device != ',' && *device != ')')
979 {
980 char ch = *device;
981 #ifdef SUPPORT_NETBOOT
982 if (*device == 'f' || *device == 'h'
983 || (*device == 'n' && network_ready)
984 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
985 #else
986 if (*device == 'f' || *device == 'h'
987 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
988 #endif /* SUPPORT_NETBOOT */
989 {
990 /* user has given '([fhn]', check for resp. add 'd' and
991 let disk_choice handle what disks we have */
992 if (!*(device + 1))
993 {
994 device++;
995 *device++ = 'd';
996 *device = '\0';
997 return device;
998 }
999 else if (*(device + 1) == 'd' && !*(device + 2))
1000 return device + 2;
1001 }
1002
1003 if ((*device == 'f'
1004 || *device == 'h'
1005 #ifdef SUPPORT_NETBOOT
1006 || (*device == 'n' && network_ready)
1007 #endif
1008 || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
1009 && (device += 2, (*(device - 1) != 'd')))
1010 errnum = ERR_NUMBER_PARSING;
1011
1012 #ifdef SUPPORT_NETBOOT
1013 if (ch == 'n' && network_ready)
1014 current_drive = NETWORK_DRIVE;
1015 else
1016 #endif /* SUPPORT_NETBOOT */
1017 {
1018 if (ch == 'c' && cdrom_drive != GRUB_INVALID_DRIVE)
1019 current_drive = cdrom_drive;
1020 else
1021 {
1022 safe_parse_maxint (&device, (int *) ¤t_drive);
1023
1024 disk_choice = 0;
1025 if (ch == 'h')
1026 current_drive += 0x80;
1027 }
1028 }
1029 }
1030
1031 if (errnum)
1032 return 0;
1033
1034 if (*device == ')')
1035 {
1036 part_choice = PART_CHOSEN;
1037 result = 1;
1038 }
1039 else if (*device == ',')
1040 {
1041 /* Either an absolute PC or BSD partition. */
1042 disk_choice = 0;
1043 part_choice ++;
1044 device++;
1045
1046 if (*device >= '0' && *device <= '9')
1047 {
1048 part_choice ++;
1049 current_partition = 0;
1050
1051 if (!(current_drive & 0x80)
1052 || !safe_parse_maxint (&device, (int *) ¤t_partition)
1053 || current_partition > 254)
1054 {
1055 errnum = ERR_DEV_FORMAT;
1056 return 0;
1057 }
1058
1059 current_partition = (current_partition << 16) + 0xFFFF;
1060
1061 if (*device == ',')
1062 device++;
1063
1064 if (*device >= 'a' && *device <= 'h')
1065 {
1066 current_partition = (((*(device++) - 'a') << 8)
1067 | (current_partition & 0xFF00FF));
1068 }
1069 }
1070 else if (*device >= 'a' && *device <= 'h')
1071 {
1072 part_choice ++;
1073 current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF;
1074 }
1075
1076 if (*device == ')')
1077 {
1078 if (part_choice == PART_DISK)
1079 {
1080 current_partition = saved_partition;
1081 part_choice ++;
1082 }
1083
1084 result = 1;
1085 }
1086 }
1087 }
1088
1089 if (! sane_partition ())
1090 return 0;
1091
1092 if (result)
1093 return device + 1;
1094 else
1095 {
1096 if (!*device)
1097 incomplete = 1;
1098 errnum = ERR_DEV_FORMAT;
1099 }
1100
1101 return 0;
1102
1103 #endif /* ! STAGE1_5 */
1104 }
1105
1106 /*
1107 * This performs a "mount" on the current device, both drive and partition
1108 * number.
1109 */
1110
1111 int
open_device(void)1112 open_device (void)
1113 {
1114 if (open_partition ())
1115 attempt_mount ();
1116
1117 if (errnum != ERR_NONE)
1118 return 0;
1119
1120 return 1;
1121 }
1122
1123
1124 #ifndef STAGE1_5
1125 int
set_bootdev(int hdbias)1126 set_bootdev (int hdbias)
1127 {
1128 int i, j;
1129
1130 /* Copy the boot partition information to 0x7be-0x7fd for chain-loading. */
1131 if ((saved_drive & 0x80) && cur_part_addr)
1132 {
1133 if (rawread (saved_drive, cur_part_offset,
1134 0, SECTOR_SIZE, (char *) SCRATCHADDR))
1135 {
1136 char *dst, *src;
1137
1138 /* Need only the partition table.
1139 XXX: We cannot use grub_memmove because BOOT_PART_TABLE
1140 (0x07be) is less than 0x1000. */
1141 dst = (char *) BOOT_PART_TABLE;
1142 src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET;
1143 while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH)
1144 *dst++ = *src++;
1145
1146 /* Set the active flag of the booted partition. */
1147 for (i = 0; i < 4; i++)
1148 PC_SLICE_FLAG (BOOT_PART_TABLE, i) = 0;
1149
1150 *((unsigned char *) cur_part_addr) = PC_SLICE_FLAG_BOOTABLE;
1151 boot_part_addr = cur_part_addr;
1152 }
1153 else
1154 return 0;
1155 }
1156
1157 /*
1158 * Set BSD boot device.
1159 */
1160 i = (saved_partition >> 16) + 2;
1161 if (saved_partition == 0xFFFFFF)
1162 i = 1;
1163 else if ((saved_partition >> 16) == 0xFF)
1164 i = 0;
1165
1166 /* FIXME: extremely evil hack!!! */
1167 j = 2;
1168 if (saved_drive & 0x80)
1169 j = bsd_evil_hack;
1170
1171 return MAKEBOOTDEV (j, (i >> 4), (i & 0xF),
1172 ((saved_drive - hdbias) & 0x7F),
1173 ((saved_partition >> 8) & 0xFF));
1174 }
1175 #endif /* STAGE1_5 */
1176
1177
1178 static char *
setup_part(char * filename)1179 setup_part (char *filename)
1180 {
1181 #ifdef STAGE1_5
1182
1183 if (! (filename = set_device (filename)))
1184 {
1185 current_drive = GRUB_INVALID_DRIVE;
1186 return 0;
1187 }
1188
1189 # ifndef NO_BLOCK_FILES
1190 if (*filename != '/')
1191 open_partition ();
1192 else
1193 # endif /* ! NO_BLOCK_FILES */
1194 open_device ();
1195
1196 #else /* ! STAGE1_5 */
1197
1198 if (*filename == '(')
1199 {
1200 if ((filename = set_device (filename)) == 0)
1201 {
1202 current_drive = GRUB_INVALID_DRIVE;
1203 return 0;
1204 }
1205 # ifndef NO_BLOCK_FILES
1206 if (*filename != '/')
1207 open_partition ();
1208 else
1209 # endif /* ! NO_BLOCK_FILES */
1210 open_device ();
1211 }
1212 else if (saved_drive != current_drive
1213 || saved_partition != current_partition
1214 || (*filename == '/' && fsys_type == NUM_FSYS)
1215 || buf_drive == -1)
1216 {
1217 current_drive = saved_drive;
1218 current_partition = saved_partition;
1219 /* allow for the error case of "no filesystem" after the partition
1220 is found. This makes block files work fine on no filesystem */
1221 # ifndef NO_BLOCK_FILES
1222 if (*filename != '/')
1223 open_partition ();
1224 else
1225 # endif /* ! NO_BLOCK_FILES */
1226 open_device ();
1227 }
1228
1229 #endif /* ! STAGE1_5 */
1230
1231 if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT))
1232 return 0;
1233 else
1234 errnum = 0;
1235
1236 #ifndef STAGE1_5
1237 if (!sane_partition ())
1238 return 0;
1239 #endif
1240
1241 return filename;
1242 }
1243
1244
1245 #ifndef STAGE1_5
1246 /*
1247 * This prints the filesystem type or gives relevant information.
1248 */
1249
1250 void
print_fsys_type(void)1251 print_fsys_type (void)
1252 {
1253 if (! do_completion)
1254 {
1255 printf (" Filesystem type ");
1256
1257 if (fsys_type != NUM_FSYS)
1258 printf ("is %s, ", fsys_table[fsys_type].name);
1259 else
1260 printf ("unknown, ");
1261
1262 if (current_partition == 0xFFFFFF)
1263 printf ("using whole disk\n");
1264 else
1265 printf ("partition type 0x%x\n", current_slice & 0xFF);
1266 }
1267 }
1268 #endif /* STAGE1_5 */
1269
1270 #ifndef STAGE1_5
1271 /* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
1272 part into UNIQUE_STRING. */
1273 void
print_a_completion(char * name)1274 print_a_completion (char *name)
1275 {
1276 /* If NAME is "." or "..", do not count it. */
1277 if (grub_strcmp (name, ".") == 0 || grub_strcmp (name, "..") == 0)
1278 return;
1279
1280 if (do_completion)
1281 {
1282 char *buf = unique_string;
1283
1284 if (! unique)
1285 while ((*buf++ = *name++))
1286 ;
1287 else
1288 {
1289 while (*buf && (*buf == *name))
1290 {
1291 buf++;
1292 name++;
1293 }
1294 /* mismatch, strip it. */
1295 *buf = '\0';
1296 }
1297 }
1298 else
1299 grub_printf (" %s", name);
1300
1301 unique++;
1302 }
1303
1304 /*
1305 * This lists the possible completions of a device string, filename, or
1306 * any sane combination of the two.
1307 */
1308
1309 int
print_completions(int is_filename,int is_completion)1310 print_completions (int is_filename, int is_completion)
1311 {
1312 char *buf = (char *) COMPLETION_BUF;
1313 char *ptr = buf;
1314
1315 unique_string = (char *) UNIQUE_BUF;
1316 *unique_string = 0;
1317 unique = 0;
1318 do_completion = is_completion;
1319
1320 if (! is_filename)
1321 {
1322 /* Print the completions of builtin commands. */
1323 struct builtin **builtin;
1324
1325 if (! is_completion)
1326 grub_printf (" Possible commands are:");
1327
1328 for (builtin = builtin_table; (*builtin); builtin++)
1329 {
1330 /* If *BUILTIN cannot be run in the command-line, skip it. */
1331 if (! ((*builtin)->flags & BUILTIN_CMDLINE))
1332 continue;
1333
1334 if (substring (buf, (*builtin)->name) <= 0)
1335 print_a_completion ((*builtin)->name);
1336 }
1337
1338 if (is_completion && *unique_string)
1339 {
1340 if (unique == 1)
1341 {
1342 char *u = unique_string + grub_strlen (unique_string);
1343
1344 *u++ = ' ';
1345 *u = 0;
1346 }
1347
1348 grub_strcpy (buf, unique_string);
1349 }
1350
1351 if (! is_completion)
1352 grub_putchar ('\n');
1353
1354 print_error ();
1355 do_completion = 0;
1356 if (errnum)
1357 return -1;
1358 else
1359 return unique - 1;
1360 }
1361
1362 if (*buf == '/' || (ptr = set_device (buf)) || incomplete)
1363 {
1364 errnum = 0;
1365
1366 if (*buf == '(' && (incomplete || ! *ptr))
1367 {
1368 if (! part_choice)
1369 {
1370 /* disk completions */
1371 int disk_no, i, j;
1372 struct geometry geom;
1373
1374 if (! is_completion)
1375 grub_printf (" Possible disks are: ");
1376
1377 if (!ptr
1378 || *(ptr-1) != 'd'
1379 #ifdef SUPPORT_NETBOOT
1380 || *(ptr-2) != 'n'
1381 #endif /* SUPPORT_NETBOOT */
1382 || *(ptr-2) != 'c')
1383 {
1384 for (i = (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'h') ? 1:0);
1385 i < (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'f') ? 1:2);
1386 i++)
1387 {
1388 for (j = 0; j < 8; j++)
1389 {
1390 disk_no = (i * 0x80) + j;
1391 if ((disk_choice || disk_no == current_drive)
1392 && ! get_diskinfo (disk_no, &geom))
1393 {
1394 char dev_name[8];
1395
1396 grub_sprintf (dev_name, "%cd%d", i ? 'h':'f', j);
1397 print_a_completion (dev_name);
1398 }
1399 }
1400 }
1401 }
1402
1403 if (cdrom_drive != GRUB_INVALID_DRIVE
1404 && (disk_choice || cdrom_drive == current_drive)
1405 && (!ptr
1406 || *(ptr-1) == '('
1407 || (*(ptr-1) == 'd' && *(ptr-2) == 'c')))
1408 print_a_completion ("cd");
1409
1410 # ifdef SUPPORT_NETBOOT
1411 if (network_ready
1412 && (disk_choice || NETWORK_DRIVE == current_drive)
1413 && (!ptr
1414 || *(ptr-1) == '('
1415 || (*(ptr-1) == 'd' && *(ptr-2) == 'n')))
1416 print_a_completion ("nd");
1417 # endif /* SUPPORT_NETBOOT */
1418
1419 if (is_completion && *unique_string)
1420 {
1421 ptr = buf;
1422 while (*ptr != '(')
1423 ptr--;
1424 ptr++;
1425 grub_strcpy (ptr, unique_string);
1426 if (unique == 1)
1427 {
1428 ptr += grub_strlen (ptr);
1429 if (*unique_string == 'h')
1430 {
1431 *ptr++ = ',';
1432 *ptr = 0;
1433 }
1434 else
1435 {
1436 *ptr++ = ')';
1437 *ptr = 0;
1438 }
1439 }
1440 }
1441
1442 if (! is_completion)
1443 grub_putchar ('\n');
1444 }
1445 else
1446 {
1447 /* partition completions */
1448 if (part_choice == PART_CHOSEN
1449 && open_partition ()
1450 && ! IS_PC_SLICE_TYPE_BSD (current_slice))
1451 {
1452 unique = 1;
1453 ptr = buf + grub_strlen (buf);
1454 if (*(ptr - 1) != ')')
1455 {
1456 *ptr++ = ')';
1457 *ptr = 0;
1458 }
1459 }
1460 else
1461 {
1462 if (! is_completion)
1463 grub_printf (" Possible partitions are:\n");
1464 real_open_partition (1);
1465
1466 if (is_completion && *unique_string)
1467 {
1468 ptr = buf;
1469 while (*ptr++ != ',')
1470 ;
1471 grub_strcpy (ptr, unique_string);
1472 }
1473 }
1474 }
1475 }
1476 else if (ptr && *ptr == '/')
1477 {
1478 /* filename completions */
1479 if (! is_completion)
1480 grub_printf (" Possible files are:");
1481
1482 dir (buf);
1483
1484 if (is_completion && *unique_string)
1485 {
1486 ptr += grub_strlen (ptr);
1487 while (*ptr != '/')
1488 ptr--;
1489 ptr++;
1490
1491 grub_strcpy (ptr, unique_string);
1492
1493 if (unique == 1)
1494 {
1495 ptr += grub_strlen (unique_string);
1496
1497 /* Check if the file UNIQUE_STRING is a directory. */
1498 *ptr = '/';
1499 *(ptr + 1) = 0;
1500
1501 dir (buf);
1502
1503 /* Restore the original unique value. */
1504 unique = 1;
1505
1506 if (errnum)
1507 {
1508 /* Regular file */
1509 errnum = 0;
1510 *ptr = ' ';
1511 *(ptr + 1) = 0;
1512 }
1513 }
1514 }
1515
1516 if (! is_completion)
1517 grub_putchar ('\n');
1518 }
1519 else
1520 errnum = ERR_BAD_FILENAME;
1521 }
1522
1523 print_error ();
1524 do_completion = 0;
1525 if (errnum)
1526 return -1;
1527 else
1528 return unique - 1;
1529 }
1530 #endif /* STAGE1_5 */
1531
1532
1533 /*
1534 * This is the generic file open function.
1535 */
1536
1537 int
grub_open(char * filename)1538 grub_open (char *filename)
1539 {
1540 #ifndef NO_DECOMPRESSION
1541 compressed_file = 0;
1542 #endif /* NO_DECOMPRESSION */
1543
1544 /* if any "dir" function uses/sets filepos, it must
1545 set it to zero before returning if opening a file! */
1546 filepos = 0;
1547
1548 if (!(filename = setup_part (filename)))
1549 return 0;
1550
1551 #ifndef NO_BLOCK_FILES
1552 block_file = 0;
1553 #endif /* NO_BLOCK_FILES */
1554
1555 /* This accounts for partial filesystem implementations. */
1556 fsmax = MAXINT;
1557
1558 if (*filename != '/')
1559 {
1560 #ifndef NO_BLOCK_FILES
1561 char *ptr = filename;
1562 int tmp, list_addr = BLK_BLKLIST_START;
1563 filemax = 0;
1564
1565 while (list_addr < BLK_MAX_ADDR)
1566 {
1567 tmp = 0;
1568 safe_parse_maxint (&ptr, &tmp);
1569 errnum = 0;
1570
1571 if (*ptr != '+')
1572 {
1573 if ((*ptr && *ptr != '/' && !isspace (*ptr))
1574 || tmp == 0 || tmp > filemax)
1575 errnum = ERR_BAD_FILENAME;
1576 else
1577 filemax = tmp;
1578
1579 break;
1580 }
1581
1582 /* since we use the same filesystem buffer, mark it to
1583 be remounted */
1584 fsys_type = NUM_FSYS;
1585
1586 BLK_BLKSTART (list_addr) = tmp;
1587 ptr++;
1588
1589 if (!safe_parse_maxint (&ptr, &tmp)
1590 || tmp == 0
1591 || (*ptr && *ptr != ',' && *ptr != '/' && !isspace (*ptr)))
1592 {
1593 errnum = ERR_BAD_FILENAME;
1594 break;
1595 }
1596
1597 BLK_BLKLENGTH (list_addr) = tmp;
1598
1599 filemax += (tmp * SECTOR_SIZE);
1600 list_addr += BLK_BLKLIST_INC_VAL;
1601
1602 if (*ptr != ',')
1603 break;
1604
1605 ptr++;
1606 }
1607
1608 if (list_addr < BLK_MAX_ADDR && ptr != filename && !errnum)
1609 {
1610 block_file = 1;
1611 BLK_CUR_FILEPOS = 0;
1612 BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1613 BLK_CUR_BLKNUM = 0;
1614
1615 #ifndef NO_DECOMPRESSION
1616 return gunzip_test_header ();
1617 #else /* NO_DECOMPRESSION */
1618 return 1;
1619 #endif /* NO_DECOMPRESSION */
1620 }
1621 #else /* NO_BLOCK_FILES */
1622 errnum = ERR_BAD_FILENAME;
1623 #endif /* NO_BLOCK_FILES */
1624 }
1625
1626 if (!errnum && fsys_type == NUM_FSYS)
1627 errnum = ERR_FSYS_MOUNT;
1628
1629 # ifndef STAGE1_5
1630 /* set "dir" function to open a file */
1631 print_possibilities = 0;
1632 # endif
1633
1634 if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
1635 {
1636 #ifndef NO_DECOMPRESSION
1637 return gunzip_test_header ();
1638 #else /* NO_DECOMPRESSION */
1639 return 1;
1640 #endif /* NO_DECOMPRESSION */
1641 }
1642
1643 return 0;
1644 }
1645
1646
1647 int
grub_read(char * buf,int len)1648 grub_read (char *buf, int len)
1649 {
1650 /* Make sure "filepos" is a sane value */
1651 if ((filepos < 0) || (filepos > filemax))
1652 filepos = filemax;
1653
1654 /* Make sure "len" is a sane value */
1655 if ((len < 0) || (len > (filemax - filepos)))
1656 len = filemax - filepos;
1657
1658 /* if target file position is past the end of
1659 the supported/configured filesize, then
1660 there is an error */
1661 if (filepos + len > fsmax)
1662 {
1663 errnum = ERR_FILELENGTH;
1664 return 0;
1665 }
1666
1667 #ifndef NO_DECOMPRESSION
1668 if (compressed_file)
1669 return gunzip_read (buf, len);
1670 #endif /* NO_DECOMPRESSION */
1671
1672 #ifndef NO_BLOCK_FILES
1673 if (block_file)
1674 {
1675 int size, off, ret = 0;
1676
1677 while (len && !errnum)
1678 {
1679 /* we may need to look for the right block in the list(s) */
1680 if (filepos < BLK_CUR_FILEPOS)
1681 {
1682 BLK_CUR_FILEPOS = 0;
1683 BLK_CUR_BLKLIST = BLK_BLKLIST_START;
1684 BLK_CUR_BLKNUM = 0;
1685 }
1686
1687 /* run BLK_CUR_FILEPOS up to filepos */
1688 while (filepos > BLK_CUR_FILEPOS)
1689 {
1690 if ((filepos - (BLK_CUR_FILEPOS & ~(SECTOR_SIZE - 1)))
1691 >= SECTOR_SIZE)
1692 {
1693 BLK_CUR_FILEPOS += SECTOR_SIZE;
1694 BLK_CUR_BLKNUM++;
1695
1696 if (BLK_CUR_BLKNUM >= BLK_BLKLENGTH (BLK_CUR_BLKLIST))
1697 {
1698 BLK_CUR_BLKLIST += BLK_BLKLIST_INC_VAL;
1699 BLK_CUR_BLKNUM = 0;
1700 }
1701 }
1702 else
1703 BLK_CUR_FILEPOS = filepos;
1704 }
1705
1706 off = filepos & (SECTOR_SIZE - 1);
1707 size = ((BLK_BLKLENGTH (BLK_CUR_BLKLIST) - BLK_CUR_BLKNUM)
1708 * SECTOR_SIZE) - off;
1709 if (size > len)
1710 size = len;
1711
1712 disk_read_func = disk_read_hook;
1713
1714 /* read current block and put it in the right place in memory */
1715 devread (BLK_BLKSTART (BLK_CUR_BLKLIST) + BLK_CUR_BLKNUM,
1716 off, size, buf);
1717
1718 disk_read_func = NULL;
1719
1720 len -= size;
1721 filepos += size;
1722 ret += size;
1723 buf += size;
1724 }
1725
1726 if (errnum)
1727 ret = 0;
1728
1729 return ret;
1730 }
1731 #endif /* NO_BLOCK_FILES */
1732
1733 if (fsys_type == NUM_FSYS)
1734 {
1735 errnum = ERR_FSYS_MOUNT;
1736 return 0;
1737 }
1738
1739 return (*(fsys_table[fsys_type].read_func)) (buf, len);
1740 }
1741
1742 #ifndef STAGE1_5
1743 /* Reposition a file offset. */
1744 int
grub_seek(int offset)1745 grub_seek (int offset)
1746 {
1747 if (offset > filemax || offset < 0)
1748 return -1;
1749
1750 filepos = offset;
1751 return offset;
1752 }
1753
1754 int
dir(char * dirname)1755 dir (char *dirname)
1756 {
1757 #ifndef NO_DECOMPRESSION
1758 compressed_file = 0;
1759 #endif /* NO_DECOMPRESSION */
1760
1761 if (!(dirname = setup_part (dirname)))
1762 return 0;
1763
1764 if (*dirname != '/')
1765 errnum = ERR_BAD_FILENAME;
1766
1767 if (fsys_type == NUM_FSYS)
1768 errnum = ERR_FSYS_MOUNT;
1769
1770 if (errnum)
1771 return 0;
1772
1773 /* set "dir" function to list completions */
1774 print_possibilities = 1;
1775
1776 return (*(fsys_table[fsys_type].dir_func)) (dirname);
1777 }
1778 #endif /* STAGE1_5 */
1779
1780 void
grub_close(void)1781 grub_close (void)
1782 {
1783 #ifndef NO_BLOCK_FILES
1784 if (block_file)
1785 return;
1786 #endif /* NO_BLOCK_FILES */
1787
1788 if (fsys_table[fsys_type].close_func != 0)
1789 (*(fsys_table[fsys_type].close_func)) ();
1790 }
1791