[virt-tools-list] [PATCH libosinfo] Handle short reads when extracting ISO headers
Daniel P. Berrange
berrange at redhat.com
Fri Mar 16 15:01:02 UTC 2012
From: "Daniel P. Berrange" <berrange at redhat.com>
You cannot assume that g_input_stream_read_async will return
as many bytes as you requested. It is perfectly valid to get
a short read. Code must be prepared to repeat the read operation
multiple times until all data is read, or EOF/error occurs.
---
osinfo/osinfo_media.c | 113 ++++++++++++++++++++++++++++++++----------------
1 files changed, 75 insertions(+), 38 deletions(-)
diff --git a/osinfo/osinfo_media.c b/osinfo/osinfo_media.c
index 32b1025..77359c6 100644
--- a/osinfo/osinfo_media.c
+++ b/osinfo/osinfo_media.c
@@ -76,6 +76,9 @@ struct _CreateFromLocationAsyncData {
PrimaryVolumeDescriptor pvd;
SupplementaryVolumeDescriptor svd;
+
+ gsize offset;
+ gsize length;
};
static void create_from_location_async_data_free
@@ -570,30 +573,44 @@ static void on_svd_read (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
- OsinfoMedia *ret = NULL;
+ OsinfoMedia *media = NULL;
GInputStream *stream = G_INPUT_STREAM(source);
gchar *uri;
GError *error = NULL;
CreateFromLocationAsyncData *data;
+ gssize ret;
data = (CreateFromLocationAsyncData *)user_data;
- if (g_input_stream_read_finish(stream,
- res,
- &error) < sizeof(data->svd)) {
- if (error)
- g_prefix_error(&error,
- "Failed to read supplementary volume descriptor");
- else
- g_set_error(&error,
- OSINFO_MEDIA_ERROR,
- OSINFO_MEDIA_ERROR_NO_SVD,
- "Supplementary volume descriptor unavailable");
-
-
+ ret = g_input_stream_read_finish(stream,
+ res,
+ &error);
+ if (ret < 0) {
+ g_prefix_error(&error,
+ "Failed to read supplementary volume descriptor: ");
+ goto EXIT;
+ }
+ if (ret == 0) {
+ g_set_error(&error,
+ OSINFO_MEDIA_ERROR,
+ OSINFO_MEDIA_ERROR_NO_SVD,
+ "Supplementary volume descriptor was truncated");
goto EXIT;
}
+ data->offset += ret;
+ if (data->offset < data->length) {
+ g_input_stream_read_async(stream,
+ ((gchar *)&data->svd + data->offset),
+ data->length - data->offset,
+ data->priority,
+ data->cancellable,
+ on_svd_read,
+ data);
+ return;
+ }
+
+
data->svd.system[MAX_SYSTEM - 1] = 0;
if (strncmp(BOOTABLE_TAG, data->svd.system, sizeof(BOOTABLE_TAG) != 0)) {
@@ -606,27 +623,27 @@ static void on_svd_read (GObject *source,
}
uri = g_file_get_uri(data->file);
- ret = g_object_new(OSINFO_TYPE_MEDIA,
- "id", uri,
- NULL);
- osinfo_entity_set_param(OSINFO_ENTITY(ret),
+ media = g_object_new(OSINFO_TYPE_MEDIA,
+ "id", uri,
+ NULL);
+ osinfo_entity_set_param(OSINFO_ENTITY(media),
OSINFO_MEDIA_PROP_URL,
uri);
g_free(uri);
if (!is_str_empty (data->pvd.volume))
- osinfo_entity_set_param(OSINFO_ENTITY(ret),
+ osinfo_entity_set_param(OSINFO_ENTITY(media),
OSINFO_MEDIA_PROP_VOLUME_ID,
data->pvd.volume);
if (!is_str_empty (data->pvd.system))
- osinfo_entity_set_param(OSINFO_ENTITY(ret),
+ osinfo_entity_set_param(OSINFO_ENTITY(media),
OSINFO_MEDIA_PROP_SYSTEM_ID,
data->pvd.system);
if (!is_str_empty (data->pvd.publisher))
- osinfo_entity_set_param(OSINFO_ENTITY(ret),
+ osinfo_entity_set_param(OSINFO_ENTITY(media),
OSINFO_MEDIA_PROP_PUBLISHER_ID,
data->pvd.publisher);
if (!is_str_empty (data->pvd.application))
- osinfo_entity_set_param(OSINFO_ENTITY(ret),
+ osinfo_entity_set_param(OSINFO_ENTITY(media),
OSINFO_MEDIA_PROP_APPLICATION_ID,
data->pvd.application);
@@ -634,7 +651,7 @@ EXIT:
if (error != NULL)
g_simple_async_result_take_error(data->res, error);
else
- g_simple_async_result_set_op_res_gpointer(data->res, ret, NULL);
+ g_simple_async_result_set_op_res_gpointer(data->res, media, NULL);
g_simple_async_result_complete (data->res);
g_object_unref(stream);
@@ -648,23 +665,37 @@ static void on_pvd_read (GObject *source,
GInputStream *stream = G_INPUT_STREAM(source);
CreateFromLocationAsyncData *data;
GError *error = NULL;
+ gssize ret;
data = (CreateFromLocationAsyncData *)user_data;
- if (g_input_stream_read_finish(stream,
- res,
- &error) < sizeof(data->pvd)) {
- if (error)
- g_prefix_error(&error, "Failed to read primary volume descriptor");
- else
- g_set_error(&error,
- OSINFO_MEDIA_ERROR,
- OSINFO_MEDIA_ERROR_NO_PVD,
- "Primary volume descriptor unavailable");
-
+ ret = g_input_stream_read_finish(stream,
+ res,
+ &error);
+ if (ret < 0) {
+ g_prefix_error(&error, "Failed to read primary volume descriptor: ");
+ goto ON_ERROR;
+ }
+ if (ret == 0) {
+ g_set_error(&error,
+ OSINFO_MEDIA_ERROR,
+ OSINFO_MEDIA_ERROR_NO_PVD,
+ "Primary volume descriptor was truncated");
goto ON_ERROR;
}
+ data->offset += ret;
+ if (data->offset < data->length) {
+ g_input_stream_read_async(stream,
+ ((gchar*)&data->pvd) + data->offset,
+ data->length - data->offset,
+ data->priority,
+ data->cancellable,
+ on_pvd_read,
+ data);
+ return;
+ }
+
data->pvd.volume[MAX_VOLUME - 1] = 0;
data->pvd.system[MAX_SYSTEM - 1] = 0;
data->pvd.publisher[MAX_PUBLISHER - 1] = 0;
@@ -679,9 +710,12 @@ static void on_pvd_read (GObject *source,
goto ON_ERROR;
}
+ data->offset = 0;
+ data->length = sizeof(data->svd);
+
g_input_stream_read_async(stream,
- &data->svd,
- sizeof(data->svd),
+ (gchar *)&data->svd,
+ data->length,
data->priority,
data->cancellable,
on_svd_read,
@@ -719,9 +753,12 @@ static void on_location_skipped(GObject *source,
return;
}
+ data->offset = 0;
+ data->length = sizeof(data->pvd);
+
g_input_stream_read_async(stream,
- &data->pvd,
- sizeof(data->pvd),
+ (gchar *)&data->pvd,
+ data->length,
data->priority,
data->cancellable,
on_pvd_read,
--
1.7.7.6
More information about the virt-tools-list
mailing list