From 90881d24d3f6d5fb207e97df3b91bbea8598e84e Mon Sep 17 00:00:00 2001
From: Martin Matuska <martin@matuska.org>
Date: Tue, 29 Nov 2016 16:47:37 +0100
Subject: [PATCH 1/2] archive_write_disk_posix.c: make *_fsobj functions more
 readable

Upstream-Status: Backported

Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
 libarchive/archive_write_disk_posix.c | 121 +++++++++++++++++-----------------
 1 file changed, 61 insertions(+), 60 deletions(-)

diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index 17c23b0..d786bc2 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -336,6 +336,8 @@ struct archive_write_disk {
 
 #define HFS_BLOCKS(s)	((s) >> 12)
 
+static void	fsobj_error(int *, struct archive_string *, int, const char *,
+		    const char *);
 static int	check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags);
 static int	check_symlinks(struct archive_write_disk *);
 static int	create_filesystem_object(struct archive_write_disk *);
@@ -2005,8 +2007,9 @@ restore_entry(struct archive_write_disk *a)
 
 	if (en) {
 		/* Everything failed; give up here. */
-		archive_set_error(&a->archive, en, "Can't create '%s'",
-		    a->name);
+		if ((&a->archive)->error == NULL)
+			archive_set_error(&a->archive, en, "Can't create '%s'",
+			    a->name);
 		return (ARCHIVE_FAILED);
 	}
 
@@ -2388,6 +2391,17 @@ current_fixup(struct archive_write_disk *a, const char *pathname)
 	return (a->current_fixup);
 }
 
+/* Error helper for new *_fsobj functions */
+static void
+fsobj_error(int *a_eno, struct archive_string *a_estr,
+    int err, const char *errstr, const char *path)
+{
+	if (a_eno)
+		*a_eno = err;
+	if (a_estr)
+		archive_string_sprintf(a_estr, errstr, path);
+}
+
 /*
  * TODO: Someday, integrate this with the deep dir support; they both
  * scan the path and both can be optimized by comparing against other
@@ -2400,7 +2414,7 @@ current_fixup(struct archive_write_disk *a, const char *pathname)
  * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
  */
 static int
-check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
+check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, int flags)
 {
 #if !defined(HAVE_LSTAT)
 	/* Platform doesn't have lstat, so we can't look for symlinks. */
@@ -2474,19 +2488,20 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 			if (errno == ENOENT) {
 				break;
 			} else {
-				/* Treat any other error as fatal - best to be paranoid here
-				 * Note: This effectively disables deep directory
-				 * support when security checks are enabled.
-				 * Otherwise, very long pathnames that trigger
-				 * an error here could evade the sandbox.
-				 * TODO: We could do better, but it would probably
-				 * require merging the symlink checks with the
-				 * deep-directory editing. */
-				if (error_number) *error_number = errno;
-				if (error_string)
-					archive_string_sprintf(error_string,
-							"Could not stat %s",
-							path);
+				/*
+				 * Treat any other error as fatal - best to be
+				 * paranoid here.
+				 * Note: This effectively disables deep
+				 * directory support when security checks are
+				 * enabled. Otherwise, very long pathnames that
+				 * trigger an error here could evade the
+				 * sandbox.
+				 * TODO: We could do better, but it would
+				 * probably require merging the symlink checks
+				 * with the deep-directory editing.
+				 */
+				fsobj_error(a_eno, a_estr, errno,
+				    "Could not stat %s", path);
 				res = ARCHIVE_FAILED;
 				break;
 			}
@@ -2494,11 +2509,8 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 			if (!last) {
 				if (chdir(head) != 0) {
 					tail[0] = c;
-					if (error_number) *error_number = errno;
-					if (error_string)
-						archive_string_sprintf(error_string,
-								"Could not chdir %s",
-								path);
+					fsobj_error(a_eno, a_estr, errno,
+					    "Could not chdir %s", path);
 					res = (ARCHIVE_FATAL);
 					break;
 				}
@@ -2514,11 +2526,9 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 				 */
 				if (unlink(head)) {
 					tail[0] = c;
-					if (error_number) *error_number = errno;
-					if (error_string)
-						archive_string_sprintf(error_string,
-								"Could not remove symlink %s",
-								path);
+					fsobj_error(a_eno, a_estr, errno,
+					    "Could not remove symlink %s",
+					    path);
 					res = ARCHIVE_FAILED;
 					break;
 				}
@@ -2529,13 +2539,14 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 				 * symlink with another symlink.
 				 */
 				tail[0] = c;
-				/* FIXME:  not sure how important this is to restore
+				/*
+				 * FIXME:  not sure how important this is to
+				 * restore
+				 */
+				/*
 				if (!S_ISLNK(path)) {
-					if (error_number) *error_number = 0;
-					if (error_string)
-						archive_string_sprintf(error_string,
-								"Removing symlink %s",
-								path);
+					fsobj_error(a_eno, a_estr, 0,
+					    "Removing symlink %s", path);
 				}
 				*/
 				/* Symlink gone.  No more problem! */
@@ -2545,22 +2556,17 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 				/* User asked us to remove problems. */
 				if (unlink(head) != 0) {
 					tail[0] = c;
-					if (error_number) *error_number = 0;
-					if (error_string)
-						archive_string_sprintf(error_string,
-								"Cannot remove intervening symlink %s",
-								path);
+					fsobj_error(a_eno, a_estr, 0,
+					    "Cannot remove intervening "
+					    "symlink %s", path);
 					res = ARCHIVE_FAILED;
 					break;
 				}
 				tail[0] = c;
 			} else {
 				tail[0] = c;
-				if (error_number) *error_number = 0;
-				if (error_string)
-					archive_string_sprintf(error_string,
-							"Cannot extract through symlink %s",
-							path);
+				fsobj_error(a_eno, a_estr, 0,
+				    "Cannot extract through symlink %s", path);
 				res = ARCHIVE_FAILED;
 				break;
 			}
@@ -2577,10 +2583,8 @@ check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error
 	if (restore_pwd >= 0) {
 		r = fchdir(restore_pwd);
 		if (r != 0) {
-			if(error_number) *error_number = errno;
-			if(error_string)
-				archive_string_sprintf(error_string,
-						"chdir() failure");
+			fsobj_error(a_eno, a_estr, errno,
+			    "chdir() failure", "");
 		}
 		close(restore_pwd);
 		restore_pwd = -1;
@@ -2688,17 +2692,16 @@ cleanup_pathname_win(struct archive_write_disk *a)
  * is set) if the path is absolute.
  */
 static int
-cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
+cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+    int flags)
 {
 	char *dest, *src;
 	char separator = '\0';
 
 	dest = src = path;
 	if (*src == '\0') {
-		if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
-		if (error_string)
-		    archive_string_sprintf(error_string,
-			    "Invalid empty pathname");
+		fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+		    "Invalid empty ", "pathname");
 		return (ARCHIVE_FAILED);
 	}
 
@@ -2708,10 +2711,8 @@ cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *err
 	/* Skip leading '/'. */
 	if (*src == '/') {
 		if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
-			if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
-			if (error_string)
-			    archive_string_sprintf(error_string,
-				    "Path is absolute");
+			fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+			    "Path is ", "absolute");
 			return (ARCHIVE_FAILED);
 		}
 
@@ -2738,11 +2739,11 @@ cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *err
 			} else if (src[1] == '.') {
 				if (src[2] == '/' || src[2] == '\0') {
 					/* Conditionally warn about '..' */
-					if (flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
-						if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
-						if (error_string)
-						    archive_string_sprintf(error_string,
-							    "Path contains '..'");
+					if (flags
+					    & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
+						fsobj_error(a_eno, a_estr,
+						    ARCHIVE_ERRNO_MISC,
+						    "Path contains ", "'..'");
 						return (ARCHIVE_FAILED);
 					}
 				}
-- 
2.7.4

