3
* Canonical Ltd. (All rights reserved)
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of version 2 of the GNU General Public
7
* License published by the Free Software Foundation.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, contact Novell, Inc. or Canonical,
27
#define _(s) gettext(s)
30
#include <sys/types.h>
35
* dirat_for_each: iterate over a directory calling cb for each entry
36
* @dir: already opened directory (MAY BE NULL)
37
* @name: name of the directory (MAY BE NULL)
38
* @data: data pointer to pass to the callback fn (MAY BE NULL)
39
* @cb: the callback to pass entry too (NOT NULL)
41
* Iterate over the entries in a directory calling cb for each entry.
42
* The directory to iterate is determined by a combination of @dir and
45
* IF @name is a relative path it is determine relative to at @dir if it
46
* is specified, else it the lookup is done relative to the current
49
* If @name is not specified then @dir is used as the directory to iterate
52
* It is an error if both @name and @dir are null
54
* The cb function is called with the DIR in use and the name of the
55
* file in that directory. If the file is to be opened it should
56
* use the openat, fstatat, and related fns.
58
* Returns: 0 on success, else -1 and errno is set to the error code
60
int dirat_for_each(DIR *dir, const char *name, void *data,
61
int (* cb)(DIR *, const char *, struct stat *, void *))
63
struct dirent *dirent = NULL, *ent;
67
if (!cb || (!dir && !name)) {
72
if (dir && (!name || *name != '/')) {
73
dirent = (struct dirent *)
74
malloc(offsetof(struct dirent, d_name) +
75
fpathconf(dirfd(dir), _PC_NAME_MAX) + 1);
77
dirent = (struct dirent *)
78
malloc(offsetof(struct dirent, d_name) +
79
pathconf(name, _PC_NAME_MAX) + 1);
82
PDEBUG("could not alloc dirent");
87
if (dir && *name != '/') {
88
int fd = openat(dirfd(dir), name, O_RDONLY);
95
PDEBUG("Open dir '%s': %s\n", name, d ? "succeeded" : "failed");
98
} else { /* dir && !name */
99
PDEBUG("Recieved cache directory\n");
103
for (error = readdir_r(d, dirent, &ent);
104
error == 0 && ent != NULL;
105
error = readdir_r(d, dirent, &ent)) {
108
if (strcmp(ent->d_name, ".") == 0 ||
109
strcmp(ent->d_name, "..") == 0)
112
if (fstatat(dirfd(d), ent->d_name, &my_stat, 0)) {
113
PDEBUG("stat failed for '%s'", name);
117
if (cb(d, ent->d_name, &my_stat, data)) {
118
PDEBUG("dir_for_each callback failed\n");