Загрузка данных


Here are the corrected and complete implementations. Compile with `gcc -Wall -o <name> <name>.c`.

### `remftrash.c`
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
#include <stdarg.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static void log_msg(const char *tag, const char *fmt, ...) {
    char logpath[PATH_MAX];
    const char *home = getenv("HOME");
    if (!home) return;
    snprintf(logpath, sizeof(logpath), "%s/.backup_manager.log", home);
    FILE *f = fopen(logpath, "a");
    if (!f) return;
    fprintf(f, "[%s] ", tag);
    va_list ap; va_start(ap, fmt);
    vfprintf(f, fmt, ap); va_end(ap);
    fprintf(f, "\n");
    fclose(f);
}

int main(int argc, char *argv[]) {
    if (argc != 2) { printf("Error: exactly one filename required.\n"); return 1; }

    const char *home = getenv("HOME");
    if (!home) { printf("Error: HOME environment variable not set.\n"); return 1; }

    char trash_dir[PATH_MAX];
    snprintf(trash_dir, sizeof(trash_dir), "%s/.trash", home);
    if (mkdir(trash_dir, 0755) == -1 && errno != EEXIST) {
        printf("Error: cannot create trash directory.\n"); return 1;
    }

    char src_abs[PATH_MAX];
    if (!realpath(argv[1], src_abs)) {
        printf("Error: file not found or invalid path.\n"); return 1;
    }
    if (access(src_abs, F_OK) == -1) {
        printf("Error: source file does not exist.\n"); return 1;
    }

    char counter_path[PATH_MAX];
    snprintf(counter_path, sizeof(counter_path), "%s/.counter", trash_dir);
    FILE *cf = fopen(counter_path, "r+");
    if (!cf) cf = fopen(counter_path, "w+");
    if (!cf) { printf("Error: counter file access failed.\n"); return 1; }

    int next_id = 0;
    if (fscanf(cf, "%d", &next_id) != 1) next_id = 1;

    char link_path[PATH_MAX];
    snprintf(link_path, sizeof(link_path), "%s/%d", trash_dir, next_id);
    if (link(src_abs, link_path) == -1) {
        printf("Error: failed to create hard link.\n"); fclose(cf); return 1;
    }
    if (unlink(src_abs) == -1) {
        printf("Error: failed to remove original file.\n");
        unlink(link_path); fclose(cf); return 1;
    }

    fseek(cf, 0, SEEK_SET);
    fprintf(cf, "%d", next_id + 1);
    fclose(cf);

    char log_path[PATH_MAX];
    snprintf(log_path, sizeof(log_path), "%s/trash.log", trash_dir);
    FILE *lf = fopen(log_path, "a");
    if (!lf) { printf("Error: failed to open trash log.\n"); return 1; }
    fprintf(lf, "%d - %s\n", next_id, src_abs);
    fclose(lf);

    log_msg("TRASH", "Moved %s to trash as %d", argv[1], next_id);
    return 0;
}
```

### `unftrash.c`
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
#include <stdarg.h>
#include <libgen.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static void log_msg(const char *tag, const char *fmt, ...) {
    char logpath[PATH_MAX];
    const char *home = getenv("HOME");
    if (!home) return;
    snprintf(logpath, sizeof(logpath), "%s/.backup_manager.log", home);
    FILE *f = fopen(logpath, "a");
    if (!f) return;
    fprintf(f, "[%s] ", tag);
    va_list ap; va_start(ap, fmt);
    vfprintf(f, fmt, ap); va_end(ap);
    fprintf(f, "\n");
    fclose(f);
}

int main(int argc, char *argv[]) {
    if (argc != 2) { printf("Error: exactly one filename required.\n"); return 1; }

    const char *home = getenv("HOME");
    if (!home) { printf("Error: HOME not set.\n"); return 1; }

    char log_path[PATH_MAX], trash_dir[PATH_MAX];
    snprintf(log_path, sizeof(log_path), "%s/.trash/trash.log", home);
    snprintf(trash_dir, sizeof(trash_dir), "%s/.trash", home);

    FILE *lf = fopen(log_path, "r");
    if (!lf) { printf("Error: trash log not found.\n"); return 1; }

    char line[PATH_MAX + 100];
    int found = 0;
    while (fgets(line, sizeof(line), lf)) {
        line[strcspn(line, "\n")] = 0;
        char *dash = strchr(line, '-');
        if (!dash) continue;
        *dash = '\0'; dash += 2;

        char base_buf[PATH_MAX], dir_buf[PATH_MAX];
        strncpy(base_buf, basename(dash), sizeof(base_buf) - 1);
        base_buf[sizeof(base_buf) - 1] = '\0';
        strncpy(dir_buf, dash, sizeof(dir_buf) - 1);
        dir_buf[sizeof(dir_buf) - 1] = '\0';

        if (strcmp(base_buf, argv[1]) != 0 && strcmp(dash, argv[1]) != 0) continue;
        found = 1;

        printf("Found: %s\nRestore to original location? (y/n): ", dash);
        char choice; scanf(" %c", &choice);
        if (choice != 'y' && choice != 'Y') continue;

        char link_path[PATH_MAX], restore_dir[PATH_MAX], dest[PATH_MAX];
        snprintf(link_path, sizeof(link_path), "%s/%s", trash_dir, line);
        strncpy(restore_dir, dirname(dir_buf), sizeof(restore_dir) - 1);
        restore_dir[sizeof(restore_dir) - 1] = '\0';

        if (access(restore_dir, F_OK | W_OK | X_OK) == -1) {
            snprintf(restore_dir, sizeof(restore_dir), "%s", home);
            printf("Original directory missing. Restoring to home directory.\n");
        }

        snprintf(dest, sizeof(dest), "%s/%s", restore_dir, base_buf);
        if (link(link_path, dest) == -1) {
            printf("Error: restore failed.\n"); continue;
        }
        unlink(link_path);
        log_msg("TRASH", "Restored %s to %s", base_buf, restore_dir);
        printf("Restored successfully.\n");
    }
    fclose(lf);
    if (!found) printf("No matching files found in trash.\n");
    return 0;
}
```

### `makebackup.c`
```c
#define _XOPEN_SOURCE 700
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static void log_msg(const char *tag, const char *fmt, ...) {
    char logpath[PATH_MAX];
    const char *home = getenv("HOME");
    if (!home) return;
    snprintf(logpath, sizeof(logpath), "%s/.backup_manager.log", home);
    FILE *f = fopen(logpath, "a");
    if (!f) return;
    fprintf(f, "[%s] ", tag);
    va_list ap; va_start(ap, fmt);
    vfprintf(f, fmt, ap); va_end(ap);
    fprintf(f, "\n");
    fclose(f);
}

static unsigned long get_dir_size(const char *path) {
    DIR *d = opendir(path);
    if (!d) return 0;
    unsigned long size = 0;
    struct dirent *e;
    while ((e = readdir(d))) {
        if (e->d_name[0] == '.') continue;
        char fpath[PATH_MAX];
        snprintf(fpath, sizeof(fpath), "%s/%s", path, e->d_name);
        struct stat st;
        if (stat(fpath, &st) == 0)
            size += S_ISDIR(st.st_mode) ? get_dir_size(fpath) : st.st_size;
    }
    closedir(d);
    return size;
}

int main() {
    const char *home = getenv("HOME");
    if (!home) { printf("Error: HOME not set.\n"); return 1; }

    char src_dir[PATH_MAX], home_dir[PATH_MAX], report_path[PATH_MAX];
    snprintf(home_dir, sizeof(home_dir), "%s", home);
    snprintf(src_dir, sizeof(src_dir), "%s/listtask", home);
    snprintf(report_path, sizeof(report_path), "%s/backup-report", home);

    if (access(src_dir, F_OK) == -1) { printf("Error: source directory listtask not found.\n"); return 1; }

    time_t now = time(NULL);
    struct tm *tm_now = localtime(&now);
    char datestr[11];
    strftime(datestr, sizeof(datestr), "%Y%m%d", tm_now);

    char active_dir[PATH_MAX] = "";
    DIR *hd = opendir(home_dir);
    if (!hd) { printf("Error: cannot open home directory.\n"); return 1; }
    struct dirent *e;
    while ((e = readdir(hd))) {
        if (strncmp(e->d_name, "Backup-", 7) == 0) {
            char dstr[9];
            strncpy(dstr, e->d_name + 7, 8); dstr[8] = '\0';
            struct tm ct = {0};
            if (strptime(dstr, "%Y%m%d", &ct)) {
                ct.tm_year += 1900; ct.tm_mon += 1;
                time_t t = mktime(&ct);
                double diff = difftime(now, t) / 86400.0;
                if (diff < 7.0 && strlen(active_dir) == 0)
                    snprintf(active_dir, sizeof(active_dir), "%s/%s", home_dir, e->d_name);
            }
        }
    }
    closedir(hd);

    unsigned long need = get_dir_size(src_dir);
    struct statvfs stvfs;
    if (statvfs(home_dir, &stvfs) == 0) {
        unsigned long free_space = stvfs.f_bavail * stvfs.f_frsize;
        if (free_space < need) { printf("Error: insufficient disk space.\n"); return 1; }
    }

    char target[PATH_MAX];
    if (strlen(active_dir) > 0) {
        snprintf(target, sizeof(target), "%s", active_dir);
        FILE *rf = fopen(report_path, "a");
        if (rf) { fprintf(rf, "[BACKUP] Updating existing: %s on %s\n", basename(active_dir), datestr); fclose(rf); }
        log_msg("BACKUP", "Updating existing backup %s", basename(active_dir));
    } else {
        snprintf(target, sizeof(target), "%s/Backup-%s", home_dir, datestr);
        if (mkdir(target, 0755) == -1) { printf("Error: failed to create backup dir.\n"); return 1; }
        FILE *rf = fopen(report_path, "a");
        if (rf) { fprintf(rf, "[BACKUP] Created new: Backup-%s on %s\n", datestr, datestr); fclose(rf); }
        log_msg("BACKUP", "Created new backup directory Backup-%s", datestr);
    }

    DIR *sd = opendir(src_dir);
    if (!sd) { printf("Error: cannot open source directory.\n"); return 1; }
    FILE *rf = fopen(report_path, "a");
    while ((e = readdir(sd))) {
        if (e->d_name[0] == '.') continue;
        char s[PATH_MAX], t[PATH_MAX];
        snprintf(s, sizeof(s), "%s/%s", src_dir, e->d_name);
        snprintf(t, sizeof(t), "%s/%s", target, e->d_name);

        struct stat ss, ts;
        int ts_ok = (stat(t, &ts) == 0);
        if (stat(s, &ss) != 0) continue;

        if (!ts_ok) {
            if (link(s, t) == 0) {
                if (rf) fprintf(rf, "Copied: %s\n", e->d_name);
                log_msg("BACKUP", "Copied new file: %s", e->d_name);
            }
        } else if (ss.st_size != ts.st_size) {
            char vt[PATH_MAX];
            snprintf(vt, sizeof(vt), "%s.%s", t, datestr);
            if (rename(t, vt) == 0 && link(s, t) == 0) {
                if (rf) fprintf(rf, "Versioned: %s -> %s.%s\n", e->d_name, e->d_name, datestr);
                if (rf) fprintf(rf, "Copied new: %s\n", e->d_name);
                log_msg("BACKUP", "Versioned and replaced: %s", e->d_name);
            }
        } else {
            if (rf) fprintf(rf, "Skipped (unchanged): %s\n", e->d_name);
        }
    }
    if (rf) fclose(rf);
    closedir(sd);

    char cmd[PATH_MAX + 200];
    snprintf(cmd, sizeof(cmd), "tar -czf %s/Backup-%s.tar.gz -C %s %s 2>/dev/null",
             home_dir, datestr, home_dir, basename(target));
    system(cmd);
    log_msg("BACKUP", "Backup compressed successfully");
    printf("Backup process completed.\n");
    return 0;
}
```

### `restorebackup.c`
```c
#define _XOPEN_SOURCE 700
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static void log_msg(const char *tag, const char *fmt, ...) {
    char logpath[PATH_MAX];
    const char *home = getenv("HOME");
    if (!home) return;
    snprintf(logpath, sizeof(logpath), "%s/.backup_manager.log", home);
    FILE *f = fopen(logpath, "a");
    if (!f) return;
    fprintf(f, "[%s] ", tag);
    va_list ap; va_start(ap, fmt);
    vfprintf(f, fmt, ap); va_end(ap);
    fprintf(f, "\n");
    fclose(f);
}

int main() {
    const char *home = getenv("HOME");
    if (!home) { printf("Error: HOME not set.\n"); return 1; }

    DIR *hd = opendir(home);
    if (!hd) { printf("Error: cannot open home directory.\n"); return 1; }

    struct dirent *e;
    char latest_dir[PATH_MAX] = "";
    time_t latest_time = 0;

    while ((e = readdir(hd))) {
        if (strncmp(e->d_name, "Backup-", 7) == 0) {
            char dstr[9];
            strncpy(dstr, e->d_name + 7, 8); dstr[8] = '\0';
            struct tm ct = {0};
            if (strptime(dstr, "%Y%m%d", &ct)) {
                ct.tm_year += 1900; ct.tm_mon += 1;
                time_t t = mktime(&ct);
                if (t > latest_time) {
                    latest_time = t;
                    snprintf(latest_dir, sizeof(latest_dir), "%s/%s", home, e->d_name);
                }
            }
        }
    }
    closedir(hd);

    if (strlen(latest_dir) == 0) { printf("Error: no backup directories found.\n"); return 1; }

    char dst_dir[PATH_MAX];
    snprintf(dst_dir, sizeof(dst_dir), "%s/listtask", home);
    mkdir(dst_dir, 0755);

    DIR *sd = opendir(latest_dir);
    if (!sd) { printf("Error: cannot open backup directory.\n"); return 1; }

    while ((e = readdir(sd))) {
        if (e->d_name[0] == '.') continue;
        size_t len = strlen(e->d_name);
        if (len > 10 && e->d_name[len - 9] == '.') {
            char tail[10];
            strncpy(tail, e->d_name + len - 8, 8); tail[8] = '\0';
            int is_date = 1;
            for(int i=0; i<8; i++) if (tail[i] < '0' || tail[i] > '9') { is_date = 0; break; }
            if (is_date) continue;
        }

        char s[PATH_MAX], t[PATH_MAX];
        snprintf(s, sizeof(s), "%s/%s", latest_dir, e->d_name);
        snprintf(t, sizeof(t), "%s/%s", dst_dir, e->d_name);
        unlink(t);
        if (link(s, t) == 0) log_msg("BACKUP", "Restored: %s", e->d_name);
        else printf("Warning: failed to restore %s\n", e->d_name);
    }
    closedir(sd);
    printf("Backup restored successfully.\n");
    return 0;
}
```

### `menu.sh`
```bash
#!/bin/bash
compile() { gcc -Wall -o "$1" "$1.c" 2>/dev/null; }

for prog in remftrash unftrash makebackup restorebackup; do
    [[ -x "./$prog" ]] || compile "$prog"
done

while true; do
    printf "\n1. Move file to trash\n2. Restore file from trash\n3. Create backup\n4. Restore backup\n5. Exit\nSelect: "
    read choice
    case $choice in
        1) printf "Filename: "; read f; ./remftrash "$f" ;;
        2) printf "Filename: "; read f; ./unftrash "$f" ;;
        3) ./makebackup ;;
        4) ./restorebackup ;;
        5) exit 0 ;;
        *) printf "Invalid option.\n" ;;
    esac
done
```