util-lib: use trailing slash in chase_symlinks, fd_is_mount_point, path_is_mount_point
The kernel will reply with -ENOTDIR when we try to access a non-directory under
a name which ends with a slash. But our functions would strip the trailing slash
under various circumstances. Keep the trailing slash, so that
path_is_mount_point("/path/to/file/") return -ENOTDIR when /path/to/file/ is a file.
Tests are added for this change in behaviour.
Also, when called with a trailing slash, path_is_mount_point() would get
"" from basename(), and call name_to_handle_at(3, "", ...), and always
return -ENOENT. Now it'll return -ENOTDIR if the mount point is a file, and
true if it is a directory and a mount point.
v2:
- use strip_trailing_chars()
v3:
- instead of stripping trailing chars(), do the opposite — preserve them.
This commit is contained in:
+11
-2
@@ -661,10 +661,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
||||
|
||||
todo += m;
|
||||
|
||||
/* Just a single slash? Then we reached the end. */
|
||||
if (isempty(first) || path_equal(first, "/"))
|
||||
/* Empty? Then we reached the end. */
|
||||
if (isempty(first))
|
||||
break;
|
||||
|
||||
/* Just a single slash? Then we reached the end. */
|
||||
if (path_equal(first, "/")) {
|
||||
/* Preserve the trailing slash */
|
||||
if (!strextend(&done, "/", NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Just a dot? Then let's eat this up. */
|
||||
if (path_equal(first, "/."))
|
||||
continue;
|
||||
|
||||
@@ -277,6 +277,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
|
||||
|
||||
if (path_equal(t, "/"))
|
||||
return 1;
|
||||
@@ -301,7 +302,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd_is_mount_point(fd, basename(t), flags);
|
||||
return fd_is_mount_point(fd, last_path_component(t), flags);
|
||||
}
|
||||
|
||||
int path_get_mnt_id(const char *path, int *ret) {
|
||||
|
||||
@@ -703,6 +703,34 @@ char* dirname_malloc(const char *path) {
|
||||
return dir2;
|
||||
}
|
||||
|
||||
const char *last_path_component(const char *path) {
|
||||
/* Finds the last component of the path, preserving the
|
||||
* optional trailing slash that signifies a directory.
|
||||
* a/b/c → c
|
||||
* a/b/c/ → c/
|
||||
* / → /
|
||||
* // → /
|
||||
* /foo/a → a
|
||||
* /foo/a/ → a/
|
||||
* This is different than basename, which returns "" when
|
||||
* a trailing slash is present.
|
||||
*/
|
||||
|
||||
unsigned l, k;
|
||||
|
||||
l = k = strlen(path);
|
||||
while (k > 0 && path[k-1] == '/')
|
||||
k--;
|
||||
|
||||
if (k == 0) /* the root directory */
|
||||
return path + l - 1;
|
||||
|
||||
while (k > 0 && path[k-1] != '/')
|
||||
k--;
|
||||
|
||||
return path + k;
|
||||
}
|
||||
|
||||
bool filename_is_valid(const char *p) {
|
||||
const char *e;
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ char *prefix_root(const char *root, const char *path);
|
||||
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
|
||||
|
||||
char* dirname_malloc(const char *path);
|
||||
const char *last_path_component(const char *path);
|
||||
|
||||
bool filename_is_valid(const char *p) _pure_;
|
||||
bool path_is_normalized(const char *p) _pure_;
|
||||
|
||||
Reference in New Issue
Block a user