diff options
author | Karel Zak | 2013-02-04 11:28:09 +0100 |
---|---|---|
committer | Karel Zak | 2013-02-04 11:28:09 +0100 |
commit | cd0fe5c1659d4144610ffd76500002e98b873e0b (patch) | |
tree | 889cb6f7bd291fbc3b6eb0e690af826fa2288224 /libblkid | |
parent | newgrp: more robust crypt() usage (diff) | |
download | kernel-qcow2-util-linux-cd0fe5c1659d4144610ffd76500002e98b873e0b.tar.gz kernel-qcow2-util-linux-cd0fe5c1659d4144610ffd76500002e98b873e0b.tar.xz kernel-qcow2-util-linux-cd0fe5c1659d4144610ffd76500002e98b873e0b.zip |
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 <kzak@redhat.com>
Diffstat (limited to 'libblkid')
-rw-r--r-- | libblkid/src/blkid.h.in | 1 | ||||
-rw-r--r-- | libblkid/src/blkid.sym | 7 | ||||
-rw-r--r-- | libblkid/src/probe.c | 111 |
3 files changed, 97 insertions, 22 deletions
diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in index a41bd99d0..44f2aa7b6 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 62f981f4c..cf2a16f94 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 eabcf9010..f7f90761a 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -948,7 +948,10 @@ int blkid_do_probe(blkid_probe pr) * </programlisting> * </example> * - * 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. + * + * <example> + * <title>wipe all superblock, but use libblkid only for probing</title> + * <programlisting> + * 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); + * } + * </programlisting> + * </example> + * + * 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; } |