Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 31 May 2010 03:44:56 GMT
From:      Garrett Cooper <gcooper@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 179000 for review
Message-ID:  <201005310344.o4V3iuql095095@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@179000?ac=10

Change 179000 by gcooper@gcooper-bayonetta on 2010/05/31 03:44:51

	
	Make sure that unpack_to_buffer never lets data hit the disk by using
	archive_read_data(3).

Affected files ...

.. //depot/projects/soc2007/gcooper-pkg_install-enhancements-simplified/lib/libpkg/file.c#19 edit

Differences ...

==== //depot/projects/soc2007/gcooper-pkg_install-enhancements-simplified/lib/libpkg/file.c#19 (text+ko) ====

@@ -335,10 +335,8 @@
 				 ARCHIVE_EXTRACT_FFLAGS|ARCHIVE_EXTRACT_XATTR)
 
 /*
- * Unpack a single file, denoted by file, to a buffer; this call uses
- * unpack_to_fd to first open the file, and once that has been completed
- * it opens the file and proceeds to read it into the buffer which will 
- * need to be freed by the user at a later date.
+ * Unpack a single file, denoted by file, to a buffer. It proceeds to read it
+ * into the buffer which will need to be freed by the user at a later date.
  *
  * Returns an address to a buffer with the contents of *file if successful, or
  * returns NULL on failure.
@@ -347,39 +345,98 @@
 unpack_to_buffer(const char *pkg, const char *file)
 {
 
-	struct stat sb;
+	struct archive *archive;
+	struct archive_entry *archive_entry;
+	Boolean found_match = FALSE;
+
+	int64_t buf_size;
+
 	char *buf = NULL; 
-	int fd;
-	int serrno;
+	const char *entry_pathname = NULL;
+	const char *error = NULL;
+	int archive_fd = -1;
+	int r;
+
+	errno = 0;
+
+	if ((archive = archive_read_new()) != NULL) {
+
+		if (archive_read_support_compression_all(archive)
+		    != ARCHIVE_OK ||
+		    archive_read_support_format_tar(archive) != ARCHIVE_OK)
+			error = archive_error_string(archive);
+		/*
+		 * Avoid potential race conditions with
+		 * archive_read_open_filename(3), by opening the file
+		 * beforehand.
+		 */
+		else if (pkg == NULL)
+			archive_fd = fileno(stdin);
+		else
+			archive_fd = open(pkg, O_RDONLY);
+
+	}
+
+	/* The initial open failed or archive(3) failed to open the file. */
+	if (archive_fd == -1 || archive == NULL) ;
+	/* archive(3) failed to open the file descriptor. */
+	else if (archive_read_open_fd(archive, archive_fd,
+	    ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
+		error = archive_error_string(archive);
+	else
+		while (error == NULL && found_match == FALSE &&
+		    (r = archive_read_next_header(archive, &archive_entry)) ==
+		     ARCHIVE_OK) {
+
+			entry_pathname = archive_entry_pathname(archive_entry);
+
+			if (strncmp(file, entry_pathname, PATH_MAX) == 0) {
+
+				/* 
+				 * Regardless of whether or not extract passes,
+				 * we found our target file so let's exit
+				 * quickly because the underlying issue is most
+				 * likely unrecoverable.
+				 */
+				found_match = TRUE;
+
+				buf_size = archive_entry_size(archive_entry);
+
+				if (buf_size == 0)
+					errno = EINVAL;
+				else {
+
+					buf = malloc(sizeof(char)*buf_size);
+
+					if (buf == NULL)
+						error = strerror(errno);
+					else {
 
-	if ((fd = unpack_to_fd(pkg, file)) != -1) {
+						r = archive_read_data(archive,
+						    buf, buf_size);
 
-		if (fstat(fd, &sb) == 0) {
+						if (r != ARCHIVE_OK)
+							error = archive_error_string(archive);
 
-			/*
-			 * User either passed in a non-NULL value or we need
-			 * to malloc on the fly and let the user deal with it
-			 * later.
-			 */
-			buf = malloc(sb.st_size);
-			if (buf != NULL) {
+					}
 
-				if (read(fd, buf, sb.st_size) != sb.st_size) {
-					free(buf);
-					buf = NULL;
 				}
 
 			}
 
 		}
-	}
+
+#if 0
+	/*
+	 * This should be stored in a global buffer or something similar that's
+	 * retrievable via pkg_error or something of that flavor.
+	 */
+	if (errno != 0)
+		error = strerror(errno);
+#endif
 
-	if (0 <= fd) {
-		serrno = errno;
-		close(fd);
-		if (serrno != 0)
-			errno = serrno;
-	}
+	if (archive != NULL)
+		archive_read_finish(archive);
 
 	return (buf);
 
@@ -402,7 +459,8 @@
 	Boolean extract_whole_archive = FALSE;
 	const char *entry_pathname = NULL;
 	const char *error = NULL;
-	int archive_fd = -1, r;
+	int archive_fd = -1;
+	int r;
 
 	errno = 0;
 
@@ -490,9 +548,8 @@
 
 	const char *entry_pathname = NULL;
 	const char *error = NULL;
+	int archive_fd = -1, r;
 	int fd = -1;
-	/* int fd = -1; */
-	int archive_fd = -1, r;
 
 	errno = 0;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005310344.o4V3iuql095095>