From: Karel Zak Date: Mon, 4 Feb 2013 10:28:09 +0000 (+0100) Subject: libblkid: add blkid_probe_step_back() X-Git-Tag: v2.23-rc1~256 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cd0fe5c1659d4144610ffd76500002e98b873e0b;p=thirdparty%2Futil-linux.git libblkid: add blkid_probe_step_back() It seems that blkid_do_probe() is too high-level solution for some mkfs programs (for example ext4 mkfs supports "undo" so all write operations has to be implemented by filesystem specific functions). The new function blkid_probe_step_back() resets internal libblkid buffers and move probing stuff one step back. It means that the previously used probing function will be called again in the next blkid_do_probe() call. This allows to modify on-disk data and check for backup superblocks or alternative magic strings. Something like: while (blkid_do_probe(pr) == 0) { ... get SBMAGIC_OFFSET and SBMAGIC len ... ... use your private seek & write() ... blkid_probe_step_back(pr); } References: https://bugzilla.redhat.com/show_bug.cgi?id=902512 Signed-off-by: Karel Zak --- diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in index a41bd99d0c..44f2aa7b6e 100644 --- a/libblkid/src/blkid.h.in +++ b/libblkid/src/blkid.h.in @@ -414,6 +414,7 @@ extern int blkid_probe_has_value(blkid_probe pr, const char *name) __ul_attribute__((warn_unused_result)); extern int blkid_do_wipe(blkid_probe pr, int dryrun); +extern int blkid_probe_step_back(blkid_probe pr); /* * Deprecated functions/macros diff --git a/libblkid/src/blkid.sym b/libblkid/src/blkid.sym index 62f981f4c2..cf2a16f944 100644 --- a/libblkid/src/blkid.sym +++ b/libblkid/src/blkid.sym @@ -146,3 +146,10 @@ global: blkid_do_wipe; } BLKID_2.20; +/* + * symbols since util-linux 2.23 + */ +BLKID_2.23 { +global: + blkid_probe_step_back; +} BLKID_2.21; diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index eabcf9010b..f7f90761a2 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -948,7 +948,10 @@ int blkid_do_probe(blkid_probe pr) * * * - * Returns: 0 on success, 1 when probing is done and -1 in case of error. + * See also blkid_probe_step_back() if you cannot use this build-in wipe + * function, but you want to use libblkid probing as a source for wiping. + * + * Returns: 0 on success, and -1 in case of error. */ int blkid_do_wipe(blkid_probe pr, int dryrun) { @@ -1006,30 +1009,94 @@ int blkid_do_wipe(blkid_probe pr, int dryrun) if (write_all(fd, buf, len)) return -1; fsync(fd); + return blkid_probe_step_back(pr); + } - blkid_probe_reset_buffer(pr); + return 0; +} - if (chn->idx >= 0) { - chn->idx--; - DBG(DEBUG_LOWPROBE, - printf("do_wipe: moving %s chain index to %d\n", - chn->driver->name, - chn->idx)); - } - if (chn->idx == -1) { - /* blkid_do_probe() goes to the next chain if the index - * of the current chain is -1, so we have to set the - * chain pointer to the previos chain. - */ - size_t idx = chn->driver->id > 0 ? - chn->driver->id - 1 : 0; - - if (idx > 0) - pr->cur_chain = &pr->chains[idx]; - else if (idx == 0) - pr->cur_chain = NULL; - } +/** + * blkid_probe_step_back(): + * @pr: prober + * + * This function move pointer to the probing chain one step back -- it means + * that the previously used probing function will be called again in the next + * blkid_do_probe() call. + * + * This is necessary for example if you erase or modify on-disk superblock + * according to the current libblkid probing result. + * + * + * wipe all superblock, but use libblkid only for probing + * + * pr = blkid_new_probe_from_filename(devname); + * + * blkid_probe_enable_superblocks(pr, 1); + * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); + * + * while (blkid_do_probe(pr) == 0) { + * const char *ostr = NULL; + * size_t len = 0; + * + * // superblocks + * if (blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &ostr, NULL) == 0) + * blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); + * + * // partition tables + * if (len == 0 && blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &ostr, NULL) == 0) + * blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); + * + * if (!len || !str) + * continue; + * + * // convert ostr to the real offset by off = strtoll(ostr, NULL, 10); + * // use your stuff to errase @len bytes at the @off + * .... + * + * // retry the last probing to check for backup superblocks ..etc. + * blkid_probe_step_back(pr); + * } + * + * + * + * Returns: 0 on success, and -1 in case of error. + */ +int blkid_probe_step_back(blkid_probe pr) +{ + struct blkid_chain *chn; + + if (!pr) + return -1; + + chn = pr->cur_chain; + if (!chn) + return -1; + + blkid_probe_reset_buffer(pr); + + if (chn->idx >= 0) { + chn->idx--; + DBG(DEBUG_LOWPROBE, + printf("step back: moving %s chain index to %d\n", + chn->driver->name, + chn->idx)); } + + if (chn->idx == -1) { + /* blkid_do_probe() goes to the next chain if the index + * of the current chain is -1, so we have to set the + * chain pointer to the previous chain. + */ + size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0; + + DBG(DEBUG_LOWPROBE, printf("step back: moving to previous chain\n")); + + if (idx > 0) + pr->cur_chain = &pr->chains[idx]; + else if (idx == 0) + pr->cur_chain = NULL; + } + return 0; }