Загрузка данных
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
```