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;
210 GnomeVFSFileInfo *info;
212 /* Check the file exists so we don't get a bogus DELETED event */
213 info = gnome_vfs_file_info_new ();
214 result = gnome_vfs_get_file_info (uri,
216 GNOME_VFS_FILE_INFO_DEFAULT);
217 gnome_vfs_file_info_unref (info);
219 if (result != GNOME_VFS_OK)
222 monitor = g_new0 (VFolderMonitor, 1);
223 monitor->callback = callback;
224 monitor->user_data = user_data;
225 monitor->uri = g_strdup (uri);
227 #ifndef VFOLDER_DEBUG_WITHOUT_MONITORING
228 result = gnome_vfs_monitor_add (&monitor->vfs_handle,
231 monitor_callback_internal,
234 result = GNOME_VFS_ERROR_NOT_SUPPORTED;
237 if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) {
238 monitor->ctime = ctime_for_uri (uri);
240 G_LOCK (stat_monitors);
241 if (stat_timeout_tag == 0) {
243 g_timeout_add (TIMEOUT_SECONDS * 1000,
248 stat_monitors = g_slist_prepend (stat_monitors, monitor);
249 G_UNLOCK (stat_monitors);
256 vfolder_monitor_dir_new (const gchar *uri,
257 GnomeVFSMonitorCallback callback,
260 return monitor_start_internal (GNOME_VFS_MONITOR_DIRECTORY,
267 vfolder_monitor_file_new (const gchar *uri,
268 GnomeVFSMonitorCallback callback,
271 return monitor_start_internal (GNOME_VFS_MONITOR_FILE,
278 vfolder_monitor_freeze (VFolderMonitor *monitor)
280 monitor->frozen = TRUE;
282 if (monitor->vfs_handle) {
283 gnome_vfs_monitor_cancel (monitor->vfs_handle);
284 monitor->vfs_handle = NULL;
289 vfolder_monitor_thaw (VFolderMonitor *monitor)
291 if (!monitor->frozen)
294 monitor->frozen = FALSE;
296 if (gnome_vfs_monitor_add (&monitor->vfs_handle,
299 monitor_callback_internal,
300 monitor) != GNOME_VFS_OK)
301 monitor->vfs_handle = NULL;
305 vfolder_monitor_cancel (VFolderMonitor *monitor)
307 if (monitor->vfs_handle)
308 gnome_vfs_monitor_cancel (monitor->vfs_handle);
310 G_LOCK (stat_monitors);
311 stat_monitors = g_slist_remove (stat_monitors, monitor);
313 if (!stat_monitors) {
314 g_source_remove (stat_timeout_tag);
315 stat_timeout_tag = 0;
317 G_UNLOCK (stat_monitors);
320 g_free (monitor->uri);
325 * Stolen from eel_make_directory_and_parents from libeel
327 static GnomeVFSResult
328 make_directory_and_parents_from_uri (GnomeVFSURI *uri, guint permissions)
330 GnomeVFSResult result;
331 GnomeVFSURI *parent_uri;
334 * Make the directory, and return right away unless there's
335 * a possible problem with the parent.
337 result = gnome_vfs_make_directory_for_uri (uri, permissions);
338 if (result != GNOME_VFS_ERROR_NOT_FOUND)
341 /* If we can't get a parent, we are done. */
342 parent_uri = gnome_vfs_uri_get_parent (uri);
347 * If we can get a parent, use a recursive call to create
348 * the parent and its parents.
350 result = make_directory_and_parents_from_uri (parent_uri, permissions);
351 gnome_vfs_uri_unref (parent_uri);
352 if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_FILE_EXISTS)
356 * A second try at making the directory after the parents
357 * have all been created.
359 result = gnome_vfs_make_directory_for_uri (uri, permissions);
364 vfolder_make_directory_and_parents (const gchar *uri,
365 gboolean skip_filename,
368 GnomeVFSURI *file_uri, *parent_uri;
369 GnomeVFSResult result;
371 file_uri = gnome_vfs_uri_new (uri);
374 parent_uri = gnome_vfs_uri_get_parent (file_uri);
375 gnome_vfs_uri_unref (file_uri);
376 file_uri = parent_uri;
379 result = make_directory_and_parents_from_uri (file_uri, permissions);
380 gnome_vfs_uri_unref (file_uri);
382 return result == GNOME_VFS_ERROR_FILE_EXISTS ? GNOME_VFS_OK : result;
387 vfolder_timestamp_file_name (const gchar *file)
392 gettimeofday (&tv, NULL);
394 ret = g_strdup_printf ("%d-%s",
395 (int) (tv.tv_sec ^ tv.tv_usec),
402 vfolder_untimestamp_file_name (const gchar *file)
406 while (file [n] && g_ascii_isdigit (file [n]))
408 n = (file [n] == '-') ? n + 1 : 0;
410 return g_strdup (file [n] ? &file [n] : NULL);
414 vfolder_check_extension (const char *name, const char *ext_check)
418 ext = strrchr (name, '.');
419 if (ext && !strcmp (ext, ext_check))
426 vfolder_escape_home (const gchar *file)
429 return g_strconcat (g_get_home_dir (), &file[1], NULL);
431 return g_strdup (file);
434 /* Ripped from gfileutils.c:g_build_pathv() */
436 vfolder_build_uri (const gchar *first_element,
440 gboolean is_first = TRUE;
441 const gchar *next_element;
444 va_start (args, first_element);
446 result = g_string_new (NULL);
447 next_element = first_element;
450 const gchar *element;
455 element = next_element;
456 next_element = va_arg (args, gchar *);
464 start += strspn (start, "/");
466 end = start + strlen (start);
469 while (end > start + 1 && end [-1] == '/')
473 if (end > start + 1 &&
474 !strncmp (end - 1, "://", 3))
480 g_string_append_c (result, '/');
482 g_string_append_len (result, start, end - start);
490 return g_string_free (result, FALSE);