chiark / gitweb /
util-lib: Fix chase_symlinks() with absolute symlinks (#5185)
author3chas3 <ciwillia@brocade.com>
Tue, 31 Jan 2017 13:21:15 +0000 (08:21 -0500)
committerSven Eden <yamakuzure@gmx.net>
Mon, 17 Jul 2017 15:58:36 +0000 (17:58 +0200)
If chase_symlinks() encouters an absolute symlink, it resets the todo
buffer to just the newly discovered symlink and discards any of the
remaining previous symlink path.  Regardless of whether or not the
symlink is absolute or relative, we need to preserve the remainder of
the path that has not yet been resolved.

src/basic/fs-util.c

index 05f10c86f827a9c9f86aa73794f8f014dddf6138..f6fb7cabc48a8c7ab198fe5fb252c62a096f9b8b 100644 (file)
@@ -728,6 +728,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         return -errno;
 
                 if (S_ISLNK(st.st_mode)) {
+                        char *joined;
+
                         _cleanup_free_ char *destination = NULL;
 
                         /* This is a symlink, in this case read the destination. But let's make sure we don't follow
@@ -751,9 +753,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                 if (fd < 0)
                                         return -errno;
 
-                                free_and_replace(buffer, destination);
-
-                                todo = buffer;
                                 free(done);
 
                                 /* Note that we do not revalidate the root, we take it as is. */
@@ -765,19 +764,17 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                                 return -ENOMEM;
                                 }
 
-                        } else {
-                                char *joined;
+                        }
 
-                                /* A relative destination. If so, this is what we'll prefix what's left to do with what
-                                 * we just read, and start the loop again, but remain in the current directory. */
+                        /* Prefix what's left to do with what we just read, and start the loop again,
+                         * but remain in the current directory. */
 
-                                joined = strjoin("/", destination, todo);
-                                if (!joined)
-                                        return -ENOMEM;
+                        joined = strjoin("/", destination, todo);
+                        if (!joined)
+                                return -ENOMEM;
 
-                                free(buffer);
-                                todo = buffer = joined;
-                        }
+                        free(buffer);
+                        todo = buffer = joined;
 
                         continue;
                 }