Beispiel #1
0
// 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/**
 * 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;
}