// Change the modified time of file int ug_modify_file_time (const gchar *file_utf8, time_t mod_time) { struct utimbuf utb; gchar* file; int retval; utb.actime = time (NULL); utb.modtime = mod_time; file = g_filename_from_utf8 (file_utf8, -1, NULL, NULL, NULL); retval = g_utime (file, &utb); g_free (file); return retval; }
static DownloadResult_t download( const char *hostname, const char *uri, const char *fn, DownloadFileOptions *options, gboolean ftp, void *handle) { FILE *f; int ret; gchar *tmpfilename; gboolean failure = FALSE; CurlDownloadOptions cdo = {0, NULL, NULL}; /* Check file */ if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == TRUE ) { if (options == NULL || (!options->check_file_server_time && !options->use_etag)) { /* Nothing to do as file already exists and we don't want to check server */ return DOWNLOAD_NOT_REQUIRED; } time_t tile_age = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "download_tile_age")->u; /* Get the modified time of this file */ GStatBuf buf; (void)g_stat ( fn, &buf ); time_t file_time = buf.st_mtime; if ( (time(NULL) - file_time) < tile_age ) { /* File cache is too recent, so return */ return DOWNLOAD_NOT_REQUIRED; } if (options != NULL && options->check_file_server_time) { cdo.time_condition = file_time; } if (options != NULL && options->use_etag) { get_etag(fn, &cdo); } } else { gchar *dir = g_path_get_dirname ( fn ); if ( g_mkdir_with_parents ( dir , 0777 ) != 0) g_warning ("%s: Failed to mkdir %s", __FUNCTION__, dir ); g_free ( dir ); } tmpfilename = g_strdup_printf("%s.tmp", fn); if (!lock_file ( tmpfilename ) ) { g_debug("%s: Couldn't take lock on temporary file \"%s\"\n", __FUNCTION__, tmpfilename); g_free ( tmpfilename ); if (options->use_etag) g_free ( cdo.etag ); return DOWNLOAD_FILE_WRITE_ERROR; } f = g_fopen ( tmpfilename, "w+b" ); /* truncate file and open it */ if ( ! f ) { g_warning("Couldn't open temporary file \"%s\": %s", tmpfilename, g_strerror(errno)); g_free ( tmpfilename ); if (options->use_etag) g_free ( cdo.etag ); return DOWNLOAD_FILE_WRITE_ERROR; } /* Call the backend function */ ret = curl_download_get_url ( hostname, uri, f, options, ftp, &cdo, handle ); DownloadResult_t result = DOWNLOAD_SUCCESS; if (ret != CURL_DOWNLOAD_NO_ERROR && ret != CURL_DOWNLOAD_NO_NEWER_FILE) { g_debug("%s: download failed: curl_download_get_url=%d", __FUNCTION__, ret); failure = TRUE; result = DOWNLOAD_HTTP_ERROR; } if (!failure && options != NULL && options->check_file != NULL && ! options->check_file(f)) { g_debug("%s: file content checking failed", __FUNCTION__); failure = TRUE; result = DOWNLOAD_CONTENT_ERROR; } fclose ( f ); f = NULL; if (failure) { g_warning(_("Download error: %s"), fn); if ( g_remove ( tmpfilename ) != 0 ) g_warning( ("Failed to remove: %s"), tmpfilename); unlock_file ( tmpfilename ); g_free ( tmpfilename ); if ( options != NULL && options->use_etag ) { g_free ( cdo.etag ); g_free ( cdo.new_etag ); } return result; } if (ret == CURL_DOWNLOAD_NO_NEWER_FILE) { (void)g_remove ( tmpfilename ); // update mtime of local copy // Not security critical, thus potential Time of Check Time of Use race condition is not bad // coverity[toctou] if ( g_utime ( fn, NULL ) != 0 ) g_warning ( "%s couldn't set time on: %s", __FUNCTION__, fn ); } else { if ( options != NULL && options->convert_file ) options->convert_file ( tmpfilename ); if ( options != NULL && options->use_etag ) { if ( cdo.new_etag ) { /* server returned an etag value */ set_etag(fn, tmpfilename, &cdo); } } /* move completely-downloaded file to permanent location */ if ( g_rename ( tmpfilename, fn ) ) g_warning ("%s: file rename failed [%s] to [%s]", __FUNCTION__, tmpfilename, fn ); } unlock_file ( tmpfilename ); g_free ( tmpfilename ); if ( options != NULL && options->use_etag ) { g_free ( cdo.etag ); g_free ( cdo.new_etag ); } return DOWNLOAD_SUCCESS; }
/** * a_geotag_write_exif_gps: * @filename: The image file to save information in * @coord: The location * @alt: The elevation * @direction: The image direction (if NAN then these direction fields are not written) * @direction_ref: The image direction value type * * Returns: A value indicating success: 0, or some other value for failure * */ gint a_geotag_write_exif_gps ( const gchar *filename, VikCoord coord, gdouble alt, gdouble direction, VikWaypointImageDirectionRef direction_ref, gboolean no_change_mtime ) { gint result = 0; // OK so far... // Save mtime for later use struct stat stat_save; if ( no_change_mtime ) if ( stat ( filename, &stat_save ) != 0 ) g_warning ( "%s couldn't read: %s", __FUNCTION__, filename ); #ifdef HAVE_LIBGEXIV2 GExiv2Metadata *gemd = gexiv2_metadata_new (); if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) { struct LatLon ll; vik_coord_to_latlon ( &coord, &ll ); if ( ! gexiv2_metadata_set_gps_info ( gemd, ll.lon, ll.lat, alt ) ) { result = 1; // Failed } else { if ( !isnan(direction) ) { gint nom = (gint)round(direction * 10.0); gboolean set_d = gexiv2_metadata_set_exif_tag_rational ( gemd, EXIF_GPS_IMGDIR, nom, 10 ); if ( !set_d ) result = 1; // Failed gboolean set_r = gexiv2_metadata_set_tag_string ( gemd, EXIF_GPS_IMGDIR_REF, direction_ref == WP_IMAGE_DIRECTION_REF_TRUE ? "T" : "M" ); if ( !set_r ) result = 1; // Failed } // Still OK to save - no fails yet if ( result == 0 ) { GError *error = NULL; if ( ! gexiv2_metadata_save_file ( gemd, filename, &error ) ) { result = 2; g_warning ( "Write EXIF failure:%s" , error->message ); g_error_free ( error ); } } } } metadata_free ( gemd ); #else #ifdef HAVE_LIBEXIF /* Appears libexif doesn't actually support writing EXIF data directly to files Thus embed command line exif writing method within Viking (for example this is done by Enlightment - http://www.enlightenment.org/ ) This appears to be JPEG only, but is probably 99% of our use case Alternatively consider using libexiv2 and C++... */ // Actual EXIF settings here... JPEGData *jdata; /* Parse the JPEG file. */ jdata = jpeg_data_new (); jpeg_data_load_file (jdata, filename); // Get current values ExifData *ed = exif_data_new_from_file ( filename ); if ( !ed ) ed = exif_data_new (); // Update ExifData with our new settings ExifEntry *ee; // // I don't understand it, but when saving the 'ed' nothing gets set after putting in the GPS ID tag - so it must come last // (unless of course there is some bug in the setting of the ID, that prevents subsequent tags) // ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, alt, ee, exif_data_get_byte_order(ed) ); // byte 0 meaning "sea level" or 1 if the value is negative. ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_IFD_GPS); convert_to_entry ( alt < 0.0 ? "1" : "0", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_IFD_GPS); // see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html convert_to_entry ( "MANUAL", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_MAP_DATUM, EXIF_IFD_GPS); convert_to_entry ( "WGS-84", 0.0, ee, exif_data_get_byte_order(ed) ); struct LatLon ll; vik_coord_to_latlon ( &coord, &ll ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE_REF, EXIF_IFD_GPS); // N or S convert_to_entry ( ll.lat < 0.0 ? "S" : "N", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lat, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_IFD_GPS); // E or W convert_to_entry ( ll.lon < 0.0 ? "W" : "E", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lon, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_GPS); //convert_to_entry ( "2 0 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); convert_to_entry ( "2 2 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); jpeg_data_set_exif_data (jdata, ed); if ( jdata ) { /* Save the modified image. */ result = jpeg_data_save_file (jdata, filename); // Convert result from 1 for success, 0 for failure into our scheme result = !result; jpeg_data_unref (jdata); } else { // Epic fail - file probably not a JPEG result = 2; } exif_data_free ( ed ); #endif #endif if ( no_change_mtime ) { // Restore mtime, using the saved value struct stat stat_tmp; struct utimbuf utb; (void)stat ( filename, &stat_tmp ); utb.actime = stat_tmp.st_atime; utb.modtime = stat_save.st_mtime; // Not security critical, thus potential Time of Check Time of Use race condition is not bad // coverity[toctou] if ( g_utime ( filename, &utb ) != 0 ) g_warning ( "%s couldn't set time on: %s", __FUNCTION__, filename ); } return result; }