summaryrefslogtreecommitdiff
path: root/utils/mtp
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2010-10-06 16:04:38 +0200
committerAleksander Morgado <aleksander@lanedo.com>2010-10-06 16:04:53 +0200
commitcf32e9f0ac960f7303f1ef4e6ed0a8ce24532feb (patch)
treeda1b376ae99de6594737cd0203e04e83b0f1885c /utils/mtp
parentdf3f7aa3965c638f218c95b59451433042bc5f1a (diff)
downloadtracker-cf32e9f0ac960f7303f1ef4e6ed0a8ce24532feb.tar.gz
utils: Added new mtp sync simulator
Diffstat (limited to 'utils/mtp')
-rw-r--r--utils/mtp/.gitignore1
-rw-r--r--utils/mtp/Makefile.am29
-rw-r--r--utils/mtp/mtp-dummy.c467
3 files changed, 497 insertions, 0 deletions
diff --git a/utils/mtp/.gitignore b/utils/mtp/.gitignore
new file mode 100644
index 000000000..40844a530
--- /dev/null
+++ b/utils/mtp/.gitignore
@@ -0,0 +1 @@
+mtp-dummy
diff --git a/utils/mtp/Makefile.am b/utils/mtp/Makefile.am
new file mode 100644
index 000000000..5ce4d9eb2
--- /dev/null
+++ b/utils/mtp/Makefile.am
@@ -0,0 +1,29 @@
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES = \
+ -DLOCALEDIR=\""$(localedir)"\" \
+ -DG_LOG_DOMAIN=\"Tracker\" \
+ -DTRACKER_COMPILATION \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -I$(top_builddir)/src/libtracker-sparql \
+ $(WARN_CFLAGS) \
+ $(GCOV_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(GIO_CFLAGS) \
+ $(GTHREAD_CFLAGS) \
+ $(GLIB2_CFLAGS)
+
+libs = \
+ $(top_builddir)/src/libtracker-sparql/libtracker-sparql-@TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-common/libtracker-common.la \
+ $(DBUS_LIBS) \
+ $(GIO_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(GLIB2_LIBS) \
+ $(GCOV_LIBS)
+
+noinst_PROGRAMS = mtp-dummy
+
+mtp_dummy_SOURCES = mtp-dummy.c
+mtp_dummy_LDADD = $(libs) \ No newline at end of file
diff --git a/utils/mtp/mtp-dummy.c b/utils/mtp/mtp-dummy.c
new file mode 100644
index 000000000..4e46cdb2d
--- /dev/null
+++ b/utils/mtp/mtp-dummy.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan.frade@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <glib.h>
+#include <tracker-sparql.h>
+
+#define COPY_TIMEOUT_MS 100
+
+static gint copy_rate = 1024; /* 1MByte/second */
+static gint n_copies = 1;
+static gchar **remaining;
+static GFile *file;
+static gchar *file_uri;
+static GFile *destdir;
+static gchar *destdir_uri;
+static gboolean use_hidden;
+
+/* copy_rate*1024*COPY_TIMEOUT_MS/1000 */
+static gint timeout_copy_rate;
+
+static gchar *buffer;
+static gsize buffer_size;
+
+static GMainLoop *loop;
+static GList *task_list;
+static GList *task_list_li;
+
+/* Note: don't use a GOutputStream, as that actually
+ * creates a hidden temporary file */
+
+typedef struct {
+ GFile *destfile;
+ GFile *destfile_hidden;
+ FILE *fp;
+ gsize bytes_copied;
+ gsize bytes_remaining;
+} CopyTask;
+
+static GOptionEntry entries[] = {
+ { "rate", 'r', 0, G_OPTION_ARG_INT, &copy_rate,
+ "Rate of copy, in KBytes per second",
+ "1024"
+ },
+ { "copies", 'c', 0, G_OPTION_ARG_INT, &n_copies,
+ "Number of copies to be done",
+ "1"
+ },
+ { "hidden", 'h', 0, G_OPTION_ARG_NONE, &use_hidden,
+ "Use a hidden temp file while copying",
+ NULL,
+ },
+ { G_OPTION_REMAINING, 0, 0,
+ G_OPTION_ARG_STRING_ARRAY, &remaining,
+ "file destdir",
+ "FILE DESTDIR",
+ },
+ { NULL }
+};
+
+static void
+update_store (GFile *destfile)
+{
+ gchar *sparql;
+ GError *error = NULL;
+ TrackerSparqlConnection *connection;
+ gchar *uri;
+
+ uri = g_file_get_uri (destfile);
+ sparql = g_strdup_printf ("DELETE {?file a rdfs:Resource} "
+ "WHERE {?file nie:url <%s> } "
+ "INSERT { _:x a nfo:FileDataObject;"
+ " nie:url <%s> }",
+ uri, uri);
+
+ g_print (" Updating store with new resource '%s'\n", uri);
+
+ /* Get connection */
+ connection = tracker_sparql_connection_get (NULL, &error);
+
+ /* Run a synchronous update query */
+ tracker_sparql_connection_update (connection,
+ sparql,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ /* Some error happened performing the query, not good */
+ g_error ("Couldn't update store for '%s': %s",
+ uri,
+ error ? error->message : "unknown error");
+ }
+
+ g_free (uri);
+ g_free (sparql);
+ g_object_unref (connection);
+}
+
+static gboolean
+context_init (gint argc,
+ gchar **argv)
+{
+ GOptionContext *context;
+ gint n_remaining;
+ gchar *file_path;
+ GError *error = NULL;
+
+ /* Setup context */
+ context = g_option_context_new ("- Simulate MTP daemon");
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_parse (context, &argc, &argv, NULL);
+ g_option_context_free (context);
+
+ /* Check input arguments */
+ n_remaining = remaining ? g_strv_length (remaining) : 0;
+ if (n_remaining != 2)
+ {
+ g_printerr ("You must provide FILE and DESTDIR\n");
+ return FALSE;
+ }
+
+ /* Get and check input file */
+ file = g_file_new_for_commandline_arg (remaining[0]);
+ file_uri = g_file_get_uri (file);
+ file_path = g_file_get_path (file);
+ if (g_file_query_file_type (file,
+ G_FILE_QUERY_INFO_NONE,
+ NULL) != G_FILE_TYPE_REGULAR)
+ {
+ g_printerr ("File '%s' is not a valid regular file\n",
+ file_uri);
+ return FALSE;
+ }
+
+ /* Get destination directory */
+ destdir = g_file_new_for_commandline_arg (remaining[1]);
+ destdir_uri = g_file_get_uri (destdir);
+ if (g_file_query_file_type (destdir,
+ G_FILE_QUERY_INFO_NONE,
+ NULL) != G_FILE_TYPE_DIRECTORY)
+ {
+ g_printerr ("Destination path '%s' is not a valid directory\n",
+ destdir_uri);
+ return FALSE;
+ }
+
+ /* Check n_copies */
+ if (n_copies == 0)
+ {
+ g_printerr ("Number of copies must be greater than 0\n");
+ return FALSE;
+ }
+
+ /* Check rate */
+ if (copy_rate == 0)
+ {
+ g_printerr ("Copy rate must be greater than 0\n");
+ return FALSE;
+ }
+
+ /* copy_rate*1024*COPY_TIMEOUT_MS/1000 */
+ timeout_copy_rate = copy_rate * 1024.0 * COPY_TIMEOUT_MS / 1000.0;
+
+ /* Read all input file contents */
+ if (!g_file_get_contents (file_path,
+ &buffer,
+ &buffer_size,
+ &error))
+ {
+ g_error ("Couldn't load file '%s' contents: %s",
+ file_uri,
+ error ? error->message : "unknown error");
+ }
+
+ g_print ("\
+Simulating MTP daemon with:\n\
+ * File: %s (%" G_GSIZE_FORMAT " bytes)\n\
+ * Destdir: %s\n\
+ * Copies: %d\n\
+ * Rate: %d KBytes/s (%d bytes every %d ms)\n",
+ file_uri,
+ buffer_size,
+ destdir_uri,
+ n_copies,
+ copy_rate,
+ timeout_copy_rate,
+ COPY_TIMEOUT_MS);
+
+ return TRUE;
+}
+
+static void
+context_deinit (void)
+{
+ g_object_unref (file);
+ g_free (file_uri);
+ g_object_unref (destdir);
+ g_free (destdir_uri);
+ g_free (buffer);
+}
+
+static gboolean
+task_run_cb (gpointer data)
+{
+ CopyTask *current;
+ gsize n_write;
+
+ /* Get current task */
+ current = task_list_li ? task_list_li->data : NULL;
+
+ /* Stop looping? */
+ if (!current)
+ {
+ g_print ("\n\nNo more tasks to run, finishing...\n");
+ g_main_loop_quit (loop);
+ return FALSE;
+ }
+
+ /* If we just started copying it... */
+ if (!current->fp)
+ {
+ gchar *destfile_path;
+ g_print ("Running new copy task...\n");
+
+ destfile_path = (use_hidden ?
+ g_file_get_path (current->destfile_hidden) :
+ g_file_get_path (current->destfile));
+
+ /* Get file pointer */
+ current->fp = fopen (destfile_path, "w");
+ if (!current->fp)
+ {
+ g_error ("Couldn't get file pointer: %s",
+ g_strerror (errno));
+ }
+
+ /* Create new item in the store right away */
+ update_store (use_hidden ?
+ current->destfile_hidden :
+ current->destfile);
+ g_free (destfile_path);
+ }
+
+ /* Copy bytes */
+ n_write = MIN (current->bytes_remaining, timeout_copy_rate);
+ if (fwrite (&buffer[current->bytes_copied],
+ 1,
+ n_write,
+ current->fp) != n_write)
+ {
+ g_error ("Couldn't write in output file: %s",
+ g_strerror (errno));
+ }
+
+ current->bytes_remaining -= n_write;
+ current->bytes_copied += n_write;
+
+ /* Finished with this task? */
+ if (current->bytes_remaining == 0)
+ {
+ fclose (current->fp);
+ current->fp = NULL;
+
+ if (use_hidden)
+ {
+ GError *error = NULL;
+
+ /* Copying finished, now MOVE to the final path */
+ if (!g_file_move (current->destfile_hidden,
+ current->destfile,
+ G_FILE_COPY_OVERWRITE,
+ NULL,
+ NULL,
+ NULL,
+ &error))
+ {
+ g_error ("Couldn't copy file to the final destination: %s",
+ error ? error->message : "unknown error");
+ }
+ }
+
+ /* Setup next task */
+ task_list_li = g_list_next (task_list_li);
+ }
+
+ return TRUE;
+}
+
+static void
+setup_tasks (void)
+{
+ gint i;
+ gchar *input_file_basename;
+
+ input_file_basename = g_file_get_basename (file);
+
+ for (i=n_copies-1; i>=0; i--)
+ {
+ CopyTask *task;
+ gchar *basename;
+
+ basename = g_strdup_printf ("file-copy-%d-%s",
+ i,
+ input_file_basename);
+
+ task = g_new0 (CopyTask, 1);
+ task->destfile = g_file_get_child (destdir, basename);
+ task->bytes_remaining = buffer_size;
+
+ if (use_hidden)
+ {
+ gchar *basename_hidden;
+
+ basename_hidden = g_strdup_printf (".mtp-dummy.file-copy-%d-%s",
+ i,
+ input_file_basename);
+ task->destfile_hidden = g_file_get_child (destdir, basename_hidden);
+ g_free (basename_hidden);
+ }
+
+ task_list = g_list_prepend (task_list, task);
+
+ g_free (basename);
+ }
+
+ /* Setup first task */
+ task_list_li = task_list;
+
+ /* Timeout every N milliseconds */
+ g_timeout_add (COPY_TIMEOUT_MS,
+ task_run_cb,
+ NULL);
+}
+
+static void
+check_duplicates_for_uri (const gchar *uri)
+{
+ GError *error = NULL;
+ TrackerSparqlConnection *connection;
+ TrackerSparqlCursor *cursor;
+ gchar *sparql;
+
+ sparql = g_strdup_printf ("SELECT ?u WHERE { ?u nie:url <%s> }",
+ uri);
+
+ /* As we know only read-only queries will be done, it's enough
+ * to use a connection with only direct-access setup.
+ */
+ connection = tracker_sparql_connection_get_direct (NULL, &error);
+ if (!connection)
+ {
+ g_error ("Couldn't obtain a direct connection to the Tracker store: %s",
+ error ? error->message : "unknown error");
+ }
+
+ /* Make a synchronous query to the store */
+ cursor = tracker_sparql_connection_query (connection,
+ sparql,
+ NULL,
+ &error);
+ if (error)
+ {
+ /* Some error happened performing the query, not good */
+ g_error ("Couldn't query the Tracker Store: '%s'",
+ error ? error->message : "unknown error");
+ }
+
+ /* Check results... */
+ if (!cursor)
+ {
+ g_print (" For '%s' found 0 results!\n", uri);
+ }
+ else
+ {
+ gint i = 0;
+
+ g_print (" For '%s' found:\n", uri);
+ /* Iterate, synchronously, the results... */
+ while (tracker_sparql_cursor_next (cursor, NULL, &error))
+ {
+ g_print (" [%d]: %s\n",
+ i++,
+ tracker_sparql_cursor_get_string (cursor, 0, NULL));
+ }
+ g_print (" A total of '%d' results were found\n", i);
+
+ g_object_unref (cursor);
+ }
+
+ g_object_unref (connection);
+}
+
+static void
+check_duplicates (void)
+{
+
+ g_print ("\nChecking duplicates...\n");
+
+ task_list_li = task_list;
+
+ while (task_list_li)
+ {
+ CopyTask *current;
+ gchar *uri;
+
+ current = task_list_li->data;
+ uri = g_file_get_uri (current->destfile);
+
+ check_duplicates_for_uri (uri);
+
+ g_free (uri);
+ g_object_unref (current->destfile);
+ g_free (current);
+ task_list_li = g_list_next (task_list_li);;
+ }
+
+ g_list_free (task_list);
+}
+
+int main (int argc, char **argv)
+{
+ /* Initialize stuff */
+ g_thread_init (NULL);
+ g_type_init ();
+
+ /* Initialize context */
+ if (!context_init (argc, argv))
+ {
+ g_printerr ("Couldn't setup context, exiting.");
+ return -1;
+ }
+
+ /* Setup tasks */
+ setup_tasks ();
+
+ /* Run */
+ g_print ("\nStarting...\n\n");
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ /* Check for duplicates and cleanup copied files */
+ check_duplicates ();
+
+ context_deinit ();
+ return 0;
+}
+