diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-07-14 13:53:59 +0100 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-07-14 13:53:59 +0100 |
commit | 6af68a0b67cdcceeb945b0ee9b561ac2101b8331 (patch) | |
tree | 29e9e9e9ba56b06b26bcb486f574053846dd0ce6 | |
parent | 553243f2ea27fb81d0f446a86bd381611ff41ddb (diff) | |
download | xen-6af68a0b67cdcceeb945b0ee9b561ac2101b8331.tar.gz xen-6af68a0b67cdcceeb945b0ee9b561ac2101b8331.tar.bz2 xen-6af68a0b67cdcceeb945b0ee9b561ac2101b8331.zip |
lomount: Major rewrite: handle large files and GPT partition.
Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
-rw-r--r-- | tools/misc/lomount/lomount.c | 396 |
1 files changed, 265 insertions, 131 deletions
diff --git a/tools/misc/lomount/lomount.c b/tools/misc/lomount/lomount.c index 85e5f3b584..d04a95bfc4 100644 --- a/tools/misc/lomount/lomount.c +++ b/tools/misc/lomount/lomount.c @@ -4,6 +4,9 @@ * Copyright (c) 2004 Jim Brown * Copyright (c) 2004 Brad Watson * Copyright (c) 2004 Mulyadi Santosa + * Major rewrite by Tristan Gingold: + * - Handle GPT partitions + * - Handle large files * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,6 +44,8 @@ enum ERR_MOUNT // Other failure of mount command }; +#define _LARGEFILE_SOURCE +#define _FILE_OFFSET_BITS 64 #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -63,22 +68,179 @@ struct pentry unsigned char end_head; unsigned int end_cylinder; unsigned char end_sector; - unsigned long start_sector_abs; - unsigned long no_of_sectors_abs; + unsigned long long start_sector_abs; + unsigned long long no_of_sectors_abs; }; -int loadptable(const char *diskimage, struct pentry parttbl[], struct pentry **exttbl, int * valid) +static void +disp_entry (struct pentry *p) +{ + printf ("%10llu - %10llu: %02x %x\n", + SECSIZE * p->start_sector_abs, + SECSIZE * (p->start_sector_abs + p->no_of_sectors_abs - 1), + p->system, + p->bootable); +} + +static unsigned long +read_le4 (unsigned char *p) +{ + return (unsigned long) p[0] + | ((unsigned long) p[1] << 8) + | ((unsigned long) p[2] << 16) + | ((unsigned long) p[3] << 24); +} + +static unsigned long long +read_le8 (unsigned char *p) +{ + return (unsigned long long) p[0] + | ((unsigned long long) p[1] << 8) + | ((unsigned long long) p[2] << 16) + | ((unsigned long long) p[3] << 24) + | ((unsigned long long) p[4] << 32) + | ((unsigned long long) p[5] << 40) + | ((unsigned long long) p[6] << 48) + | ((unsigned long long) p[7] << 56); +} + +/* Return true if the partition table is a GPT protective MBR. */ +static int +check_gpt (struct pentry *part, int nbr_part) +{ + if (nbr_part != 4) + return 0; + if (part[0].system == 0xee + && part[1].no_of_sectors_abs == 0 + && part[2].no_of_sectors_abs == 0 + && part[3].no_of_sectors_abs == 0) + return 1; + return 0; +} + +static int +load_gpt (const char *diskimage, struct pentry *parttbl[]) +{ + FILE *fd; + size_t size; + int fail = -1; + unsigned char data[SECSIZE]; + unsigned long long entries_lba; + unsigned long entry_size; + struct pentry *part; + int nbr_part; + unsigned long long off; + int i; + + fd = fopen(diskimage, "r"); + if (fd == NULL) + { + perror(diskimage); + goto done; + } + fseeko (fd, SECSIZE, SEEK_SET); + size = fread (&data, 1, sizeof(data), fd); + if (size < (size_t)sizeof(data)) + { + fprintf(stderr, "Could not read the GPT header of %s.\n", + diskimage); + goto done; + } + + if (memcmp (data, "EFI PART", 8) != 0) + { + fprintf (stderr, "Bad GPT signature\n"); + goto done; + } + + entries_lba = read_le8 (&data[72]); + nbr_part = read_le4 (&data[80]); + entry_size = read_le4 (&data[84]); + +#ifdef DEBUG + fprintf(stderr, "lba entries: %lu, nbr_part: %u, entry_size: %lu\n", + entries_lba, nbr_part, entry_size); +#endif + part = malloc (nbr_part * sizeof (struct pentry)); + if (part == NULL) + { + fprintf(stderr,"Cannot allocate memory\n"); + goto done; + } + memset (part, 0, nbr_part * sizeof (struct pentry)); + *parttbl = part; + + off = entries_lba * SECSIZE; + for (i = 0; i < nbr_part; i++) + { + static const char unused_guid[16] = {0}; + fseeko (fd, off, SEEK_SET); + size = fread (&data, 1, 128, fd); + if (size < 128) + { + fprintf(stderr, "Could not read a GPT entry of %s.\n", + diskimage); + goto done; + } + if (memcmp (&data[0], unused_guid, 16) == 0) + { + part[i].start_sector_abs = 0; + part[i].no_of_sectors_abs = 0; + } + else + { + part[i].start_sector_abs = read_le8 (&data[32]); + part[i].no_of_sectors_abs = read_le8 (&data[40]); +#ifdef DEBUG + fprintf (stderr, "%d: %llu - %llu\n", i, + part[i].start_sector_abs, + part[i].no_of_sectors_abs); +#endif + /* Convert end to a number. */ + part[i].no_of_sectors_abs -= + part[i].start_sector_abs - 1; + } + off += entry_size; + } + + fail = nbr_part; + +done: + if (fd) + fclose(fd); + return fail; +} + +/* Read an MBR entry. */ +static void +read_mbr_record (unsigned char pi[16], struct pentry *res) +{ + res->bootable = *pi; + res->start_head = *(pi + 1); + res->start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300); + res->start_sector = *(pi + 2) & 0x3f; + res->system = *(pi + 4); + res->end_head = *(pi + 5); + res->end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300); + res->end_sector = *(pi + 6) & 0x3f; + res->start_sector_abs = read_le4 (&pi[8]); + res->no_of_sectors_abs = read_le4 (&pi[12]); +} + +/* Returns the number of partitions, -1 in case of failure. */ +int load_mbr(const char *diskimage, struct pentry *parttbl[]) { FILE *fd; size_t size; - int fail = 1; - int i, total_known_sectors = 0; + int fail = -1; + int nbr_part; + int i; unsigned char *pi; unsigned char data [SECSIZE]; - unsigned long extent = 0, old_extent = 0, e_count = 1; - struct pentry exttbls[4]; + unsigned long long extent; + struct pentry *part; - *valid = 0; + nbr_part = 0; fd = fopen(diskimage, "r"); if (fd == NULL) @@ -92,102 +254,61 @@ int loadptable(const char *diskimage, struct pentry parttbl[], struct pentry **e fprintf(stderr, "Could not read the entire first sector of %s.\n", diskimage); goto done; } - for (i = 0; i < 4; i++) + + if (data [510] != 0x55 || data [511] != 0xaa) { - pi = &data [446 + 16 * i]; - parttbl [i].bootable = *pi; - parttbl [i].start_head = *(pi + 1); - parttbl [i].start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300); - parttbl [i].start_sector = *(pi + 2) & 0x3f; - parttbl [i].system = *(pi + 4); - parttbl [i].end_head = *(pi + 5); - parttbl [i].end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300); - parttbl [i].end_sector = *(pi + 6) & 0x3f; - parttbl [i].start_sector_abs = - (unsigned long) *(pi + 8) | ((unsigned long) *(pi + 9) << 8) | ((unsigned long) *(pi + 10) << 16) | ((unsigned long) *(pi + 11) << 24); - parttbl [i].no_of_sectors_abs = - (unsigned long) *(pi + 12) | ((unsigned long) *(pi + 13) << 8) | ((unsigned long) *(pi + 14) << 16) | ((unsigned long) *(pi + 15) << 24); - if (parttbl[i].system == 0xF || parttbl[i].system == 0x5) - { - extent = parttbl[i].start_sector_abs * SECSIZE; - /* save the location of the "real" extended partition */ - old_extent = extent; - } + fprintf(stderr,"MBR signature mismatch (invalid partition table?)\n"); + goto done; } - *valid = (data [510] == 0x55 && data [511] == 0xaa) ? 1 : 0; - for (i = 0; i < 4; i++) + + /* There is at most 4*4 + 4 = 20 entries, also there should be only + one extended partition. */ + part = malloc (20 * sizeof (struct pentry)); + if (part == NULL) { - total_known_sectors += parttbl[i].no_of_sectors_abs; + fprintf(stderr,"Cannot allocate memory\n"); + goto done; } - /* Extended Partition layout format was obtained from - http://wigner.cped.ornl.gov/the-gang/att-0520/03-Partition.htm */ -#ifdef DEBUG - if (extent != 0) + *parttbl = part; + + /* Read MBR. */ + nbr_part = 4; + for (i = 0; i < 4; i++) { - printf("extended partition detected at offset %ld\n", extent); + pi = &data [446 + 16 * i]; + read_mbr_record (pi, &part[i]); } -#endif - while (extent != 0) + + /* Read extended partitions. */ + for (i = 0; i < 4; i++) { -/* according to realloc(3) passing NULL as pointer is same as calling malloc() */ - exttbl[0] = realloc(exttbl[0], e_count * sizeof(struct pentry)); - fseek(fd, extent, SEEK_SET); - size = fread (&data, 1, sizeof(data), fd); - if (size < (size_t)sizeof(data)) - { - fprintf(stderr, "Could not read extended partition of %s.", diskimage); - goto done; - } - /* only first 2 entrys are used in extented partition tables */ - for (i = 0; i < 2; i++) + if (part[i].system == 0xF || part[i].system == 0x5) { - pi = &data [446 + 16 * i]; - exttbls [i].bootable = *pi; - exttbls [i].start_head = *(pi + 1); - exttbls [i].start_cylinder = *(pi + 3) | ((*(pi + 2) << 2) & 0x300); - exttbls [i].start_sector = *(pi + 2) & 0x3f; - exttbls [i].system = *(pi + 4); - exttbls [i].end_head = *(pi + 5); - exttbls [i].end_cylinder = *(pi + 7) | ((*(pi + 6) << 2) & 0x300); - exttbls [i].end_sector = *(pi + 6) & 0x3f; - exttbls [i].start_sector_abs = - (unsigned long) *(pi + 8) | ((unsigned long) *(pi + 9) << 8) | ((unsigned long) *(pi + 10) << 16) | ((unsigned long) *(pi + 11) << 24); - exttbls [i].no_of_sectors_abs = - (unsigned long) *(pi + 12) | ((unsigned long) *(pi + 13) << 8) | ((unsigned long) *(pi + 14) << 16) | ((unsigned long) *(pi + 15) << 24); - if (i == 0) + int j; + + extent = part[i].start_sector_abs * SECSIZE; + + fseeko (fd, extent, SEEK_SET); + size = fread (&data, 1, sizeof(data), fd); + if (size < (size_t)sizeof(data)) { - //memmove((void *)exttbl[e_count-1], (void *)exttbls[i], sizeof(struct pentry)); - //memmove() seems broken! - exttbl[0][e_count-1].bootable = exttbls [i].bootable; - exttbl[0][e_count-1].start_head = exttbls [i].start_head; - exttbl[0][e_count-1].start_cylinder = exttbls [i].start_cylinder; - exttbl[0][e_count-1].start_sector = exttbls [i].start_sector; - exttbl[0][e_count-1].system = exttbls [i].system; - exttbl[0][e_count-1].end_head = exttbls [i].end_head; - exttbl[0][e_count-1].end_cylinder = exttbls [i].end_cylinder; - exttbl[0][e_count-1].end_sector = exttbls [i].end_sector; - exttbl[0][e_count-1].start_sector_abs = exttbls [i].start_sector_abs; - exttbl[0][e_count-1].no_of_sectors_abs = exttbls [i].no_of_sectors_abs; - /* adjust for start of image instead of start of ext partition */ - exttbl[0][e_count-1].start_sector_abs += (extent/SECSIZE); -#ifdef DEBUG - printf("extent %ld start_sector_abs %ld\n", extent, exttbl[0][e_count-1].start_sector_abs); -#endif - //else if (parttbl[i].system == 0x5) + fprintf(stderr, "Could not read extended partition of %s.", diskimage); + goto done; } - else if (i == 1) + + for (j = 0; j < 4; j++) { - extent = (exttbls[i].start_sector_abs * SECSIZE); - if (extent) - extent += old_extent; + int n; + pi = &data [446 + 16 * j]; + n = nbr_part + j; + read_mbr_record (pi, &part[n]); } + + nbr_part += 4; } - e_count ++; } -#ifdef DEBUG - printf("e_count = %ld\n", e_count); -#endif - fail = 0; + + fail = nbr_part; done: if (fd) @@ -197,8 +318,8 @@ done: void usage(void) { - fprintf(stderr, "You must specify at least -diskimage and -partition.\n"); - fprintf(stderr, "All other arguments are passed through to 'mount'.\n"); + fprintf(stderr, "Usage: lomount [-verbose] [OPTIONS] -diskimage FILE -partition NUM [OPTIONS]\n"); + fprintf(stderr, "All OPTIONS are passed through to 'mount'.\n"); fprintf(stderr, "ex. lomount -t fs-type -diskimage hda.img -partition 1 /mnt\n"); exit(ERR_USAGE); } @@ -206,14 +327,17 @@ void usage(void) int main(int argc, char ** argv) { int status; - struct pentry perttbl [4]; - struct pentry *exttbl[1], *parttbl; + int nbr_part; + struct pentry *parttbl; char buf[BUF], argv2[BUF]; - const char * diskimage = 0; - int partition = 0, sec, num = 0, pnum = 0, i, valid; + const char * diskimage = NULL; + int partition = 0; + unsigned long long sec, num, pnum; + int i; size_t argv2_len = sizeof(argv2); + int verbose = 0; + argv2[0] = '\0'; - exttbl[0] = NULL; for (i = 1; i < argc; i ++) { @@ -231,6 +355,10 @@ int main(int argc, char ** argv) i++; partition = atoi(argv[i]); } + else if (strcmp(argv[i], "-verbose")==0) + { + verbose++; + } else { size_t len = strlen(argv[i]); @@ -241,59 +369,65 @@ int main(int argc, char ** argv) len -= (len+1); } } - if (! diskimage || partition < 1) + if (! diskimage || partition < 0) usage(); - if (loadptable(diskimage, perttbl, exttbl, &valid)) + nbr_part = load_mbr(diskimage, &parttbl); + if (check_gpt (parttbl, nbr_part)) { + free (parttbl); + nbr_part = load_gpt (diskimage, &parttbl); + } + if (nbr_part < 0) return ERR_PART_PARSE; - if (!valid) + if (partition == 0) { - fprintf(stderr, "Warning: disk image does not appear to describe a valid partition table.\n"); + printf("Please specify a partition number. Table is:\n"); + printf("Num Start - End OS Bootable\n"); + for (i = 0; i < nbr_part; i++) + { + if (parttbl[i].no_of_sectors_abs != 0) + { + printf ("%2d: ", i + 1); + disp_entry (&parttbl[i]); + } + } + if (partition == 0) + return 0; } /* NOTE: need to make sure this always rounds down */ //sec = total_known_sectors / sizeof_diskimage; -/* The above doesn't work unless the disk image is completely filled by -partitions ... unused space will thrown off the sector size. The calculation -assumes the disk image is completely filled, and that the few sectors used -to store the partition table/MBR are few enough that the calculated value is -off by (larger than) a value less than one. */ + /* The above doesn't work unless the disk image is completely + filled by partitions ... unused space will thrown off the + sector size. The calculation assumes the disk image is + completely filled, and that the few sectors used to store + the partition table/MBR are few enough that the calculated + value is off by (larger than) a value less than one. */ sec = 512; /* TODO: calculate real sector size */ #ifdef DEBUG printf("sec: %d\n", sec); #endif - if (partition > 4) + if (partition > nbr_part) { - if (exttbl[0] == NULL) - { - fprintf(stderr, "No extended partitions were found in %s.\n", diskimage); - return ERR_NO_EPART; - } - parttbl = exttbl[0]; - if (parttbl[partition-5].no_of_sectors_abs == 0) - { - fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage); - return ERR_NO_PART; - } - partition -= 4; + fprintf(stderr, "Bad partition number\n"); + return ERR_NO_EPART; } - else + num = parttbl[partition-1].start_sector_abs; + if (num == 0) { - parttbl = perttbl; - if (parttbl[partition-1].no_of_sectors_abs == 0) - { - fprintf(stderr, "Partition %d was not found in %s.\n", partition, diskimage); - return ERR_NO_PART; - } + fprintf(stderr, "Partition %d was not found in %s.\n", + partition, diskimage); + return ERR_NO_PART; } - num = parttbl[partition-1].start_sector_abs; + pnum = sec * num; #ifdef DEBUG printf("offset = %d\n", pnum); #endif - snprintf(buf, sizeof(buf), "mount -oloop,offset=%d %s %s", pnum, diskimage, argv2); -#ifdef DEBUG - printf("%s\n", buf); -#endif + snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s", + pnum, diskimage, argv2); + if (verbose) + printf("%s\n", buf); + status = system(buf); if (WIFEXITED(status)) status = WEXITSTATUS(status); |