GFileInfo * gvfs_file_info_demarshal (char *data, gsize size) { guint32 num_attrs, i; GInputStream *memstream; GDataInputStream *in; GFileInfo *info; char *attr, *str, **strv; GFileAttributeType type; GFileAttributeStatus status; GObject *obj; int objtype; memstream = g_memory_input_stream_new_from_data (data, size, NULL); in = g_data_input_stream_new (memstream); g_object_unref (memstream); info = g_file_info_new (); num_attrs = g_data_input_stream_read_uint32 (in, NULL, NULL); for (i = 0; i < num_attrs; i++) { attr = read_string (in); type = g_data_input_stream_read_byte (in, NULL, NULL); status = g_data_input_stream_read_byte (in, NULL, NULL); switch (type) { case G_FILE_ATTRIBUTE_TYPE_STRING: str = read_string (in); g_file_info_set_attribute_string (info, attr, str); g_free (str); break; case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING: str = read_string (in); g_file_info_set_attribute_byte_string (info, attr, str); g_free (str); break; case G_FILE_ATTRIBUTE_TYPE_STRINGV: strv = read_stringv (in); g_file_info_set_attribute_stringv (info, attr, strv); g_strfreev (strv); break; case G_FILE_ATTRIBUTE_TYPE_BOOLEAN: g_file_info_set_attribute_boolean (info, attr, g_data_input_stream_read_byte (in, NULL, NULL)); break; case G_FILE_ATTRIBUTE_TYPE_UINT32: g_file_info_set_attribute_uint32 (info, attr, g_data_input_stream_read_uint32 (in, NULL, NULL)); break; case G_FILE_ATTRIBUTE_TYPE_INT32: g_file_info_set_attribute_int32 (info, attr, g_data_input_stream_read_int32 (in, NULL, NULL)); break; case G_FILE_ATTRIBUTE_TYPE_UINT64: g_file_info_set_attribute_uint64 (info, attr, g_data_input_stream_read_uint64 (in, NULL, NULL)); break; case G_FILE_ATTRIBUTE_TYPE_INT64: g_file_info_set_attribute_int64 (info, attr, g_data_input_stream_read_int64 (in, NULL, NULL)); break; case G_FILE_ATTRIBUTE_TYPE_OBJECT: objtype = g_data_input_stream_read_byte (in, NULL, NULL); obj = NULL; if (objtype == 1) { char *icon_str; icon_str = read_string (in); obj = (GObject *)g_icon_new_for_string (icon_str, NULL); g_free (icon_str); } else { g_warning ("Unsupported GFileInfo object type %d\n", objtype); g_free (attr); goto out; } g_file_info_set_attribute_object (info, attr, obj); if (obj) g_object_unref (obj); break; case G_FILE_ATTRIBUTE_TYPE_INVALID: break; default: g_warning ("Unsupported GFileInfo attribute type %d\n", type); g_free (attr); goto out; break; } g_file_info_set_attribute_status (info, attr, status); g_free (attr); } out: g_object_unref (in); return info; }
static gchar * extract_content_parent_process (PopplerDocument *document, int fd[2], pid_t child_pid) { GInputStream *input_stream; GDataInputStream *datain_stream; GString *content = NULL; GError *error = NULL; GTimer *timer = NULL; gsize bytes_expected = -1; gboolean timed_out = FALSE; gboolean finished = FALSE; struct timeval timeout; fd_set rfds; /* This is the parent process waiting for the content extractor to * finish in time. */ g_debug ("Parent: Content extraction now starting in child process (pid = %d)", child_pid); /* Set up gio streams */ input_stream = g_unix_input_stream_new (fd[0], FALSE); datain_stream = g_data_input_stream_new (input_stream); /* Watch FD to see when it has input. */ FD_ZERO(&rfds); FD_SET(fd[0], &rfds); /* We give the content extractor 10 seconds to do its job */ timeout.tv_sec = EXTRACTION_PROCESS_TIMEOUT; timeout.tv_usec = 0; /* We also use our own timer because timeouts in select() * can be inconsistent across UNIX platforms. Some update the * timeout and some don't. */ timer = g_timer_new (); /* So, this is fairly simple, what we're doing here is using * select() to know when the child process has written some or * all the data and we then avoid the child blocking by * reading from that stream. We couple with this with a * timeout of 10 seconds so if we receive nothing then we know * we can kill the process because it is taking too long. * * We use waitpid() to know if the process quit because it has * finished or if it is still processing data and needs to be * killed. */ while (!finished) { int retval; /* 1a. Wait for data on the FD and limit by timeout */ retval = select (fd[0] + 1, &rfds, NULL, NULL, &timeout); /* 2. Did we error? Have data? or just timeout? */ if (retval == -1) { perror ("select()"); finished = TRUE; } else if (retval == 1) { gsize bytes_remaining = bytes_expected; gboolean read_finished = FALSE; if (g_timer_elapsed (timer, NULL) >= EXTRACTION_PROCESS_TIMEOUT) { finished = TRUE; timed_out = TRUE; continue; } /* 3. Start reading data */ if (bytes_expected == -1) { /* We only need to read the size once before the data! */ bytes_expected = (gsize) g_data_input_stream_read_int64 (datain_stream, NULL, &error); if (error) { g_warning ("Call to g_data_input_stream_read_int64() failed, %s", error->message); g_error_free (error); finished = TRUE; continue; } g_debug ("Parent: Expected bytes to read is %" G_GSSIZE_FORMAT "", bytes_expected); bytes_remaining = bytes_expected; content = g_string_new (""); } /* 4. Read until done from stream and concatenate data */ while (!read_finished) { gchar buf[BUFFER_SIZE]; gsize bytes_read; memset (buf, 0, BUFFER_SIZE); bytes_read = g_input_stream_read (G_INPUT_STREAM (datain_stream), buf, MIN (BUFFER_SIZE, bytes_remaining), NULL, &error); g_debug ("Parent: Bytes read is %" G_GSSIZE_FORMAT "," "bytes remaining is %" G_GSSIZE_FORMAT "", bytes_read, MAX (bytes_remaining - bytes_read, 0)); if (bytes_read == -1 || error) { g_warning ("Call to g_input_stream_read() failed, %s", error ? error->message : "no error given"); g_clear_error (&error); read_finished = TRUE; finished = TRUE; } else { content = g_string_append (content, buf); bytes_remaining -= bytes_read; bytes_remaining = MAX (bytes_remaining, 0); if (bytes_read == 0) { /* We finished reading */ g_debug ("Parent: Finished reading all bytes"); read_finished = TRUE; } /* Are we finished reading everything */ if (bytes_remaining < 1) { finished = TRUE; } } } } else { /* 3. We must have timed out with no data in select() */ finished = TRUE; timed_out = TRUE; g_debug ("Parent: Must have timed out with no data in select()"); } } if (timed_out) { g_debug ("Parent: Child process took too long. We waited %d seconds, so we're going to kill it!", EXTRACTION_PROCESS_TIMEOUT); kill (child_pid, SIGKILL); } else { g_debug ("Parent: Data received in %2.2f seconds (timeout is %d seconds)", g_timer_elapsed (timer, NULL), EXTRACTION_PROCESS_TIMEOUT); } g_timer_destroy (timer); g_object_unref (datain_stream); g_object_unref (input_stream); close (fd[0]); return content ? g_string_free (content, FALSE) : NULL; }