summaryrefslogtreecommitdiff
path: root/daemon/gvfsbackendcomputer.c
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2008-01-08 15:07:59 +0000
committerAlexander Larsson <alexl@src.gnome.org>2008-01-08 15:07:59 +0000
commit518a0d444e149bf0fedbd768aa8440417999338e (patch)
tree9a3594954fdeab503fd60dba1cb3fd2d00245552 /daemon/gvfsbackendcomputer.c
parent382cd3e2d4c520859e49cf46eb3da5d19a563469 (diff)
downloadgvfs-518a0d444e149bf0fedbd768aa8440417999338e.tar.gz
Add initial computer backend
2008-01-08 Alexander Larsson <alexl@redhat.com> * daemon/Makefile.am: * daemon/computer.mount.in: * daemon/gvfsbackendcomputer.[ch]: Add initial computer backend * daemon/gvfsbackend.h: * daemon/gvfsjobunmountmountable.[ch]: Add umount_mountable calls svn path=/trunk/; revision=1078
Diffstat (limited to 'daemon/gvfsbackendcomputer.c')
-rw-r--r--daemon/gvfsbackendcomputer.c791
1 files changed, 791 insertions, 0 deletions
diff --git a/daemon/gvfsbackendcomputer.c b/daemon/gvfsbackendcomputer.c
new file mode 100644
index 00000000..90cf7fb8
--- /dev/null
+++ b/daemon/gvfsbackendcomputer.c
@@ -0,0 +1,791 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ */
+
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+#include <glib/gurifuncs.h>
+
+#include "gvfsbackendcomputer.h"
+#include "gvfsmonitor.h"
+#include "gvfsjobopenforread.h"
+#include "gvfsjobread.h"
+#include "gvfsjobseekread.h"
+#include "gvfsjobopenforwrite.h"
+#include "gvfsjobwrite.h"
+#include "gvfsjobclosewrite.h"
+#include "gvfsjobseekwrite.h"
+#include "gvfsjobsetdisplayname.h"
+#include "gvfsjobqueryinfo.h"
+#include "gvfsjobdelete.h"
+#include "gvfsjobqueryfsinfo.h"
+#include "gvfsjobqueryattributes.h"
+#include "gvfsjobenumerate.h"
+#include "gvfsjobcreatemonitor.h"
+#include "gvfsdaemonprotocol.h"
+
+typedef struct {
+ char *filename;
+ char *display_name;
+ GIcon *icon;
+ GFile *root;
+ int prio;
+ gboolean can_mount;
+ gboolean can_unmount;
+ gboolean can_eject;
+
+ GDrive *drive;
+ GVolume *volume;
+ GMount *mount;
+} ComputerFile;
+
+static ComputerFile root = { "/" };
+
+struct _GVfsBackendComputer
+{
+ GVfsBackend parent_instance;
+
+ GVolumeMonitor *volume_monitor;
+
+ GVfsMonitor *root_monitor;
+
+ GList *files;
+
+ guint recompute_idle_tag;
+
+ GMountSpec *mount_spec;
+};
+
+G_DEFINE_TYPE (GVfsBackendComputer, g_vfs_backend_computer, G_VFS_TYPE_BACKEND);
+
+static void
+computer_file_free (ComputerFile *file)
+{
+ g_free (file->filename);
+ g_free (file->display_name);
+ if (file->icon)
+ g_object_unref (file->icon);
+ if (file->root)
+ g_object_unref (file->root);
+
+ if (file->drive)
+ g_object_unref (file->drive);
+ if (file->volume)
+ g_object_unref (file->volume);
+ if (file->mount)
+ g_object_unref (file->mount);
+
+ g_slice_free (ComputerFile, file);
+}
+
+/* Assumes filename equal */
+static gboolean
+computer_file_equal (ComputerFile *a,
+ ComputerFile *b)
+{
+ if (strcmp (a->display_name, b->display_name) != 0)
+ return FALSE;
+
+ if (!g_icon_equal (a->icon, b->icon))
+ return FALSE;
+
+ if ((a->root != NULL && b->root != NULL &&
+ !g_file_equal (a->root, b->root)) ||
+ (a->root != NULL && b->root == NULL) ||
+ (a->root == NULL && b->root != NULL))
+ return FALSE;
+
+ if (a->prio != b->prio)
+ return FALSE;
+
+ if (a->can_mount != b->can_mount ||
+ a->can_unmount != b->can_unmount ||
+ a->can_eject != b->can_eject)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void object_changed (GVolumeMonitor *monitor,
+ gpointer object,
+ GVfsBackendComputer *backend);
+
+static void
+g_vfs_backend_computer_finalize (GObject *object)
+{
+ GVfsBackendComputer *backend;
+
+ backend = G_VFS_BACKEND_COMPUTER (object);
+
+ if (backend->volume_monitor)
+ {
+ g_signal_handlers_disconnect_by_func(backend->volume_monitor, object_changed, backend);
+ g_object_unref (backend->volume_monitor);
+ }
+
+ g_mount_spec_unref (backend->mount_spec);
+
+ if (backend->recompute_idle_tag)
+ {
+ g_source_remove (backend->recompute_idle_tag);
+ backend->recompute_idle_tag = 0;
+ }
+
+ g_object_unref (backend->root_monitor);
+
+ if (G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_backend_computer_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_backend_computer_init (GVfsBackendComputer *computer_backend)
+{
+ GVfsBackend *backend = G_VFS_BACKEND (computer_backend);
+ GMountSpec *mount_spec;
+
+ g_vfs_backend_set_display_name (backend, _("Computer"));
+ g_vfs_backend_set_icon_name (backend, "gnome-fs-client");
+ g_vfs_backend_set_user_visible (backend, FALSE);
+
+ mount_spec = g_mount_spec_new ("computer");
+ g_vfs_backend_set_mount_spec (backend, mount_spec);
+ computer_backend->mount_spec = mount_spec;
+}
+
+static gboolean
+filename_is_used (GList *files, const char *filename)
+{
+ ComputerFile *file;
+
+ while (files != NULL)
+ {
+ file = files->data;
+
+ if (file->filename == NULL)
+ return FALSE;
+
+ if (strcmp (file->filename, filename) == 0)
+ return TRUE;
+
+ files = files->next;
+ }
+ return FALSE;
+}
+
+static int
+sort_file_by_filename (ComputerFile *a, ComputerFile *b)
+{
+ return strcmp (a->filename, b->filename);
+}
+
+static void
+convert_slashes (char *str)
+{
+ char *s;
+
+ while ((s = strchr (str, '/')) != NULL)
+ *s = '\\';
+}
+
+static void
+update_from_files (GVfsBackendComputer *backend,
+ GList *files)
+{
+ GList *old_files;
+ GList *oldl, *newl;
+ char *filename;
+ ComputerFile *old, *new;
+ int cmp;
+
+ old_files = backend->files;
+ backend->files = files;
+
+ /* Generate change events */
+ oldl = old_files;
+ newl = files;
+ while (oldl != NULL || newl != NULL)
+ {
+ if (oldl == NULL)
+ {
+ cmp = 1;
+ new = newl->data;
+ old = NULL;
+ }
+ else if (newl == NULL)
+ {
+ cmp = -1;
+ new = NULL;
+ old = oldl->data;
+ }
+ else
+ {
+ new = newl->data;
+ old = oldl->data;
+ cmp = strcmp (old->filename, new->filename);
+ }
+
+ if (cmp == 0)
+ {
+ if (!computer_file_equal (old, new))
+ {
+ filename = g_strconcat ("/", new->filename, NULL);
+ g_vfs_monitor_emit_event (backend->root_monitor,
+ G_FILE_MONITOR_EVENT_CHANGED,
+ backend->mount_spec, filename,
+ NULL, NULL);
+ g_free (filename);
+ }
+
+ oldl = oldl->next;
+ newl = newl->next;
+ }
+ else if (cmp < 0)
+ {
+ filename = g_strconcat ("/", old->filename, NULL);
+ g_vfs_monitor_emit_event (backend->root_monitor,
+ G_FILE_MONITOR_EVENT_DELETED,
+ backend->mount_spec, filename,
+ NULL, NULL);
+ g_free (filename);
+ oldl = oldl->next;
+ }
+ else
+ {
+ filename = g_strconcat ("/", new->filename, NULL);
+ g_vfs_monitor_emit_event (backend->root_monitor,
+ G_FILE_MONITOR_EVENT_CREATED,
+ backend->mount_spec, filename,
+ NULL, NULL);
+ g_free (filename);
+ newl = newl->next;
+ }
+ }
+
+ g_list_foreach (old_files, (GFunc)computer_file_free, NULL);
+}
+
+static void
+recompute_files (GVfsBackendComputer *backend)
+{
+ GVolumeMonitor *volume_monitor;
+ GList *drives, *volumes, *mounts, *l, *ll;
+ GDrive *drive;
+ GVolume *volume;
+ GMount *mount;
+ ComputerFile *file;
+ GList *files;
+ char *basename, *filename;
+ const char *extension;
+ int uniq;
+
+ volume_monitor = backend->volume_monitor;
+
+ files = NULL;
+
+ /* first go through all connected drives */
+ drives = g_volume_monitor_get_connected_drives (volume_monitor);
+ for (l = drives; l != NULL; l = l->next)
+ {
+ drive = l->data;
+
+ volumes = g_drive_get_volumes (drive);
+ if (volumes != NULL)
+ {
+ for (ll = volumes; ll != NULL; ll = ll->next)
+ {
+ volume = ll->data;
+
+ file = g_slice_new (ComputerFile);
+ file->drive = g_object_ref (drive);
+ file->volume = volume; /* Takes ref */
+ file->mount = g_volume_get_mount (volume);
+ file->prio = -3;
+ files = g_list_prepend (files, file);
+ }
+ }
+ else
+ {
+ /* No volume, single drive */
+
+ file = g_slice_new0 (ComputerFile);
+ file->drive = g_object_ref (drive);
+ file->volume = NULL;
+ file->mount = NULL;
+ file->prio = -3;
+
+ files = g_list_prepend (files, file);
+ }
+
+ g_object_unref (drive);
+ }
+ g_list_free (drives);
+
+ /* add all volumes that is not associated with a drive */
+ volumes = g_volume_monitor_get_volumes (volume_monitor);
+ for (l = volumes; l != NULL; l = l->next)
+ {
+ volume = l->data;
+ drive = g_volume_get_drive (volume);
+ if (drive == NULL)
+ {
+ file = g_slice_new0 (ComputerFile);
+ file->drive = NULL;
+ file->volume = g_object_ref (volume);
+ file->mount = g_volume_get_mount (volume);
+ file->prio = -2;
+
+ files = g_list_prepend (files, file);
+ }
+ else
+ g_object_unref (drive);
+
+ g_object_unref (volume);
+ }
+ g_list_free (volumes);
+
+ /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
+ mounts = g_volume_monitor_get_mounts (volume_monitor);
+ for (l = mounts; l != NULL; l = l->next)
+ {
+ mount = l->data;
+ volume = g_mount_get_volume (mount);
+ if (volume == NULL)
+ {
+ file = g_slice_new0 (ComputerFile);
+ file->drive = NULL;
+ file->volume = NULL;
+ file->mount = g_object_ref (mount);
+ file->prio = -1;
+
+ files = g_list_prepend (files, file);
+ }
+ else
+ g_object_unref (volume);
+
+ g_object_unref (mount);
+ }
+ g_list_free (mounts);
+
+ files = g_list_reverse (files);
+
+ for (l = files; l != NULL; l = l->next)
+ {
+ file = l->data;
+
+ if (file->mount)
+ {
+ file->icon = g_mount_get_icon (file->mount);
+ file->display_name = g_mount_get_name (file->mount);
+ file->root = g_mount_get_root (file->mount);
+ file->can_unmount = g_mount_can_unmount (file->mount);
+ file->can_eject = g_mount_can_eject (file->mount);
+ }
+ else if (file->volume)
+ {
+ file->icon = g_volume_get_icon (file->volume);
+ file->display_name = g_volume_get_name (file->volume);
+ file->can_mount = g_volume_can_mount (file->volume);
+ file->can_eject = g_volume_can_eject (file->volume);
+ }
+ else /* drive */
+ {
+ file->icon = g_drive_get_icon (file->drive);
+ file->display_name = g_drive_get_name (file->drive);
+ file->can_eject = g_drive_can_eject (file->drive);
+ }
+
+ if (file->drive)
+ {
+ basename = g_drive_get_name (file->drive);
+ extension = ".drive";
+ }
+ else if (file->volume)
+ {
+ basename = g_volume_get_name (file->volume);
+ extension = ".volume";
+ }
+ else /* mount */
+ {
+ basename = g_mount_get_name (file->mount);
+ extension = ".mount";
+ }
+
+ convert_slashes (basename); /* No slashes in filenames */
+ uniq = 1;
+ filename = g_strconcat (basename, extension, NULL);
+ while (filename_is_used (files, filename))
+ {
+ g_free (filename);
+ filename = g_strdup_printf ("%s-%d%s",
+ basename,
+ uniq++,
+ extension);
+ }
+
+ g_free (basename);
+ file->filename = filename;
+ }
+
+ files = g_list_sort (files, (GCompareFunc)sort_file_by_filename);
+
+ update_from_files (backend, files);
+}
+
+static gboolean
+recompute_files_in_idle (GVfsBackendComputer *backend)
+{
+ backend->recompute_idle_tag = 0;
+
+ recompute_files (backend);
+
+ return FALSE;
+}
+
+static void
+object_changed (GVolumeMonitor *monitor,
+ gpointer object,
+ GVfsBackendComputer *backend)
+{
+ if (backend->recompute_idle_tag == 0)
+ backend->recompute_idle_tag =
+ g_idle_add ((GSourceFunc)recompute_files_in_idle,
+ backend);
+}
+
+static gboolean
+try_mount (GVfsBackend *backend,
+ GVfsJobMount *job,
+ GMountSpec *mount_spec,
+ GMountSource *mount_source,
+ gboolean is_automount)
+{
+ GVfsBackendComputer *computer_backend = G_VFS_BACKEND_COMPUTER (backend);
+ int i;
+ char *signals[] = {
+ "volume-added",
+ "volume-removed",
+ "volume-changed",
+ "mount-added",
+ "mount-removed",
+ "mount-changed",
+ "drive-connected",
+ "drive-disconnected",
+ "drive-changed",
+ NULL
+ };
+
+ computer_backend->volume_monitor = g_volume_monitor_get ();
+
+ /* TODO: connect all signals to object_changed */
+
+ for (i = 0; signals[i] != NULL; i++)
+ g_signal_connect_data (computer_backend->volume_monitor,
+ signals[i],
+ (GCallback)object_changed,
+ backend,
+ NULL, 0);
+
+ computer_backend->root_monitor = g_vfs_monitor_new (g_vfs_backend_get_daemon (backend));
+
+ recompute_files (computer_backend);
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ return TRUE;
+}
+
+static ComputerFile *
+lookup (GVfsBackendComputer *backend,
+ GVfsJob *job,
+ const char *filename)
+{
+ GList *l;
+ ComputerFile *file;
+
+ if (*filename != '/')
+ goto out;
+
+ while (*filename == '/')
+ filename++;
+
+ if (*filename == 0)
+ return &root;
+
+ if (strchr (filename, '/') != NULL)
+ goto out;
+
+ for (l = backend->files; l != NULL; l = l->next)
+ {
+ file = l->data;
+
+ if (strcmp (file->filename, filename) == 0)
+ return file;
+ }
+
+ out:
+ g_vfs_job_failed (job, G_IO_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ _("File doesn't exist"));
+ return NULL;
+}
+
+
+static gboolean
+try_open_for_read (GVfsBackend *backend,
+ GVfsJobOpenForRead *job,
+ const char *filename)
+{
+ ComputerFile *file;
+
+ file = lookup (G_VFS_BACKEND_COMPUTER (backend),
+ G_VFS_JOB (job), filename);
+
+ if (file == &root)
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_IS_DIRECTORY,
+ _("Can't open directory"));
+ else if (file != NULL)
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Can't open mountable file"));
+ return TRUE;
+}
+
+static void
+file_info_from_file (ComputerFile *file,
+ GFileInfo *info)
+{
+ char *uri;
+
+ g_file_info_set_name (info, file->filename);
+ g_file_info_set_display_name (info, file->display_name);
+
+ if (file->icon)
+ g_file_info_set_icon (info, file->icon);
+
+ if (file->root)
+ {
+ uri = g_file_get_uri (file->root);
+
+ g_file_info_set_attribute_string (info,
+ G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
+ uri);
+ g_free (uri);
+ }
+
+ g_file_info_set_sort_order (info, file->prio);
+
+ g_file_info_set_file_type (info, G_FILE_TYPE_MOUNTABLE);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT, file->can_mount);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT, file->can_unmount);
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT, file->can_eject);
+
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
+}
+
+static gboolean
+try_enumerate (GVfsBackend *backend,
+ GVfsJobEnumerate *job,
+ const char *filename,
+ GFileAttributeMatcher *attribute_matcher,
+ GFileQueryInfoFlags flags)
+{
+ ComputerFile *file;
+ GList *l;
+ GFileInfo *info;
+
+ file = lookup (G_VFS_BACKEND_COMPUTER (backend),
+ G_VFS_JOB (job), filename);
+
+ if (file != &root)
+ {
+ if (file != NULL)
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_NOT_DIRECTORY,
+ _("Can't enumerate non-directory"));
+ return TRUE;
+ }
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ /* Enumerate root */
+ for (l = G_VFS_BACKEND_COMPUTER (backend)->files; l != NULL; l = l->next)
+ {
+ file = l->data;
+
+ info = g_file_info_new ();
+
+ file_info_from_file (file, info);
+ g_vfs_job_enumerate_add_info (job, info);
+ g_object_unref (info);
+ }
+
+ g_vfs_job_enumerate_done (job);
+
+ return TRUE;
+}
+
+static gboolean
+try_query_info (GVfsBackend *backend,
+ GVfsJobQueryInfo *job,
+ const char *filename,
+ GFileQueryInfoFlags flags,
+ GFileInfo *info,
+ GFileAttributeMatcher *matcher)
+{
+ ComputerFile *file;
+
+ file = lookup (G_VFS_BACKEND_COMPUTER (backend),
+ G_VFS_JOB (job), filename);
+
+ if (file == &root)
+ {
+ GIcon *icon;
+
+ g_file_info_set_name (info, "/");
+ g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+ g_file_info_set_display_name (info, _("Computer"));
+ icon = g_themed_icon_new ("gnome-fs-client");
+ g_file_info_set_icon (info, icon);
+ g_object_unref (icon);
+ }
+ else if (file != NULL)
+ file_info_from_file (file, info);
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ return TRUE;
+}
+
+static gboolean
+try_create_dir_monitor (GVfsBackend *backend,
+ GVfsJobCreateMonitor *job,
+ const char *filename,
+ GFileMonitorFlags flags)
+{
+ ComputerFile *file;
+ GVfsBackendComputer *computer_backend;
+
+ computer_backend = G_VFS_BACKEND_COMPUTER (backend);
+
+ file = lookup (computer_backend,
+ G_VFS_JOB (job), filename);
+
+ if (file != &root)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Can't open mountable file"));
+ return TRUE;
+ }
+
+ g_vfs_job_create_monitor_set_obj_path (job,
+ g_vfs_monitor_get_object_path (computer_backend->root_monitor));
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ return TRUE;
+}
+
+static gboolean
+try_mount_mountable (GVfsBackend *backend,
+ GVfsJobMountMountable *job,
+ const char *filename,
+ GMountSource *mount_source)
+{
+ ComputerFile *file;
+
+ file = lookup (G_VFS_BACKEND_COMPUTER (backend),
+ G_VFS_JOB (job), filename);
+
+ if (file == &root)
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_NOT_MOUNTABLE_FILE,
+ _("Can't open directory"));
+ else if (file != NULL)
+ {
+#if 0
+ if (file->volume)
+ {
+ /* TODO: Implement */
+ g_volume_mount (file->volume,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ }
+ else if (file->drive)
+ {
+ /* TODO: Poll for media? */
+ }
+ else
+#endif
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Can't mount file"));
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+try_unmount_mountable (GVfsBackend *backend,
+ GVfsJobMountMountable *job,
+ const char *filename)
+{
+}
+
+static gboolean
+try_eject_mountable (GVfsBackend *backend,
+ GVfsJobMountMountable *job,
+ const char *filename)
+{
+}
+
+static void
+g_vfs_backend_computer_class_init (GVfsBackendComputerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_backend_computer_finalize;
+
+ backend_class->try_mount = try_mount;
+ backend_class->try_open_for_read = try_open_for_read;
+ backend_class->try_query_info = try_query_info;
+ backend_class->try_enumerate = try_enumerate;
+ backend_class->try_create_dir_monitor = try_create_dir_monitor;
+}