Introduce new static function real_path_internal()

It accepts a new parameter, die_on_error. If die_on_error is false, it simply cleans up after itself and returns NULL rather than dying. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net>

Michael Haggerty committed Oct 28, 2012 at 17:16 UTC 038e55fec2153a8195236d57dced4bbb001ccf3c
1 file changed +72 -21
abspath.c
+72 -21
@@ -15,15 +15,26 @@ int is_directory(const char *path)
15 #define MAXDEPTH 5
16
17 /*
18 - * Use this to get the real path, i.e. resolve links. If you want an
19 - * absolute path but don't mind links, use absolute_path.
18 + * Return the real path (i.e., absolute path, with symlinks resolved
19 + * and extra slashes removed) equivalent to the specified path. (If
20 + * you want an absolute path but don't mind links, use
21 + * absolute_path().) The return value is a pointer to a static
22 + * buffer.
23 + *
24 + * The input and all intermediate paths must be shorter than MAX_PATH.
25 + * The directory part of path (i.e., everything up to the last
26 + * dir_sep) must denote a valid, existing directory, but the last
27 + * component need not exist. If die_on_error is set, then die with an
28 + * informative error message if there is a problem. Otherwise, return
29 + * NULL on errors (without generating any output).
30 *
31 * If path is our buffer, then return path, as it's already what the
32 * user wants.
33 */
24 -const char *real_path(const char *path)
34 +static const char *real_path_internal(const char *path, int die_on_error)
35 {
36 static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
37 + char *retval = NULL;
38 char cwd[1024] = "";
39 int buf_index = 1;
40
@@ -35,11 +46,19 @@ const char *real_path(const char *path)
46 if (path == buf || path == next_buf)
47 return path;
48
38 - if (!*path)
39 - die("The empty string is not a valid path");
49 + if (!*path) {
50 + if (die_on_error)
51 + die("The empty string is not a valid path");
52 + else
53 + goto error_out;
54 + }
55
41 - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
42 - die ("Too long path: %.*s", 60, path);
56 + if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
57 + if (die_on_error)
58 + die("Too long path: %.*s", 60, path);
59 + else
60 + goto error_out;
61 + }
62
63 while (depth--) {
64 if (!is_directory(buf)) {
@@ -54,20 +73,36 @@ const char *real_path(const char *path)
73 }
74
75 if (*buf) {
57 - if (!*cwd && !getcwd(cwd, sizeof(cwd)))
58 - die_errno ("Could not get current working directory");
76 + if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
77 + if (die_on_error)
78 + die_errno("Could not get current working directory");
79 + else
80 + goto error_out;
81 + }
82
60 - if (chdir(buf))
61 - die_errno ("Could not switch to '%s'", buf);
83 + if (chdir(buf)) {
84 + if (die_on_error)
85 + die_errno("Could not switch to '%s'", buf);
86 + else
87 + goto error_out;
88 + }
89 + }
90 + if (!getcwd(buf, PATH_MAX)) {
91 + if (die_on_error)
92 + die_errno("Could not get current working directory");
93 + else
94 + goto error_out;
95 }
63 - if (!getcwd(buf, PATH_MAX))
64 - die_errno ("Could not get current working directory");
96
97 if (last_elem) {
98 size_t len = strlen(buf);
68 - if (len + strlen(last_elem) + 2 > PATH_MAX)
69 - die ("Too long path name: '%s/%s'",
70 - buf, last_elem);
99 + if (len + strlen(last_elem) + 2 > PATH_MAX) {
100 + if (die_on_error)
101 + die("Too long path name: '%s/%s'",
102 + buf, last_elem);
103 + else
104 + goto error_out;
105 + }
106 if (len && !is_dir_sep(buf[len-1]))
107 buf[len++] = '/';
108 strcpy(buf + len, last_elem);
@@ -77,10 +112,18 @@ const char *real_path(const char *path)
112
113 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
114 ssize_t len = readlink(buf, next_buf, PATH_MAX);
80 - if (len < 0)
81 - die_errno ("Invalid symlink '%s'", buf);
82 - if (PATH_MAX <= len)
83 - die("symbolic link too long: %s", buf);
115 + if (len < 0) {
116 + if (die_on_error)
117 + die_errno("Invalid symlink '%s'", buf);
118 + else
119 + goto error_out;
120 + }
121 + if (PATH_MAX <= len) {
122 + if (die_on_error)
123 + die("symbolic link too long: %s", buf);
124 + else
125 + goto error_out;
126 + }
127 next_buf[len] = '\0';
128 buf = next_buf;
129 buf_index = 1 - buf_index;
@@ -89,10 +132,18 @@ const char *real_path(const char *path)
132 break;
133 }
134
135 + retval = buf;
136 +error_out:
137 + free(last_elem);
138 if (*cwd && chdir(cwd))
139 die_errno ("Could not change back to '%s'", cwd);
140
95 - return buf;
141 + return retval;
142 +}
143 +
144 +const char *real_path(const char *path)
145 +{
146 + return real_path_internal(path, 1);
147 }
148
149 static const char *get_pwd_cwd(void)