@@ -15,15 +15,26 @@ int is_directory(const char *path)
1515#define MAXDEPTH 5
1616
1717/*
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).
2030 *
2131 * If path is our buffer, then return path, as it's already what the
2232 * user wants.
2333 */
24- const char * real_path (const char * path )
34+ static const char * real_path_internal (const char * path , int die_on_error )
2535{
2636 static char bufs [2 ][PATH_MAX + 1 ], * buf = bufs [0 ], * next_buf = bufs [1 ];
37+ char * retval = NULL ;
2738 char cwd [1024 ] = "" ;
2839 int buf_index = 1 ;
2940
@@ -35,11 +46,19 @@ const char *real_path(const char *path)
3546 if (path == buf || path == next_buf )
3647 return path ;
3748
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+ }
4055
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+ }
4362
4463 while (depth -- ) {
4564 if (!is_directory (buf )) {
@@ -54,20 +73,36 @@ const char *real_path(const char *path)
5473 }
5574
5675 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+ }
5982
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 ;
6295 }
63- if (!getcwd (buf , PATH_MAX ))
64- die_errno ("Could not get current working directory" );
6596
6697 if (last_elem ) {
6798 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+ }
71106 if (len && !is_dir_sep (buf [len - 1 ]))
72107 buf [len ++ ] = '/' ;
73108 strcpy (buf + len , last_elem );
@@ -77,10 +112,18 @@ const char *real_path(const char *path)
77112
78113 if (!lstat (buf , & st ) && S_ISLNK (st .st_mode )) {
79114 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+ }
84127 next_buf [len ] = '\0' ;
85128 buf = next_buf ;
86129 buf_index = 1 - buf_index ;
@@ -89,10 +132,18 @@ const char *real_path(const char *path)
89132 break ;
90133 }
91134
135+ retval = buf ;
136+ error_out :
137+ free (last_elem );
92138 if (* cwd && chdir (cwd ))
93139 die_errno ("Could not change back to '%s'" , cwd );
94140
95- return buf ;
141+ return retval ;
142+ }
143+
144+ const char * real_path (const char * path )
145+ {
146+ return real_path_internal (path , 1 );
96147}
97148
98149static const char * get_pwd_cwd (void )
0 commit comments