bug in partnew module
Closed this issue · 2 comments
a1ive commented
bug in partnew module
a1ive commented
shared.h
struct master_and_dos_boot_sector {
/* 00 */ char dummy1[0x0b]; /* at offset 0, normally there is a short JMP instuction(opcode is 0xEB) */
/* 0B */ unsigned short bytes_per_sector __attribute__ ((packed));/* seems always to be 512, so we just use 512 */
/* 0D */ unsigned char sectors_per_cluster;/* non-zero, the power of 2, i.e., 2^n */
/* 0E */ unsigned short reserved_sectors __attribute__ ((packed));/* FAT=non-zero, NTFS=0? */
/* 10 */ unsigned char number_of_fats;/* NTFS=0; FAT=1 or 2 */
/* 11 */ unsigned short root_dir_entries __attribute__ ((packed));/* FAT32=0, NTFS=0, FAT12/16=non-zero */
/* 13 */ unsigned short total_sectors_short __attribute__ ((packed));/* FAT32=0, NTFS=0, FAT12/16=any */
/* 15 */ unsigned char media_descriptor;/* range from 0xf0 to 0xff */
/* 16 */ unsigned short sectors_per_fat __attribute__ ((packed));/* FAT32=0, NTFS=0, FAT12/16=non-zero */
/* 18 */ unsigned short sectors_per_track __attribute__ ((packed));/* range from 1 to 63 */
/* 1A */ unsigned short total_heads __attribute__ ((packed));/* range from 1 to 256 */
/* 1C */ unsigned long hidden_sectors __attribute__ ((packed));/* any value */
/* 20 */ unsigned long total_sectors_long __attribute__ ((packed));/* FAT32=non-zero, NTFS=0, FAT12/16=any */
/* 24 */ unsigned long sectors_per_fat32 __attribute__ ((packed));/* FAT32=non-zero, NTFS=any, FAT12/16=any */
/* 28 */ unsigned long long total_sectors_long_long __attribute__ ((packed));/* NTFS=non-zero, FAT12/16/32=any */
/* 30 */ char dummy2[0x18e];
/* Partition Table, starting at offset 0x1BE */
/* 1BE */ struct {
/* +00 */ unsigned char boot_indicator;
/* +01 */ unsigned char start_head;
/* +02 */ unsigned short start_sector_cylinder __attribute__ ((packed));
/* +04 */ unsigned char system_indicator;
/* +05 */ unsigned char end_head;
/* +06 */ unsigned short end_sector_cylinder __attribute__ ((packed));
/* +08 */ unsigned long start_lba __attribute__ ((packed));
/* +0C */ unsigned long total_sectors __attribute__ ((packed));
/* +10 */
} P[4];
/* 1FE */ unsigned short boot_signature __attribute__ ((packed));/* 0xAA55 */
};
a1ive commented
/* partnew PART TYPE START LEN */
static int
partnew_func (char *arg, int flags)
{
unsigned long long new_type, new_start, new_len;
unsigned long start_cl, start_ch, start_dh;
unsigned long end_cl, end_ch, end_dh;
unsigned long current_drive_bak;
unsigned long current_partition_bak;
char *filename;
unsigned long entry1, i;
unsigned long active = -1;
errnum = 0;
if (grub_memcmp (arg, "--active", 8) == 0)
{
active = 0x80;
arg = skip_to (0, arg);
}
/* Get the drive and the partition. */
if (! set_device (arg))
return 0;
entry1 = current_partition >> 16;
/* The partition must a primary partition. */
if (entry1 > 3 || (current_partition & 0xFFFF) != 0xFFFF)
{
errnum = ERR_BAD_ARGUMENT;
return 0;
}
/* Get the new partition type. */
arg = skip_to (0, arg);
if (! safe_parse_maxint (&arg, &new_type))
return 0;
/* The partition type is unsigned char. */
if (new_type > 0xFF)
{
errnum = ERR_BAD_ARGUMENT;
return 0;
}
/* Get the new partition start and length. */
arg = skip_to (0, arg);
filename = arg;
current_drive_bak = 0;
if ((! safe_parse_maxint (&arg, &new_start))
|| ((arg = skip_to (0, arg)), (! safe_parse_maxint (&arg, &new_len))))
{
current_drive_bak = current_drive;
current_partition_bak = current_partition;
arg = filename;
filename = set_device (filename);
if (errnum)
{
/* No device specified. Default to the root device. */
current_drive = saved_drive;
current_partition = saved_partition;
filename = 0;
errnum = 0;
}
if (current_drive != current_drive_bak)
{
printf_debug0 ("Cannot create a partition in drive %X from a file in drive %X.\n", current_drive_bak, current_drive);
errnum = ERR_BAD_ARGUMENT;
return 0;
}
if (current_partition == 0xFFFFFF)
{
printf_debug0 ("Cannot create a partition with a blocklist of a whole drive.\n");
errnum = ERR_BAD_ARGUMENT;
return 0;
}
query_block_entries = -1; /* query block list only */
blocklist_func (arg, flags);
if (errnum == 0)
{
if (query_block_entries != 1)
return ! (errnum = ERR_NON_CONTIGUOUS);
new_start = map_start_sector[0];
new_len = (filemax + 0x1ff) >> SECTOR_BITS;
}
else
return ! errnum;
if (new_start == part_start && part_start && new_len == 1)
new_len = part_length;
if (new_start < part_start || new_start + new_len > (unsigned long)(part_start + part_length))
{
printf_debug0 ("Cannot create a partition that exceeds the partition boundary.\n");
return ! (errnum = ERR_BAD_ARGUMENT);
}
/* Read the first sector. */
if (! rawread (current_drive, new_start, 0, SECTOR_SIZE, (unsigned long long)(unsigned int)mbr, 0xedde0d90))
return 0;
#define BS ((struct master_and_dos_boot_sector *)mbr)
/* try to find out the filesystem type */
if (BS->boot_signature == 0xAA55 && ! probe_bpb(BS))
{
if ((new_type & 0xFFFFFFEF) == 0) /* auto filesystem type */
{
new_type |=
filesystem_type == 1 ? 0x0E /* FAT12 */ :
filesystem_type == 2 ? 0x0E /* FAT16 */ :
filesystem_type == 3 ? 0x0C /* FAT32 */ :
filesystem_type == 4 ? 0x07 /* NTFS */ :
filesystem_type == 6 ? 0x07 /* exFAT */ :
/*filesystem_type == 5 ?*/ 0x83 /* EXT2 */;
if (filesystem_type == 5)
new_type = 0x83; /* EXT2 */
}
printf_debug0 ("%s BPB found %s the leading 0xEB (jmp). Hidden sectors=0x%X\n",
(filesystem_type == 1 ? "FAT12" :
filesystem_type == 2 ? "FAT16" :
filesystem_type == 3 ? "FAT32" :
filesystem_type == 4 ? "NTFS" :
filesystem_type == 6 ? "exFAT" :
/*filesystem_type == 5 ?*/ "EXT2 GRLDR"),
(BS->dummy1[0] == (char)0xEB ? "with" : "but WITHOUT"),
BS->hidden_sectors);
if (BS->hidden_sectors != new_start)
{
printf_debug0 ("Changing hidden sectors 0x%X to 0x%lX... ", BS->hidden_sectors, (unsigned long long)new_start);
BS->hidden_sectors = new_start;
/* Write back/update the boot sector. */
if (! rawwrite (current_drive, new_start, (unsigned long long)(unsigned int)mbr))
{
printf_debug0 ("failure.\n");
return 0;
} else {
printf_debug0 ("success.\n");
}
}
}
#undef BS
current_drive = current_drive_bak;
current_partition = current_partition_bak;
}
/* Read the MBR. */
if (! rawread (current_drive, 0, 0, SECTOR_SIZE, (unsigned long long)(unsigned int)mbr, 0xedde0d90))
return 0;
if (current_drive_bak) /* creating a partition from a file */
{
/* if the entry is not empty, it should be a part of another
* partition, that is, it should be covered by another partition. */
if (PC_SLICE_START (mbr, entry1) != 0 || PC_SLICE_LENGTH (mbr, entry1) != 0)
{
for (i = 0; i < 4; i++)
{
if (i == entry1)
continue;
if (PC_SLICE_START (mbr, entry1) < PC_SLICE_START (mbr, i))
continue;
if (PC_SLICE_START (mbr, entry1) + PC_SLICE_LENGTH (mbr, entry1)
> PC_SLICE_START (mbr, i) + PC_SLICE_LENGTH (mbr, i))
continue;
break; /* found */
}
if (i >= 4)
{
/* not found */
printf_debug0 ("Cannot overwrite an independent partition.\n");
return ! (errnum = ERR_BAD_ARGUMENT);
}
}
}
if (new_type == 0 && new_start == 0 && new_len == 0)
{
/* empty the entry */
start_dh = start_cl = start_ch = end_dh = end_cl = end_ch = 0;
}else{
if (new_start == 0 || new_len == 0)
{
errnum = ERR_BAD_PART_TABLE;
return 0;
}
/* Store the partition information in the MBR. */
lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
}
if (active == 0x80)
{
/* Activate this partition */
PC_SLICE_FLAG (mbr, entry1) = 0x80;
} else {
if (PC_SLICE_FLAG (mbr, entry1) != 0x80)
PC_SLICE_FLAG (mbr, entry1) = 0;
}
/* Deactivate other partitions */
if (PC_SLICE_FLAG (mbr, entry1) == 0x80)
{
for (i = 0; i < 4; i++)
{
if (i == entry1)
continue;
if (PC_SLICE_FLAG (mbr, i) != 0)
{
if (debug > 0)
{
if (PC_SLICE_FLAG (mbr, i) == 0x80)
{
grub_printf ("The active flag(0x80) of partition %d was changed to 0.\n", (unsigned long)i);
} else {
grub_printf ("The invalid active flag(0x%X) of partition %d was changed to 0.\n", (unsigned long)(PC_SLICE_FLAG (mbr, i)), (unsigned long)i);
}
}
PC_SLICE_FLAG (mbr, i) = 0;
}
}
}
PC_SLICE_HEAD (mbr, entry1) = start_dh;
PC_SLICE_SEC (mbr, entry1) = start_cl;
PC_SLICE_CYL (mbr, entry1) = start_ch;
PC_SLICE_TYPE (mbr, entry1) = new_type;
PC_SLICE_EHEAD (mbr, entry1) = end_dh;
PC_SLICE_ESEC (mbr, entry1) = end_cl;
PC_SLICE_ECYL (mbr, entry1) = end_ch;
PC_SLICE_START (mbr, entry1) = new_start;
PC_SLICE_LENGTH (mbr, entry1) = new_len;
/* Make sure that the MBR has a valid signature. */
PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
/* Write back the MBR to the disk. */
buf_track = -1;
if (! rawwrite (current_drive, 0, (unsigned long long)(unsigned int)mbr))
return 0;
return 1;
}