static void file_info_from_message (SoupMessage *msg, GFileInfo *info, GFileAttributeMatcher *matcher) { const char *text; GHashTable *params; char *basename; char *ed_name; basename = ed_name = NULL; /* prefer the filename from the Content-Disposition (rfc2183) header if one if present. See bug 551298. */ if (soup_message_headers_get_content_disposition (msg->response_headers, NULL, ¶ms)) { const char *name = g_hash_table_lookup (params, "filename"); if (name) basename = g_strdup (name); g_hash_table_destroy (params); } if (basename == NULL) { const SoupURI *uri; uri = soup_message_get_uri (msg); basename = http_uri_get_basename (uri->path); } g_debug ("basename:%s\n", basename); /* read http/1.1 rfc, until then we copy the local files * behaviour */ if (basename != NULL && (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME) || g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME))) ed_name = gvfs_file_info_populate_names_as_local (info, basename); g_free (basename); g_free (ed_name); if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH) { goffset start, end, length; gboolean ret; ret = soup_message_headers_get_content_range (msg->response_headers, &start, &end, &length); if (ret && length != -1) { g_file_info_set_size (info, length); } else if (!ret) { length = soup_message_headers_get_content_length (msg->response_headers); g_file_info_set_size (info, length); } } g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR); text = soup_message_headers_get_content_type (msg->response_headers, NULL); if (text) { GIcon *icon; g_file_info_set_content_type (info, text); g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, text); icon = g_content_type_get_icon (text); g_file_info_set_icon (info, icon); g_object_unref (icon); icon = g_content_type_get_symbolic_icon (text); g_file_info_set_symbolic_icon (info, icon); g_object_unref (icon); } text = soup_message_headers_get_one (msg->response_headers, "Last-Modified"); if (text) { SoupDate *sd; GTimeVal tv; sd = soup_date_new_from_string(text); if (sd) { soup_date_to_timeval (sd, &tv); g_file_info_set_modification_time (info, &tv); soup_date_free (sd); } } text = soup_message_headers_get_one (msg->response_headers, "ETag"); if (text) { g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, text); } }
/* Note: This function does not report errors as a GError because there’s no * harm in the stamp file not being updated: it just means we’re going to check * again for updates sooner than otherwise. */ static void update_stamp_file (guint64 last_successful_update_secs, guint update_interval_days, guint randomized_delay_days) { const gchar *stamp_dir = get_stamp_dir (); g_autofree gchar *stamp_path = NULL; g_autoptr(GFile) stamp_file = NULL; g_autoptr(GError) error = NULL; GTimeVal mtime; g_autofree gchar *next_update = NULL; g_autoptr(GFileInfo) file_info = NULL; if (g_mkdir_with_parents (stamp_dir, 0755) != 0) { int saved_errno = errno; const char *err_str = g_strerror (saved_errno); critical (EOS_UPDATER_CONFIGURATION_ERROR_MSGID, "Failed to create updater timestamp directory: %s", err_str); return; } /* This will be subject to year 2038 problems on 32-bit architectures. * FIXME: Fix that by dropping use of #GTimeVal. */ mtime.tv_sec = (glong) last_successful_update_secs; mtime.tv_usec = 0; stamp_path = g_build_filename (stamp_dir, UPDATE_STAMP_NAME, NULL); stamp_file = g_file_new_for_path (stamp_path); g_file_replace_contents (stamp_file, "", 0, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error); if (error) { critical (EOS_UPDATER_STAMP_ERROR_MSGID, "Failed to write updater stamp file: %s", error->message); return; } /* Set the file’s mtime to include the randomised delay. This will result in * the mtime either being now, or some number of days in the future. Setting * the mtime to the future should not be a problem, as the stamp file is only * accessed by eos-autoupdater, so the semantics of the mtime are clear. */ file_info = g_file_query_info (stamp_file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, &error); if (error != NULL) { critical (EOS_UPDATER_STAMP_ERROR_MSGID, "Failed to get stamp file info: %s", error->message); return; } if (randomized_delay_days > 0) { gint32 actual_delay_days = g_random_int_range (0, (gint32) randomized_delay_days + 1); mtime.tv_sec += (glong) actual_delay_days * (glong) SEC_PER_DAY; } g_file_info_set_modification_time (file_info, &mtime); g_file_set_attributes_from_info (stamp_file, file_info, G_FILE_QUERY_INFO_NONE, NULL, &error); if (error != NULL) { critical (EOS_UPDATER_STAMP_ERROR_MSGID, "Failed to set stamp file info: %s", error->message); return; } /* A little bit of help for debuggers. */ mtime.tv_sec += (glong) update_interval_days * (glong) SEC_PER_DAY; next_update = g_time_val_to_iso8601 (&mtime); g_debug ("Wrote stamp file. Next update at %s", next_update); }
static gboolean fl_parser_fill_file_info (GFileInfo *info, const char **attr) { gint i; for (i = 0; attr[i]; ++i) { const gchar *name; const gchar *value; name = attr[i]; value = attr[++i]; if (strcmp (name, "name") == 0) { char *display_name; /* Apparently someone decided it was a good idea * to send name="" mem-type="MMC" */ if (!value || strcmp (value, "") == 0) { return FALSE; } g_file_info_set_name (info, value); display_name = g_filename_display_name (value); g_file_info_set_display_name (info, display_name); d(g_print ("Name: '%s'\n", display_name)); g_free (display_name); } else if (strcmp (name, "size") == 0) { g_file_info_set_size (info, strtoll (value, NULL, 10)); d(g_print ("Size: '%"G_GINT64_FORMAT"'\n", g_file_info_get_size (info))); } else if (strcmp (name, "modified") == 0) { GTimeVal time; if (g_time_val_from_iso8601 (value, &time) == FALSE) continue; g_file_info_set_modification_time (info, &time); d(g_print ("Modified: '%s' = '%d'\n", value, (int)time.tv_sec)); } else if (strcmp (name, "created") == 0) { GTimeVal time; if (g_time_val_from_iso8601 (value, &time) == FALSE) continue; g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED, time.tv_sec); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CREATED_USEC, time.tv_usec); d(g_print ("Created: '%s' = '%d'\n", value, (int)time.tv_sec)); } else if (strcmp (name, "accessed") == 0) { GTimeVal time; if (g_time_val_from_iso8601 (value, &time) == FALSE) continue; g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS, time.tv_sec); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, time.tv_usec); d(g_print ("Accessed: '%s' = '%d'\n", value, (int)time.tv_sec)); } else if (strcmp (name, "user-perm") == 0) { /* The permissions don't map well to unix semantics, * since the user is most likely not the same on both * sides. We map the user permissions to "other" on the * local side. D is treated as write, otherwise files * can't be deleted through the module, even if it * should be possible. */ if (strstr (value, "R")) { g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); } if (strstr (value, "W") || strstr (value, "D")) { g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); } } else if (strcmp (name, "group-perm") == 0) { /* Ignore for now */ d(g_print ("Group permissions: '%s'\n", value)); } else if (strcmp (name, "other-perm") == 0) { /* Ignore for now */ d(g_print ("Other permissions: '%s'\n", value)); } else if (strcmp (name, "owner") == 0) { /* Ignore for now */ d(g_print ("Owner: '%s'\n", value)); } else if (strcmp (name, "group") == 0) { /* Ignore for now */ d(g_print ("Group: '%s'\n", value)); } else if (strcmp (name, "type") == 0) { g_file_info_set_content_type (info, value); d(g_print ("Mime-Type: '%s'\n", value)); } else if (strcmp (name, "xml:lang") == 0) { d(g_print ("Lang: '%s'\n", value)); } else if (strcmp (name, "mem-type") == 0) { guint device; if (value == NULL || value[0] == '\0') continue; device = om_mem_type_id_from_string (value); g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_RDEV, device); d(g_print ("Mem-Type: '%s' (%d)\n", value, device)); } else { d(g_print ("Unknown Attribute: %s = %s\n", name, value)); } } if (g_file_info_get_name (info) == NULL) { /* Required attribute */ /* Set error */ return FALSE; } return TRUE; }
static gboolean g_vfs_ftp_dir_cache_funcs_process (GInputStream * stream, int debug_id, const GVfsFtpFile * dir, GVfsFtpDirCacheEntry *entry, gboolean is_unix, GCancellable * cancellable, GError ** error) { struct list_state state = { NULL, }; GDataInputStream *data; GFileInfo *info; int type; GVfsFtpFile *file; char *line, *s; gsize length; /* protect against code reorg - in current code, error never is NULL */ g_assert (error != NULL); g_assert (*error == NULL); data = g_data_input_stream_new (stream); /* we use LF only, because the mozilla code can handle lines ending in CR */ g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_LF); while ((line = g_data_input_stream_read_line (data, &length, cancellable, error))) { struct list_result result = { 0, }; GFileType file_type = G_FILE_TYPE_UNKNOWN; GTimeVal tv = { 0, 0 }; /* strip trailing \r - ParseFTPList only removes it if the line ends in \r\n, * but we stripped the \n already. */ if (length > 0 && line[length - 1] == '\r') line[--length] = '\0'; g_debug ("<<%2d << %s\n", debug_id, line); type = ParseFTPList (line, &state, &result); if (type != 'd' && type != 'f' && type != 'l') { g_free (line); continue; } /* don't list . and .. directories * Let's hope they're not important files on some ftp servers */ if (result.fe_fnlen == 1 && result.fe_fname[0] == '.') { g_free (line); continue; } if (result.fe_fnlen == 2 && result.fe_fname[0] == '.' && result.fe_fname[1] == '.') { g_free (line); continue; } s = g_strndup (result.fe_fname, result.fe_fnlen); file = g_vfs_ftp_file_new_child (dir, s, NULL); g_free (s); if (file == NULL) { g_debug ("# invalid filename, skipping"); g_free (line); continue; } info = g_file_info_new (); s = g_path_get_basename (g_vfs_ftp_file_get_gvfs_path (file)); g_file_info_set_name (info, s); g_free (s); if (type == 'l') { char *link; link = g_strndup (result.fe_lname, result.fe_lnlen); g_file_info_set_symlink_target (info, link); g_file_info_set_is_symlink (info, TRUE); g_free (link); } g_file_info_set_size (info, g_ascii_strtoull (result.fe_size, NULL, 10)); /* If unix format then parse the attributes */ if (state.lstyle == 'U') { char file_mode[10], uid[64], gid[64]; guint32 mode; /* POSIX ls -l form: mode, links, owner, group */ if (sscanf(line, "%10c %*u %63s %63s", file_mode, uid, gid) == 3) { if (g_vfs_ftp_parse_mode (file_mode, &mode, &file_type)) { g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, mode); g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER, uid); g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP, gid); } } else g_debug ("# unknown listing format\n"); } if (file_type == G_FILE_TYPE_UNKNOWN) { file_type = type == 'f' ? G_FILE_TYPE_REGULAR : type == 'l' ? G_FILE_TYPE_SYMBOLIC_LINK : G_FILE_TYPE_DIRECTORY; } gvfs_file_info_populate_default (info, g_vfs_ftp_file_get_gvfs_path (file), file_type); if (is_unix) g_file_info_set_is_hidden (info, result.fe_fnlen > 0 && result.fe_fname[0] == '.'); /* Workaround: * result.fetime.tm_year contains actual year instead of offset-from-1900, * which mktime expects. */ if (result.fe_time.tm_year >= 1900) result.fe_time.tm_year -= 1900; tv.tv_sec = mktime (&result.fe_time); if (tv.tv_sec != -1) g_file_info_set_modification_time (info, &tv); g_vfs_ftp_dir_cache_entry_add (entry, file, info); g_free (line); } g_object_unref (data); return *error != NULL; }