aboutsummaryrefslogtreecommitdiff
path: root/src/util/disk_iterator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/disk_iterator.c')
-rw-r--r--src/util/disk_iterator.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/util/disk_iterator.c b/src/util/disk_iterator.c
new file mode 100644
index 000000000..118823df6
--- /dev/null
+++ b/src/util/disk_iterator.c
@@ -0,0 +1,166 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 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.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file util/disk_iterator.c
22 * @brief asynchronous iteration over a directory
23 * @author Christian Grothoff
24 * @author Nils Durner
25 */
26
27
28/**
29 * Opaque handle used for iterating over a directory.
30 */
31struct GNUNET_DISK_DirectoryIterator
32{
33
34 /**
35 * Function to call on directory entries.
36 */
37 GNUNET_DISK_DirectoryIteratorCallback callback;
38
39 /**
40 * Closure for @e callback.
41 */
42 void *callback_cls;
43
44 /**
45 * Reference to directory.
46 */
47 DIR *directory;
48
49 /**
50 * Directory name.
51 */
52 char *dirname;
53
54 /**
55 * Next filename to process.
56 */
57 char *next_name;
58
59 /**
60 * Our priority.
61 */
62 enum GNUNET_SCHEDULER_Priority priority;
63
64};
65
66
67/**
68 * Task used by the directory iterator.
69 */
70static void
71directory_iterator_task (void *cls,
72 const struct GNUNET_SCHEDULER_TaskContext *tc)
73{
74 struct GNUNET_DISK_DirectoryIterator *iter = cls;
75 char *name;
76
77 name = iter->next_name;
78 GNUNET_assert (name != NULL);
79 iter->next_name = NULL;
80 iter->callback (iter->callback_cls, iter, name, iter->dirname);
81 GNUNET_free (name);
82}
83
84
85/**
86 * This function must be called during the DiskIteratorCallback
87 * (exactly once) to schedule the task to process the next
88 * filename in the directory (if there is one).
89 *
90 * @param iter opaque handle for the iterator
91 * @param can set to #GNUNET_YES to terminate the iteration early
92 * @return #GNUNET_YES if iteration will continue,
93 * #GNUNET_NO if this was the last entry (and iteration is complete),
94 * #GNUNET_SYSERR if abort was YES
95 */
96int
97GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
98 int can)
99{
100 struct dirent *finfo;
101
102 GNUNET_assert (iter->next_name == NULL);
103 if (can == GNUNET_YES)
104 {
105 CLOSEDIR (iter->directory);
106 GNUNET_free (iter->dirname);
107 GNUNET_free (iter);
108 return GNUNET_SYSERR;
109 }
110 while (NULL != (finfo = READDIR (iter->directory)))
111 {
112 if ((0 == strcmp (finfo->d_name, ".")) ||
113 (0 == strcmp (finfo->d_name, "..")))
114 continue;
115 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
116 DIR_SEPARATOR_STR, finfo->d_name);
117 break;
118 }
119 if (finfo == NULL)
120 {
121 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
122 return GNUNET_NO;
123 }
124 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
125 iter);
126 return GNUNET_YES;
127}
128
129
130/**
131 * Scan a directory for files using the scheduler to run a task for
132 * each entry. The name of the directory must be expanded first (!).
133 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
134 * may provide a simpler API.
135 *
136 * @param prio priority to use
137 * @param dir_name the name of the directory
138 * @param callback the method to call for each file
139 * @param callback_cls closure for @a callback
140 * @return #GNUNET_YES if directory is not empty and @a callback
141 * will be called later, #GNUNET_NO otherwise, #GNUNET_SYSERR on error.
142 */
143int
144GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
145 const char *dir_name,
146 GNUNET_DISK_DirectoryIteratorCallback
147 callback, void *callback_cls)
148{
149 struct GNUNET_DISK_DirectoryIterator *di;
150
151 di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
152 di->callback = callback;
153 di->callback_cls = callback_cls;
154 di->directory = OPENDIR (dir_name);
155 if (di->directory == NULL)
156 {
157 GNUNET_free (di);
158 callback (callback_cls, NULL, NULL, NULL);
159 return GNUNET_SYSERR;
160 }
161 di->dirname = GNUNET_strdup (dir_name);
162 di->priority = prio;
163 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
164}
165
166/* end of disk_iterator */