2 This file is part of GNUnet.
3 Copyright (C) 2001--2013 Christian Grothoff (and other contributing authors)
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file util/disk_iterator.c
22 * @brief asynchronous iteration over a directory
23 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
32 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
34 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
38 * Opaque handle used for iterating over a directory.
40 struct GNUNET_DISK_DirectoryIterator
44 * Function to call on directory entries.
46 GNUNET_DISK_DirectoryIteratorCallback callback;
49 * Closure for @e callback.
54 * Reference to directory.
64 * Next filename to process.
71 enum GNUNET_SCHEDULER_Priority priority;
77 * Task used by the directory iterator.
80 directory_iterator_task (void *cls,
81 const struct GNUNET_SCHEDULER_TaskContext *tc)
83 struct GNUNET_DISK_DirectoryIterator *iter = cls;
86 name = iter->next_name;
87 GNUNET_assert (name != NULL);
88 iter->next_name = NULL;
89 iter->callback (iter->callback_cls, iter, name, iter->dirname);
95 * This function must be called during the DiskIteratorCallback
96 * (exactly once) to schedule the task to process the next
97 * filename in the directory (if there is one).
99 * @param iter opaque handle for the iterator
100 * @param can set to #GNUNET_YES to terminate the iteration early
101 * @return #GNUNET_YES if iteration will continue,
102 * #GNUNET_NO if this was the last entry (and iteration is complete),
103 * #GNUNET_SYSERR if abort was YES
106 GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter,
109 struct dirent *finfo;
111 GNUNET_assert (iter->next_name == NULL);
112 if (can == GNUNET_YES)
114 CLOSEDIR (iter->directory);
115 GNUNET_free (iter->dirname);
117 return GNUNET_SYSERR;
119 while (NULL != (finfo = READDIR (iter->directory)))
121 if ((0 == strcmp (finfo->d_name, ".")) ||
122 (0 == strcmp (finfo->d_name, "..")))
124 GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname,
125 DIR_SEPARATOR_STR, finfo->d_name);
130 GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES);
133 GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task,
140 * Scan a directory for files using the scheduler to run a task for
141 * each entry. The name of the directory must be expanded first (!).
142 * If a scheduler does not need to be used, GNUNET_DISK_directory_scan
143 * may provide a simpler API.
145 * @param prio priority to use
146 * @param dir_name the name of the directory
147 * @param callback the method to call for each file
148 * @param callback_cls closure for @a callback
149 * @return #GNUNET_YES if directory is not empty and @a callback
150 * will be called later, #GNUNET_NO otherwise, #GNUNET_SYSERR on error.
153 GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio,
154 const char *dir_name,
155 GNUNET_DISK_DirectoryIteratorCallback
156 callback, void *callback_cls)
158 struct GNUNET_DISK_DirectoryIterator *di;
160 di = GNUNET_new (struct GNUNET_DISK_DirectoryIterator);
161 di->callback = callback;
162 di->callback_cls = callback_cls;
163 di->directory = OPENDIR (dir_name);
164 if (di->directory == NULL)
167 callback (callback_cls, NULL, NULL, NULL);
168 return GNUNET_SYSERR;
170 di->dirname = GNUNET_strdup (dir_name);
172 return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO);
175 /* end of disk_iterator */