]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/canonicalize: refactor canonicalize_path()
authorKarel Zak <kzak@redhat.com>
Tue, 1 Jul 2025 09:19:29 +0000 (11:19 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 28 Aug 2025 10:07:27 +0000 (12:07 +0200)
 * introduce do_canonicalize() with proper return values

 * use do_canonicalize() everywhere

Signed-off-by: Karel Zak <kzak@redhat.com>
lib/canonicalize.c

index b36115f1929141a3d189a99a9385174da0c928d4..728783d3a661ae0b7e56d91c1cd7f80780f9aa66 100644 (file)
@@ -118,28 +118,57 @@ char *ul_absolute_path(const char *path)
        return res;
 }
 
-char *canonicalize_path(const char *path)
+/*
+ * Returns: <0 on error, 1 is cannot be canonicalized (errno is set); 0 on success
+ */
+static int __attribute__((nonnull(2)))
+do_canonicalize(const char *path, char **result)
 {
        char *canonical, *dmname;
 
-       if (!path || !*path)
-               return NULL;
+       *result = NULL;
+
+       if (!path || !*path) {
+               errno = EINVAL;
+               return -errno;
+       }
 
+       errno = 0;
        canonical = realpath(path, NULL);
        if (!canonical)
-               return strdup(path);
+               return 1;
 
        if (is_dm_devname(canonical, &dmname)) {
                char *dm = canonicalize_dm_name(dmname);
                if (dm) {
                        free(canonical);
-                       return dm;
+                       canonical = dm;
                }
        }
 
-       return canonical;
+       if (canonical)
+               *result = canonical;
+       return 0;
 }
 
+/*
+ * Always returns a newly allocated string or NULL in case of an error. An
+ * unreachable path is not an error (!), and in this case, it just duplicates
+ * @path.
+ */
+char *canonicalize_path(const char *path)
+{
+       char *canonical = NULL;
+
+       if (do_canonicalize(path, &canonical) == 1)
+               return strdup(path);
+
+       return canonical;
+}
+/*
+ * Almost like canonicalize_path() but drops permissions (suid, etc.) to
+ * canonicalize the path. Returns NULL if the path is unreachable
+ */
 char *canonicalize_path_restricted(const char *path)
 {
        char *canonical = NULL;
@@ -172,21 +201,11 @@ char *canonicalize_path_restricted(const char *path)
 
                if (drop_permissions() != 0)
                        canonical = NULL;       /* failed */
-               else {
-                       char *dmname = NULL;
-
-                       canonical = realpath(path, NULL);
-                       if (canonical && is_dm_devname(canonical, &dmname)) {
-                               char *dm = canonicalize_dm_name(dmname);
-                               if (dm) {
-                                       free(canonical);
-                                       canonical = dm;
-                               }
-                       }
-               }
+               else
+                       do_canonicalize(path, &canonical);
 
-               len = canonical ? (ssize_t) strlen(canonical) :
-                         errno ? -errno : -EINVAL;
+               len = canonical ?(ssize_t) strlen(canonical) :
+                               errno ? -errno : -EINVAL;
 
                /* send length or errno */
                write_all(pipes[1], (char *) &len, sizeof(len));