[Spice-devel] [phodav PATCH 1/2 v2] spice-webdavd: Automount shared folder on Windows

Lukas Venhoda lvenhoda at redhat.com
Thu Feb 25 14:19:23 UTC 2016


Try to connect to shared folder automatically on Windows.

On each loop of run_service(), run a GTask, that waits for half a second.
If read_thread() returns, it means, that sharing is not yet connected,
and the map_drive task is cancelled.

If the map_drive task is NOT cancelled, it enumerates free drive
letters, and maps shared folder to highest possible (from Z: to A:).

If all drive letters are already assigned, stop the service.
---
Changes since v1:
 - Changed GThread to a GTask
 - Only wait half a second, instead of 5

Changes since RFC:
 - Calling WNetAddConnection2() blindly was slow and caause many threads to spawn.
    - Now only call it once, when it is sure, that it will connect.
 - Now connects to a * drive, instead of always Z:
 - Thread is now spawned and joined every time run_service() is called.
---
 Makefile.am           |  4 +++
 spice/spice-webdavd.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 6127f93..d8e2d53 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,6 +87,10 @@ spice_webdavd_LDADD =		\
 	$(PIE_LDFLAGS)		\
 	$(NULL)

+if OS_WIN32
+spice_webdavd_LDADD += -lnetapi32 -lmpr
+endif
+
 deps.txt:
 	$(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@

diff --git a/spice/spice-webdavd.c b/spice/spice-webdavd.c
index f9c5cf1..55b7bbb 100644
--- a/spice/spice-webdavd.c
+++ b/spice/spice-webdavd.c
@@ -737,11 +737,88 @@ open_mux_path (const char *path)
   mux_queue = output_queue_new (G_OUTPUT_STREAM (mux_ostream));
 }

+#ifdef G_OS_WIN32
+gchar drive_letter;
+
+static gchar
+get_free_drive_letter(void)
+{
+  const guint32 max_mask = 1 << 25;
+  guint32 drives;
+  guint32 mask;
+  gint i;
+
+  drives = GetLogicalDrives ();
+
+  for (i = 0; i < 26; i++)
+    {
+      mask = max_mask >> i;
+      if ((drives & mask) == 0)
+        return 'Z' - i;
+    }
+
+  return 0;
+}
+
+static void
+map_drive(GTask *task,
+          gpointer source_object,
+          gpointer task_data,
+          GCancellable *cancellable)
+{
+  static int loop_time = G_USEC_PER_SEC/10;
+  GCancellable * cancel_map = task_data;
+  gchar local_name[3];
+  gchar remote_name[] = "http://localhost:9843/";
+  NETRESOURCE net_resource;
+  guint32 retval;
+  gint i;
+
+  for (i = 0; i < 5; ++i)
+    {
+      if (g_cancellable_is_cancelled (cancel_map))
+        return;
+      else
+        g_usleep (loop_time);
+    }
+
+  if ((drive_letter = get_free_drive_letter ()) == 0)
+      g_error ("all drive letters already assigned.");
+
+  local_name[0] = drive_letter;
+  local_name[1] = ':';
+  local_name[2] = 0;
+
+  net_resource.dwType = RESOURCETYPE_DISK;
+  net_resource.lpLocalName = local_name;
+  net_resource.lpRemoteName = remote_name;
+  net_resource.lpProvider = NULL;
+
+  retval = WNetAddConnection2 (&net_resource, NULL, NULL, CONNECT_TEMPORARY);
+
+  if (retval == NO_ERROR)
+    g_debug ("map_drive ok");
+  else if (retval == ERROR_ALREADY_ASSIGNED)
+    g_debug ("map_drive already asigned");
+  else
+    g_error ("map_drive error %d", retval);
+
+  return;
+}
+#endif
+
 static void
 run_service (void)
 {
   g_debug ("Run service");

+#ifdef G_OS_WIN32
+  GCancellable * cancel_map = g_cancellable_new ();
+  GTask * map_drive_task = g_task_new (NULL, NULL, NULL, NULL);
+  g_task_set_task_data (map_drive_task, cancel_map, NULL);
+  g_task_run_in_thread (map_drive_task, map_drive);
+#endif
+
   g_socket_service_start (socket_service);

   cancel = g_cancellable_new ();
@@ -775,6 +852,10 @@ run_service (void)
   g_main_loop_run (loop);
   g_main_loop_unref (loop);

+#ifdef G_OS_WIN32
+  g_cancellable_cancel (cancel_map);
+#endif
+
   g_cancellable_cancel (cancel);

   g_clear_object (&mux_istream);
--
2.5.0



More information about the Spice-devel mailing list