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:
Zbigniew Jędrzejewski-Szmek
2017-11-30 20:43:25 +01:00
parent ca4d708dc4
commit b12d25a8d6
7 changed files with 115 additions and 18 deletions
+11 -2
View File
@@ -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;
+2 -1
View File
@@ -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) {
+28
View File
@@ -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;
+1
View File
@@ -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_;