]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib,loopdev: add missing functions
authorKarel Zak <kzak@redhat.com>
Tue, 20 Dec 2011 17:25:04 +0000 (18:25 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 22 Dec 2011 11:19:38 +0000 (12:19 +0100)
 - 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>
include/loopdev.h
lib/loopdev.c

index e675dab91ba75dab75d9790cee025cc40901c29f..27f9668ebabbdf6f9ea43b6976f4e820451a7c75 100644 (file)
@@ -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 */
index 3dfa78a400b36cc14952096128024787fcc88af5..fa23b0e90e9104b726b928cd41ec9f67383d685d 100644 (file)
@@ -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;
 }
 
@@ -689,6 +775,67 @@ int loopcxt_is_readonly(struct loopdev_cxt *lc)
        return 0;
 }
 
+/*
+ * @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()!
  */
@@ -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);