diff options
-rw-r--r-- | shlibs/blkid/src/blkidP.h | 8 | ||||
-rw-r--r-- | shlibs/blkid/src/partitions/partitions.c | 80 | ||||
-rw-r--r-- | shlibs/blkid/src/probe.c | 53 | ||||
-rw-r--r-- | shlibs/blkid/src/superblocks/superblocks.c | 36 |
4 files changed, 165 insertions, 12 deletions
diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index c37f73062..41eba9102 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -196,6 +196,7 @@ struct blkid_struct_probe mode_t mode; /* struct stat.sb_mode */ int flags; /* private libray flags */ + int prob_flags; /* always zeroized by blkid_do_*() */ struct list_head buffers; /* list of buffers */ @@ -206,10 +207,12 @@ struct blkid_struct_probe int nvals; /* number of assigned vals */ }; -/* flags */ +/* private flags */ #define BLKID_PRIVATE_FD (1 << 1) /* see blkid_new_probe_from_filename() */ #define BLKID_TINY_DEV (1 << 2) /* <= 1.47MiB (floppy or so) */ #define BLKID_CDROM_DEV (1 << 3) /* is a CD/DVD drive */ +/* private probing flags */ +#define BLKID_PARTS_IGNORE_PT (1 << 1) /* ignore partition table */ /* * Evaluation methods (for blkid_eval_* API) @@ -390,6 +393,9 @@ extern int blkid_probe_set_dimension(blkid_probe pr, extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr); +extern int blkid_probe_is_covered_by_pt(blkid_probe pr, + blkid_loff_t offset, blkid_loff_t size); + extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn); extern int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, struct blkid_prval *vals, int nvals); diff --git a/shlibs/blkid/src/partitions/partitions.c b/shlibs/blkid/src/partitions/partitions.c index 293ee86aa..9d8f3db7a 100644 --- a/shlibs/blkid/src/partitions/partitions.c +++ b/shlibs/blkid/src/partitions/partitions.c @@ -582,6 +582,9 @@ static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) if (chn->binary) partitions_init_data(pr, chn); + if (pr->prob_flags & BLKID_PARTS_IGNORE_PT) + goto details_only; + DBG(DEBUG_LOWPROBE, printf("--> starting probing loop [PARTS idx=%d]\n", chn->idx)); @@ -620,6 +623,7 @@ static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) chn->idx)); } +details_only: /* * Gather PART_ENTRY_* values if the current device is a partition. */ @@ -764,6 +768,82 @@ nothing: return rc; } +/* + * This function is compatible with blkid_probe_get_partitions(), but the + * result is not stored in @pr and all probing is independent on the + * status of @pr. It's possible to call this function from arbitrary + * place without a care about @pr. + */ +static blkid_partlist blkid_probe_get_independent_partlist(blkid_probe pr) +{ + + blkid_partlist ls = NULL, org_ls = NULL; + struct blkid_chain *chn = &pr->chains[BLKID_CHAIN_PARTS]; + struct blkid_prval vals[BLKID_NVALS_PARTS]; + int nvals = BLKID_NVALS_PARTS; + int idx; + + /* save old results */ + nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals); + idx = chn->idx; + if (chn->data) { + org_ls = chn->data; + chn->data = NULL; + } + + ls = blkid_probe_get_partitions(pr); + + /* restore original results */ + chn->data = org_ls; + chn->idx = idx; + + blkid_probe_chain_reset_vals(pr, chn); + blkid_probe_append_vals(pr, vals, nvals); + + return ls; +} + +/* + * Returns 1 if the device is whole-disk and the area specified by @offset and + * @size is covered by any partition. + */ +int blkid_probe_is_covered_by_pt(blkid_probe pr, + blkid_loff_t offset, blkid_loff_t size) +{ + blkid_partlist ls = NULL; + blkid_loff_t start, end; + int nparts, i, rc = 0; + + DBG(DEBUG_LOWPROBE, printf( + "=> checking if off=%jd size=%jd covered by PT\n", + offset, size)); + + ls = blkid_probe_get_independent_partlist(pr); + if (!ls) + goto done; + + nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + goto done; + + end = (offset + size) >> 9; + start = offset >> 9; + + for (i = 0; i < nparts; i++) { + blkid_partition par = &ls->parts[i]; + + if (start >= par->start && end <= par->start + par->size) { + rc = 1; + break; + } + } +done: + partitions_free_data(pr, (void *)ls); + + DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT")); + return rc; +} + /** * blkid_known_pttype: * @pttype: partiton name diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 56e66a311..9021a7e84 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -290,21 +290,33 @@ struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) { - int rc; + int rc, org_prob_flags; + struct blkid_chain *org_chn; if (!pr || !chn) return NULL; + /* save the current setting -- the binary API has to be completely + * independent on the current probing status + */ + org_chn = pr->cur_chain; + org_prob_flags = pr->prob_flags; + pr->cur_chain = chn; + pr->prob_flags = 0; chn->binary = TRUE; blkid_probe_chain_reset_position(chn); rc = chn->driver->probe(pr, chn); chn->binary = FALSE; - pr->cur_chain = NULL; blkid_probe_chain_reset_position(chn); + /* restore the original setting + */ + pr->cur_chain = org_chn; + pr->prob_flags = org_prob_flags; + if (rc != 0) return NULL; @@ -679,6 +691,22 @@ int blkid_probe_set_dimension(blkid_probe pr, return 0; } +static inline void blkid_probe_start(blkid_probe pr) +{ + if (pr) { + pr->cur_chain = NULL; + pr->prob_flags = 0; + } +} + +static inline void blkid_probe_end(blkid_probe pr) +{ + if (pr) { + pr->cur_chain = NULL; + pr->prob_flags = 0; + } +} + /** * blkid_do_probe: * @pr: prober @@ -730,9 +758,10 @@ int blkid_do_probe(blkid_probe pr) do { struct blkid_chain *chn = pr->cur_chain; - if (!chn) + if (!chn) { + blkid_probe_start(pr); chn = pr->cur_chain = &pr->chains[0]; - + } /* we go to the next chain only when the previous probing * result was nothing (rc == 1) and when the current chain is * disabled or we are at end of the current chain (chain->idx + @@ -747,8 +776,10 @@ int blkid_do_probe(blkid_probe pr) if (idx < BLKID_NCHAINS) chn = pr->cur_chain = &pr->chains[idx]; - else + else { + blkid_probe_end(pr); return 1; /* all chains already probed */ + } } chn->binary = FALSE; /* for sure... */ @@ -780,7 +811,9 @@ int blkid_do_probe(blkid_probe pr) * * Note about suberblocks chain -- the function does not check for filesystems * when a RAID signature is detected. The function also does not check for - * collision between RAIDs. The first detected RAID is returned. + * collision between RAIDs. The first detected RAID is returned. The function + * checks for collision between partition table and RAID signature -- it's + * recommended to enable partitions chain together with superblocks chain. * * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is * detected and -1 on case of error. @@ -792,6 +825,8 @@ int blkid_do_safeprobe(blkid_probe pr) if (!pr) return -1; + blkid_probe_start(pr); + for (i = 0; i < BLKID_NCHAINS; i++) { struct blkid_chain *chn; @@ -819,7 +854,7 @@ int blkid_do_safeprobe(blkid_probe pr) } done: - pr->cur_chain = NULL; + blkid_probe_end(pr); if (rc < 0) return rc; return count ? 0 : 1; @@ -844,6 +879,8 @@ int blkid_do_fullprobe(blkid_probe pr) if (!pr) return -1; + blkid_probe_start(pr); + for (i = 0; i < BLKID_NCHAINS; i++) { int rc; struct blkid_chain *chn; @@ -872,7 +909,7 @@ int blkid_do_fullprobe(blkid_probe pr) } done: - pr->cur_chain = NULL; + blkid_probe_end(pr); if (rc < 0) return rc; return count ? 0 : 1; diff --git a/shlibs/blkid/src/superblocks/superblocks.c b/shlibs/blkid/src/superblocks/superblocks.c index 6ed0de6e6..b46e59633 100644 --- a/shlibs/blkid/src/superblocks/superblocks.c +++ b/shlibs/blkid/src/superblocks/superblocks.c @@ -478,14 +478,17 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) int idx = -1; int count = 0; int intol = 0; - int rc; + int rc, bin_org = chn->binary; + + chn->binary = TRUE; while ((rc = superblocks_probe(pr, chn)) == 0) { - if (blkid_probe_is_tiny(pr) && !count) + if (blkid_probe_is_tiny(pr) && !count) { /* floppy or so -- returns the first result. */ + chn->binary = bin_org; return 0; - + } if (!count) { /* save the first result */ nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals); @@ -500,6 +503,9 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) if (!(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT)) intol++; } + + chn->binary = bin_org; + if (rc < 0) return rc; /* error */ if (count > 1 && intol) { @@ -519,6 +525,30 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) superblocks_copy_data(chn->data, sb); chn->idx = idx; + /* + * Check for collisions between RAID and partition table + */ + if (sb && sb->usage == BLKID_USAGE_RAID && + sb->magic_off > pr->size / 2 && + (S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) && + blkid_probe_is_covered_by_pt(pr, sb->magic_off, 0x200)) { + /* + * Ignore the result if the detected RAID superblock is + * within some existing partition (for example RAID on + * the last partition). + */ + blkid_probe_chain_reset_vals(pr, chn); + return 1; + } + + /* + * The RAID device could be partitioned. The problem are RAID1 devices + * where the partition table is visible from underlaying devices. We + * have to ignore such partition tables. + */ + if (sb && sb->usage == BLKID_USAGE_RAID) + pr->prob_flags |= BLKID_PARTS_IGNORE_PT; + return 0; } |