Commit fb2198db6b48ce3c5e3cecaa03ecb179c5a02382

Edward Thomson 2019-06-23T16:23:59

futils_filesize: use `uint64_t` for object size Instead of using a signed type (`off_t`) use `uint64_t` for the maximum size of files.

diff --git a/src/diff_file.c b/src/diff_file.c
index 4496832..6c9a8e0 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -330,8 +330,10 @@ static int diff_file_content_load_workdir_file(
 	if (fd < 0)
 		return fd;
 
-	if (!fc->file->size &&
-		!(fc->file->size = git_futils_filesize(fd)))
+	if (!fc->file->size)
+	    error = git_futils_filesize(&fc->file->size, fd);
+
+	if (error < 0 || !fc->file->size)
 		goto cleanup;
 
 	if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
diff --git a/src/futils.c b/src/futils.c
index 7454844..c508c74 100644
--- a/src/futils.c
+++ b/src/futils.c
@@ -112,7 +112,7 @@ int git_futils_truncate(const char *path, int mode)
 	return 0;
 }
 
-git_off_t git_futils_filesize(git_file fd)
+int git_futils_filesize(uint64_t *out, git_file fd)
 {
 	struct stat sb;
 
@@ -121,7 +121,13 @@ git_off_t git_futils_filesize(git_file fd)
 		return -1;
 	}
 
-	return sb.st_size;
+	if (sb.st_size < 0) {
+		git_error_set(GIT_ERROR_INVALID, "invalid file size");
+		return -1;
+	}
+
+	*out = sb.st_size;
+	return 0;
 }
 
 mode_t git_futils_canonical_mode(mode_t raw_mode)
@@ -309,16 +315,14 @@ int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
 int git_futils_mmap_ro_file(git_map *out, const char *path)
 {
 	git_file fd = git_futils_open_ro(path);
-	git_off_t len;
+	uint64_t len;
 	int result;
 
 	if (fd < 0)
 		return fd;
 
-	if ((len = git_futils_filesize(fd)) < 0) {
-		result = -1;
+	if ((result = git_futils_filesize(&len, fd)) < 0)
 		goto out;
-	}
 
 	if (!git__is_sizet(len)) {
 		git_error_set(GIT_ERROR_OS, "file `%s` too large to mmap", path);
diff --git a/src/futils.h b/src/futils.h
index 1e2d3f9..e6fd22b 100644
--- a/src/futils.h
+++ b/src/futils.h
@@ -255,7 +255,7 @@ extern int git_futils_truncate(const char *path, int mode);
 /**
  * Get the filesize in bytes of a file
  */
-extern git_off_t git_futils_filesize(git_file fd);
+extern int git_futils_filesize(uint64_t *out, git_file fd);
 
 #define GIT_PERMS_IS_EXEC(MODE)		(((MODE) & 0111) != 0)
 #define GIT_PERMS_CANONICAL(MODE)	(GIT_PERMS_IS_EXEC(MODE) ? 0755 : 0644)
diff --git a/src/odb.c b/src/odb.c
index 2998a2d..68d9a9a 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -320,20 +320,26 @@ int git_odb__hashlink(git_oid *out, const char *path)
 
 int git_odb_hashfile(git_oid *out, const char *path, git_object_t type)
 {
-	git_object_size_t size;
-	int result, fd = git_futils_open_ro(path);
-	if (fd < 0)
+	uint64_t size;
+	int fd, error = 0;
+
+	if ((fd = git_futils_open_ro(path)) < 0)
 		return fd;
 
-	if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
+	if ((error = git_futils_filesize(&size, fd)) < 0)
+		goto done;
+
+	if (!git__is_sizet(size)) {
 		git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
-		p_close(fd);
-		return -1;
+		error = -1;
+		goto done;
 	}
 
-	result = git_odb__hashfd(out, fd, (size_t)size, type);
+	error = git_odb__hashfd(out, fd, (size_t)size, type);
+
+done:
 	p_close(fd);
-	return result;
+	return error;
 }
 
 int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
diff --git a/src/repository.c b/src/repository.c
index 5871e95..14968d7 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2545,7 +2545,7 @@ int git_repository_hashfile(
 	int error;
 	git_filter_list *fl = NULL;
 	git_file fd = -1;
-	git_off_t len;
+	uint64_t len;
 	git_buf full_path = GIT_BUF_INIT;
 
 	assert(out && path && repo); /* as_path can be NULL */
@@ -2582,11 +2582,8 @@ int git_repository_hashfile(
 		goto cleanup;
 	}
 
-	len = git_futils_filesize(fd);
-	if (len < 0) {
-		error = (int)len;
+	if ((error = git_futils_filesize(&len, fd)) < 0)
 		goto cleanup;
-	}
 
 	if (!git__is_sizet(len)) {
 		git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");