[glib] Fix GWin32DirectoryMonitor



commit d105f431b0b684ed47e1c23ca283e38e522ce545
Author: Tor Lillqvist <tml iki fi>
Date:   Fri Oct 23 00:46:50 2009 +0300

    Fix GWin32DirectoryMonitor
    
    GWin32DirectoryMonitor was quite broken, but nobody had apparently
    noticed, or at least not filed any bug. Only now with a bleeding edge
    GTK+ file chooser does the code get exercised in common programs like
    gtk-demo or GIMP, apparently. Bug #598899.

 gio/win32/gwin32directorymonitor.c |   67 ++++++++++++++++++++++++++---------
 1 files changed, 50 insertions(+), 17 deletions(-)
---
diff --git a/gio/win32/gwin32directorymonitor.c b/gio/win32/gwin32directorymonitor.c
index 4590ff6..6e9fa68 100644
--- a/gio/win32/gwin32directorymonitor.c
+++ b/gio/win32/gwin32directorymonitor.c
@@ -64,9 +64,29 @@ g_win32_directory_monitor_finalize (GObject *base)
 {
   GWin32DirectoryMonitor *self;
   self = G_WIN32_DIRECTORY_MONITOR (base);
-  
-  g_free (self->priv->file_notify_buffer);
-  g_free (self->priv);
+
+  if (self->priv->hDirectory == INVALID_HANDLE_VALUE)
+    {
+      /* If we don't have a directory handle we can free
+       * self->priv->file_notify_buffer and self->priv here. The
+       * callback won't be called obviously any more (and presumably
+       * never has been called).
+       */
+      g_free (self->priv->file_notify_buffer);
+      self->priv->file_notify_buffer = NULL;
+      g_free (self->priv);
+    }
+  else
+    {
+      /* If we have a directory handle, the OVERLAPPED struct is
+       * passed once more to the callback as a result of the
+       * CloseHandle() done in the cancel method, so self->priv has to
+       * be kept around. The GWin32DirectoryMonitor object is
+       * disappearing, so can't leave a pointer to it in
+       * self->priv->self.
+       */
+      self->priv->self = NULL;
+    }
 
   if (G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize) (base);
@@ -78,7 +98,13 @@ g_win32_directory_monitor_cancel (GFileMonitor *base)
   GWin32DirectoryMonitor *self;
   self = G_WIN32_DIRECTORY_MONITOR (base);
 
-  /* This triggers a last callback() with nBytes=0 */ 
+  /* This triggers a last callback() with nBytes==0. */
+
+  /* Actually I am not so sure about that, it seems to trigger a last
+   * callback allright, but the way to recognize that it is the final
+   * one is not to check for nBytes==0, I think that was a
+   * misunderstanding.
+   */ 
   if (self->priv->hDirectory != INVALID_HANDLE_VALUE)
     CloseHandle (self->priv->hDirectory);
 
@@ -94,7 +120,7 @@ g_win32_directory_monitor_callback (DWORD        error,
 {
   gulong offset;
   PFILE_NOTIFY_INFORMATION pfile_notify_walker;
-  gulong file_name_len;
+  glong file_name_len;
   gchar *file_name;
   gchar *path;
   GFile *file;
@@ -110,23 +136,30 @@ g_win32_directory_monitor_callback (DWORD        error,
       G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_RENAMED_NEW_NAME */
     };
 
-  if (!nBytes) /* Monitor was cancelled/finalized */
-    return;
-
-  if (g_file_monitor_is_cancelled (G_FILE_MONITOR (priv->self)))
-    return; /* and ReadDirectoryChangesW doesn't get called this time */
+  /* If priv->self is NULL the GWin32DirectoryMonitor object has been destroyed. */
+  if (priv->self == NULL ||
+      g_file_monitor_is_cancelled (priv->self) ||
+      priv->file_notify_buffer == NULL)
+    {
+      g_free (priv->file_notify_buffer);
+      g_free (priv);
+      return;
+    }
 
   offset = 0;
   do {
     pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)(priv->file_notify_buffer + offset);
+    if (pfile_notify_walker->Action > 0)
+      {
+	file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
+	path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
+	file = g_file_new_for_path (path);
+	g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
+	g_object_unref (file);
+	g_free (path);
+	g_free (file_name);
+      }
     offset += pfile_notify_walker->NextEntryOffset;
-    file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
-    path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
-    file = g_file_new_for_path (path);
-    g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
-    g_object_unref (file);
-    g_free (path);
-    g_free (file_name);
   } while (pfile_notify_walker->NextEntryOffset);
 
   ReadDirectoryChangesW (priv->hDirectory,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]