Persistent logs: Compress target log on storage.

This update will use pigz to compress the log that TWRP stores
on persistent storage in order to help with storing logs on the
persist partition.

Change-Id: I16971b8b138b74a164b1b0835847177cfc6104e2
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 9034a50..e6a489f 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -184,10 +184,7 @@
 
 bool TWFunc::Path_Exists(string Path) {
 	struct stat st;
-	if (stat(Path.c_str(), &st) != 0)
-		return false;
-	else
-		return true;
+	return stat(Path.c_str(), &st) == 0;
 }
 
 Archive_Type TWFunc::Get_File_Type(string fn) {
@@ -504,24 +501,82 @@
 }
 
 void TWFunc::Copy_Log(string Source, string Destination) {
+	int logPipe[2];
+	int pigz_pid;
+	int destination_fd;
+	std::string destLogBuffer;
+
 	PartitionManager.Mount_By_Path(Destination, false);
-	FILE *destination_log = fopen(Destination.c_str(), "a");
-	if (destination_log == NULL) {
-		LOGERR("TWFunc::Copy_Log -- Can't open destination log file: '%s'\n", Destination.c_str());
-	} else {
-		FILE *source_log = fopen(Source.c_str(), "r");
-		if (source_log != NULL) {
-			fseek(source_log, Log_Offset, SEEK_SET);
-			char buffer[4096];
-			while (fgets(buffer, sizeof(buffer), source_log))
-				fputs(buffer, destination_log); // Buffered write of log file
-			Log_Offset = ftell(source_log);
-			fflush(source_log);
-			fclose(source_log);
+
+	size_t extPos = Destination.find(".gz");
+	std::string uncompressedLog(Destination);
+	uncompressedLog.replace(extPos, Destination.length(), "");
+
+	if (Path_Exists(Destination)) {
+		Archive_Type type = Get_File_Type(Destination);
+		if (type == COMPRESSED) {
+			std::string destFileBuffer;
+			std::string getCompressedContents = "pigz -c -d " + Destination;
+			if (Exec_Cmd(getCompressedContents, destFileBuffer) < 0) {
+				LOGINFO("Unable to get destination logfile contents.\n");
+				return;
+			}
+			destLogBuffer.append(destFileBuffer);
 		}
-		fflush(destination_log);
-		fclose(destination_log);
+	} else if (Path_Exists(uncompressedLog)) {
+		std::ifstream uncompressedIfs(uncompressedLog);
+		std::stringstream uncompressedSS;
+		uncompressedSS << uncompressedIfs.rdbuf();
+		uncompressedIfs.close();
+		std::string uncompressedLogBuffer(uncompressedSS.str());
+		destLogBuffer.append(uncompressedLogBuffer);
+		std::remove(uncompressedLog.c_str());
 	}
+
+	std::ifstream ifs(Source);
+	std::stringstream ss;
+	ss << ifs.rdbuf();
+	std::string srcLogBuffer(ss.str());
+	ifs.close();
+
+	if (pipe(logPipe) < 0) {
+		LOGINFO("Unable to open pipe to write to persistent log file: %s\n", Destination.c_str());
+	}
+
+	destination_fd = open(Destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+	pigz_pid = fork();
+	if (pigz_pid < 0) {
+		LOGINFO("fork() failed\n");
+		close(destination_fd);
+		close(logPipe[0]);
+		close(logPipe[1]);
+	} else if (pigz_pid == 0) {
+		close(logPipe[1]);
+		dup2(logPipe[0], fileno(stdin));
+		dup2(destination_fd, fileno(stdout));
+		if (execlp("pigz", "pigz", "-", NULL) < 0) {
+			close(destination_fd);
+			close(logPipe[0]);
+			_exit(-1);
+		}
+	} else {
+		close(logPipe[0]);
+		if (write(logPipe[1], destLogBuffer.c_str(), destLogBuffer.size()) < 0) {
+			LOGINFO("Unable to append to persistent log: %s\n", Destination.c_str());
+			close(logPipe[1]);
+			close(destination_fd);
+			return;
+		}
+		if (write(logPipe[1], srcLogBuffer.c_str(), srcLogBuffer.size()) < 0) {
+			LOGINFO("Unable to append to persistent log: %s\n", Destination.c_str());
+			close(logPipe[1]);
+			close(destination_fd);
+			return;
+		}
+		close(logPipe[1]);
+	}
+	close(destination_fd);
 }
 
 void TWFunc::Update_Log_File(void) {
@@ -540,8 +595,8 @@
 		}
 	}
 
-	std::string logCopy = recoveryDir + "log";
-	std::string lastLogCopy = recoveryDir + "last_log";
+	std::string logCopy = recoveryDir + "log.gz";
+	std::string lastLogCopy = recoveryDir + "last_log.gz";
 	copy_file(logCopy, lastLogCopy, 600);
 	Copy_Log(TMP_LOG_FILE, logCopy);
 	chown(logCopy.c_str(), 1000, 1000);
@@ -698,10 +753,23 @@
 }
 
 int TWFunc::copy_file(string src, string dst, int mode) {
-	LOGINFO("Copying file %s to %s\n", src.c_str(), dst.c_str());
-	ifstream srcfile(src.c_str(), ios::binary);
-	ofstream dstfile(dst.c_str(), ios::binary);
+	PartitionManager.Mount_By_Path(src, false);
+	PartitionManager.Mount_By_Path(dst, false);
+	if (!Path_Exists(src)) {
+		LOGINFO("Unable to find source file %s\n", src.c_str());
+		return -1;
+	}
+	std::ifstream srcfile(src, ios::binary);
+	std::ofstream dstfile(dst, ios::binary);
 	dstfile << srcfile.rdbuf();
+	if (!dstfile.bad()) {
+		LOGINFO("Copied file %s to %s\n", src.c_str(), dst.c_str());
+	}
+	else {
+		LOGINFO("Unable to copy file %s to %s\n", src.c_str(), dst.c_str());
+		return -1;
+	}
+
 	srcfile.close();
 	dstfile.close();
 	if (chmod(dst.c_str(), mode) != 0)