From 23ab7d8c4979bff05e37e2e4aff5a74da2b36c3a Mon Sep 17 00:00:00 2001 From: Haridass Selvaraj Date: Tue, 17 Dec 2013 12:06:13 +0100 Subject: [PATCH] curlftpsink: Optionally create a temporary file during FTP transfer/upload https://bugzilla.gnome.org/show_bug.cgi?id=711620 --- ext/curl/gstcurlftpsink.c | 91 +++++++++++++++++++++++++++++- ext/curl/gstcurlftpsink.h | 3 + tests/check/elements/curlftpsink.c | 21 +++++++ 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/ext/curl/gstcurlftpsink.c b/ext/curl/gstcurlftpsink.c index de248f978b..988e899261 100644 --- a/ext/curl/gstcurlftpsink.c +++ b/ext/curl/gstcurlftpsink.c @@ -65,7 +65,8 @@ /* Default values */ #define GST_CAT_DEFAULT gst_curl_ftp_sink_debug - +#define RENAME_TO "RNTO " +#define RENAME_FROM "RNFR " /* Plugin specific settings */ @@ -76,6 +77,8 @@ enum PROP_0, PROP_FTP_PORT_ARG, PROP_EPSV_MODE, + PROP_CREATE_TEMP_FILE, + PROP_CREATE_TEMP_FILE_NAME, PROP_CREATE_DIRS }; @@ -131,6 +134,18 @@ gst_curl_ftp_sink_class_init (GstCurlFtpSinkClass * klass) g_param_spec_boolean ("epsv-mode", "Extended passive mode", "Enable the use of the EPSV command when doing passive FTP transfers", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CREATE_TEMP_FILE, + g_param_spec_boolean ("create-tmp-file", "Enable or disable temporary file transfer", + "Use a temporary file name when uploading a a file. When the transfer is complete, \ + this temporary file is renamed to the final file name. This is useful for ensuring \ + that remote systems do not read a partially uploaded file", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CREATE_TEMP_FILE_NAME, + g_param_spec_string ("temp-file-name", "Creates a temporary file name with date and time", + "Filename pattern to use when generating a temporary filename for uploads", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_CREATE_DIRS, g_param_spec_boolean ("create-dirs", "Create missing directories", "Attempt to create missing directory included in the path", @@ -149,6 +164,12 @@ gst_curl_ftp_sink_finalize (GObject * gobject) GST_DEBUG ("finalizing curlftpsink"); g_free (this->ftp_port_arg); + g_free (this->tmpfile_name); + + if (this->headerlist) { + curl_slist_free_all (this->headerlist); + this->headerlist = NULL; + } G_OBJECT_CLASS (parent_class)->finalize (gobject); } @@ -156,9 +177,58 @@ gst_curl_ftp_sink_finalize (GObject * gobject) static gboolean set_ftp_dynamic_options_unlocked (GstCurlBaseSink * basesink) { - gchar *tmp = g_strdup_printf ("%s%s", basesink->url, basesink->file_name); + gchar *tmp = NULL; + GstCurlFtpSink *sink = GST_CURL_FTP_SINK (basesink); + + if(sink->tmpfile_create) { + gchar *rename_from = NULL; + gchar *rename_to = NULL; + gchar *uploadfile_as = NULL; + gchar *last_slash = NULL; + gchar *dir_name = NULL; + gchar *tmpfile_name = NULL; - curl_easy_setopt (basesink->curl, CURLOPT_URL, tmp); + if (sink->headerlist != NULL) { + curl_slist_free_all (sink->headerlist); + sink->headerlist = NULL; + } + + if (sink->tmpfile_name != NULL) { + tmpfile_name = g_strdup_printf ("%s", sink->tmpfile_name); + } else { + tmpfile_name = g_strdup_printf (".tmp.%04X%04X", g_random_int (), g_random_int ()); + } + + rename_from = g_strdup_printf ("%s%s", RENAME_FROM, tmpfile_name); + + last_slash = strrchr (basesink->file_name, '/'); + if (last_slash != NULL) { + dir_name = g_strndup (basesink->file_name, last_slash - basesink->file_name); + rename_to = g_strdup_printf ("%s%s", RENAME_TO, last_slash+1); + uploadfile_as = g_strdup_printf ("%s/%s", dir_name, tmpfile_name); + } else { + rename_to = g_strdup_printf ("%s%s", RENAME_TO, basesink->file_name); + uploadfile_as = g_strdup_printf ("%s", tmpfile_name); + } + + tmp = g_strdup_printf ("%s%s", basesink->url, uploadfile_as); + curl_easy_setopt (basesink->curl, CURLOPT_URL, tmp); + sink->headerlist = curl_slist_append (sink->headerlist, rename_from); + sink->headerlist = curl_slist_append (sink->headerlist, rename_to); + curl_easy_setopt (basesink->curl, CURLOPT_POSTQUOTE, sink->headerlist); + + g_free (rename_from); + g_free (rename_to); + g_free (uploadfile_as); + g_free (dir_name); + g_free (tmpfile_name); + if(last_slash != NULL) { + *last_slash = '\0'; + } + } else { + tmp = g_strdup_printf ("%s%s", basesink->url, basesink->file_name); + curl_easy_setopt (basesink->curl, CURLOPT_URL, tmp); + } g_free (tmp); @@ -230,6 +300,15 @@ gst_curl_ftp_sink_set_property (GObject * object, guint prop_id, sink->epsv_mode = g_value_get_boolean (value); GST_DEBUG_OBJECT (sink, "epsv-mode set to %d", sink->epsv_mode); break; + case PROP_CREATE_TEMP_FILE: + sink->tmpfile_create = g_value_get_boolean (value); + GST_DEBUG_OBJECT (sink, "create-tmp-file set to %d", sink->tmpfile_create); + break; + case PROP_CREATE_TEMP_FILE_NAME: + g_free (sink->tmpfile_name); + sink->tmpfile_name = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "tmp-file-name set to %s", sink->tmpfile_name); + break; case PROP_CREATE_DIRS: sink->create_dirs = g_value_get_boolean (value); GST_DEBUG_OBJECT (sink, "create-dirs set to %d", sink->create_dirs); @@ -260,6 +339,12 @@ gst_curl_ftp_sink_get_property (GObject * object, guint prop_id, case PROP_EPSV_MODE: g_value_set_boolean (value, sink->epsv_mode); break; + case PROP_CREATE_TEMP_FILE: + g_value_set_boolean (value, sink->tmpfile_create); + break; + case PROP_CREATE_TEMP_FILE_NAME: + g_value_set_string (value, sink->tmpfile_name); + break; case PROP_CREATE_DIRS: g_value_set_boolean (value, sink->create_dirs); break; diff --git a/ext/curl/gstcurlftpsink.h b/ext/curl/gstcurlftpsink.h index 4cfc4b63d6..95555eaa91 100644 --- a/ext/curl/gstcurlftpsink.h +++ b/ext/curl/gstcurlftpsink.h @@ -44,8 +44,11 @@ struct _GstCurlFtpSink GstCurlTlsSink parent; /*< private > */ + struct curl_slist *headerlist; gchar *ftp_port_arg; gboolean epsv_mode; + gboolean tmpfile_create; + gchar *tmpfile_name; gboolean create_dirs; }; diff --git a/tests/check/elements/curlftpsink.c b/tests/check/elements/curlftpsink.c index 05a9f60f5f..dd61ead924 100644 --- a/tests/check/elements/curlftpsink.c +++ b/tests/check/elements/curlftpsink.c @@ -41,6 +41,8 @@ GST_START_TEST (test_properties) gchar *res_location = NULL; gchar *res_file_name = NULL; gchar *res_ftp_port = NULL; + gchar *res_tmp_file_name = NULL; + gboolean res_create_tmpfile; gboolean res_epsv_mode; gboolean res_create_dirs; @@ -51,6 +53,8 @@ GST_START_TEST (test_properties) g_object_set (G_OBJECT (sink), "ftp-port", "1.2.3.4:0", NULL); g_object_set (G_OBJECT (sink), "epsv-mode", FALSE, NULL); g_object_set (G_OBJECT (sink), "create-dirs", FALSE, NULL); + g_object_set (G_OBJECT (sink), "create-tmp-file", FALSE, NULL); + g_object_set (G_OBJECT (sink), "temp-file-name", "test_tmp_file_", NULL); g_object_get (sink, "location", &res_location, @@ -58,6 +62,8 @@ GST_START_TEST (test_properties) "ftp-port", &res_ftp_port, "epsv-mode", &res_epsv_mode, "create-dirs", &res_create_dirs, + "create-tmp-file", &res_create_tmpfile, + "temp-file-name", &res_tmp_file_name, NULL); fail_unless (strncmp (res_location, "mylocation", strlen ("mylocation")) @@ -66,11 +72,16 @@ GST_START_TEST (test_properties) == 0); fail_unless (strncmp (res_ftp_port, "1.2.3.4:0", strlen ("1.2.3.4:0")) == 0); + fail_unless (strncmp (res_tmp_file_name, "test_tmp_file_", strlen ("test_tmp_file_")) + == 0); fail_unless (res_epsv_mode == FALSE); fail_unless (res_create_dirs == FALSE); + fail_unless (res_create_tmpfile == FALSE); + g_free (res_location); g_free (res_file_name); g_free (res_ftp_port); + g_free (res_tmp_file_name); /* change properties */ g_object_set (G_OBJECT (sink), "location", "newlocation", NULL); @@ -78,6 +89,8 @@ GST_START_TEST (test_properties) g_object_set (G_OBJECT (sink), "ftp-port", "", NULL); g_object_set (G_OBJECT (sink), "epsv-mode", TRUE, NULL); g_object_set (G_OBJECT (sink), "create-dirs", TRUE, NULL); + g_object_set (G_OBJECT (sink), "create-tmp-file", TRUE, NULL); + g_object_set (G_OBJECT (sink), "temp-file-name", "test_tmp_file_", NULL); g_object_get (sink, "location", &res_location, @@ -85,6 +98,8 @@ GST_START_TEST (test_properties) "ftp-port", &res_ftp_port, "epsv-mode", &res_epsv_mode, "create-dirs", &res_create_dirs, + "create-tmp-file", &res_create_tmpfile, + "temp-file-name", &res_tmp_file_name, NULL); fail_unless (strncmp (res_location, "newlocation", strlen ("newlocation")) @@ -93,11 +108,17 @@ GST_START_TEST (test_properties) == 0); fail_unless (strncmp (res_ftp_port, "", strlen ("")) == 0); + fail_unless (strncmp (res_tmp_file_name, "test_tmp_file_", strlen ("test_tmp_file_")) + == 0); fail_unless (res_epsv_mode == TRUE); fail_unless (res_create_dirs == TRUE); + fail_unless (res_create_dirs == TRUE); + fail_unless (res_create_tmpfile == TRUE); + g_free (res_location); g_free (res_file_name); g_free (res_ftp_port); + g_free (res_tmp_file_name); cleanup_curlftpsink (sink); }