📄 disk_io.c
字号:
errnum = ERR_BAD_PART_TABLE; return 0; } /* Read the BSD label. */ if (! rawread (drive, *start + BSD_LABEL_SECTOR, 0, SECTOR_SIZE, buf)) return 0; /* Check if it is valid. */ if (! BSD_LABEL_CHECK_MAG (buf)) { errnum = ERR_BAD_PART_TABLE; return 0; } bsd_part_no = -1; } /* Search next valid BSD partition. */ for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++) { if (BSD_PART_TYPE (buf, i)) { /* Note that *TYPE and *PARTITION were set for current PC slice. */ *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF); *start = BSD_PART_START (buf, i); *len = BSD_PART_LENGTH (buf, i); *partition = (*partition & 0xFF00FF) | (i << 8);#ifndef STAGE1_5 /* XXX */ if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI) bsd_evil_hack = 4;#endif /* ! STAGE1_5 */ return 1; } } errnum = ERR_NO_PART; return 0; } /* Get next PC slice. Be careful of that this function may return an empty PC slice (i.e. a partition whose type is zero) as well. */ int next_pc_slice (void) { int pc_slice_no = (*partition & 0xFF0000) >> 16; /* If this is the first time... */ if (pc_slice_no == 0xFF) { *offset = 0; *ext_offset = 0; *entry = -1; pc_slice_no = -1; } /* Read the MBR or the boot sector of the extended partition. */ if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf)) return 0; /* Check if it is valid. */ if (! PC_MBR_CHECK_SIG (buf)) { errnum = ERR_BAD_PART_TABLE; return 0; } /* Increase the entry number. */ (*entry)++; /* If this is out of current partition table... */ if (*entry == PC_SLICE_MAX) { int i; /* Search the first extended partition in current table. */ for (i = 0; i < PC_SLICE_MAX; i++) { if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (buf, i))) { /* Found. Set the new offset and the entry number, and restart this function. */ *offset = *ext_offset + PC_SLICE_START (buf, i); if (! *ext_offset) *ext_offset = *offset; *entry = -1; return next_pc_slice (); } } errnum = ERR_NO_PART; return 0; } *type = PC_SLICE_TYPE (buf, *entry); *start = *offset + PC_SLICE_START (buf, *entry); *len = PC_SLICE_LENGTH (buf, *entry); /* The calculation of a PC slice number is complicated, because of the rather odd definition of extended partitions. Even worse, there is no guarantee that this is consistent with every operating systems. Uggh. */ if (pc_slice_no < PC_SLICE_MAX || (! IS_PC_SLICE_TYPE_EXTENDED (*type) && *type != PC_SLICE_TYPE_NONE)) pc_slice_no++; *partition = (pc_slice_no << 16) | 0xFFFF; return 1; } /* Start the body of this function. */ #ifndef STAGE1_5 if (current_drive == NETWORK_DRIVE) return 0;#endif /* If previous partition is a BSD partition or a PC slice which contains BSD partitions... */ if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff)) || ! (drive & 0x80)) { if (*type == PC_SLICE_TYPE_NONE) *type = PC_SLICE_TYPE_FREEBSD; /* Get next BSD partition, if any. */ if (next_bsd_partition ()) return 1; /* If the destination partition is a BSD partition and current BSD partition has any error, abort the operation. */ if ((dest & 0xFF00) != 0xFF00 && ((dest & 0xFF0000) == 0xFF0000 || (dest & 0xFF0000) == (*partition & 0xFF0000))) return 0; /* Ignore the error. */ errnum = ERR_NONE; } return next_pc_slice ();}#ifndef STAGE1_5static unsigned long cur_part_offset;static unsigned long cur_part_addr;#endif/* Open a partition. */intreal_open_partition (int flags){ unsigned long dest_partition = current_partition; unsigned long part_offset; unsigned long ext_offset; int entry; char buf[SECTOR_SIZE]; int bsd_part, pc_slice; /* For simplicity. */ auto int next (void); int next (void) { int ret = next_partition (current_drive, dest_partition, ¤t_partition, ¤t_slice, &part_start, &part_length, &part_offset, &entry, &ext_offset, buf); bsd_part = (current_partition >> 8) & 0xFF; pc_slice = current_partition >> 16; return ret; } #ifndef STAGE1_5 /* network drive */ if (current_drive == NETWORK_DRIVE) return 1; if (! sane_partition ()) return 0;#endif bsd_evil_hack = 0; current_slice = 0; part_start = 0; /* Make sure that buf_geom is valid. */ if (buf_drive != current_drive) { if (get_diskinfo (current_drive, &buf_geom)) { errnum = ERR_NO_DISK; return 0; } buf_drive = current_drive; buf_track = -1; } part_length = buf_geom.total_sectors; /* If this is the whole disk, return here. */ if (! flags && current_partition == 0xFFFFFF) return 1; if (flags) dest_partition = 0xFFFFFF; /* Initialize CURRENT_PARTITION for next_partition. */ current_partition = 0xFFFFFF; while (next ()) {#ifndef STAGE1_5 loop_start: cur_part_offset = part_offset; cur_part_addr = BOOT_PART_TABLE + (entry << 4);#endif /* ! STAGE1_5 */ /* If this is a valid partition... */ if (current_slice) {#ifndef STAGE1_5 /* Display partition information. */ if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice)) { if (! do_completion) { if (current_drive & 0x80) grub_printf (" Partition num: %d, ", current_partition >> 16); if (! IS_PC_SLICE_TYPE_BSD (current_slice)) check_and_print_mount (); else { int got_part = 0; int saved_slice = current_slice; while (next ()) { if (bsd_part == 0xFF) break; if (! got_part) { grub_printf ("[BSD sub-partitions immediately follow]\n"); got_part = 1; } grub_printf (" BSD Partition num: \'%c\', ", bsd_part + 'a'); check_and_print_mount (); } if (! got_part) grub_printf (" No BSD sub-partition found, partition type 0x%x\n", saved_slice); if (errnum) { errnum = ERR_NONE; break; } goto loop_start; } } else { if (bsd_part != 0xFF) { char str[16]; if (! (current_drive & 0x80) || (dest_partition >> 16) == pc_slice) grub_sprintf (str, "%c)", bsd_part + 'a'); else grub_sprintf (str, "%d,%c)", pc_slice, bsd_part + 'a'); print_a_completion (str); } else if (! IS_PC_SLICE_TYPE_BSD (current_slice)) { char str[8]; grub_sprintf (str, "%d)", pc_slice); print_a_completion (str); } } } errnum = ERR_NONE;#endif /* ! STAGE1_5 */ /* Check if this is the destination partition. */ if (! flags && (dest_partition == current_partition || ((dest_partition >> 16) == 0xFF && ((dest_partition >> 8) & 0xFF) == bsd_part))) return 1; } }#ifndef STAGE1_5 if (flags) { if (! (current_drive & 0x80)) { current_partition = 0xFFFFFF; check_and_print_mount (); } errnum = ERR_NONE; return 1; }#endif /* ! STAGE1_5 */ return 0;}intopen_partition (void){ return real_open_partition (0);}#ifndef STAGE1_5/* XX used for device completion in 'set_device' and 'print_completions' */static int incomplete, disk_choice;static enum{ PART_UNSPECIFIED = 0, PART_DISK, PART_CHOSEN,}part_choice;#endif /* ! STAGE1_5 */char *set_device (char *device){#ifdef STAGE1_5 /* In Stage 1.5, the first 4 bytes of FILENAME has a device number. */ unsigned long dev = *((unsigned long *) device); int drive = (dev >> 24) & 0xFF; int partition = dev & 0xFFFFFF; /* If DRIVE is disabled, use SAVED_DRIVE instead. */ if (drive == GRUB_INVALID_DRIVE) current_drive = saved_drive; else current_drive = drive; /* The `partition' part must always have a valid number. */ current_partition = partition; return device + sizeof (unsigned long); #else /* ! STAGE1_5 */ int result = 0; incomplete = 0; disk_choice = 1; part_choice = PART_UNSPECIFIED; current_drive = saved_drive; current_partition = 0xFFFFFF; if (*device == '(' && !*(device + 1)) /* user has given '(' only, let disk_choice handle what disks we have */ return device + 1; if (*device == '(' && *(++device)) { if (*device != ',' && *device != ')') { char ch = *device;#ifdef SUPPORT_NETBOOT if (*device == 'f' || *device == 'h' || (*device == 'n' && network_ready) || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))#else if (*device == 'f' || *device == 'h' || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))#endif /* SUPPORT_NETBOOT */ { /* user has given '([fhn]', check for resp. add 'd' and let disk_choice handle what disks we have */ if (!*(device + 1)) { device++; *device++ = 'd'; *device = '\0'; return device; } else if (*(device + 1) == 'd' && !*(device + 2)) return device + 2; } if ((*device == 'f' || *device == 'h'#ifdef SUPPORT_NETBOOT || (*device == 'n' && network_ready)#endif || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE)) && (device += 2, (*(device - 1) != 'd'))) errnum = ERR_NUMBER_PARSING; #ifdef SUPPORT_NETBOOT if (ch == 'n' && network_ready) current_drive = NETWORK_DRIVE; else#endif /* SUPPORT_NETBOOT */ { if (ch == 'c' && cdrom_drive != GRUB_INVALID_DRIVE) current_drive = cdrom_drive; else { safe_parse_maxint (&device, (int *) ¤t_drive); disk_choice = 0; if (ch == 'h') current_drive += 0x80; } } } if (errnum) return 0; if (*device == ')') { part_choice = PART_CHOSEN; result = 1; } else if (*device == ',') { /* Either an absolute PC or BSD partition. */ disk_choice = 0; part_choice ++; device++; if (*device >= '0' && *device <= '9') { part_choice ++; current_partition = 0; if (!(current_drive & 0x80) || !safe_parse_maxint (&device, (int *) ¤t_partition) || current_partition > 254) { errnum = ERR_DEV_FORMAT; return 0; } current_partition = (current_partition << 16) + 0xFFFF; if (*device == ',') device++; if (*device >= 'a' && *device <= 'h') { current_partition = (((*(device++) - 'a') << 8) | (current_partition & 0xFF00FF)); } } else if (*device >= 'a' && *device <= 'h') { part_choice ++; current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF; } if (*device == ')') { if (part_choice == PART_DISK) { current_partition = saved_partition; part_choice ++; } result = 1; } } } if (! sane_partition ()) return 0; if (result) return device + 1; else { if (!*device) incomplete = 1; errnum = ERR_DEV_FORMAT; } return 0; #endif /* ! STAGE1_5 */}/* * This performs a "mount" on the current device, both drive and partition * number. */intopen_device (void){ if (open_partition ()) attempt_mount (); if (errnum != ERR_NONE) return 0; return 1;}#ifndef STAGE1_5intset_bootdev (int hdbias){ int i, j; /* Copy the boot partition information to 0x7be-0x7fd for chain-loading. */ if ((saved_drive & 0x80) && cur_part_addr) { if (rawread (saved_drive, cur_part_offset, 0, SECTOR_SIZE, (char *) SCRATCHADDR)) { char *dst, *src; /* Need only the partition table. XXX: We cannot use grub_memmove because BOOT_PART_TABLE (0x07be) is less than 0x1000. */ dst = (char *) BOOT_PART_TABLE; src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET; while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH) *dst++ = *src++; /* Set the active flag of the booted partition. */ for (i = 0; i < 4; i++) PC_SLICE_FLAG (BOOT_PART_TABLE, i) = 0; *((unsigned char *) cur_part_addr) = PC_SLICE_FLAG_BOOTABLE; boot_part_addr = cur_part_addr; } else return 0; } /* * Set BSD boot device. */ i = (saved_partition >> 16) + 2; if (saved_partition == 0xFFFFFF) i = 1; else if ((saved_partition >> 16) == 0xFF) i = 0; /* FIXME: extremely evil hack!!! */ j = 2; if (saved_drive & 0x80) j = bsd_evil_hack; return MAKEBOOTDEV (j, (i >> 4), (i & 0xF), ((saved_drive - hdbias) & 0x7F), ((saved_partition >> 8) & 0xFF));}#endif /* STAGE1_5 */static char *setup_part (char *filename){#ifdef STAGE1_5 if (! (filename = set_device (filename))) { current_drive = GRUB_INVALID_DRIVE; return 0; } # ifndef NO_BLOCK_FILES if (*filename != '/') open_partition (); else# endif /* ! NO_BLOCK_FILES */ open_device ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -