<div dir="ltr">Ping for pushing<div class="gmail_extra"><br><div class="gmail_quote">On Thu, May 26, 2016 at 1:01 PM, Victor Toso <span dir="ltr"><<a href="mailto:lists@victortoso.com" target="_blank">lists@victortoso.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<span class=""><br>
On Wed, May 25, 2016 at 03:51:42PM +0200, Lukáš Venhoda wrote:<br>
> From: Lukas Venhoda <<a href="mailto:lvenhoda@redhat.com">lvenhoda@redhat.com</a>><br>
><br>
> Try to connect to shared folder automatically on Windows.<br>
><br>
> On each loop of run_service(), run a GTask, that waits for half a second.<br>
> If read_thread() returns, it means, that sharing is not yet connected,<br>
> and the map_drive task is cancelled.<br>
><br>
> If the map_drive task is NOT cancelled, it enumerates free drive letters,<br>
> and maps Spice Folder to highest possible (from Z: to A:).<br>
><br>
> If all drive letters are already assigned, show a critical error, but<br>
> don't stop the service. The folder can still be accessed trough other<br>
> means.<br>
<br>
</span>Acked-by: Victor Toso <<a href="mailto:victortoso@redhat.com">victortoso@redhat.com</a>><br>
<div><div class="h5"><br>
> ---<br>
> Changes since v6:<br>
>  - Fixed build<br>
><br>
> Changes since v5:<br>
>  - fixed indentation<br>
>  - fixed * indentaion<br>
>  - removed return from void functions<br>
><br>
> Changes since v4:<br>
>  - Changed cancel_map to MapDriveData structure<br>
>  - Added error checking for GetLogicalDrives()<br>
>  - Moved defines and variables around<br>
>  - Renamed some functions and variables<br>
>  - Better debug messages<br>
><br>
> Changes since v3:<br>
>  - Added init_netresource and clear_netresource functions<br>
>     - Should clean up the map_drive function<br>
>     - Better handeling of adress to map/unmap<br>
>        - Not hardcoded port<br>
>  - Syntax cleanup<br>
>  - Changed criticals to warnings<br>
>  - Better TODO<br>
><br>
> Changes since v2:<br>
>  - Changed for loop to gpoll<br>
>  - split map_drive into 2 functions<br>
>  - added enum for return values of map_drive<br>
>  - added TODO for renaming the drive<br>
>  - added explanation for the 0.5 delay into commit log<br>
><br>
> Changes since v1:<br>
>  - Changed GThread to a GTask<br>
>  - Only wait half a second, instead of 5<br>
><br>
> Changes since RFC:<br>
>  - Calling WNetAddConnection2() blindly was slow and caause many threads to spawn.<br>
>     - Now only call it once, when it is sure, that it will connect.<br>
>  - Now connects to a * drive, instead of always Z:<br>
>  - Thread is now spawned and joined every time run_service() is called.<br>
> ---<br>
>  Makefile.am           |   4 ++<br>
>  spice/spice-webdavd.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++<br>
>  2 files changed, 144 insertions(+)<br>
><br>
> diff --git a/Makefile.am b/Makefile.am<br>
> index 6127f93..d8e2d53 100644<br>
> --- a/Makefile.am<br>
> +++ b/Makefile.am<br>
> @@ -87,6 +87,10 @@ spice_webdavd_LDADD =              \<br>
>       $(PIE_LDFLAGS)          \<br>
>       $(NULL)<br>
><br>
> +if OS_WIN32<br>
> +spice_webdavd_LDADD += -lnetapi32 -lmpr<br>
> +endif<br>
> +<br>
>  deps.txt:<br>
>       $(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@<br>
><br>
> diff --git a/spice/spice-webdavd.c b/spice/spice-webdavd.c<br>
> index f9c5cf1..9783459 100644<br>
> --- a/spice/spice-webdavd.c<br>
> +++ b/spice/spice-webdavd.c<br>
> @@ -737,11 +737,146 @@ open_mux_path (const char *path)<br>
>    mux_queue = output_queue_new (G_OUTPUT_STREAM (mux_ostream));<br>
>  }<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +#define MAX_SHARED_FOLDER_NAME_SIZE 64<br>
> +#define MAX_DRIVE_LETTER_SIZE 3<br>
> +typedef enum _MapDriveEnum<br>
> +{<br>
> +  MAP_DRIVE_OK,<br>
> +  MAP_DRIVE_TRY_AGAIN,<br>
> +  MAP_DRIVE_ERROR<br>
> +} MapDriveEnum;<br>
> +<br>
> +typedef struct _MapDriveData<br>
> +{<br>
> +  GCancellable *cancel_map;<br>
> +} MapDriveData;<br>
> +<br>
> +static gchar<br>
> +get_free_drive_letter(void)<br>
> +{<br>
> +  const guint32 max_mask = 1 << 25;<br>
> +  guint32 drives;<br>
> +  gint i;<br>
> +<br>
> +  drives = GetLogicalDrives ();<br>
> +  if (drives == 0)<br>
> +    {<br>
> +      g_warning ("%s", g_win32_error_message (GetLastError ()));<br>
> +      return 0;<br>
> +    }<br>
> +<br>
> +  for (i = 0; i < 26; i++)<br>
> +    {<br>
> +      guint32 mask = max_mask >> i;<br>
> +      if ((drives & mask) == 0)<br>
> +        return 'z' - i;<br>
> +    }<br>
> +<br>
> +  return 0;<br>
> +}<br>
> +<br>
> +/* User is required to call netresource_free, when no longer needed. */<br>
> +static void<br>
> +netresource_init(NETRESOURCE *net_resource, const gchar drive_letter)<br>
> +{<br>
> +  net_resource->dwType = RESOURCETYPE_DISK;<br>
> +  net_resource->lpLocalName = g_strdup_printf("%c:", drive_letter);<br>
> +  net_resource->lpRemoteName = g_strdup_printf("http://localhost:%d/", port);<br>
> +  net_resource->lpProvider = NULL;<br>
> +}<br>
> +<br>
> +static void<br>
> +netresource_free(NETRESOURCE *net_resource)<br>
> +{<br>
> +  g_free(net_resource->lpLocalName);<br>
> +  g_free(net_resource->lpRemoteName);<br>
> +}<br>
> +<br>
> +static MapDriveEnum<br>
> +map_drive(const gchar drive_letter)<br>
> +{<br>
> +  NETRESOURCE net_resource;<br>
> +  guint32 errn;<br>
> +<br>
> +  netresource_init(&net_resource, drive_letter);<br>
> +  errn = WNetAddConnection2 (&net_resource, NULL, NULL, CONNECT_TEMPORARY);<br>
> +  netresource_free(&net_resource);<br>
> +<br>
> +  if (errn == NO_ERROR)<br>
> +    {<br>
> +      g_debug ("Shared folder mapped to %c succesfully", drive_letter);<br>
> +      return MAP_DRIVE_OK;<br>
> +    }<br>
> +  else if (errn == ERROR_ALREADY_ASSIGNED)<br>
> +    {<br>
> +      g_debug ("Drive letter %c is already assigned", drive_letter);<br>
> +      return MAP_DRIVE_TRY_AGAIN;<br>
> +    }<br>
> +<br>
> +  g_warning ("map_drive error %d", errn);<br>
> +  return MAP_DRIVE_ERROR;<br>
> +}<br>
> +<br>
> +static void<br>
> +map_drive_cb(GTask *task,<br>
> +             gpointer source_object,<br>
> +             gpointer task_data,<br>
> +             GCancellable *cancellable)<br>
> +{<br>
> +  const guint32 delay = 500; //half a second<br>
> +  MapDriveData *map_drive_data = task_data;<br>
> +  gchar drive_letter;<br>
> +  GPollFD cancel_pollfd;<br>
> +  guint32 ret = 0;<br>
> +<br>
> +  if (!g_cancellable_make_pollfd (map_drive_data->cancel_map, &cancel_pollfd))<br>
> +    {<br>
> +      g_critical ("GPollFD failed to create.");<br>
> +      return;<br>
> +    }<br>
> +<br>
> +  ret = g_poll (&cancel_pollfd, 1, delay);<br>
> +  g_cancellable_release_fd (map_drive_data->cancel_map);<br>
> +<br>
> +  if (ret != 0)<br>
> +    {<br>
> +      return;<br>
> +    }<br>
> +<br>
> +  while (TRUE)<br>
> +    {<br>
> +      drive_letter = get_free_drive_letter ();<br>
> +      if (drive_letter == 0)<br>
> +        {<br>
> +          g_warning ("all drive letters already assigned.");<br>
> +          break;<br>
> +        }<br>
> +<br>
> +      if (map_drive (drive_letter) != MAP_DRIVE_TRY_AGAIN)<br>
> +        {<br>
> +          break;<br>
> +        }<br>
> +      //TODO: After mapping, rename network drive from \\localhost@PORT\DavWWWRoot<br>
> +      //      to something like SPICE Shared Folder<br>
> +    }<br>
> +}<br>
> +#endif<br>
> +<br>
>  static void<br>
>  run_service (void)<br>
>  {<br>
>    g_debug ("Run service");<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +  MapDriveData map_drive_data;<br>
> +  map_drive_data.cancel_map = g_cancellable_new ();<br>
> +  GTask *map_drive_task = g_task_new (NULL, NULL, NULL, NULL);<br>
> +  g_task_set_task_data (map_drive_task, &map_drive_data, NULL);<br>
> +  g_task_run_in_thread (map_drive_task, map_drive_cb);<br>
> +  g_object_unref (map_drive_task);<br>
> +#endif<br>
> +<br>
>    g_socket_service_start (socket_service);<br>
><br>
>    cancel = g_cancellable_new ();<br>
> @@ -775,6 +910,11 @@ run_service (void)<br>
>    g_main_loop_run (loop);<br>
>    g_main_loop_unref (loop);<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +  g_cancellable_cancel (map_drive_data.cancel_map);<br>
> +  g_object_unref (map_drive_data.cancel_map);<br>
> +#endif<br>
> +<br>
>    g_cancellable_cancel (cancel);<br>
><br>
>    g_clear_object (&mux_istream);<br>
> --<br>
> 2.5.5<br>
><br>
</div></div>> _______________________________________________<br>
> Spice-devel mailing list<br>
> <a href="mailto:Spice-devel@lists.freedesktop.org">Spice-devel@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/spice-devel" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Lukas Venhoda</div>
</div></div>