1
+ #include < iostream>
2
+ #include < vector>
3
+ #include < queue>
4
+ #include < dirent.h>
5
+ #include < sys/stat.h>
6
+ #include < wait.h>
7
+ #include < unistd.h>
8
+ #include < sys/types.h>
9
+ #include < cstring>
10
+
11
+ #define NOSIZE INT64_MAX
12
+
13
+ static const std::string help = " Usage:"
14
+ " \n\t path [options] - find files by path with options."
15
+ " \n\n\t Options:"
16
+ " \n\t\t -inum inum - inode number;"
17
+ " \n\t\t -name name - file name;"
18
+ " \n\t\t -size [-=+]size - file's size(less, equal, more);"
19
+ " \n\t\t -nlinks num - file's hardlinks;"
20
+ " \n\t\t -exec path - file to execute;\n " ;
21
+
22
+
23
+ struct usage {
24
+
25
+ std::string path;
26
+
27
+ int needs_inum = 0 ;
28
+ ino_t inum;
29
+
30
+ int needs_name = 0 ;
31
+ std::string name;
32
+
33
+ int64_t size_sign = NOSIZE;
34
+ off_t size;
35
+
36
+ int needs_nlinks = 0 ;
37
+ nlink_t nlinks;
38
+
39
+ int needs_exec = 0 ;
40
+ std::string exec_path;
41
+ };
42
+
43
+ static bool ok = true ;
44
+ static std::string reason;
45
+
46
+ usage parse_arguments (int & argc, char * argv[]) {
47
+ usage arguments;
48
+ arguments.path = argv[1 ];
49
+ for (int i = 2 ; i < argc; i += 2 ) {
50
+ std::string option (argv[i]);
51
+ std::string value (argv[i + 1 ]);
52
+ if (option == " -inum" ) {
53
+ arguments.needs_inum = 1 ;
54
+ arguments.inum = std::stoul (value);
55
+ } else if (option == " -name" ) {
56
+ arguments.needs_name = 1 ;
57
+ arguments.name = value;
58
+ } else if (option == " -size" ) {
59
+ char sign = value[0 ];
60
+ int64_t size_sign;
61
+ switch (sign) {
62
+ case ' -' :
63
+ size_sign = -1 ;
64
+ break ;
65
+ case ' =' :
66
+ size_sign = 0 ;
67
+ break ;
68
+ case ' +' :
69
+ size_sign = 1 ;
70
+ break ;
71
+ default :
72
+ ok = false ;
73
+ reason = " Wrong usage of \" size\" option" ;
74
+ return arguments;
75
+ }
76
+ arguments.size_sign = size_sign;
77
+ arguments.size = std::stoul (value.substr (1 ));
78
+ } else if (option == " -nlinks" ) {
79
+ arguments.needs_nlinks = 1 ;
80
+ arguments.nlinks = std::stoul (value);
81
+ } else if (option == " -exec" ) {
82
+ arguments.needs_exec = 1 ;
83
+ arguments.exec_path = value;
84
+ } else {
85
+ ok = false ;
86
+ reason = " Unknown option" ;
87
+ return arguments;
88
+ }
89
+ }
90
+ return arguments;
91
+ }
92
+
93
+ bool check (const usage& arguments, const struct stat & sb, const std::string& name) {
94
+ bool satisfy = true ;
95
+ if (arguments.needs_nlinks ) {
96
+ satisfy &= (arguments.nlinks == sb.st_nlink );
97
+ }
98
+ if (arguments.needs_name ) {
99
+ satisfy &= (arguments.name == name);
100
+ }
101
+ if (arguments.needs_inum ) {
102
+ satisfy &= (arguments.inum == sb.st_ino );
103
+ }
104
+ if (arguments.size_sign != NOSIZE) {
105
+ switch (arguments.size_sign ) {
106
+ case -1 :
107
+ satisfy &= (sb.st_size < arguments.size );
108
+ break ;
109
+ case 0 :
110
+ satisfy &= (sb.st_size == arguments.size );
111
+ break ;
112
+ case 1 :
113
+ satisfy &= (sb.st_size > arguments.size );
114
+ break ;
115
+ default :
116
+ break ;
117
+ }
118
+ }
119
+ return satisfy;
120
+ }
121
+
122
+ void find (const usage& arguments, std::vector<std::string>& result) {
123
+ std::queue<std::string> queue;
124
+ queue.push (arguments.path );
125
+ while (!queue.empty ()) {
126
+ std::string cur_dir = queue.front ();
127
+ queue.pop ();
128
+ DIR* dir = opendir (cur_dir.data ());
129
+ if (dir == nullptr ) {
130
+ perror (" opendir" );
131
+ continue ;
132
+ }
133
+ struct dirent * entry;
134
+ while ((entry = readdir (dir)) != nullptr ) {
135
+ auto relative_path = entry->d_name ;
136
+ if (!relative_path || strcmp (relative_path, " ." ) == 0 || strcmp (relative_path, " .." ) == 0 ) {
137
+ continue ;
138
+ }
139
+ auto path = cur_dir + " /" + relative_path;
140
+ struct stat sb;
141
+ int ret = lstat (path.data (), &sb);
142
+ if (ret == -1 ) {
143
+ perror (" lstat" );
144
+ continue ;
145
+ }
146
+
147
+ if (S_ISDIR (sb.st_mode )) {
148
+ queue.push (path);
149
+ } else {
150
+ if (check (arguments, sb, relative_path)) {
151
+ result.push_back (path);
152
+ }
153
+ }
154
+ }
155
+ closedir (dir);
156
+ }
157
+ }
158
+
159
+ void execute (std::string& filepath, std::vector<std::string>& result) {
160
+ int status;
161
+ pid_t pid = fork ();
162
+ if (pid == -1 ) {
163
+ perror (" fork" );
164
+ exit (EXIT_FAILURE);
165
+ }
166
+ if (pid == 0 ) {
167
+ std::vector<char *> args;
168
+ args.reserve (result.size ());
169
+ for (auto & file : result) {
170
+ args.push_back (&(file[0 ]));
171
+ }
172
+ args.emplace_back (nullptr );
173
+
174
+ int err = execv (filepath.data (), args.data ());
175
+ if (err == -1 ) {
176
+ perror (" execv" );
177
+ exit (EXIT_FAILURE);
178
+ }
179
+ } else {
180
+ do {
181
+ pid_t wait_pid = waitpid (pid, &status, WUNTRACED | WCONTINUED);
182
+ if (wait_pid == -1 ) {
183
+ perror (" waitpid" );
184
+ exit (EXIT_FAILURE);
185
+ }
186
+
187
+ if (WIFEXITED (status)) {
188
+ printf (" Normal exited, status = %d\n " , WEXITSTATUS (status));
189
+ } else if (WIFSIGNALED (status)) {
190
+ printf (" Was killed by signal %d\n " , WTERMSIG (status));
191
+ } else if (WIFSTOPPED (status)) {
192
+ printf (" Was stopped by signal %d\n " , WSTOPSIG (status));
193
+ } else if (WIFCONTINUED (status)) {
194
+ printf (" Was continued\n " );
195
+ }
196
+ } while (!WIFEXITED (status) && !WIFSIGNALED (status));
197
+ }
198
+ }
199
+
200
+ int main (int argc, char * argv[]) {
201
+ std::cout << help << std::endl;
202
+ if (argc <= 1 ) {
203
+ std::cout << " Wrong usage, see help" << std::endl;
204
+ }
205
+ usage arguments = parse_arguments (argc, argv);
206
+ if (!ok) {
207
+ std::cerr << reason << " , see help" << std::endl;
208
+ exit (EXIT_FAILURE);
209
+ }
210
+
211
+ std::vector<std::string> result;
212
+ find (arguments, result);
213
+
214
+ for (const std::string& file : result) {
215
+ std::cout << file << std::endl;
216
+ }
217
+
218
+ if (arguments.needs_exec ) {
219
+ execute (arguments.exec_path , result);
220
+ }
221
+
222
+ return 0 ;
223
+ }
0 commit comments