1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4 * Copyright (C) 2001 Ximian, Inc.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
23 #include <sys/types.h>
29 #include <glib/gstdio.h>
33 #define SUBFOLDER_DIR_NAME "subfolders"
34 #define SUBFOLDER_DIR_NAME_LEN 10
38 * @prefix: a prefix to prepend to the path, or %NULL
39 * @path: the virtual path to convert to a filesystem path.
41 * This converts the "virtual" path @path into an expanded form that
42 * allows a given name to refer to both a file and a directory. The
43 * expanded path will have a "subfolders" directory inserted between
44 * each path component. If the path ends with "/", the returned
45 * physical path will end with "/subfolders"
47 * If @prefix is non-%NULL, it will be prepended to the returned path.
49 * Return value: the expanded path
52 e_path_to_physical (const char *prefix, const char *vpath)
65 /* Calculate the length of the real path. */
66 ppath_len = strlen (vpath);
67 ppath_len++; /* For the ending zero. */
69 prefix_len = strlen (prefix);
70 ppath_len += prefix_len;
71 ppath_len++; /* For the separating slash. */
73 /* Take account of the fact that we need to translate every
74 * separator into `subfolders/'.
78 newp = strchr (p, '/');
82 ppath_len += SUBFOLDER_DIR_NAME_LEN;
83 ppath_len++; /* For the separating slash. */
85 /* Skip consecutive slashes. */
92 ppath = g_malloc (ppath_len);
95 memcpy (dp, prefix, prefix_len);
99 /* Copy the mangled path. */
102 newp = strchr (p, '/');
108 memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too. */
111 memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN);
112 dp += SUBFOLDER_DIR_NAME_LEN;
116 /* Skip consecutive slashes. */
128 find_folders_recursive (const char *physical_path, const char *path,
129 EPathFindFoldersCallback callback, gpointer data)
132 char *subfolder_directory_path;
136 if (!callback (physical_path, path, data))
139 subfolder_directory_path = g_strdup_printf ("%s/%s", physical_path, SUBFOLDER_DIR_NAME);
141 /* On the top level, we have no folders and,
142 * consequently, no subfolder directory.
145 subfolder_directory_path = g_strdup (physical_path);
148 /* Now scan the subfolders and load them. */
149 dir = g_dir_open (subfolder_directory_path, 0, NULL);
151 g_free (subfolder_directory_path);
157 struct stat file_stat;
162 dirent = g_dir_read_name (dir);
166 file_path = g_strdup_printf ("%s/%s", subfolder_directory_path,
169 if (g_stat (file_path, &file_stat) < 0 ||
170 ! S_ISDIR (file_stat.st_mode)) {
175 new_path = g_strdup_printf ("%s/%s", path, dirent);
177 ok = find_folders_recursive (file_path, new_path, callback, data);
184 g_free (subfolder_directory_path);
190 * e_path_find_folders:
191 * @prefix: directory to start from
192 * @callback: Callback to invoke on each folder
193 * @data: Data for @callback
195 * Walks the folder tree starting at @prefix and calls @callback
198 * Return value: %TRUE on success, %FALSE if an error occurs at any point
201 e_path_find_folders (const char *prefix,
202 EPathFindFoldersCallback callback,
205 return find_folders_recursive (prefix, "", callback, data);
211 * @prefix: a prefix to prepend to the path, or %NULL
212 * @path: the virtual path to convert to a filesystem path.
214 * This removes the directory pointed to by @prefix and @path
215 * and attempts to remove its parent "subfolders" directory too
218 * Return value: -1 (with errno set) if it failed to rmdir the
219 * specified directory. 0 otherwise, whether or not it removed
220 * the parent directory.
223 e_path_rmdir (const char *prefix, const char *vpath)
225 char *physical_path, *p;
227 /* Remove the directory itself */
228 physical_path = e_path_to_physical (prefix, vpath);
229 if (g_rmdir (physical_path) == -1) {
230 g_free (physical_path);
234 /* Attempt to remove its parent "subfolders" directory,
235 * ignoring errors since it might not be empty.
238 p = strrchr (physical_path, '/');
240 g_free (physical_path);
244 p = strrchr (physical_path, '/');
245 if (!p || strcmp (p + 1, SUBFOLDER_DIR_NAME) != 0) {
246 g_free (physical_path);
250 g_rmdir (physical_path);
251 g_free (physical_path);