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>maint
							parent
							
								
									652398a88e
								
							
						
					
					
						commit
						038e55fec2
					
				
							
								
								
									
										89
									
								
								abspath.c
								
								
								
								
							
							
						
						
									
										89
									
								
								abspath.c
								
								
								
								
							|  | @ -15,15 +15,26 @@ int is_directory(const char *path) | ||||||
| #define MAXDEPTH 5 | #define MAXDEPTH 5 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Use this to get the real path, i.e. resolve links. If you want an |  * Return the real path (i.e., absolute path, with symlinks resolved | ||||||
|  * absolute path but don't mind links, use absolute_path. |  * and extra slashes removed) equivalent to the specified path.  (If | ||||||
|  |  * you want an absolute path but don't mind links, use | ||||||
|  |  * absolute_path().)  The return value is a pointer to a static | ||||||
|  |  * buffer. | ||||||
|  |  * | ||||||
|  |  * The input and all intermediate paths must be shorter than MAX_PATH. | ||||||
|  |  * The directory part of path (i.e., everything up to the last | ||||||
|  |  * dir_sep) must denote a valid, existing directory, but the last | ||||||
|  |  * component need not exist.  If die_on_error is set, then die with an | ||||||
|  |  * informative error message if there is a problem.  Otherwise, return | ||||||
|  |  * NULL on errors (without generating any output). | ||||||
|  * |  * | ||||||
|  * If path is our buffer, then return path, as it's already what the |  * If path is our buffer, then return path, as it's already what the | ||||||
|  * user wants. |  * user wants. | ||||||
|  */ |  */ | ||||||
| const char *real_path(const char *path) | static const char *real_path_internal(const char *path, int die_on_error) | ||||||
| { | { | ||||||
| 	static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; | 	static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; | ||||||
|  | 	char *retval = NULL; | ||||||
| 	char cwd[1024] = ""; | 	char cwd[1024] = ""; | ||||||
| 	int buf_index = 1; | 	int buf_index = 1; | ||||||
|  |  | ||||||
|  | @ -35,11 +46,19 @@ const char *real_path(const char *path) | ||||||
| 	if (path == buf || path == next_buf) | 	if (path == buf || path == next_buf) | ||||||
| 		return path; | 		return path; | ||||||
|  |  | ||||||
| 	if (!*path) | 	if (!*path) { | ||||||
|  | 		if (die_on_error) | ||||||
| 			die("The empty string is not a valid path"); | 			die("The empty string is not a valid path"); | ||||||
|  | 		else | ||||||
|  | 			goto error_out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) | 	if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) { | ||||||
| 		die ("Too long path: %.*s", 60, path); | 		if (die_on_error) | ||||||
|  | 			die("Too long path: %.*s", 60, path); | ||||||
|  | 		else | ||||||
|  | 			goto error_out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	while (depth--) { | 	while (depth--) { | ||||||
| 		if (!is_directory(buf)) { | 		if (!is_directory(buf)) { | ||||||
|  | @ -54,20 +73,36 @@ const char *real_path(const char *path) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (*buf) { | 		if (*buf) { | ||||||
| 			if (!*cwd && !getcwd(cwd, sizeof(cwd))) | 			if (!*cwd && !getcwd(cwd, sizeof(cwd))) { | ||||||
| 				die_errno ("Could not get current working directory"); | 				if (die_on_error) | ||||||
|  | 					die_errno("Could not get current working directory"); | ||||||
| 			if (chdir(buf)) | 				else | ||||||
| 				die_errno ("Could not switch to '%s'", buf); | 					goto error_out; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (chdir(buf)) { | ||||||
|  | 				if (die_on_error) | ||||||
|  | 					die_errno("Could not switch to '%s'", buf); | ||||||
|  | 				else | ||||||
|  | 					goto error_out; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (!getcwd(buf, PATH_MAX)) { | ||||||
|  | 			if (die_on_error) | ||||||
|  | 				die_errno("Could not get current working directory"); | ||||||
|  | 			else | ||||||
|  | 				goto error_out; | ||||||
| 		} | 		} | ||||||
| 		if (!getcwd(buf, PATH_MAX)) |  | ||||||
| 			die_errno ("Could not get current working directory"); |  | ||||||
|  |  | ||||||
| 		if (last_elem) { | 		if (last_elem) { | ||||||
| 			size_t len = strlen(buf); | 			size_t len = strlen(buf); | ||||||
| 			if (len + strlen(last_elem) + 2 > PATH_MAX) | 			if (len + strlen(last_elem) + 2 > PATH_MAX) { | ||||||
| 				die ("Too long path name: '%s/%s'", | 				if (die_on_error) | ||||||
|  | 					die("Too long path name: '%s/%s'", | ||||||
| 					    buf, last_elem); | 					    buf, last_elem); | ||||||
|  | 				else | ||||||
|  | 					goto error_out; | ||||||
|  | 			} | ||||||
| 			if (len && !is_dir_sep(buf[len-1])) | 			if (len && !is_dir_sep(buf[len-1])) | ||||||
| 				buf[len++] = '/'; | 				buf[len++] = '/'; | ||||||
| 			strcpy(buf + len, last_elem); | 			strcpy(buf + len, last_elem); | ||||||
|  | @ -77,10 +112,18 @@ const char *real_path(const char *path) | ||||||
|  |  | ||||||
| 		if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { | 		if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { | ||||||
| 			ssize_t len = readlink(buf, next_buf, PATH_MAX); | 			ssize_t len = readlink(buf, next_buf, PATH_MAX); | ||||||
| 			if (len < 0) | 			if (len < 0) { | ||||||
| 				die_errno ("Invalid symlink '%s'", buf); | 				if (die_on_error) | ||||||
| 			if (PATH_MAX <= len) | 					die_errno("Invalid symlink '%s'", buf); | ||||||
|  | 				else | ||||||
|  | 					goto error_out; | ||||||
|  | 			} | ||||||
|  | 			if (PATH_MAX <= len) { | ||||||
|  | 				if (die_on_error) | ||||||
| 					die("symbolic link too long: %s", buf); | 					die("symbolic link too long: %s", buf); | ||||||
|  | 				else | ||||||
|  | 					goto error_out; | ||||||
|  | 			} | ||||||
| 			next_buf[len] = '\0'; | 			next_buf[len] = '\0'; | ||||||
| 			buf = next_buf; | 			buf = next_buf; | ||||||
| 			buf_index = 1 - buf_index; | 			buf_index = 1 - buf_index; | ||||||
|  | @ -89,10 +132,18 @@ const char *real_path(const char *path) | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	retval = buf; | ||||||
|  | error_out: | ||||||
|  | 	free(last_elem); | ||||||
| 	if (*cwd && chdir(cwd)) | 	if (*cwd && chdir(cwd)) | ||||||
| 		die_errno ("Could not change back to '%s'", cwd); | 		die_errno ("Could not change back to '%s'", cwd); | ||||||
|  |  | ||||||
| 	return buf; | 	return retval; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char *real_path(const char *path) | ||||||
|  | { | ||||||
|  | 	return real_path_internal(path, 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| static const char *get_pwd_cwd(void) | static const char *get_pwd_cwd(void) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Michael Haggerty
						Michael Haggerty