diff --git a/gio/Makefile.am b/gio/Makefile.am
index a84830b91..44ade08f5 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -313,11 +313,12 @@ win32_actual_sources = \
win32_more_sources_for_vcproj = \
gwin32appinfo.c \
gregistrysettingsbackend.c \
- win32/gwin32directorymonitor.c \
win32/gwinhttpfile.c \
win32/gwinhttpfileinputstream.c \
win32/gwinhttpfileoutputstream.c \
- win32/gwinhttpvfs.c
+ win32/gwinhttpvfs.c \
+ win32/gwin32fsmonitorutils.c \
+ win32/gwin32filemonitor.c
if OS_WIN32
appinfo_sources += gwin32appinfo.c gwin32appinfo.h
diff --git a/gio/win32/Makefile.am b/gio/win32/Makefile.am
index a48c68f03..2fc10f65e 100644
--- a/gio/win32/Makefile.am
+++ b/gio/win32/Makefile.am
@@ -3,8 +3,10 @@ include $(top_srcdir)/glib.mk
noinst_LTLIBRARIES += libgiowin32.la
libgiowin32_la_SOURCES = \
- gwin32directorymonitor.c \
- gwin32directorymonitor.h \
+ gwin32fsmonitorutils.c \
+ gwin32fsmonitorutils.h \
+ gwin32filemonitor.c \
+ gwin32filemonitor.h \
gwinhttpvfs.c \
gwinhttpvfs.h \
gwinhttpfile.c \
diff --git a/gio/win32/gwin32directorymonitor.c b/gio/win32/gwin32directorymonitor.c
deleted file mode 100644
index b5f192e03..000000000
--- a/gio/win32/gwin32directorymonitor.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* GIO - GLib Input, Output and Streaming Library
- *
- * Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see .
- *
- * Author: Vlad Grecescu
- *
- */
-
-#include "config.h"
-#include "gwin32directorymonitor.h"
-#include
-
-G_DEFINE_TYPE_WITH_CODE (GWin32DirectoryMonitor,
- g_win32_directory_monitor,
- G_TYPE_LOCAL_DIRECTORY_MONITOR,
- g_io_extension_point_implement (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
- g_define_type_id,
- "readdirectorychanges",
- 20))
-
-struct _GWin32DirectoryMonitorPrivate {
- OVERLAPPED overlapped;
- DWORD buffer_allocated_bytes;
- gchar *file_notify_buffer;
- DWORD buffer_filled_bytes;
- HANDLE hDirectory;
- /* Needed in the APC where we only have this private struct */
- GFileMonitor *self;
-};
-
-static void g_win32_directory_monitor_finalize (GObject *base);
-static gboolean g_win32_directory_monitor_cancel (GFileMonitor *base);
-
-static GObject *g_win32_directory_monitor_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties);
-
-static gboolean
-g_win32_directory_monitor_is_supported (void)
-{
- return TRUE;
-}
-
-static void
-g_win32_directory_monitor_finalize (GObject *base)
-{
- GWin32DirectoryMonitor *self;
- self = G_WIN32_DIRECTORY_MONITOR (base);
-
- 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);
-}
-
-static gboolean
-g_win32_directory_monitor_cancel (GFileMonitor *base)
-{
- GWin32DirectoryMonitor *self;
- self = G_WIN32_DIRECTORY_MONITOR (base);
-
- /* 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);
-
- if (G_FILE_MONITOR_CLASS (g_win32_directory_monitor_parent_class)->cancel)
- (*G_FILE_MONITOR_CLASS (g_win32_directory_monitor_parent_class)->cancel) (base);
- return TRUE;
-}
-
-static void CALLBACK
-g_win32_directory_monitor_callback (DWORD error,
- DWORD nBytes,
- LPOVERLAPPED lpOverlapped)
-{
- gulong offset;
- PFILE_NOTIFY_INFORMATION pfile_notify_walker;
- glong file_name_len;
- gchar *file_name;
- gchar *path;
- GFile *file;
- GWin32DirectoryMonitorPrivate *priv = (GWin32DirectoryMonitorPrivate *) lpOverlapped;
-
- static GFileMonitorEvent events[] =
- {
- 0,
- G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_ADDED */
- G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_REMOVED */
- G_FILE_MONITOR_EVENT_CHANGED, /* FILE_ACTION_MODIFIED */
- G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_RENAMED_OLD_NAME */
- G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_RENAMED_NEW_NAME */
- };
-
- /* 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;
- } while (pfile_notify_walker->NextEntryOffset);
-
- ReadDirectoryChangesW (priv->hDirectory,
- (gpointer)priv->file_notify_buffer,
- priv->buffer_allocated_bytes,
- FALSE,
- FILE_NOTIFY_CHANGE_FILE_NAME |
- FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_ATTRIBUTES |
- FILE_NOTIFY_CHANGE_SIZE,
- &priv->buffer_filled_bytes,
- &priv->overlapped,
- g_win32_directory_monitor_callback);
-}
-
-static GObject *
-g_win32_directory_monitor_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties) {
- GObject *obj;
- GWin32DirectoryMonitorClass *klass;
- GObjectClass *parent_class;
- GWin32DirectoryMonitor *self;
- wchar_t *wdirname;
-
- klass = G_WIN32_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_WIN32_DIRECTORY_MONITOR));
- parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
- obj = parent_class->constructor (type, n_construct_properties, construct_properties);
- self = G_WIN32_DIRECTORY_MONITOR (obj);
- wdirname = g_utf8_to_utf16 (G_LOCAL_DIRECTORY_MONITOR (obj)->dirname, -1, NULL, NULL, NULL);
-
- self->priv->hDirectory = CreateFileW (wdirname,
- FILE_LIST_DIRECTORY,
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
-
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
- NULL);
- g_free (wdirname);
- if (self->priv->hDirectory == INVALID_HANDLE_VALUE)
- {
- /* Ignore errors */
- return obj;
- }
-
- ReadDirectoryChangesW (self->priv->hDirectory,
- (gpointer)self->priv->file_notify_buffer,
- self->priv->buffer_allocated_bytes,
- FALSE,
- FILE_NOTIFY_CHANGE_FILE_NAME |
- FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_ATTRIBUTES |
- FILE_NOTIFY_CHANGE_SIZE,
- &self->priv->buffer_filled_bytes,
- &self->priv->overlapped,
- g_win32_directory_monitor_callback);
- /* Ignore errors */
-
- return obj;
-}
-
-static void
-g_win32_directory_monitor_class_init (GWin32DirectoryMonitorClass *klass)
-{
- g_win32_directory_monitor_parent_class = g_type_class_peek_parent (klass);
-
- G_OBJECT_CLASS (klass)->constructor = g_win32_directory_monitor_constructor;
- G_OBJECT_CLASS (klass)->finalize = g_win32_directory_monitor_finalize;
- G_FILE_MONITOR_CLASS (klass)->cancel = g_win32_directory_monitor_cancel;
-
- G_LOCAL_DIRECTORY_MONITOR_CLASS (klass)->mount_notify = FALSE;
- G_LOCAL_DIRECTORY_MONITOR_CLASS (klass)->is_supported = g_win32_directory_monitor_is_supported;
-}
-
-static void
-g_win32_directory_monitor_init (GWin32DirectoryMonitor *self)
-{
- self->priv = (GWin32DirectoryMonitorPrivate*)g_new0 (GWin32DirectoryMonitorPrivate, 1);
- g_assert (self->priv != 0);
-
- self->priv->buffer_allocated_bytes = 32768;
- self->priv->file_notify_buffer = g_new0 (gchar, self->priv->buffer_allocated_bytes);
- g_assert (self->priv->file_notify_buffer);
-
- self->priv->self = G_FILE_MONITOR (self);
-}
diff --git a/gio/win32/gwin32directorymonitor.h b/gio/win32/gwin32directorymonitor.h
deleted file mode 100644
index 3e0774879..000000000
--- a/gio/win32/gwin32directorymonitor.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* GIO - GLib Input, Output and Streaming Library
- *
- * Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see .
- *
- * Author: Vlad Grecescu
- *
- */
-#ifndef __G_WIN32_DIRECTORY_MONITOR_H__
-#define __G_WIN32_DIRECTORY_MONITOR_H__
-
-#include
-#include
-#include
-#include
-#include
-
-#include "gio/glocaldirectorymonitor.h"
-#include "gio/giomodule.h"
-
-G_BEGIN_DECLS
-
-
-#define G_TYPE_WIN32_DIRECTORY_MONITOR (g_win32_directory_monitor_get_type ())
-#define G_WIN32_DIRECTORY_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_DIRECTORY_MONITOR, GWin32DirectoryMonitor))
-#define G_WIN32_DIRECTORY_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_WIN32_DIRECTORY_MONITOR, GWin32DirectoryMonitorClass))
-#define G_IS_WIN32_DIRECTORY_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_WIN32_DIRECTORY_MONITOR))
-#define G_IS_WIN32_DIRECTORY_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_WIN32_DIRECTORY_MONITOR))
-#define G_WIN32_DIRECTORY_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_WIN32_DIRECTORY_MONITOR, GWin32DirectoryMonitorClass))
-
-typedef struct _GWin32DirectoryMonitor GWin32DirectoryMonitor;
-typedef struct _GWin32DirectoryMonitorClass GWin32DirectoryMonitorClass;
-typedef struct _GWin32DirectoryMonitorPrivate GWin32DirectoryMonitorPrivate;
-
-struct _GWin32DirectoryMonitor {
- GLocalDirectoryMonitor parent_instance;
- GWin32DirectoryMonitorPrivate * priv;
-};
-struct _GWin32DirectoryMonitorClass {
- GLocalDirectoryMonitorClass parent_class;
-};
-
-GType g_win32_directory_monitor_get_type (void);
-void g_win32_directory_monitor_register (GIOModule *module);
-
-G_END_DECLS
-
-#endif /* __G_WIN32_DIRECTORY_MONITOR_H__ */
diff --git a/gio/win32/gwin32filemonitor.c b/gio/win32/gwin32filemonitor.c
new file mode 100644
index 000000000..1b93b82e4
--- /dev/null
+++ b/gio/win32/gwin32filemonitor.c
@@ -0,0 +1,105 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see .
+ *
+ * Author: Vlad Grecescu
+ * Author: Chun-wei Fan
+ *
+ */
+
+#include "config.h"
+
+#include "gwin32filemonitor.h"
+#include "gwin32fsmonitorutils.h"
+
+#include
+
+G_DEFINE_TYPE_WITH_CODE (GWin32FileMonitor, g_win32_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
+ g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id, "win32filemonitor", 20))
+
+static void
+g_win32_file_monitor_start (GLocalFileMonitor *monitor,
+ const gchar *dirname,
+ const gchar *basename,
+ const gchar *filename,
+ GFileMonitorSource *source)
+{
+ GWin32FileMonitor *win32_monitor = G_WIN32_FILE_MONITOR (monitor);
+ gboolean isfile = (filename == NULL && basename == NULL) ? FALSE : TRUE;
+
+ win32_monitor->priv->fms = source;
+
+ if (isfile)
+ if (basename != NULL)
+ g_win32_fs_monitor_init (win32_monitor->priv, dirname, basename, TRUE);
+ else
+ g_win32_fs_monitor_init (win32_monitor->priv, NULL, filename, TRUE);
+ else
+ g_win32_fs_monitor_init (win32_monitor->priv, dirname, NULL, FALSE);
+}
+
+static gboolean
+g_win32_file_monitor_is_supported (void)
+{
+ return TRUE;
+}
+
+static void
+g_win32_file_monitor_init (GWin32FileMonitor* monitor)
+{
+ monitor->priv = g_win32_fs_monitor_create (TRUE);
+
+ monitor->priv->self = G_FILE_MONITOR (monitor);
+}
+
+static void
+g_win32_file_monitor_finalize (GObject *base)
+{
+ GWin32FileMonitor *monitor;
+ monitor = G_WIN32_FILE_MONITOR (base);
+
+ g_win32_fs_monitor_finalize (monitor->priv);
+
+ if (G_OBJECT_CLASS (g_win32_file_monitor_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_win32_file_monitor_parent_class)->finalize) (base);
+}
+
+static gboolean
+g_win32_file_monitor_cancel (GFileMonitor* monitor)
+{
+ GWin32FileMonitor *file_monitor;
+ file_monitor = G_WIN32_FILE_MONITOR (monitor);
+
+ g_win32_fs_monitor_close_handle (file_monitor->priv);
+
+ return TRUE;
+}
+
+static void
+g_win32_file_monitor_class_init (GWin32FileMonitorClass *klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
+ GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
+ GLocalFileMonitorClass *local_file_monitor_class = G_LOCAL_FILE_MONITOR_CLASS (klass);
+
+ gobject_class->finalize = g_win32_file_monitor_finalize;
+ file_monitor_class->cancel = g_win32_file_monitor_cancel;
+
+ local_file_monitor_class->is_supported = g_win32_file_monitor_is_supported;
+ local_file_monitor_class->start = g_win32_file_monitor_start;
+}
diff --git a/gio/win32/gwin32filemonitor.h b/gio/win32/gwin32filemonitor.h
new file mode 100644
index 000000000..5aef2ba3f
--- /dev/null
+++ b/gio/win32/gwin32filemonitor.h
@@ -0,0 +1,62 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see .
+ *
+ * Author: Chun-wei Fan
+ *
+ */
+#ifndef __G_WIN32_FILE_MONITOR_H__
+#define __G_WIN32_FILE_MONITOR_H__
+
+#include
+#include
+#include
+#include
+#include
+
+#include "gio/gfilemonitor.h"
+#include "gio/glocalfilemonitor.h"
+#include "gio/giomodule.h"
+
+#include "gwin32fsmonitorutils.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_WIN32_FILE_MONITOR (g_win32_file_monitor_get_type ())
+#define G_WIN32_FILE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_FILE_MONITOR, GWin32FileMonitor))
+#define G_WIN32_FILE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_WIN32_FILE_MONITOR, GWin32FileMonitorClass))
+#define G_IS_WIN32_FILE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_WIN32_FILE_MONITOR))
+#define G_IS_WIN32_FILE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_WIN32_FILE_MONITOR))
+#define G_WIN32_FILE_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_WIN32_FILE_MONITOR, GWin32FileMonitorClass))
+
+typedef struct _GWin32FileMonitor GWin32FileMonitor;
+typedef struct _GWin32FileMonitorClass GWin32FileMonitorClass;
+typedef struct _GWin32FileMonitorPrivate GWin32FileMonitorPrivate;
+
+struct _GWin32FileMonitor {
+ GLocalFileMonitor parent_instance;
+ GWin32FSMonitorPrivate * priv;
+};
+struct _GWin32FileMonitorClass {
+ GLocalFileMonitorClass parent_class;
+};
+
+GType g_win32_file_monitor_get_type (void);
+void g_win32_file_monitor_register (GIOModule *module);
+
+G_END_DECLS
+
+#endif /* __G_WIN32_FILE_MONITOR_H__ */
diff --git a/gio/win32/gwin32fsmonitorutils.c b/gio/win32/gwin32fsmonitorutils.c
new file mode 100644
index 000000000..6901561b8
--- /dev/null
+++ b/gio/win32/gwin32fsmonitorutils.c
@@ -0,0 +1,422 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2015 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see .
+ *
+ * Author: Vlad Grecescu
+ * Author: Chun-wei Fan
+ *
+ */
+
+#include "config.h"
+
+#include "gwin32fsmonitorutils.h"
+#include "gio/gfile.h"
+
+#include
+
+#define MAX_PATH_LONG 32767 /* Support Paths longer than MAX_PATH (260) characters */
+
+static gboolean
+g_win32_fs_monitor_handle_event (GWin32FSMonitorPrivate *monitor,
+ gchar *filename,
+ PFILE_NOTIFY_INFORMATION pfni)
+{
+ GFileMonitorEvent fme;
+ PFILE_NOTIFY_INFORMATION pfni_next;
+ WIN32_FILE_ATTRIBUTE_DATA attrib_data = {0, };
+ gchar *renamed_file = NULL;
+
+ switch (pfni->Action)
+ {
+ case FILE_ACTION_ADDED:
+ fme = G_FILE_MONITOR_EVENT_CREATED;
+ break;
+
+ case FILE_ACTION_REMOVED:
+ fme = G_FILE_MONITOR_EVENT_DELETED;
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ {
+ gboolean success_attribs = GetFileAttributesExW (monitor->wfullpath_with_long_prefix,
+ GetFileExInfoStandard,
+ &attrib_data);
+
+ if (monitor->file_attribs != INVALID_FILE_ATTRIBUTES &&
+ success_attribs &&
+ attrib_data.dwFileAttributes != monitor->file_attribs)
+ fme = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
+ else
+ fme = G_FILE_MONITOR_EVENT_CHANGED;
+
+ monitor->file_attribs = attrib_data.dwFileAttributes;
+ }
+ break;
+
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ if (pfni->NextEntryOffset != 0)
+ {
+ /* If the file was renamed in the same directory, we would get a
+ * FILE_ACTION_RENAMED_NEW_NAME action in the next FILE_NOTIFY_INFORMATION
+ * structure.
+ */
+ glong file_name_len = 0;
+
+ pfni_next = (PFILE_NOTIFY_INFORMATION) ((BYTE*)pfni + pfni->NextEntryOffset);
+ renamed_file = g_utf16_to_utf8 (pfni_next->FileName, pfni_next->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
+ if (pfni_next->Action == FILE_ACTION_RENAMED_NEW_NAME)
+ fme = G_FILE_MONITOR_EVENT_RENAMED;
+ else
+ fme = G_FILE_MONITOR_EVENT_MOVED_OUT;
+ }
+ else
+ fme = G_FILE_MONITOR_EVENT_MOVED_OUT;
+ break;
+
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ if (monitor->pfni_prev != NULL &&
+ monitor->pfni_prev->Action == FILE_ACTION_RENAMED_OLD_NAME)
+ {
+ /* don't bother sending events, was already sent (rename) */
+ fme = -1;
+ }
+ else
+ fme = G_FILE_MONITOR_EVENT_MOVED_IN;
+ break;
+
+ default:
+ /* The possible Windows actions are all above, so shouldn't get here */
+ g_assert_not_reached ();
+ break;
+ }
+ if (fme != -1)
+ return g_file_monitor_source_handle_event (monitor->fms,
+ fme,
+ filename,
+ renamed_file,
+ NULL,
+ g_get_monotonic_time ());
+ else
+ return FALSE;
+}
+
+
+static void CALLBACK
+g_win32_fs_monitor_callback (DWORD error,
+ DWORD nBytes,
+ LPOVERLAPPED lpOverlapped)
+{
+ gulong offset;
+ PFILE_NOTIFY_INFORMATION pfile_notify_walker;
+ GWin32FSMonitorPrivate *monitor = (GWin32FSMonitorPrivate *) lpOverlapped;
+
+ DWORD notify_filter = monitor->isfile ?
+ (FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE) :
+ (FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE);
+
+ /* If monitor->self is NULL the GWin32FileMonitor object has been destroyed. */
+ if (monitor->self == NULL ||
+ g_file_monitor_is_cancelled (monitor->self) ||
+ monitor->file_notify_buffer == NULL)
+ {
+ g_free (monitor->file_notify_buffer);
+ g_free (monitor);
+ return;
+ }
+
+ offset = 0;
+
+ do
+ {
+ pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)((BYTE*)monitor->file_notify_buffer + offset);
+ if (pfile_notify_walker->Action > 0)
+ {
+ glong file_name_len;
+ gchar *changed_file;
+
+ changed_file = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
+
+ if (monitor->isfile)
+ {
+ gint long_filename_length = wcslen (monitor->wfilename_long);
+ gint short_filename_length = wcslen (monitor->wfilename_short);
+ enum GWin32FileMonitorFileAlias alias_state;
+
+ /* If monitoring a file, check that the changed file
+ * in the directory matches the file that is to be monitored
+ * We need to check both the long and short file names for the same file.
+ *
+ * We need to send in the name of the monitored file, not its long (or short) variant,
+ * if they exist.
+ */
+
+ if (_wcsnicmp (pfile_notify_walker->FileName,
+ monitor->wfilename_long,
+ long_filename_length) == 0)
+ {
+ if (_wcsnicmp (pfile_notify_walker->FileName,
+ monitor->wfilename_short,
+ short_filename_length) == 0)
+ {
+ alias_state = G_WIN32_FILE_MONITOR_NO_ALIAS;
+ }
+ else
+ alias_state = G_WIN32_FILE_MONITOR_LONG_FILENAME;
+ }
+ else if (_wcsnicmp (pfile_notify_walker->FileName,
+ monitor->wfilename_short,
+ short_filename_length) == 0)
+ {
+ alias_state = G_WIN32_FILE_MONITOR_SHORT_FILENAME;
+ }
+ else
+ alias_state = G_WIN32_FILE_MONITOR_NO_MATCH_FOUND;
+
+ if (alias_state != G_WIN32_FILE_MONITOR_NO_MATCH_FOUND)
+ {
+ wchar_t *monitored_file_w;
+ gchar *monitored_file;
+
+ switch (alias_state)
+ {
+ case G_WIN32_FILE_MONITOR_NO_ALIAS:
+ monitored_file = g_strdup (changed_file);
+ break;
+ case G_WIN32_FILE_MONITOR_LONG_FILENAME:
+ case G_WIN32_FILE_MONITOR_SHORT_FILENAME:
+ monitored_file_w = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
+ monitored_file = g_utf16_to_utf8 (monitored_file_w + 1, -1, NULL, NULL, NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_win32_fs_monitor_handle_event (monitor, monitored_file, pfile_notify_walker);
+ g_free (monitored_file);
+ }
+ }
+ else
+ g_win32_fs_monitor_handle_event (monitor, changed_file, pfile_notify_walker);
+
+ g_free (changed_file);
+ }
+ monitor->pfni_prev = pfile_notify_walker;
+ offset += pfile_notify_walker->NextEntryOffset;
+ }
+ while (pfile_notify_walker->NextEntryOffset);
+
+ ReadDirectoryChangesW (monitor->hDirectory,
+ monitor->file_notify_buffer,
+ monitor->buffer_allocated_bytes,
+ FALSE,
+ notify_filter,
+ &monitor->buffer_filled_bytes,
+ &monitor->overlapped,
+ g_win32_fs_monitor_callback);
+}
+
+void
+g_win32_fs_monitor_init (GWin32FSMonitorPrivate *monitor,
+ gchar *dirname,
+ gchar *filename,
+ gboolean isfile)
+{
+ wchar_t *wdirname_with_long_prefix = NULL;
+ const gchar LONGPFX[] = "\\\\?\\";
+ gchar *fullpath_with_long_prefix, *dirname_with_long_prefix;
+ DWORD notify_filter = isfile ?
+ (FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE) :
+ (FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE);
+
+ gboolean success_attribs;
+ WIN32_FILE_ATTRIBUTE_DATA attrib_data = {0, };
+
+
+ if (dirname != NULL)
+ {
+ dirname_with_long_prefix = g_strconcat (LONGPFX, dirname, NULL);
+ wdirname_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
+
+ if (isfile)
+ {
+ gchar *fullpath;
+ wchar_t wlongname[MAX_PATH_LONG];
+ wchar_t wshortname[MAX_PATH_LONG];
+ wchar_t *wfullpath, *wbasename_long, *wbasename_short;
+
+ fullpath = g_build_filename (dirname, filename, NULL);
+ fullpath_with_long_prefix = g_strconcat (LONGPFX, fullpath, NULL);
+
+ wfullpath = g_utf8_to_utf16 (fullpath, -1, NULL, NULL, NULL);
+
+ monitor->wfullpath_with_long_prefix =
+ g_utf8_to_utf16 (fullpath_with_long_prefix, -1, NULL, NULL, NULL);
+
+ /* ReadDirectoryChangesW() can return the normal filename or the
+ * "8.3" format filename, so we need to keep track of both these names
+ * so that we can check against them later when it returns
+ */
+ if (GetLongPathNameW (monitor->wfullpath_with_long_prefix, wlongname, MAX_PATH_LONG) == 0)
+ {
+ wbasename_long = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
+ monitor->wfilename_long = wbasename_long != NULL ?
+ wcsdup (wbasename_long + 1) :
+ wcsdup (wfullpath);
+ }
+ else
+ {
+ wbasename_long = wcsrchr (wlongname, L'\\');
+ monitor->wfilename_long = wbasename_long != NULL ?
+ wcsdup (wbasename_long + 1) :
+ wcsdup (wlongname);
+
+ }
+
+ if (GetShortPathNameW (monitor->wfullpath_with_long_prefix, wshortname, MAX_PATH_LONG) == 0)
+ {
+ wbasename_short = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
+ monitor->wfilename_short = wbasename_short != NULL ?
+ wcsdup (wbasename_short + 1) :
+ wcsdup (wfullpath);
+ }
+ else
+ {
+ wbasename_short = wcsrchr (wshortname, L'\\');
+ monitor->wfilename_short = wbasename_short != NULL ?
+ wcsdup (wbasename_short + 1) :
+ wcsdup (wshortname);
+ }
+
+ g_free (fullpath);
+ }
+ else
+ {
+ monitor->wfilename_short = NULL;
+ monitor->wfilename_long = NULL;
+ monitor->wfullpath_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
+ }
+
+ monitor->isfile = isfile;
+ }
+ else
+ {
+ dirname_with_long_prefix = g_strconcat (LONGPFX, filename, NULL);
+ monitor->wfullpath_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
+ monitor->wfilename_long = NULL;
+ monitor->wfilename_short = NULL;
+ monitor->isfile = FALSE;
+ }
+
+ success_attribs = GetFileAttributesExW (monitor->wfullpath_with_long_prefix,
+ GetFileExInfoStandard,
+ &attrib_data);
+ if (success_attribs)
+ monitor->file_attribs = attrib_data.dwFileAttributes; /* Store up original attributes */
+ else
+ monitor->file_attribs = INVALID_FILE_ATTRIBUTES;
+ monitor->pfni_prev = NULL;
+ monitor->hDirectory = CreateFileW (wdirname_with_long_prefix != NULL ? wdirname_with_long_prefix : monitor->wfullpath_with_long_prefix,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (wdirname_with_long_prefix != NULL)
+ g_free (wdirname_with_long_prefix);
+ g_free (dirname_with_long_prefix);
+
+ if (monitor->hDirectory != INVALID_HANDLE_VALUE)
+ {
+ ReadDirectoryChangesW (monitor->hDirectory,
+ monitor->file_notify_buffer,
+ monitor->buffer_allocated_bytes,
+ FALSE,
+ notify_filter,
+ &monitor->buffer_filled_bytes,
+ &monitor->overlapped,
+ g_win32_fs_monitor_callback);
+ }
+}
+
+GWin32FSMonitorPrivate* g_win32_fs_monitor_create (gboolean isfile)
+{
+ GWin32FSMonitorPrivate* monitor = (GWin32FSMonitorPrivate*) g_new0 (GWin32FSMonitorPrivate, 1);
+ g_assert (monitor != 0);
+
+ monitor->buffer_allocated_bytes = 32784;
+ monitor->file_notify_buffer = g_new0 (FILE_NOTIFY_INFORMATION, monitor->buffer_allocated_bytes);
+ g_assert (monitor->file_notify_buffer);
+
+ return monitor;
+}
+
+void g_win32_fs_monitor_finalize (GWin32FSMonitorPrivate *monitor)
+{
+ if (monitor->hDirectory == INVALID_HANDLE_VALUE)
+ {
+ /* If we don't have a directory handle we can free
+ * monitor->file_notify_buffer and monitor here. The
+ * callback won't be called obviously any more (and presumably
+ * never has been called).
+ */
+ g_free (monitor->file_notify_buffer);
+ monitor->file_notify_buffer = NULL;
+ g_free (monitor);
+ }
+ 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 monitor has to
+ * be kept around. The GWin32DirectoryMonitor object is
+ * disappearing, so can't leave a pointer to it in
+ * monitor->self.
+ */
+ monitor->self = NULL;
+ }
+ g_free (monitor->wfullpath_with_long_prefix);
+ if (monitor->wfilename_long != NULL)
+ g_free (monitor->wfilename_long);
+ if (monitor->wfilename_short != NULL)
+ g_free (monitor->wfilename_short);
+}
+
+void g_win32_fs_monitor_close_handle (GWin32FSMonitorPrivate *monitor)
+{
+ /* 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 (monitor->hDirectory != INVALID_HANDLE_VALUE)
+ CloseHandle (monitor->hDirectory);
+}
diff --git a/gio/win32/gwin32fsmonitorutils.h b/gio/win32/gwin32fsmonitorutils.h
new file mode 100644
index 000000000..0606d671d
--- /dev/null
+++ b/gio/win32/gwin32fsmonitorutils.h
@@ -0,0 +1,76 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2014 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see .
+ *
+ * Author: Vlad Grecescu
+ * Author: Chun-wei Fan
+ *
+ */
+
+#ifndef __G_WIN32_FS_MONITOR_UTILS_H__
+#define __G_WIN32_FS_MONITOR_UTILS_H__
+
+#include
+
+#include "gio/glocalfilemonitor.h"
+
+#include "gio/gfilemonitor.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GWin32FSMonitorPrivate GWin32FSMonitorPrivate;
+
+struct _GWin32FSMonitorPrivate
+{
+ OVERLAPPED overlapped;
+ DWORD buffer_allocated_bytes;
+ PFILE_NOTIFY_INFORMATION file_notify_buffer;
+ DWORD buffer_filled_bytes;
+ HANDLE hDirectory;
+ gboolean isfile;
+ wchar_t *wfullpath_with_long_prefix;
+ wchar_t *wfilename_short;
+ wchar_t *wfilename_long;
+ DWORD file_attribs;
+ PFILE_NOTIFY_INFORMATION pfni_prev;
+ /* Needed in the APC where we only have this private struct */
+ GFileMonitor *self;
+ GFileMonitorSource *fms;
+};
+
+enum GWin32FileMonitorFileAlias
+{
+ G_WIN32_FILE_MONITOR_NO_ALIAS = 0,
+ G_WIN32_FILE_MONITOR_LONG_FILENAME,
+ G_WIN32_FILE_MONITOR_SHORT_FILENAME,
+ G_WIN32_FILE_MONITOR_NO_MATCH_FOUND
+};
+
+GWin32FSMonitorPrivate* g_win32_fs_monitor_create (gboolean isfile);
+
+void g_win32_fs_monitor_init (GWin32FSMonitorPrivate *monitor,
+ gchar *dirname,
+ gchar *filename,
+ gboolean isfile);
+
+void g_win32_fs_monitor_finalize (GWin32FSMonitorPrivate *monitor);
+
+void g_win32_fs_monitor_close_handle (GWin32FSMonitorPrivate *monitor);
+
+G_END_DECLS
+
+#endif