From a9dc850d06ecb6aa3b15c4afaadc4cc0300d794a Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Thu, 8 Aug 2013 18:06:16 +0200 Subject: [PATCH] Fix path canonicalization in make_relative_path when path doesn't exist --- ccache.c | 40 +++++++++++++++++++++++++++++++++------ test/test_argument_processing.c | 19 +++++++++---------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/ccache.c b/ccache.c index 38652e1..c02868f 100644 --- a/ccache.c +++ b/ccache.c @@ -387,12 +387,14 @@ ignore: static char * make_relative_path(char *path) { - char *relpath, *canon_path; + char *relpath, *canon_path, *path_suffix = NULL; + struct stat st; if (!base_dir || !str_startswith(path, base_dir)) { return path; } + /* Look up CWD and cache it in the global current_working_dir variable. */ if (!current_working_dir) { char *cwd = get_cwd(); if (cwd) { @@ -406,17 +408,43 @@ make_relative_path(char *path) } } + /* x_realpath only works for existing paths, so if path doesn't exist, try + * dirname(path) and assemble the path afterwards. We only bother to try + * canonicalizing one of these two paths since a compiler path argument + * typically only makes sense if path or dirname(path) exists. */ + if (stat(path, &st) != 0) { + /* path doesn't exist. */ + char *dir, *p; + dir = dirname(path); + if (stat(dir, &st) != 0) { + /* And neither does its parent directory, so no action to take. */ + free(dir); + return path; + } + path_suffix = basename(path); + p = path; + path = dirname(path); + free(p); + } + canon_path = x_realpath(path); if (canon_path) { free(path); - path = canon_path; + relpath = get_relative_path(current_working_dir, canon_path); + free(canon_path); + if (path_suffix) { + path = format("%s/%s", relpath, path_suffix); + free(relpath); + free(path_suffix); + return path; + } else { + return relpath; + } } else { /* path doesn't exist, so leave it as it is. */ + free(path_suffix); + return path; } - - relpath = get_relative_path(current_working_dir, path); - free(path); - return relpath; } /* diff --git a/test/test_argument_processing.c b/test/test_argument_processing.c index 94e46f4..6ed0daa 100644 --- a/test/test_argument_processing.c +++ b/test/test_argument_processing.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Joel Rosdahl + * Copyright (C) 2010-2013 Joel Rosdahl * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -90,20 +90,19 @@ TEST(sysroot_should_be_rewritten_if_basedir_is_used) { extern char *base_dir; extern char *current_working_dir; - struct args *orig = - args_init_from_string("cc --sysroot=/some/directory -c foo.c"); + char *arg_string; + struct args *orig; struct args *act_cpp = NULL, *act_cc = NULL; - create_file("foo.c", ""); - - CHECK(cc_process_args(orig, &act_cpp, &act_cc)); - CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=/some/directory"); - cc_reset(); - base_dir = "/some"; + create_file("foo.c", ""); current_working_dir = get_cwd(); + arg_string = format("cc --sysroot=%s/foo -c foo.c", current_working_dir); + orig = args_init_from_string(arg_string); + + base_dir = "/"; CHECK(cc_process_args(orig, &act_cpp, &act_cc)); - CHECK(str_startswith(act_cpp->argv[1], "--sysroot=../")); + CHECK(str_startswith(act_cpp->argv[1], "--sysroot=./foo")); args_free(orig); base_dir = NULL; -- 1.7.10.4