Skip to content

Commit

Permalink
Initial homework submit
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyaBizyaev committed Apr 10, 2019
1 parent f2bf5d2 commit b259fb3
Show file tree
Hide file tree
Showing 14 changed files with 774 additions and 14 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CMakeLists.txt.user
cmake-build-debug
.directory
.idea
19 changes: 19 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.1)

set(CMAKE_CXX_STANDARD 14)

project(find)

add_executable(find find.cpp
actor.cpp
actor.h
environment.cpp
environment.h
platform.h
programconditions.cpp
programconditions.h
query.cpp
query.h)

install(TARGETS find
RUNTIME DESTINATION bin)
9 changes: 9 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
MIT License

Copyright (c) 2019 Ilya Bizyaev

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 changes: 31 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
# Необходимо написать подмножество утилиты find.

## Программа должна:

- Первым аргументом принимать абсолютный путь, в котором будет производиться поиск файлов.
- По-умолчанию выводить в стандартный поток вывода все найденные файлы по этому пути
- Поддерживать аргумент -inum num. Аргумент задает номер инода
- Поддерживать аргумент -name name. Аргумент задает имя файла
- Поддерживать аргумент -size [-=+]size. Аргумент задает фильтр файлов по размеру(меньше, равен, больше)
- Поддерживать аргумент -nlinks num. Аргумент задает количество hardlink'ов у файлов
- Поддерживать аргумент -exec path. Аргумент задает путь до исполняемого файла, которому в качестве единственного аргумент нужно передать найденный в иерархии файл
- Поддерживать комбинацию аргументов. Например хочется найти все файлы с размером больше 1GB и скормить их утилите /usr/bin/sha1sum.
- Выполнять поиск рекурсивно, в том числе во всех вложенных директориях.
- Сильные духом призываются к выполнению задания с использованием системного вызова getdents(2). Остальные могут использовать readdir и opendir для чтения содержимого директории.
# find - a basic file search utility

## Goal
This is an educational project, aimed at understanding how to interact with
POSIX and Linux-specific APIs to retrieve file information.

## Features:
* Filter by wildcards, size ranges, inodes and link counts
* Print search results to stdout or pass to an executable

## Building
```
$ mkdir build
$ cd build
$ cmake ..
$ make
```

Requires a C++14 compiler.

## Usage
Please refer to `find --help` for details.

## Testing
Tested by hand on Linux 4.12.

## Copyright
Ilya Bizyaev, 2019 (<[email protected]>)

Licensed under MIT terms.

67 changes: 67 additions & 0 deletions actor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <iostream>

#include "actor.h"
#include "programconditions.h"

int execute_program(const std::string& path,
const std::vector<std::string>& args,
const std::map<std::string, std::string>& env)
{
pid_t pid = fork();
if (!pid) {
// We are a child
ProgramConditions conditions(args, env);
execve(path.c_str(), conditions.get_argv(), conditions.get_envp());
// This code will only execute if execve has failed
std::cerr << "Failed to execute the program: " << strerror(errno) << std::endl;
exit(EXIT_FAILURE);
} else if (pid > 0) {
// We are a parent
int status;
pid_t result = waitpid(pid, &status, 0);
if (result > 0) {
if (WIFEXITED(status)) {
// terminated normally
int exit_code = WEXITSTATUS(status);
return exit_code;
} else { // WIFSIGNALED(status)
// terminated due to an uncaught signal
int signal_number = WTERMSIG(status);
return -signal_number;
}
} else {
// Process wait failure
std::error_code ec(errno, std::system_category());
throw std::system_error(ec, "Failed to wait for child return");
}
} else {
// Fork failure
std::error_code ec(errno, std::system_category());
throw std::system_error(ec, "Failed to spawn child process");
}
}

void Actor::set_executable(const std::string &executable)
{
m_args = { executable };
}

void Actor::process(const std::string &filename)
{
if (m_args.empty()) {
std::cout << filename << std::endl;
} else {
m_args.push_back(filename);
}
}

void Actor::submit(const std::map<std::string, std::string> &env)
{
if (!m_args.empty()) {
execute_program(m_args.front(), m_args, env);
}
}
24 changes: 24 additions & 0 deletions actor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef ACTOR_H
#define ACTOR_H

#include <string.h>
#include <vector>
#include <map>

/*!
* Manages actions for located files
* By default, prints file list to stdout
*/
class Actor
{
public:
Actor() = default;

void set_executable(const std::string& executable);
void process(const std::string& filename);
void submit(const std::map<std::string, std::string>& env);
private:
std::vector<std::string> m_args;
};

#endif // ACTOR_H
75 changes: 75 additions & 0 deletions environment.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <unistd.h>

#include <sstream>

#include "environment.h"

Environment::Environment(char *envp[])
{
for (; *envp != nullptr; ++envp) {
set_variable(std::string(*envp));
}
if (m_environ.find("PATH") == m_environ.end()) {
// Assuming default value for LSB
set_variable("PATH=/bin:/sbin:/usr/bin:/usr/sbin");
}
}

void Environment::update_paths(const std::string& path_value)
{
m_paths.clear();
std::stringstream ss(path_value);

std::string segment;
while (std::getline(ss, segment, ':'))
{
m_paths.push_back(segment);
}
}

void Environment::set_variable(const std::string& assignment)
{
size_t eq = assignment.find('=');
std::string key, value;
if (eq != std::string::npos) {
key = assignment.substr(0, eq);
value = assignment.substr(eq + 1);
} else {
key = assignment;
value = "";
}

m_environ[key] = value;
if (key == "PATH") {
update_paths(value);
}
}

void Environment::unset_variable(const std::string& var)
{
m_environ.erase(var);
}

const std::map<std::string, std::string>& Environment::get_variables()
{
return m_environ;
}

std::string Environment::find_executable(const std::string& filename) const
{
if (executable_exists(filename)) {
return filename;
}
for (const auto& prefix : m_paths) {
std::string attempt = prefix + "/" + filename;
if (executable_exists(attempt)) {
return attempt;
}
}
return "";
}

bool Environment::executable_exists(const std::string &filename) const
{
return access(filename.c_str(), X_OK) != -1;
}
29 changes: 29 additions & 0 deletions environment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H

#include <map>
#include <string>
#include <vector>

/*!
* Manages shell environment variables
* For PATH, keeps an up-to-date searchable paths list
*/
class Environment
{
public:
explicit Environment(char *envp[]);

void update_paths(const std::string& path_value);
void set_variable(const std::string& assignment);
void unset_variable(const std::string& var);
const std::map<std::string, std::string>& get_variables();
std::string find_executable(const std::string& filename) const;
private:
bool executable_exists(const std::string& filename) const;

std::map<std::string, std::string> m_environ;
std::vector<std::string> m_paths;
};

#endif // ENVIRONMENT_H
Loading

0 comments on commit b259fb3

Please sign in to comment.