1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 * vfolder-util.c - Utility functions for wrapping monitors and
4 * filename/uri parsing.
6 * Copyright (C) 2002 Ximian, Inc.
8 * The Gnome Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * The Gnome Library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with the Gnome Library; see the file COPYING.LIB. If not,
20 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
23 * Author: Alex Graveley <alex@ximian.com>
24 * Based on original code by George Lebl <jirka@5z.com>.
34 #include <libgnomevfs/gnome-vfs-file-info.h>
35 #include <libgnomevfs/gnome-vfs-ops.h>
37 #include "vfolder-util.h"
38 #include "vfolder-common.h"
40 /* assumes vuri->path already set */
42 vfolder_uri_parse_internal (GnomeVFSURI *uri, VFolderURI *vuri)
44 vuri->scheme = (gchar *) gnome_vfs_uri_get_scheme (uri);
46 vuri->ends_in_slash = FALSE;
48 if (strncmp (vuri->scheme, "all-", strlen ("all-")) == 0) {
49 vuri->scheme += strlen ("all-");
50 vuri->is_all_scheme = TRUE;
52 vuri->is_all_scheme = FALSE;
54 if (vuri->path != NULL) {
55 int last_slash = strlen (vuri->path) - 1;
58 /* Note: This handling of paths is somewhat evil, may need a
61 /* kill leading slashes, that is make sure there is
63 for (first = vuri->path; *first == '/'; first++)
65 if (first != vuri->path) {
70 /* kill trailing slashes (leave first if all slashes) */
71 while (last_slash > 0 && vuri->path [last_slash] == '/') {
72 vuri->path [last_slash--] = '\0';
73 vuri->ends_in_slash = TRUE;
76 /* get basename start */
77 while (last_slash >= 0 && vuri->path [last_slash] != '/')
81 vuri->file = vuri->path + last_slash + 1;
83 vuri->file = vuri->path;
85 if (vuri->file[0] == '\0' &&
86 strcmp (vuri->path, "/") == 0) {
90 vuri->ends_in_slash = TRUE;
101 monitor_callback_internal (GnomeVFSMonitorHandle *handle,
102 const gchar *monitor_uri,
103 const gchar *info_uri,
104 GnomeVFSMonitorEventType event_type,
107 VFolderMonitor *monitor = (VFolderMonitor *) user_data;
113 "RECEIVED MONITOR: %s, %s, %s%s%s\n",
115 info_uri + strlen (monitor_uri),
116 event_type == GNOME_VFS_MONITOR_EVENT_CREATED ? "CREATED" : "",
117 event_type == GNOME_VFS_MONITOR_EVENT_DELETED ? "DELETED" : "",
118 event_type == GNOME_VFS_MONITOR_EVENT_CHANGED ? "CHANGED" : ""));
120 (*monitor->callback) (handle,
127 #define TIMEOUT_SECONDS 3
129 static GSList *stat_monitors = NULL;
130 G_LOCK_DEFINE_STATIC (stat_monitors);
131 static guint stat_timeout_tag = 0;
134 ctime_for_uri (const gchar *uri)
136 GnomeVFSFileInfo *info;
137 GnomeVFSResult result;
140 info = gnome_vfs_file_info_new ();
142 result = gnome_vfs_get_file_info (uri,
144 GNOME_VFS_FILE_INFO_DEFAULT);
145 if (result == GNOME_VFS_OK) {
149 gnome_vfs_file_info_unref (info);
155 monitor_timeout_cb (gpointer user_data)
161 * Copy the stat_monitors list in case the callback removes/adds
162 * monitors (which is likely).
164 G_LOCK (stat_monitors);
165 copy = g_slist_copy (stat_monitors);
166 G_UNLOCK (stat_monitors);
168 for (iter = copy; iter; iter = iter->next) {
169 VFolderMonitor *monitor = iter->data;
172 G_LOCK (stat_monitors);
173 if (g_slist_position (stat_monitors, iter) < 0) {
174 G_UNLOCK (stat_monitors);
177 G_UNLOCK (stat_monitors);
182 ctime = ctime_for_uri (monitor->uri);
183 if (ctime == monitor->ctime)
186 (*monitor->callback) ((GnomeVFSMonitorHandle *) monitor,
190 GNOME_VFS_MONITOR_EVENT_DELETED :
191 GNOME_VFS_MONITOR_EVENT_CHANGED,
194 monitor->ctime = ctime;
202 static VFolderMonitor *
203 monitor_start_internal (GnomeVFSMonitorType type,
205 GnomeVFSMonitorCallback callback,
208 GnomeVFSResult result;
209 VFolderMonitor *monitor;
211 GnomeVFSFileInfo *info;
213 /* Check the file exists so we don't get a bogus DELETED event */
214 info = gnome_vfs_file_info_new ();
215 result = gnome_vfs_get_file_info (uri,
217 GNOME_VFS_FILE_INFO_DEFAULT);
218 gnome_vfs_file_info_unref (info);
220 if (result != GNOME_VFS_OK)
224 monitor = g_new0 (VFolderMonitor, 1);
225 monitor->callback = callback;
226 monitor->user_data = user_data;
227 monitor->uri = g_strdup (uri);
229 #ifndef VFOLDER_DEBUG_WITHOUT_MONITORING
230 result = gnome_vfs_monitor_add (&monitor->vfs_handle,
233 monitor_callback_internal,
236 result = GNOME_VFS_ERROR_NOT_SUPPORTED;
239 if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) {
240 monitor->ctime = ctime_for_uri (uri);
242 G_LOCK (stat_monitors);
243 if (stat_timeout_tag == 0) {
245 g_timeout_add (TIMEOUT_SECONDS * 1000,
250 stat_monitors = g_slist_prepend (stat_monitors, monitor);
251 G_UNLOCK (stat_monitors);
258 vfolder_monitor_dir_new (const gchar *uri,
259 GnomeVFSMonitorCallback callback,
262 return monitor_start_internal (GNOME_VFS_MONITOR_DIRECTORY,
269 vfolder_monitor_file_new (const gchar *uri,
270 GnomeVFSMonitorCallback callback,
273 return monitor_start_internal (GNOME_VFS_MONITOR_FILE,
280 vfolder_monitor_freeze (VFolderMonitor *monitor)
282 monitor->frozen = TRUE;
284 if (monitor->vfs_handle) {
285 gnome_vfs_monitor_cancel (monitor->vfs_handle);
286 monitor->vfs_handle = NULL;
291 vfolder_monitor_thaw (VFolderMonitor *monitor)
293 if (!monitor->frozen)
296 monitor->frozen = FALSE;
298 if (gnome_vfs_monitor_add (&monitor->vfs_handle,
301 monitor_callback_internal,
302 monitor) != GNOME_VFS_OK)
303 monitor->vfs_handle = NULL;
307 vfolder_monitor_cancel (VFolderMonitor *monitor)
309 if (monitor->vfs_handle)
310 gnome_vfs_monitor_cancel (monitor->vfs_handle);
312 G_LOCK (stat_monitors);
313 stat_monitors = g_slist_remove (stat_monitors, monitor);
315 if (!stat_monitors) {
316 g_source_remove (stat_timeout_tag);
317 stat_timeout_tag = 0;
319 G_UNLOCK (stat_monitors);
322 g_free (monitor->uri);
327 * Stolen from eel_make_directory_and_parents from libeel
329 static GnomeVFSResult
330 make_directory_and_parents_from_uri (GnomeVFSURI *uri, guint permissions)
332 GnomeVFSResult result;
333 GnomeVFSURI *parent_uri;
336 * Make the directory, and return right away unless there's
337 * a possible problem with the parent.
339 result = gnome_vfs_make_directory_for_uri (uri, permissions);
340 if (result != GNOME_VFS_ERROR_NOT_FOUND)
343 /* If we can't get a parent, we are done. */
344 parent_uri = gnome_vfs_uri_get_parent (uri);
349 * If we can get a parent, use a recursive call to create
350 * the parent and its parents.
352 result = make_directory_and_parents_from_uri (parent_uri, permissions);
353 gnome_vfs_uri_unref (parent_uri);
354 if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS)
358 * A second try at making the directory after the parents
359 * have all been created.
361 result = gnome_vfs_make_directory_for_uri (uri, permissions);
366 vfolder_make_directory_and_parents (const gchar *uri,
367 gboolean skip_filename,
370 GnomeVFSURI *file_uri, *parent_uri;
371 GnomeVFSResult result;
373 file_uri = gnome_vfs_uri_new (uri);
376 parent_uri = gnome_vfs_uri_get_parent (file_uri);
377 gnome_vfs_uri_unref (file_uri);
378 file_uri = parent_uri;
381 result = make_directory_and_parents_from_uri (file_uri, permissions);
382 gnome_vfs_uri_unref (file_uri);
384 return result == GNOME_VFS_ERROR_FILE_EXISTS ? GNOME_VFS_OK : result;
389 vfolder_timestamp_file_name (const gchar *file)
394 gettimeofday (&tv, NULL);
396 ret = g_strdup_printf ("%d-%s",
397 (int) (tv.tv_sec ^ tv.tv_usec),
404 vfolder_untimestamp_file_name (const gchar *file)
408 while (file [n] && g_ascii_isdigit (file [n]))
410 n = (file [n] == '-') ? n + 1 : 0;
412 return g_strdup (file [n] ? &file [n] : NULL);
416 vfolder_check_extension (const char *name, const char *ext_check)
420 ext = strrchr (name, '.');
421 if (ext && !strcmp (ext, ext_check))
428 vfolder_escape_home (const gchar *file)
431 return g_strconcat (g_get_home_dir (), &file[1], NULL);
433 return g_strdup (file);
436 /* Ripped from gfileutils.c:g_build_pathv() */
438 vfolder_build_uri (const gchar *first_element,
442 gboolean is_first = TRUE;
443 const gchar *next_element;
446 va_start (args, first_element);
448 result = g_string_new (NULL);
449 next_element = first_element;
452 const gchar *element;
457 element = next_element;
458 next_element = va_arg (args, gchar *);
466 start += strspn (start, "/");
468 end = start + strlen (start);
471 while (end > start + 1 && end [-1] == '/')
475 if (end > start + 1 &&
476 !strncmp (end - 1, "://", 3))
482 g_string_append_c (result, '/');
484 g_string_append_len (result, start, end - start);
492 return g_string_free (result, FALSE);