| Index: cgpt/cmd_find.c
|
| diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c
|
| index b50400e25cadfb583d0ec113b9b8c9deb1281be0..403d40f2f506276a735fd8e0502644b073af0f46 100644
|
| --- a/cgpt/cmd_find.c
|
| +++ b/cgpt/cmd_find.c
|
| @@ -28,6 +28,10 @@ static void Usage(void)
|
| " -v Be verbose in displaying matches (repeatable)\n"
|
| " -n Numeric output only\n"
|
| " -1 Fail if more than one match is found\n"
|
| + " -M FILE"
|
| + " Matching partition data must also contain FILE content\n"
|
| + " -O NUM"
|
| + " Byte offset into partition to match content (default 0)\n"
|
| "\n", progname);
|
| PrintTypes();
|
| }
|
| @@ -40,6 +44,10 @@ static int set_type = 0;
|
| static int set_label = 0;
|
| static int oneonly = 0;
|
| static int numeric = 0;
|
| +static uint8_t *matchbuf = NULL;
|
| +static uint64_t matchlen = 0;
|
| +static uint64_t matchoffset = 0;
|
| +static uint8_t *comparebuf = NULL;
|
|
|
| static Guid unique_guid;
|
| static Guid type_guid;
|
| @@ -47,6 +55,8 @@ static char *label;
|
| static int hits = 0;
|
|
|
| #define BUFSIZE 1024
|
| +// FIXME: currently we only support 512-byte sectors.
|
| +#define LBA_SIZE 512
|
|
|
|
|
| // remember one of the possibly many hits
|
| @@ -54,6 +64,86 @@ static int match_partnum = 0; // 0 for no match, 1-N for match
|
| static char match_filename[BUFSIZE]; // matching filename
|
|
|
|
|
| +// read a file into a buffer, return buffer and update size
|
| +static uint8_t *ReadFile(const char *filename, uint64_t *size) {
|
| + FILE *f;
|
| + uint8_t *buf;
|
| +
|
| + f = fopen(filename, "rb");
|
| + if (!f) {
|
| + return NULL;
|
| + }
|
| +
|
| + fseek(f, 0, SEEK_END);
|
| + *size = ftell(f);
|
| + rewind(f);
|
| +
|
| + buf = malloc(*size);
|
| + if (!buf) {
|
| + fclose(f);
|
| + return NULL;
|
| + }
|
| +
|
| + if(1 != fread(buf, *size, 1, f)) {
|
| + fclose(f);
|
| + free(buf);
|
| + return NULL;
|
| + }
|
| +
|
| + fclose(f);
|
| + return buf;
|
| +}
|
| +
|
| +// fill comparebuf with the data to be examined, returning true on success.
|
| +static int FillBuffer(int fd, uint64_t pos, uint64_t count) {
|
| + uint8_t *bufptr = comparebuf;
|
| +
|
| + if (-1 == lseek(fd, pos, SEEK_SET))
|
| + return 0;
|
| +
|
| + // keep reading until done or error
|
| + while (count) {
|
| + ssize_t bytes_read = read(fd, bufptr, count);
|
| + // negative means error, 0 means (unexpected) EOF
|
| + if (bytes_read <= 0)
|
| + return 0;
|
| + count -= bytes_read;
|
| + bufptr += bytes_read;
|
| + }
|
| +
|
| + return 1;
|
| +}
|
| +
|
| +// check partition data content. return true for match, 0 for no match or error
|
| +static int match_content(struct drive *drive, GptEntry *entry) {
|
| + uint64_t part_size;
|
| +
|
| + if (!matchlen)
|
| + return 1;
|
| +
|
| + // Ensure that the region we want to match against is inside the partition.
|
| + part_size = LBA_SIZE * (entry->ending_lba - entry->starting_lba + 1);
|
| + if (matchoffset + matchlen > part_size) {
|
| + return 0;
|
| + }
|
| +
|
| + // Read the partition data.
|
| + if (!FillBuffer(drive->fd,
|
| + (LBA_SIZE * entry->starting_lba) + matchoffset,
|
| + matchlen)) {
|
| + Error("unable to read partition data\n");
|
| + return 0;
|
| + }
|
| +
|
| + // Compare it
|
| + if (0 == memcmp(matchbuf, comparebuf, matchlen)) {
|
| + return 1;
|
| + }
|
| +
|
| + // Nope.
|
| + return 0;
|
| +}
|
| +
|
| // FIXME: This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3
|
| static void showmatch(char *filename, int partnum, GptEntry *entry) {
|
| printf("%s%d\n", filename, partnum);
|
| @@ -96,7 +186,7 @@ static int do_search(char *filename) {
|
| found = 1;
|
| }
|
| }
|
| - if (found) {
|
| + if (found && match_content(&drive, entry)) {
|
| hits++;
|
| retval++;
|
| showmatch(filename, i+1, entry);
|
| @@ -111,7 +201,7 @@ static int do_search(char *filename) {
|
|
|
| return retval;
|
| }
|
| -
|
| +
|
|
|
| #define PROC_PARTITIONS "/proc/partitions"
|
| #define DEV_DIR "/dev"
|
| @@ -128,12 +218,9 @@ static char *is_wholedev(const char *basename) {
|
| static char pathname[BUFSIZE]; // we'll return this.
|
| char tmpname[BUFSIZE];
|
|
|
| -// printf("basename is %s\n", basename);
|
| -
|
| - // It should be a block device under /dev/,
|
| + // It should be a block device under /dev/,
|
| for (i = 0; devdirs[i]; i++) {
|
| sprintf(pathname, "%s/%s", devdirs[i], basename);
|
| -// printf(" look at %s\n", pathname);
|
|
|
| if (0 != stat(pathname, &statbuf))
|
| continue;
|
| @@ -143,7 +230,6 @@ static char *is_wholedev(const char *basename) {
|
|
|
| // It should have a symlink called /sys/block/*/device
|
| sprintf(tmpname, "%s/%s/device", SYS_BLOCK_DIR, basename);
|
| -// printf(" look at %s\n", tmpname);
|
|
|
| if (0 != lstat(tmpname, &statbuf))
|
| continue;
|
| @@ -177,7 +263,7 @@ static int scan_real_devs(void) {
|
| while (fgets(line, sizeof(line), fp)) {
|
| int ma, mi;
|
| long long unsigned int sz;
|
| -
|
| +
|
| if (sscanf(line, " %d %d %llu %128[^\n ]", &ma, &mi, &sz, partname) != 4)
|
| continue;
|
|
|
| @@ -187,20 +273,20 @@ static int scan_real_devs(void) {
|
| }
|
| }
|
| }
|
| -
|
| +
|
| fclose(fp);
|
| return found;
|
| }
|
| -
|
| +
|
|
|
| int cmd_find(int argc, char *argv[]) {
|
| int i;
|
| -
|
| int errorcnt = 0;
|
| + char *e = 0;
|
| int c;
|
| -
|
| +
|
| opterr = 0; // quiet, you
|
| - while ((c=getopt(argc, argv, ":hv1nt:u:l:")) != -1)
|
| + while ((c=getopt(argc, argv, ":hv1nt:u:l:M:O:")) != -1)
|
| {
|
| switch (c)
|
| {
|
| @@ -232,6 +318,27 @@ int cmd_find(int argc, char *argv[]) {
|
| errorcnt++;
|
| }
|
| break;
|
| + case 'M':
|
| + matchbuf = ReadFile(optarg, &matchlen);
|
| + if (!matchbuf || !matchlen) {
|
| + Error("Unable to read from %s\n", optarg);
|
| + errorcnt++;
|
| + }
|
| + // Go ahead and allocate space for the comparison too
|
| + comparebuf = (uint8_t *)malloc(matchlen);
|
| + if (!comparebuf) {
|
| + Error("Unable to allocate %" PRIu64 "bytes for comparison buffer\n",
|
| + matchlen);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'O':
|
| + matchoffset = strtoull(optarg, &e, 0);
|
| + if (!*optarg || (e && *e)) {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
|
|
| case 'h':
|
| Usage();
|
| @@ -249,13 +356,16 @@ int cmd_find(int argc, char *argv[]) {
|
| break;
|
| }
|
| }
|
| + if (!set_unique && !set_type && !set_label) {
|
| + Error("You must specify at least one of -t, -u, or -l\n");
|
| + errorcnt++;
|
| + }
|
| if (errorcnt)
|
| {
|
| Usage();
|
| return CGPT_FAILED;
|
| }
|
|
|
| -
|
| if (optind < argc) {
|
| for (i=optind; i<argc; i++)
|
| do_search(argv[i]);
|
|
|