diff options
author | Karel Zak | 2011-12-20 18:25:04 +0100 |
---|---|---|
committer | Karel Zak | 2011-12-22 12:19:38 +0100 |
commit | 6c224de18bfa7c652e07685d0450e0984b27ee86 (patch) | |
tree | 34b6eec715e6c26d797f01cab94ced1e08bf5dd6 | |
parent | libblkid; fix memory leak in blkid_probe_get_wholedisk_probe() (diff) | |
download | kernel-qcow2-util-linux-6c224de18bfa7c652e07685d0450e0984b27ee86.tar.gz kernel-qcow2-util-linux-6c224de18bfa7c652e07685d0450e0984b27ee86.tar.xz kernel-qcow2-util-linux-6c224de18bfa7c652e07685d0450e0984b27ee86.zip |
lib,loopdev: add missing functions
- improve loop_info usage (don't call ioctl more than once)
- add functions to get devno and inode of the backing file
- add function for compare any file with backing file by devno + inode
or by filename
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r-- | include/loopdev.h | 12 | ||||
-rw-r--r-- | lib/loopdev.c | 207 |
2 files changed, 178 insertions, 41 deletions
diff --git a/include/loopdev.h b/include/loopdev.h index e675dab91..27f9668eb 100644 --- a/include/loopdev.h +++ b/include/loopdev.h @@ -96,6 +96,7 @@ struct loopdev_cxt { unsigned int has_info:1; /* .info contains data */ unsigned int extra_check:1; /* unusual stuff for iterator */ unsigned int debug:1; /* debug mode ON/OFF */ + unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */ struct sysfs_cxt sysfs; /* pointer to /sys/dev/block/<maj:min>/ */ struct loop_info64 info; /* for GET/SET ioctl */ @@ -120,6 +121,7 @@ enum { */ extern int is_loopdev(const char *device); extern int loopdev_is_autoclear(const char *device); + extern char *loopdev_get_backing_file(const char *device); extern int loopdev_is_used(const char *device, const char *filename, uint64_t offset, int flags); @@ -161,12 +163,22 @@ int loopcxt_set_encryption(struct loopdev_cxt *lc, const char *password); extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc); +extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno); +extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino); extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size); +extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type); +extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc); extern int loopcxt_is_autoclear(struct loopdev_cxt *lc); extern int loopcxt_is_readonly(struct loopdev_cxt *lc); extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, uint64_t offset, int flags); +extern int loopcxt_is_used(struct loopdev_cxt *lc, + struct stat *st, + const char *backing_file, + uint64_t offset, + int flags); + #endif /* UTIL_LINUX_LOOPDEV_H */ diff --git a/lib/loopdev.c b/lib/loopdev.c index 3dfa78a40..fa23b0e90 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -88,6 +88,7 @@ int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) lc->fd = -1; lc->mode = 0; lc->has_info = 0; + lc->info_failed = 0; *lc->device = '\0'; memset(&lc->info, 0, sizeof(lc->info)); @@ -236,7 +237,6 @@ struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc) } } - DBG(lc, loopdev_debug("sysfs: returns context")); return &lc->sysfs; } @@ -540,20 +540,23 @@ struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc) { int fd; - if (!lc) + if (!lc || lc->info_failed) return NULL; if (lc->has_info) return &lc->info; - DBG(lc, loopdev_debug("reading loop_info64")); - fd = loopcxt_get_fd(lc); if (fd < 0) return NULL; if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) { lc->has_info = 1; + lc->info_failed = 0; + DBG(lc, loopdev_debug("reading loop_info64 OK")); return &lc->info; + } else { + lc->info_failed = 1; + DBG(lc, loopdev_debug("reading loop_info64 FAILED")); } return NULL; @@ -587,7 +590,7 @@ char *loopcxt_get_backing_file(struct loopdev_cxt *lc) } } - DBG(lc, loopdev_debug("return backing file: %s", res)); + DBG(lc, loopdev_debug("get_backing_file [%s]", res)); return res; } @@ -610,10 +613,11 @@ int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset) if (lo) { if (offset) *offset = lo->lo_offset; - return 0; + rc = 0; } } + DBG(lc, loopdev_debug("get_offset [rc=%d]", rc)); return rc; } @@ -636,10 +640,92 @@ int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size) if (lo) { if (size) *size = lo->lo_sizelimit; - return 0; + rc = 0; } } + DBG(lc, loopdev_debug("get_sizelimit [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @devno: returns encryption type + * + * Cryptoloop is DEPRECATED! + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc = -EINVAL; + + if (lo) { + if (type) + *type = lo->lo_encrypt_type; + rc = 0; + } + DBG(lc, loopdev_debug("get_encrypt_type [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @devno: returns crypt name + * + * Cryptoloop is DEPRECATED! + * + * Returns: <0 on error, 0 on success + */ +const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + + if (lo) + return (char *) lo->lo_crypt_name; + + DBG(lc, loopdev_debug("get_crypt_name failed")); + return NULL; +} + +/* + * @lc: context + * @devno: returns backing file devno + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc = -EINVAL; + + if (lo) { + if (devno) + *devno = lo->lo_device; + rc = 0; + } + DBG(lc, loopdev_debug("get_backing_devno [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @ino: returns backing file inode + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc = -EINVAL; + + if (lo) { + if (ino) + *ino = lo->lo_inode; + rc = 0; + } + DBG(lc, loopdev_debug("get_backing_inode [rc=%d]", rc)); return rc; } @@ -690,6 +776,67 @@ int loopcxt_is_readonly(struct loopdev_cxt *lc) } /* + * @lc: context + * @st: backing file stat or NULL + * @backing_file: filename + * @offset: offset + * @flags: LOOPDEV_FL_OFFSET if @offset should not be ignored + * + * Returns 1 if the current @lc loopdev is associated with the given backing + * file. Note that the preferred way is to use devno and inode number rather + * than filename. The @backing_file filename is poor solution usable in case + * that you don't have rights to call stat(). + * + * Don't forget that old kernels provide very restricted (in size) backing + * filename by LOOP_GET_STAT64 ioctl only. + */ +int loopcxt_is_used(struct loopdev_cxt *lc, + struct stat *st, + const char *backing_file, + uint64_t offset, + int flags) +{ + ino_t ino; + dev_t dev; + + if (!lc) + return 0; + + DBG(lc, loopdev_debug("checking %s vs. %s", + loopcxt_get_device(lc), + backing_file)); + + if (st && loopcxt_get_backing_inode(lc, &ino) == 0 && + loopcxt_get_backing_devno(lc, &dev) == 0) { + + if (ino == st->st_ino && dev == st->st_dev) + goto found; + + /* don't use filename if we have devno and inode */ + return 0; + } + + /* poor man's solution */ + if (backing_file) { + char *name = loopcxt_get_backing_file(lc); + int rc = name && strcmp(name, backing_file) == 0; + + free(name); + if (rc) + goto found; + } + + return 0; +found: + if (flags & LOOPDEV_FL_OFFSET) { + uint64_t off; + + return loopcxt_get_offset(lc, &off) == 0 && off == offset; + } + return 1; +} + +/* * The setting is removed by loopcxt_set_device() loopcxt_next()! */ int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset) @@ -891,6 +1038,7 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) } memset(&lc->info, 0, sizeof(lc->info)); lc->has_info = 0; + lc->info_failed = 0; DBG(lc, loopdev_debug("setup success [rc=0]")); return 0; @@ -998,7 +1146,7 @@ int loopdev_is_used(const char *device, const char *filename, uint64_t offset, int flags) { struct loopdev_cxt lc; - char *backing = NULL; + struct stat st; int rc = 0; if (!device) @@ -1007,23 +1155,10 @@ int loopdev_is_used(const char *device, const char *filename, loopcxt_init(&lc, 0); loopcxt_set_device(&lc, device); - backing = loopcxt_get_backing_file(&lc); - if (!backing) - goto done; - if (filename && strcmp(filename, backing) != 0) - goto done; - if (flags & LOOPDEV_FL_OFFSET) { - uint64_t off; - - if (loopcxt_get_offset(&lc, &off) != 0 || off != offset) - goto done; - } + rc = !stat(filename, &st); + rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, flags); - rc = 1; -done: - free(backing); loopcxt_deinit(&lc); - return rc; } @@ -1046,33 +1181,23 @@ int loopdev_delete(const char *device) int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, uint64_t offset, int flags) { - int rc; + int rc, hasst; + struct stat st; if (!filename) return -EINVAL; + hasst = !stat(filename, &st); + rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); if (rc) return rc; - while((rc = loopcxt_next(lc)) == 0) { - char *backing = loopcxt_get_backing_file(lc); + while ((rc = loopcxt_next(lc)) == 0) { - if (!backing || strcmp(backing, filename)) { - free(backing); - continue; - } - - free(backing); - - if (flags & LOOPDEV_FL_OFFSET) { - uint64_t off; - if (loopcxt_get_offset(lc, &off) != 0 || offset != off) - continue; - } - - rc = 0; - break; + if (loopcxt_is_used(lc, hasst ? &st : NULL, + filename, offset, flags)) + break; } loopcxt_deinit_iterator(lc); |