Commit c859184bb459d9801a394dc44f5b0b0e55453263

Vicent Marti 2012-09-11T23:05:24

Properly handle p_reads

diff --git a/src/amiga/map.c b/src/amiga/map.c
index 2fb065c..c601de7 100755
--- a/src/amiga/map.c
+++ b/src/amiga/map.c
@@ -24,18 +24,15 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
 		return -1;
 	}
 
-	if((out->data = malloc(len))) {
-		p_lseek(fd, offset, SEEK_SET);
-		p_read(fd, out->data, len);
-	}
+	out->data = malloc(len);
+	GITERR_CHECK_ALLOC(out->data);
 
-	if (!out->data || (out->data == MAP_FAILED)) {
-		giterr_set(GITERR_OS, "Failed to mmap. Could not write data");
+	if (p_lseek(fd, offset, SEEK_SET) < 0 || p_read(fd, out->data, len) != len)
+		giterr_set(GITERR_OS, "mmap emulation failed");
 		return -1;
 	}
 
 	out->len = len;
-
 	return 0;
 }
 
diff --git a/src/blob.c b/src/blob.c
index 699adec..6267ae7 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -68,6 +68,7 @@ static int write_file_stream(
 	int fd, error;
 	char buffer[4096];
 	git_odb_stream *stream = NULL;
+	ssize_t read_len, written = 0;
 
 	if ((error = git_odb_open_wstream(
 			&stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < 0)
@@ -78,20 +79,18 @@ static int write_file_stream(
 		return -1;
 	}
 
-	while (!error && file_size > 0) {
-		ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
-
-		if (read_len < 0) {
-			giterr_set(
-				GITERR_OS, "Failed to create blob. Can't read whole file");
-			error = -1;
-		}
-		else if (!(error = stream->write(stream, buffer, read_len)))
-			file_size -= read_len;
+	while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
+		error = stream->write(stream, buffer, read_len);
+		written += read_len;
 	}
 
 	p_close(fd);
 
+	if (written != file_size || read_len < 0) {
+		giterr_set(GITERR_OS, "Failed to read file into stream");
+		error = -1;
+	}
+
 	if (!error)
 		error = stream->finalize_write(oid, stream);
 
diff --git a/src/filebuf.c b/src/filebuf.c
index cfc8528..b9b908c 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -73,7 +73,7 @@ static int lock_file(git_filebuf *file, int flags)
 	if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) {
 		git_file source;
 		char buffer[2048];
-		size_t read_bytes;
+		ssize_t read_bytes;
 
 		source = p_open(file->path_original, O_RDONLY);
 		if (source < 0) {
@@ -83,13 +83,18 @@ static int lock_file(git_filebuf *file, int flags)
 			return -1;
 		}
 
-		while ((read_bytes = p_read(source, buffer, 2048)) > 0) {
+		while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) {
 			p_write(file->fd, buffer, read_bytes);
 			if (file->digest)
 				git_hash_update(file->digest, buffer, read_bytes);
 		}
 
 		p_close(source);
+
+		if (read_bytes < 0) {
+			giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original);
+			return -1;
+		}
 	}
 
 	return 0;
diff --git a/src/fileops.c b/src/fileops.c
index cbe3d47..8ccf063 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -127,7 +127,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
 	/* p_read loops internally to read len bytes */
 	read_size = p_read(fd, buf->ptr, len);
 
-	if (read_size < 0) {
+	if (read_size != (ssize_t)len) {
 		giterr_set(GITERR_OS, "Failed to read descriptor");
 		return -1;
 	}
diff --git a/src/odb.c b/src/odb.c
index 0e03e40..0d3d809 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -115,6 +115,7 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
 	int hdr_len;
 	char hdr[64], buffer[2048];
 	git_hash_ctx *ctx;
+	ssize_t read_len;
 
 	hdr_len = format_object_header(hdr, sizeof(hdr), size, type);
 
@@ -123,19 +124,20 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
 
 	git_hash_update(ctx, hdr, hdr_len);
 
-	while (size > 0) {
-		ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
-
-		if (read_len < 0) {
-			git_hash_free_ctx(ctx);
-			giterr_set(GITERR_OS, "Error reading file");
-			return -1;
-		}
-
+	while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
 		git_hash_update(ctx, buffer, read_len);
 		size -= read_len;
 	}
 
+	/* If p_read returned an error code, the read obviously failed.
+	 * If size is not zero, the file was truncated after we originally
+	 * stat'd it, so we consider this a read failure too */
+	if (read_len < 0 || size > 0) {
+		git_hash_free_ctx(ctx);
+		giterr_set(GITERR_OS, "Error reading file for hashing");
+		return -1;
+	}
+
 	git_hash_final(out, ctx);
 	git_hash_free_ctx(ctx);