forked from dimkr/lazy-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
find.c
111 lines (92 loc) · 2.38 KB
/
find.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <sys/types.h>
#include <dirent.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fnmatch.h>
#if defined(__GLIBC__) && (!defined(_DIRENT_HAVE_D_TYPE))
# error "the d_type member of struct dirent is required"
#endif
#include "common.h"
#include "find.h"
bool find_all(const char *directory,
const char *pattern,
const file_callback_t callback,
void *arg) {
/* a file path */
char path[PATH_MAX] = {'\0'};
/* the directory handle */
DIR *handle = NULL;
/* a file under the directory */
struct dirent entry = {0};
struct dirent *file = NULL;
/* the return value */
bool result = false;
assert(NULL != directory);
assert(NULL != pattern);
assert(NULL != callback);
/* open the directory */
handle = opendir(directory);
if (NULL == handle) {
goto end;
}
do {
/* read the name of one file under the directory */
if (0 != readdir_r(handle, &entry, &file)) {
goto close_directory;
}
if (NULL == file) {
break;
}
switch (file->d_type) {
case DT_REG:
/* if the file is a regular file, check whether its name
* matches the pattern */
if (0 == fnmatch(pattern, file->d_name, FNM_NOESCAPE)) {
/* format the file path */
if (sizeof(path) <= snprintf(path,
sizeof(path),
"%s/%s",
directory,
file->d_name)) {
goto close_directory;
}
/* run the callback */
if (false == callback(path, arg)) {
goto close_directory;
}
}
break;
case DT_DIR:
/* ignore relative paths */
if (0 == strcmp(".", file->d_name)) {
continue;
}
if (0 == strcmp("..", file->d_name)) {
continue;
}
/* format the sub-directory path */
if (sizeof(path) <= snprintf(path,
sizeof(path),
"%s/%s",
directory,
file->d_name)) {
goto close_directory;
}
/* recurse into the sub directory */
if (false == find_all(path, pattern, callback, arg)) {
goto close_directory;
}
break;
}
} while (1);
/* report success */
result = true;
close_directory:
/* close the directory */
(void) closedir(handle);
end:
return result;
}