| 1 |
1 |
|
/* See LICENSE file for copyright and license details. */ |
|
2 |
+ |
#include <dirent.h> |
| 2 |
3 |
|
#include <stdbool.h> |
| 3 |
4 |
|
#include <stdio.h> |
| 4 |
5 |
|
#include <stdlib.h> |
|
| 6 |
7 |
|
#include <unistd.h> |
| 7 |
8 |
|
#include <sys/stat.h> |
| 8 |
9 |
|
|
| 9 |
|
- |
#define OPER(x) (oper[(x)-'a']) |
|
10 |
+ |
#define FLAG(x) (flag[(x)-'a']) |
| 10 |
11 |
|
|
| 11 |
|
- |
static bool test(const char *); |
|
12 |
+ |
static void test(const char *, const char *); |
| 12 |
13 |
|
|
| 13 |
|
- |
static bool quiet = false; |
| 14 |
|
- |
static bool oper[26]; |
|
14 |
+ |
static bool match = false; |
|
15 |
+ |
static bool flag[26]; |
| 15 |
16 |
|
static struct stat old, new; |
| 16 |
17 |
|
|
| 17 |
18 |
|
int |
| 18 |
19 |
|
main(int argc, char *argv[]) { |
| 19 |
|
- |
char buf[BUFSIZ], *p; |
| 20 |
|
- |
bool match = false; |
|
20 |
+ |
struct dirent *d; |
|
21 |
+ |
char buf[BUFSIZ]; |
|
22 |
+ |
DIR *dir; |
| 21 |
23 |
|
int opt; |
| 22 |
24 |
|
|
| 23 |
|
- |
while((opt = getopt(argc, argv, "C:bcdefghn:o:pqrsuwx")) != -1) |
|
25 |
+ |
while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuwx")) != -1) |
| 24 |
26 |
|
switch(opt) { |
| 25 |
|
- |
case 'C': /* tests relative to directory */ |
| 26 |
|
- |
if(chdir(optarg) == -1) { |
| 27 |
|
- |
perror(optarg); |
| 28 |
|
- |
exit(2); |
| 29 |
|
- |
} |
| 30 |
|
- |
break; |
| 31 |
27 |
|
case 'n': /* newer than file */ |
| 32 |
28 |
|
case 'o': /* older than file */ |
| 33 |
|
- |
if(!(OPER(opt) = stat(optarg, (opt == 'n' ? &new : &old)) == 0)) |
|
29 |
+ |
if(!(FLAG(opt) = !stat(optarg, (opt == 'n' ? &new : &old)))) |
| 34 |
30 |
|
perror(optarg); |
| 35 |
31 |
|
break; |
| 36 |
|
- |
case 'q': /* quiet (no output, just status) */ |
| 37 |
|
- |
quiet = true; |
| 38 |
|
- |
break; |
| 39 |
32 |
|
default: /* miscellaneous operators */ |
| 40 |
|
- |
OPER(opt) = true; |
|
33 |
+ |
FLAG(opt) = true; |
| 41 |
34 |
|
break; |
| 42 |
35 |
|
case '?': /* error: unknown flag */ |
| 43 |
|
- |
fprintf(stderr, "usage: %s [-bcdefghpqrsuwx] [-C dir] [-n file] [-o file] [file...]\n", argv[0]); |
|
36 |
+ |
fprintf(stderr, "usage: %s [-abcdefghlpqrsuwx] [-n file] [-o file] [file...]\n", argv[0]); |
| 44 |
37 |
|
exit(2); |
| 45 |
38 |
|
} |
| 46 |
|
- |
if(optind == argc) |
| 47 |
|
- |
while(fgets(buf, sizeof buf, stdin)) { |
| 48 |
|
- |
if(*(p = &buf[strlen(buf)-1]) == '\n') |
| 49 |
|
- |
*p = '\0'; |
| 50 |
|
- |
match |= test(buf); |
|
39 |
+ |
for(; optind < argc; optind++) |
|
40 |
+ |
if(FLAG('l') && (dir = opendir(argv[optind]))) { |
|
41 |
+ |
/* test directory contents */ |
|
42 |
+ |
while((d = readdir(dir))) |
|
43 |
+ |
if(snprintf(buf, sizeof buf, "%s/%s", argv[optind], d->d_name) < sizeof buf) |
|
44 |
+ |
test(buf, d->d_name); |
|
45 |
+ |
closedir(dir); |
| 51 |
46 |
|
} |
| 52 |
|
- |
else |
| 53 |
|
- |
while(optind < argc) |
| 54 |
|
- |
match |= test(argv[optind++]); |
|
47 |
+ |
else |
|
48 |
+ |
test(argv[optind], argv[optind]); |
| 55 |
49 |
|
|
| 56 |
50 |
|
return match ? 0 : 1; |
| 57 |
51 |
|
} |
| 58 |
52 |
|
|
| 59 |
|
- |
bool |
| 60 |
|
- |
test(const char *path) { |
| 61 |
|
- |
struct stat st; |
|
53 |
+ |
void |
|
54 |
+ |
test(const char *path, const char *name) { |
|
55 |
+ |
struct stat st, ln; |
| 62 |
56 |
|
|
| 63 |
|
- |
if((!OPER('b') || (stat(path, &st) == 0 && S_ISBLK(st.st_mode))) /* block special */ |
| 64 |
|
- |
&& (!OPER('c') || (stat(path, &st) == 0 && S_ISCHR(st.st_mode))) /* character special */ |
| 65 |
|
- |
&& (!OPER('d') || (stat(path, &st) == 0 && S_ISDIR(st.st_mode))) /* directory */ |
| 66 |
|
- |
&& (!OPER('e') || (access(path, F_OK) == 0)) /* exists */ |
| 67 |
|
- |
&& (!OPER('f') || (stat(path, &st) == 0 && S_ISREG(st.st_mode))) /* regular file */ |
| 68 |
|
- |
&& (!OPER('g') || (stat(path, &st) == 0 && (st.st_mode & S_ISGID))) /* set-group-id flag */ |
| 69 |
|
- |
&& (!OPER('h') || (lstat(path, &st) == 0 && S_ISLNK(st.st_mode))) /* symbolic link */ |
| 70 |
|
- |
&& (!OPER('n') || (stat(path, &st) == 0 && st.st_mtime > new.st_mtime)) /* newer than file */ |
| 71 |
|
- |
&& (!OPER('o') || (stat(path, &st) == 0 && st.st_mtime < old.st_mtime)) /* older than file */ |
| 72 |
|
- |
&& (!OPER('p') || (stat(path, &st) == 0 && S_ISFIFO(st.st_mode))) /* named pipe */ |
| 73 |
|
- |
&& (!OPER('r') || (access(path, R_OK) == 0)) /* readable */ |
| 74 |
|
- |
&& (!OPER('s') || (stat(path, &st) == 0 && st.st_size > 0)) /* not empty */ |
| 75 |
|
- |
&& (!OPER('u') || (stat(path, &st) == 0 && (st.st_mode & S_ISUID))) /* set-user-id flag */ |
| 76 |
|
- |
&& (!OPER('w') || (access(path, W_OK) == 0)) /* writable */ |
| 77 |
|
- |
&& (!OPER('x') || (access(path, X_OK) == 0))) { /* executable */ |
| 78 |
|
- |
if(quiet) |
|
57 |
+ |
if(!stat(path, &st) && !lstat(path, &ln) |
|
58 |
+ |
&& ( FLAG('a') || name[0] != '.') /* hidden */ |
|
59 |
+ |
&& (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ |
|
60 |
+ |
&& (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ |
|
61 |
+ |
&& (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ |
|
62 |
+ |
&& (!FLAG('e') || access(path, F_OK) == 0) /* exists */ |
|
63 |
+ |
&& (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */ |
|
64 |
+ |
&& (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */ |
|
65 |
+ |
&& (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */ |
|
66 |
+ |
&& (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */ |
|
67 |
+ |
&& (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */ |
|
68 |
+ |
&& (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */ |
|
69 |
+ |
&& (!FLAG('r') || access(path, R_OK) == 0) /* readable */ |
|
70 |
+ |
&& (!FLAG('s') || st.st_size > 0) /* not empty */ |
|
71 |
+ |
&& (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ |
|
72 |
+ |
&& (!FLAG('w') || access(path, W_OK) == 0) /* writable */ |
|
73 |
+ |
&& (!FLAG('x') || access(path, X_OK) == 0)) { /* executable */ |
|
74 |
+ |
if(FLAG('q')) |
| 79 |
75 |
|
exit(0); |
| 80 |
|
- |
puts(path); |
| 81 |
|
- |
return true; |
|
76 |
+ |
match = true; |
|
77 |
+ |
puts(name); |
| 82 |
78 |
|
} |
| 83 |
|
- |
else |
| 84 |
|
- |
return false; |
| 85 |
79 |
|
} |