]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/fileutils: add ul_basename()
authorKarel Zak <kzak@redhat.com>
Tue, 2 Jul 2024 09:14:06 +0000 (11:14 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 2 Jul 2024 12:08:20 +0000 (14:08 +0200)
Unfortunately, the basename() function can be affected by the
creativity of different libc authors, resulting in varying behavior
across implementations.

Instead, use a local implementation to ensure consistency and
portability.

Signed-off-by: Karel Zak <kzak@redhat.com>
(cherry picked from commit ff8ee29d648111eb222612ad4251e4c3b236a389)

include/fileutils.h
lib/fileutils.c

index 538eab0b74eb250f767926290728a053396a63ca..6fc93d0db829ed70c207bdce9f19a4b915a45058 100644 (file)
@@ -114,5 +114,6 @@ int ul_copy_file(int from, int to);
 
 
 extern int ul_reopen(int fd, int flags);
+extern char *ul_basename(char *path);
 
 #endif /* UTIL_LINUX_FILEUTILS */
index 7779e10e68dcfeedcf6f55d7f91b75086f98fffe..95ee516350cae32d784ad46c1a156fd2dc2e07c6 100644 (file)
@@ -2,7 +2,7 @@
  * This code is in the public domain; do with it what you wish.
  *
  * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi>
- * Copyright (C) 2012-2020 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012-2024 Karel Zak <kzak@redhat.com>
  */
 #include <stdio.h>
 #include <stdlib.h>
@@ -311,3 +311,35 @@ int ul_reopen(int fd, int flags)
 
        return open(buf, flags);
 }
+
+
+/* This is a libc-independent version of basename(), which is necessary to
+ * maintain functionality across different libc implementations. It was
+ * inspired by the behavior and implementation of glibc.
+ */
+char *ul_basename(char *path)
+{
+       char *p;
+
+       if (!path || !*path)
+               return (char *) ".";    /* ugly, static string */
+
+       p = strrchr(path, '/');
+       if (!p)
+               return path;            /* no '/', return original */
+
+       if (*(p + 1) != '\0')
+               return p + 1;           /* begin of the name */
+
+       while (p > path && *(p - 1) == '/')
+               --p;                    /* remove tailing '/' */
+
+       if (p > path) {
+               *p-- = '\0';
+               while (p > path && *(p - 1) != '/')
+                       --p;            /* move to the beginning of the name */
+       } else while (*(p + 1) != '\0')
+               ++p;
+
+       return p;
+}