[tar] Improve performance of -c/-x/-t.

* Fixes performance of -c and -x by increasing the buffer size
from 512 bytes to 8192 bytes.
* Fixes performance of -t by using lseek instead of reading the data.
* Prevents incorrect error message when trying to remove a directory
that contains files.
* Filed related bugs US-291, US-293 and US-294.

US-295 #done

Change-Id: Id971750fa6bd6d45c27bef65b72986eb20d3db70
diff --git a/tar.c b/tar.c
index 71719b0..7f2eccc 100644
--- a/tar.c
+++ b/tar.c
@@ -16,6 +16,8 @@
 #include "util.h"
 
 #define BLKSIZ 512
+// COPY_CHUNK_SIZE must be a power of 2
+#define COPY_CHUNK_SIZE 8192
 
 enum Type {
 	REG       = '0',
@@ -236,10 +238,13 @@
 	ewrite(tarfd, b, BLKSIZ);
 
 	if (fd != -1) {
-		while ((l = eread(fd, b, BLKSIZ)) > 0) {
-			if (l < BLKSIZ)
-				memset(b + l, 0, BLKSIZ - l);
-			ewrite(tarfd, b, BLKSIZ);
+		char chunk[COPY_CHUNK_SIZE];
+		while ((l = eread(fd, chunk, COPY_CHUNK_SIZE)) > 0) {
+			// Ceiling to BLKSIZ boundary
+			int ceilsize = (l + (BLKSIZ-1)) & ~(BLKSIZ-1);
+			if (l < ceilsize)
+				memset(chunk + l, 0, ceilsize - l);
+			ewrite(tarfd, chunk, ceilsize);
 		}
 		close(fd);
 	}
@@ -258,7 +263,7 @@
 
 	if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
 		eprintf("strtol %s: invalid number\n", h->mtime);
-	if (remove(fname) < 0 && errno != ENOENT)
+	if (remove(fname) < 0 && errno != ENOENT && errno != ENOTEMPTY)
 		weprintf("remove %s:", fname);
 
 	tmp = estrdup(fname);
@@ -319,9 +324,17 @@
 		eprintf("strtol %s: invalid number\n", h->gid);
 
 	if (fd != -1) {
-		for (; l > 0; l -= BLKSIZ)
-			if (eread(tarfd, b, BLKSIZ) > 0)
-				ewrite(fd, b, MIN(l, BLKSIZ));
+		char chunk[COPY_CHUNK_SIZE];
+		for (; l > 0; l -= COPY_CHUNK_SIZE) {
+			// Ceiling to BLKSIZ boundary
+			int ceilsize = (MIN(l, COPY_CHUNK_SIZE) + (BLKSIZ-1)) & ~(BLKSIZ-1);
+			if (eread(tarfd, chunk, ceilsize) != ceilsize) {
+				close(fd);
+				remove(fname);
+				eprintf("unexpected end of file reading %s.\n", fname);
+			}
+			ewrite(fd, chunk, ceilsize);
+		}
 		close(fd);
 	}
 
@@ -331,7 +344,7 @@
 	times[0].tv_sec = times[1].tv_sec = mtime;
 	times[0].tv_nsec = times[1].tv_nsec = 0;
 	if (!mflag && utimensat(AT_FDCWD, fname, times, AT_SYMLINK_NOFOLLOW) < 0)
-		weprintf("utimensat %s:\n", fname);
+		weprintf("utimensat %s %d:\n", fname, errno);
 	if (h->type == SYMLINK) {
 		if (!getuid() && lchown(fname, uid, gid))
 			weprintf("lchown %s:\n", fname);
@@ -348,11 +361,11 @@
 static void
 skipblk(ssize_t l)
 {
-	char b[BLKSIZ];
-
-	for (; l > 0; l -= BLKSIZ)
-		if (!eread(tarfd, b, BLKSIZ))
-			break;
+	// Ceiling to the next BLKSIZ boundary
+	int ceilsize = (l + (BLKSIZ-1)) & ~(BLKSIZ-1);
+	if (lseek(tarfd, ceilsize, SEEK_CUR) == -1) {
+		eprintf("unexpected end of file.\n");
+	}
 }
 
 static int