Use GInputStream for checksum computation of source files & archives

Using g_load_contents () for the checksum computation uses a lot of memory
(for large files) and actually fails for files larger than 4 GiB. Instead,
this implementation uses GInputStream to read the file in small buffers
and feeds the GChecksum manually.

Closes: #165
Approved by: alexlarsson
auto
Martin Pilarski 2018-06-15 11:14:39 +02:00 committed by Atomic Bot
parent c94db14939
commit 7cfdec0538
4 changed files with 48 additions and 37 deletions

View File

@ -397,21 +397,10 @@ builder_source_archive_download (BuilderSource *source,
if (g_file_query_exists (file, NULL))
{
if (is_local && checksums[0] != NULL)
{
g_autofree char *data = NULL;
gsize len;
if (!g_file_load_contents (file, NULL, &data, &len, NULL, error))
return FALSE;
if (!builder_verify_checksums (base_name,
data, len,
checksums, checksums_type,
error))
return FALSE;
}
return TRUE;
return !is_local || checksums[0] == NULL ||
builder_verify_checksums (base_name, file,
checksums, checksums_type,
error);
}
if (is_local)

View File

@ -361,21 +361,10 @@ builder_source_file_download (BuilderSource *source,
if (g_file_query_exists (file, NULL))
{
if (is_local && checksums[0] != NULL)
{
g_autofree char *data = NULL;
gsize len;
if (!g_file_load_contents (file, NULL, &data, &len, NULL, error))
return FALSE;
if (!builder_verify_checksums (base_name,
data, len,
checksums, checksums_type,
error))
return FALSE;
}
return TRUE;
return !is_local || checksums[0] == NULL ||
builder_verify_checksums (base_name, file,
checksums, checksums_type,
error);
}
if (is_local)

View File

@ -1857,10 +1857,11 @@ compare_checksum (const char *name,
return TRUE;
}
#define GET_BUFFER_SIZE 8192
gboolean
builder_verify_checksums (const char *name,
const char *data,
gsize len,
GFile *file,
const char *checksums[BUILDER_CHECKSUMS_LEN],
GChecksumType checksums_type[BUILDER_CHECKSUMS_LEN],
GError **error)
@ -1869,9 +1870,42 @@ builder_verify_checksums (const char *name,
for (i = 0; checksums[i] != NULL; i++)
{
g_autofree char *checksum = NULL;
checksum = g_compute_checksum_for_string (checksums_type[i], data, len);
if (!compare_checksum (name, checksums[i], checksums_type[i], checksum, error))
g_autoptr(GFileInputStream) stream = NULL;
stream = g_file_read (file, NULL, error);
if (stream == NULL)
return FALSE;
gssize bytes_read;
guchar buffer[GET_BUFFER_SIZE];
GChecksum *checksum = NULL;
const char *checksum_string = NULL;
gboolean is_valid;
checksum = g_checksum_new (checksums_type[i]);
while ((bytes_read = g_input_stream_read (G_INPUT_STREAM(stream),
buffer, GET_BUFFER_SIZE,
NULL, error)) > 0)
{
g_checksum_update (checksum, buffer, bytes_read);
}
if (bytes_read < 0)
{
is_valid = FALSE;
}
else
{
checksum_string = g_checksum_get_string (checksum);
is_valid = compare_checksum (name, checksums[i], checksums_type[i],
checksum_string, error);
}
g_checksum_free (checksum);
if (!is_valid)
return FALSE;
}

View File

@ -99,8 +99,7 @@ gsize builder_get_all_checksums (const char *checksums[BUILDER_CHECKSUMS_LEN],
const char *sha512);
gboolean builder_verify_checksums (const char *name,
const char *data,
gsize len,
GFile *file,
const char *checksums[BUILDER_CHECKSUMS_LEN],
GChecksumType checksums_type[BUILDER_CHECKSUMS_LEN],
GError **error);