Subject: [PATCH v3 05/10] abspath: convert real_path_internal() to strbuf

From: René Scharfe <[email-masked]>
Date: Mon, 28 Jul 2014 20:28:30 +0200

Use strbuf instead of fixed-sized buffers in real_path() in order to
avoid the size limitations of the latter.

Signed-off-by: Rene Scharfe <[email-masked]>
---
 abspath.c | 69 +++++++++++++++++++++++----------------------------------------
 1 file changed, 25 insertions(+), 44 deletions(-)

diff --git a/abspath.c b/abspath.c
index 911e931..16e7fa2 100644
--- a/abspath.c
+++ b/abspath.c
@@ -33,7 +33,7 @@ int is_directory(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 struct strbuf sb = STRBUF_INIT;
 	char *retval = NULL;
 
 	/*
@@ -43,14 +43,12 @@ static const char *real_path_internal(const char *path, int die_on_error)
 	 */
 	struct strbuf cwd = STRBUF_INIT;
 
-	int buf_index = 1;
-
 	int depth = MAXDEPTH;
 	char *last_elem = NULL;
 	struct stat st;
 
 	/* We've already done it */
-	if (path == buf || path == next_buf)
+	if (path == sb.buf)
 		return path;
 
 	if (!*path) {
@@ -60,26 +58,22 @@ static const char *real_path_internal(const char *path, int die_on_error)
 			goto error_out;
 	}
 
-	if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
-		if (die_on_error)
-			die("Too long path: %.*s", 60, path);
-		else
-			goto error_out;
-	}
+	strbuf_init(&sb, 0);
+	strbuf_addstr(&sb, path);
 
 	while (depth--) {
-		if (!is_directory(buf)) {
-			char *last_slash = find_last_dir_sep(buf);
+		if (!is_directory(sb.buf)) {
+			char *last_slash = find_last_dir_sep(sb.buf);
 			if (last_slash) {
 				last_elem = xstrdup(last_slash + 1);
-				last_slash[1] = '\0';
+				strbuf_setlen(&sb, last_slash - sb.buf + 1);
 			} else {
-				last_elem = xstrdup(buf);
-				*buf = '\0';
+				last_elem = xmemdupz(sb.buf, sb.len);
+				strbuf_reset(&sb);
 			}
 		}
 
-		if (*buf) {
+		if (sb.len) {
 			if (!cwd.len && strbuf_getcwd(&cwd)) {
 				if (die_on_error)
 					die_errno("Could not get current working directory");
@@ -87,14 +81,15 @@ static const char *real_path_internal(const char *path, int die_on_error)
 					goto error_out;
 			}
 
-			if (chdir(buf)) {
+			if (chdir(sb.buf)) {
 				if (die_on_error)
-					die_errno("Could not switch to '%s'", buf);
+					die_errno("Could not switch to '%s'",
+						  sb.buf);
 				else
 					goto error_out;
 			}
 		}
-		if (!getcwd(buf, PATH_MAX)) {
+		if (strbuf_getcwd(&sb)) {
 			if (die_on_error)
 				die_errno("Could not get current working directory");
 			else
@@ -102,44 +97,30 @@ static const char *real_path_internal(const char *path, int die_on_error)
 		}
 
 		if (last_elem) {
-			size_t len = strlen(buf);
-			if (len + strlen(last_elem) + 2 > PATH_MAX) {
-				if (die_on_error)
-					die("Too long path name: '%s/%s'",
-					    buf, last_elem);
-				else
-					goto error_out;
-			}
-			if (len && !is_dir_sep(buf[len - 1]))
-				buf[len++] = '/';
-			strcpy(buf + len, last_elem);
+			if (sb.len && !is_dir_sep(sb.buf[sb.len - 1]))
+				strbuf_addch(&sb, '/');
+			strbuf_addstr(&sb, last_elem);
 			free(last_elem);
 			last_elem = NULL;
 		}
 
-		if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
-			ssize_t len = readlink(buf, next_buf, PATH_MAX);
+		if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) {
+			struct strbuf next_sb = STRBUF_INIT;
+			ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0);
 			if (len < 0) {
 				if (die_on_error)
-					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_errno("Invalid symlink '%s'",
+						  sb.buf);
 				else
 					goto error_out;
 			}
-			next_buf[len] = '\0';
-			buf = next_buf;
-			buf_index = 1 - buf_index;
-			next_buf = bufs[buf_index];
+			strbuf_swap(&sb, &next_sb);
+			strbuf_release(&next_sb);
 		} else
 			break;
 	}
 
-	retval = buf;
+	retval = sb.buf;
 error_out:
 	free(last_elem);
 	if (cwd.len && chdir(cwd.buf))
-- 
2.0.2