summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--shlibs/blkid/src/blkidP.h8
-rw-r--r--shlibs/blkid/src/partitions/partitions.c80
-rw-r--r--shlibs/blkid/src/probe.c53
-rw-r--r--shlibs/blkid/src/superblocks/superblocks.c36
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;
}