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 */
35void (*disk_read_hook) (int, int, int) = NULL;
36void (*disk_read_func) (int, int, int) = NULL;
37
38#ifndef STAGE1_5
39int print_possibilities;
40
41static int do_completion;
42static int unique;
43static char *unique_string;
44
45#endif
46
47int fsmax;
48struct 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. */
92unsigned long current_drive = GRUB_INVALID_DRIVE;
93unsigned 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.  */
98unsigned 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"
107int bsd_evil_hack;
108
109/* filesystem type */
110int fsys_type = NUM_FSYS;
111#ifndef NO_BLOCK_FILES
112static int block_file = 0;
113#endif /* NO_BLOCK_FILES */
114
115/* these are the translated numbers for the open partition */
116unsigned long part_start;
117unsigned long part_length;
118
119int current_slice;
120
121/* disk buffer parameters */
122int buf_drive = -1;
123int buf_track;
124struct geometry buf_geom;
125
126/* filesystem common variables */
127int filepos;
128int filemax;
129
130static inline unsigned long
131log2 (unsigned long word)
132{
133  asm volatile ("bsfl %1,%0"
134		: "=r" (word)
135		: "r" (word));
136  return word;
137}
138
139int
140rawread (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
293int
294devread (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
332int
333rawwrite (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
365int
366devwrite (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
395static int
396sane_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
417static void
418attempt_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.  */
442int
443make_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.  */
501int
502set_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
551static void
552check_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.  */
575int
576next_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
747static unsigned long cur_part_offset;
748static unsigned long cur_part_addr;
749#endif
750
751/* Open a partition.  */
752int
753real_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				&current_partition, &current_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
923int
924open_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' */
932static int incomplete, disk_choice;
933static enum
934{
935  PART_UNSPECIFIED = 0,
936  PART_DISK,
937  PART_CHOSEN,
938}
939part_choice;
940#endif /* ! STAGE1_5 */
941
942char *
943set_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 *) &current_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 *) &current_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
1111int
1112open_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
1125int
1126set_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
1178static char *
1179setup_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
1250void
1251print_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.  */
1273void
1274print_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
1309int
1310print_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
1537int
1538grub_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
1647int
1648grub_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.  */
1744int
1745grub_seek (int offset)
1746{
1747  if (offset > filemax || offset < 0)
1748    return -1;
1749
1750  filepos = offset;
1751  return offset;
1752}
1753
1754int
1755dir (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
1780void
1781grub_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