Skip to content

Commit b1ffe76

Browse files
committed
Basic version
1 parent f2bf5d2 commit b1ffe76

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
project(HW2_Find)
3+
4+
set(CMAKE_CXX_STANDARD 14)
5+
6+
add_executable(HW2_Find find.cpp)

find.cpp

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
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\tpath [options] - find files by path with options."
15+
"\n\n\tOptions:"
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

Comments
 (0)