From 30504ce9f4a8fceca2818d54eeb04c8bf5faddbd Mon Sep 17 00:00:00 2001 From: RomkaZVO Date: Fri, 24 Jul 2026 02:38:57 +0800 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=B0=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 18 +- README.md | 7 +- index.cgi | Bin 0 -> 35424 bytes src/auth.c | 52 ++++++ src/auth.h | 7 + src/auth.o | Bin 0 -> 2960 bytes src/config.c | 121 +++++++++++++ src/config.h | 26 +++ src/config.o | Bin 0 -> 7680 bytes src/fs.c | 177 +++++++++++++++++++ src/fs.h | 37 ++++ src/fs.o | Bin 0 -> 8648 bytes src/main.c | 130 ++++++++++++++ src/main.o | Bin 0 -> 5304 bytes src/render.c | 482 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/render.h | 17 ++ src/render.o | Bin 0 -> 28136 bytes src/status.c | 52 ++++++ src/style.c | 36 ++++ src/utils.c | 95 ++++++++++ src/utils.h | 13 ++ src/utils.o | Bin 0 -> 4128 bytes status.cgi | Bin 0 -> 16392 bytes style.cgi | Bin 0 -> 16248 bytes 24 files changed, 1260 insertions(+), 10 deletions(-) create mode 100755 index.cgi create mode 100644 src/auth.c create mode 100644 src/auth.h create mode 100644 src/auth.o create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/config.o create mode 100644 src/fs.c create mode 100644 src/fs.h create mode 100644 src/fs.o create mode 100644 src/main.c create mode 100644 src/main.o create mode 100644 src/render.c create mode 100644 src/render.h create mode 100644 src/render.o create mode 100644 src/status.c create mode 100644 src/style.c create mode 100644 src/utils.c create mode 100644 src/utils.h create mode 100644 src/utils.o create mode 100755 status.cgi create mode 100755 style.cgi diff --git a/Makefile b/Makefile index 8021b18..e22f56c 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,23 @@ -# Makefile для Trashbox CGI CC = gcc -CFLAGS = -Wall -Wextra -O2 +CFLAGS = -Wall -Wextra -O2 -I./src TARGETS = index.cgi style.cgi status.cgi +SRCS_INDEX = src/main.c src/config.c src/auth.c src/fs.c src/render.c src/utils.c +OBJS_INDEX = $(SRCS_INDEX:.c=.o) + all: $(TARGETS) -index.cgi: index.c +index.cgi: $(OBJS_INDEX) + $(CC) $(CFLAGS) -o $@ $^ + +style.cgi: src/style.c $(CC) $(CFLAGS) -o $@ $< -style.cgi: style.c - $(CC) $(CFLAGS) -o $@ $< - -status.cgi: status.c +status.cgi: src/status.c $(CC) $(CFLAGS) -o $@ $< clean: - rm -f $(TARGETS) + rm -f $(OBJS_INDEX) $(TARGETS) install: all chmod +x $(TARGETS) diff --git a/README.md b/README.md index a79c861..30c8180 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,13 @@ sudo apt install nginx busybox gcc ```bash mkdir -p /home/romkazvo/www/cgi-bin cd /home/romkazvo/www/cgi-bin +git clone https://git.mashup.su/RomkaZVO/Trashbox.git ``` ### Компиляция CGI ```bash -sudo sh build.sh +cd src +make +sudo make install ``` ### Конфигурация Nginx Файл конфигурации `/etc/nginx/sites-available/trashbox`:
@@ -28,4 +31,4 @@ busybox httpd -p 127.0.0.1:8050 -h /home/romkazvo/www cat > /home/romkazvo/www/cgi-bin/.htpasswd << EOF secret:mysecretpassword EOF -``` \ No newline at end of file +``` diff --git a/index.cgi b/index.cgi new file mode 100755 index 0000000000000000000000000000000000000000..5a429eeaa7bdd5504606bdad40ca38bca2092c2a GIT binary patch literal 35424 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 ii-P(?EtorX$0@w7SCdV~%}C`tJ0!)aaRuT) +#include +#include "auth.h" +#include "config.h" + +int check_folder_password(const char *folder_name, const char *password) { + if (!password || !folder_name || password[0] == '\0') return 0; + + FILE *f = fopen(g_config.passwd_file, "r"); + if (!f) return 1; + + char line[512]; + while (fgets(line, sizeof(line), f)) { + line[strcspn(line, "\r\n")] = 0; + char *colon = strchr(line, ':'); + if (!colon) continue; + *colon = '\0'; + char *folder = line; + char *pass = colon + 1; + const char *last_slash = strrchr(folder_name, '/'); + const char *base_name = last_slash ? last_slash + 1 : folder_name; + if (strcmp(folder, folder_name) == 0 || strcmp(folder, base_name) == 0) { + fclose(f); + return strcmp(pass, password) == 0; + } + } + fclose(f); + return 1; +} + +int is_folder_protected(const char *folder_path) { + if (!folder_path || folder_path[0] == '\0') return 0; + + FILE *f = fopen(g_config.passwd_file, "r"); + if (!f) return 0; + + char line[512]; + while (fgets(line, sizeof(line), f)) { + line[strcspn(line, "\r\n")] = 0; + char *colon = strchr(line, ':'); + if (!colon) continue; + *colon = '\0'; + const char *last_slash = strrchr(folder_path, '/'); + const char *folder_name = last_slash ? last_slash + 1 : folder_path; + if (strcmp(line, folder_path) == 0 || strcmp(line, folder_name) == 0) { + fclose(f); + return 1; + } + } + fclose(f); + return 0; +} diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 0000000..f959f56 --- /dev/null +++ b/src/auth.h @@ -0,0 +1,7 @@ +#ifndef AUTH_H +#define AUTH_H + +int is_folder_protected(const char *folder_path); +int check_folder_password(const char *folder_name, const char *password); + +#endif diff --git a/src/auth.o b/src/auth.o new file mode 100644 index 0000000000000000000000000000000000000000..a9997cd0d57c870be749a65729e25c9d196150ea GIT binary patch literal 2960 zcmbVM-D@0G6hE76lQkc+v4}(}biog{V5YmJVy#$rHrwtj9ZRT~5Hu z)o27$^PvOTn1_P+2M88?@Jafh=}Jl-#OQ-4z6By`Bc)Xz8qk>aoSAz!H|wrQFU;I? zf9H43x#xH1&RfT|6D>X;@Zp1Fu(RSQz(8Qfj=5$Gx}giy**n3RgBYQlRi0M{l`|=4 zYw$Vs(#=2%ptBmB`4!pG%G5DPIh&}me#Ttr(#kpCv%$no7e!`Jb8hh}vz5}E=4^Tu%acCM*=Drh?Dt zJ~f#5F6DeL=yV62Y*||1!m@q4jn_86$i1l3L#Wdt>R>{52SBpF|7a+jFos4mg;4ac zd`OP;MV~ytOt_Ew!Qp%3H25ZZeEYiE1B|%P0XcPR2COBQ=MtP1m!L=qhoo}N&=bGR{ zh*MuN5)g-bc4TBqc23qo*7_s#ih`aq^o!|iactNy)8iS-daY;ehI{opUBlrtZypejKv;SkW?I)T$*ji?*TL27N;(sWuMMzZIV?{OD<% zCJ+bVZTM`p(+c3MH{sa>5XAX!3OJoL$LASNc_@bCml;mjJp%rrfa9&J@jn;vP67W` zz`F!|y$OCx!0FrL`}tGA#XJwQbE18U{7Ht_>-M&Qi@LodKgqjD5vy_nA%1*8=4bwEMoQlhJA>UwlRFf@e2DjzQE$?45^Oy-vsDo z+?B=9 +#include +#include +#include "config.h" + +config_t g_config; + +int load_config(const char *path) { + FILE *f = fopen(path, "r"); + if (!f) return -1; + + char line[512]; + char current_section[64] = ""; + + while (fgets(line, sizeof(line), f)) { + char *p = line; + while (*p == ' ' || *p == '\t') p++; + if (*p == '\0' || *p == '#' || *p == ';') continue; + + if (*p == '[') { + p++; + char *end = strchr(p, ']'); + if (end) { + *end = '\0'; + strncpy(current_section, p, sizeof(current_section) - 1); + current_section[sizeof(current_section) - 1] = '\0'; + } + continue; + } + + char *eq = strchr(p, '='); + if (!eq) continue; + *eq = '\0'; + char *key = p; + char *value = eq + 1; + + char *end_key = key + strlen(key) - 1; + while (end_key > key && (*end_key == ' ' || *end_key == '\t')) { + *end_key = '\0'; + end_key--; + } + + while (*value == ' ' || *value == '\t') value++; + char *end_val = value + strlen(value) - 1; + while (end_val > value && (*end_val == ' ' || *end_val == '\t' || *end_val == '\r' || *end_val == '\n')) { + *end_val = '\0'; + end_val--; + } + + if (strcmp(current_section, "paths") == 0) { + if (strcmp(key, "base_path") == 0) strncpy(g_config.base_path, value, sizeof(g_config.base_path) - 1); + else if (strcmp(key, "template_path") == 0) strncpy(g_config.template_path, value, sizeof(g_config.template_path) - 1); + else if (strcmp(key, "passwd_file") == 0) strncpy(g_config.passwd_file, value, sizeof(g_config.passwd_file) - 1); + } + else if (strcmp(current_section, "limits") == 0) { + if (strcmp(key, "max_entries") == 0) g_config.max_entries = atoi(value); + } + else if (strcmp(current_section, "hidden") == 0) { + if (strcmp(key, "dirs") == 0) { + char *token = strtok(value, ","); + g_config.hidden_dirs_count = 0; + while (token && g_config.hidden_dirs_count < 10) { + while (*token == ' ') token++; + strncpy(g_config.hidden_dirs[g_config.hidden_dirs_count], token, 255); + g_config.hidden_dirs[g_config.hidden_dirs_count][255] = '\0'; + g_config.hidden_dirs_count++; + token = strtok(NULL, ","); + } + } + else if (strcmp(key, "files") == 0) { + char *token = strtok(value, ","); + g_config.hidden_files_count = 0; + while (token && g_config.hidden_files_count < 10) { + while (*token == ' ') token++; + strncpy(g_config.hidden_files[g_config.hidden_files_count], token, 255); + g_config.hidden_files[g_config.hidden_files_count][255] = '\0'; + g_config.hidden_files_count++; + token = strtok(NULL, ","); + } + } + } + else if (strcmp(current_section, "preview") == 0) { + if (strcmp(key, "image") == 0) strncpy(g_config.preview_image, value, sizeof(g_config.preview_image) - 1); + else if (strcmp(key, "text") == 0) strncpy(g_config.preview_text, value, sizeof(g_config.preview_text) - 1); + else if (strcmp(key, "audio") == 0) strncpy(g_config.preview_audio, value, sizeof(g_config.preview_audio) - 1); + else if (strcmp(key, "video") == 0) strncpy(g_config.preview_video, value, sizeof(g_config.preview_video) - 1); + else if (strcmp(key, "pdf") == 0) strncpy(g_config.preview_pdf, value, sizeof(g_config.preview_pdf) - 1); + } + } + + fclose(f); + return 0; +} + +void set_default_config(void) { + strcpy(g_config.base_path, "/home/romkazvo/www"); + strcpy(g_config.template_path, "/home/romkazvo/www/cgi-bin/template.html"); + strcpy(g_config.passwd_file, "/home/romkazvo/www/cgi-bin/.htpasswd"); + g_config.max_entries = 1000; + g_config.hidden_dirs_count = 0; + g_config.hidden_files_count = 0; + strcpy(g_config.preview_image, "jpg,jpeg,png,gif,webp,bmp,svg,ico"); + strcpy(g_config.preview_text, "txt,md,html,htm,css,js,json,xml,csv"); + strcpy(g_config.preview_audio, "mp3,wav,ogg,flac,m4a,aac"); + strcpy(g_config.preview_video, "mp4,webm,ogv,mov,avi,mkv"); + strcpy(g_config.preview_pdf, "pdf"); +} + +int is_string_in_list(const char *str, const char *list) { + if (!list || !*list) return 0; + char temp[512]; + strncpy(temp, list, sizeof(temp) - 1); + temp[sizeof(temp) - 1] = '\0'; + char *token = strtok(temp, ","); + while (token) { + while (*token == ' ') token++; + if (strcasecmp(token, str) == 0) return 1; + token = strtok(NULL, ","); + } + return 0; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..8b1dacc --- /dev/null +++ b/src/config.h @@ -0,0 +1,26 @@ +#ifndef CONFIG_H +#define CONFIG_H + +typedef struct { + char base_path[1024]; + char template_path[1024]; + char passwd_file[1024]; + int max_entries; + char hidden_dirs[10][256]; + int hidden_dirs_count; + char hidden_files[10][256]; + int hidden_files_count; + char preview_image[512]; + char preview_text[512]; + char preview_audio[512]; + char preview_video[512]; + char preview_pdf[512]; +} config_t; + +extern config_t g_config; + +int load_config(const char *path); +void set_default_config(void); +int is_string_in_list(const char *str, const char *list); + +#endif diff --git a/src/config.o b/src/config.o new file mode 100644 index 0000000000000000000000000000000000000000..4dca6db30c1604bf5d6c88f5e9f17156a518318c GIT binary patch literal 7680 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 literal 0 HcmV?d00001 diff --git a/src/fs.c b/src/fs.c new file mode 100644 index 0000000..0921b70 --- /dev/null +++ b/src/fs.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include "fs.h" +#include "config.h" +#include "auth.h" +#include "utils.h" + +query_params_t g_params; + +int is_safe_path(const char *path) { + if (!path) return 0; + if (strstr(path, "..")) return 0; + if (strstr(path, "./")) return 0; + if (path[0] == '/') return 0; + if (strstr(path, "//")) return 0; + return 1; +} + +void safe_path_join(char *result, size_t result_size, const char *base, const char *path) { + if (!is_safe_path(path)) { + snprintf(result, result_size, "%s", base); + return; + } + snprintf(result, result_size, "%s/%s", base, path); +} + +int count_files_in_dir(const char *path) { + DIR *dir = opendir(path); + if (!dir) return 0; + struct dirent *entry; + int count = 0; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + if (entry->d_name[0] == '.') continue; + int hidden = 0; + for (int i = 0; i < g_config.hidden_files_count; i++) { + if (strcmp(entry->d_name, g_config.hidden_files[i]) == 0) { hidden = 1; break; } + } + if (hidden) continue; + count++; + } + closedir(dir); + return count; +} + +long long get_dir_size(const char *path) { + DIR *dir = opendir(path); + if (!dir) return 0; + struct dirent *entry; + struct stat statbuf; + char fullpath[1024]; + long long size = 0; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name); + if (stat(fullpath, &statbuf) == 0) { + if (S_ISDIR(statbuf.st_mode)) size += get_dir_size(fullpath); + else if (S_ISREG(statbuf.st_mode)) size += statbuf.st_size; + } + } + closedir(dir); + return size; +} + +const char* get_file_icon(const char* filename) { + const char *ext = strrchr(filename, '.'); + if (!ext) return "📄"; + ext++; + if (is_string_in_list(ext, g_config.preview_image)) return "🖼️"; + if (is_string_in_list(ext, g_config.preview_audio)) return "🎵"; + if (is_string_in_list(ext, g_config.preview_video)) return "🎬"; + if (strcasecmp(ext, "zip") == 0 || strcasecmp(ext, "rar") == 0 || + strcasecmp(ext, "7z") == 0 || strcasecmp(ext, "tar") == 0 || + strcasecmp(ext, "gz") == 0) return "📦"; + if (strcasecmp(ext, "pdf") == 0) return "📕"; + if (strcasecmp(ext, "doc") == 0 || strcasecmp(ext, "docx") == 0) return "📘"; + if (strcasecmp(ext, "xls") == 0 || strcasecmp(ext, "xlsx") == 0) return "📗"; + if (strcasecmp(ext, "txt") == 0) return "📝"; + return "📄"; +} + +int is_previewable(const char* filename) { + const char *ext = strrchr(filename, '.'); + if (!ext) return 0; + ext++; + return (is_string_in_list(ext, g_config.preview_image) || + is_string_in_list(ext, g_config.preview_text) || + is_string_in_list(ext, g_config.preview_audio) || + is_string_in_list(ext, g_config.preview_video) || + is_string_in_list(ext, g_config.preview_pdf)); +} + +void search_recursive(const char *base_path, const char *display_path, const char *search_term, entry_t *results, int *count, int max_results) { + DIR *dir = opendir(base_path); + if (!dir) return; + struct dirent *entry; + struct stat file_stat; + char full_path[1024]; + char display_subpath[1024]; + while ((entry = readdir(dir)) != NULL && *count < max_results) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + if (entry->d_name[0] == '.') continue; + int hidden = 0; + for (int i = 0; i < g_config.hidden_dirs_count; i++) { + if (strcmp(entry->d_name, g_config.hidden_dirs[i]) == 0) { hidden = 1; break; } + } + for (int i = 0; i < g_config.hidden_files_count; i++) { + if (strcmp(entry->d_name, g_config.hidden_files[i]) == 0) { hidden = 1; break; } + } + if (hidden) continue; + snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name); + if (display_path[0] == '\0') { + snprintf(display_subpath, sizeof(display_subpath), "%s", entry->d_name); + } else { + snprintf(display_subpath, sizeof(display_subpath), "%s/%s", display_path, entry->d_name); + } + if (is_folder_protected(display_subpath) || is_folder_protected(entry->d_name)) { + continue; + } + if (stat(full_path, &file_stat) == 0) { + if (my_strcasestr(entry->d_name, search_term) != NULL) { + entry_t *result = &results[*count]; + strncpy(result->name, entry->d_name, sizeof(result->name) - 1); + result->name[sizeof(result->name) - 1] = '\0'; + if (S_ISDIR(file_stat.st_mode)) { + result->is_dir = 1; + result->size = 0; + result->dir_size = get_dir_size(full_path); + result->file_count = count_files_in_dir(full_path); + result->mtime = file_stat.st_mtime; + strcpy(result->icon, "📁"); + result->is_protected = 0; + url_encode(display_subpath, result->encoded_path, sizeof(result->encoded_path)); + strncpy(result->file_url, display_subpath, sizeof(result->file_url) - 1); + (*count)++; + } else if (S_ISREG(file_stat.st_mode)) { + result->is_dir = 0; + result->size = file_stat.st_size; + result->dir_size = 0; + result->file_count = 0; + result->mtime = file_stat.st_mtime; + strcpy(result->icon, get_file_icon(entry->d_name)); + result->is_protected = 0; + url_encode(display_subpath, result->encoded_path, sizeof(result->encoded_path)); + strncpy(result->file_url, display_subpath, sizeof(result->file_url) - 1); + (*count)++; + } + } + if (S_ISDIR(file_stat.st_mode)) { + search_recursive(full_path, display_subpath, search_term, results, count, max_results); + } + } + } + closedir(dir); +} + +int compare_entries_sorted(const void *a, const void *b) { + const entry_t *entryA = (const entry_t *)a; + const entry_t *entryB = (const entry_t *)b; + if (entryA->is_dir && !entryB->is_dir) return -1; + if (!entryA->is_dir && entryB->is_dir) return 1; + int result = 0; + if (strcmp(g_params.sort_by, "size") == 0) { + long long sizeA = entryA->is_dir ? entryA->dir_size : entryA->size; + long long sizeB = entryB->is_dir ? entryB->dir_size : entryB->size; + result = (sizeA > sizeB) - (sizeA < sizeB); + } else if (strcmp(g_params.sort_by, "date") == 0) { + result = (entryA->mtime > entryB->mtime) - (entryA->mtime < entryB->mtime); + } else { + result = strcasecmp(entryA->name, entryB->name); + } + return result * g_params.sort_order; +} diff --git a/src/fs.h b/src/fs.h new file mode 100644 index 0000000..ee43d6f --- /dev/null +++ b/src/fs.h @@ -0,0 +1,37 @@ +#ifndef FS_H +#define FS_H + +#include + +typedef struct { + char name[256]; + int is_dir; + long size; + char icon[8]; + char encoded_path[1024]; + char file_url[1024]; + int is_protected; + time_t mtime; + int file_count; + long long dir_size; +} entry_t; + +typedef struct { + char sort_by[16]; + int sort_order; + char search[256]; + int recursive; +} query_params_t; + +extern query_params_t g_params; + +int is_safe_path(const char *path); +void safe_path_join(char *result, size_t result_size, const char *base, const char *path); +int count_files_in_dir(const char *path); +long long get_dir_size(const char *path); +const char* get_file_icon(const char* filename); +int is_previewable(const char* filename); +void search_recursive(const char *base_path, const char *display_path, const char *search_term, entry_t *results, int *count, int max_results); +int compare_entries_sorted(const void *a, const void *b); + +#endif diff --git a/src/fs.o b/src/fs.o new file mode 100644 index 0000000000000000000000000000000000000000..69aa0b4840b0888887dc6263c63d9d2569efd2a6 GIT binary patch literal 8648 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 +#include +#include +#include +#include "config.h" +#include "auth.h" +#include "fs.h" +#include "render.h" +#include "utils.h" + +int main() { + setlocale(LC_ALL, "en_US.UTF-8"); + setlocale(LC_CTYPE, "en_US.UTF-8"); + + if (load_config("/home/romkazvo/www/cgi-bin/config.ini") != 0) { + set_default_config(); + } + + strcpy(g_params.sort_by, "name"); + g_params.sort_order = 1; + g_params.search[0] = '\0'; + g_params.recursive = 0; + + char *query_string = getenv("QUERY_STRING"); + char display_path[1024] = ""; + char safe_display_path[1024] = ""; + char base_path[1024]; + strcpy(base_path, g_config.base_path); + + if (query_string) { + char *path_start = strstr(query_string, "path="); + if (path_start) { + path_start += 5; + char *path_end = strchr(path_start, '&'); + int path_len = path_end ? (int)(path_end - path_start) : (int)strlen(path_start); + if (path_len > 0 && path_len < (int)sizeof(display_path) - 1) { + char encoded_path[1024]; + strncpy(encoded_path, path_start, path_len); + encoded_path[path_len] = '\0'; + url_decode_enhanced(encoded_path, display_path, sizeof(display_path)); + if (!is_safe_path(display_path)) { + display_path[0] = '\0'; + strcpy(base_path, g_config.base_path); + } else { + strncpy(safe_display_path, display_path, sizeof(safe_display_path) - 1); + safe_display_path[sizeof(safe_display_path) - 1] = '\0'; + safe_path_join(base_path, sizeof(base_path), g_config.base_path, safe_display_path); + } + } + } + + char *sort_start = strstr(query_string, "sort="); + if (sort_start) { + sort_start += 5; + char *sort_end = strchr(sort_start, '&'); + int sort_len = sort_end ? (int)(sort_end - sort_start) : (int)strlen(sort_start); + if (sort_len > 0 && sort_len < (int)sizeof(g_params.sort_by)) { + strncpy(g_params.sort_by, sort_start, sort_len); + g_params.sort_by[sort_len] = '\0'; + } + } + + char *search_start = strstr(query_string, "search="); + if (search_start) { + search_start += 7; + char *search_end = strchr(search_start, '&'); + int search_len = search_end ? (int)(search_end - search_start) : (int)strlen(search_start); + if (search_len > 0 && search_len < (int)sizeof(g_params.search) - 1) { + char encoded_search[256]; + strncpy(encoded_search, search_start, search_len); + encoded_search[search_len] = '\0'; + url_decode_enhanced(encoded_search, g_params.search, sizeof(g_params.search)); + if (g_params.search[0] != '\0') { + g_params.recursive = 1; + } + } + } + + if (strstr(query_string, "password=")) { + char *error = strstr(query_string, "error=1"); + if (!error) { + char folder_name[256] = ""; + if (display_path[0]) { + char *last_slash = strrchr(display_path, '/'); + if (last_slash) strcpy(folder_name, last_slash + 1); + else strcpy(folder_name, display_path); + if (is_folder_protected(folder_name)) { + char *pass_start = strstr(query_string, "password="); + if (pass_start) { + pass_start += 9; + char *pass_end = strchr(pass_start, '&'); + int pass_len = pass_end ? (int)(pass_end - pass_start) : (int)strlen(pass_start); + if (pass_len > 0 && pass_len < 256) { + char pass_buf[256]; + strncpy(pass_buf, pass_start, pass_len); + pass_buf[pass_len] = '\0'; + char decoded_pass[256]; + url_decode_enhanced(pass_buf, decoded_pass, sizeof(decoded_pass)); + if (decoded_pass[0] == '\0') { + char encoded_path[1024]; + url_encode(display_path, encoded_path, sizeof(encoded_path)); + printf("Status: 302 Found\r\n"); + printf("Location: /cgi-bin/index.cgi?path=%s&error=1\r\n\r\n", encoded_path); + return 0; + } + if (!check_folder_password(folder_name, decoded_pass)) { + char encoded_path[1024]; + url_encode(display_path, encoded_path, sizeof(encoded_path)); + printf("Status: 302 Found\r\n"); + printf("Location: /cgi-bin/index.cgi?path=%s&error=1\r\n\r\n", encoded_path); + return 0; + } + } else { + char encoded_path[1024]; + url_encode(display_path, encoded_path, sizeof(encoded_path)); + printf("Status: 302 Found\r\n"); + printf("Location: /cgi-bin/index.cgi?path=%s&error=1\r\n\r\n", encoded_path); + return 0; + } + } + } + } + } + } + } + + printf("Content-type: text/html; charset=utf-8\n\n"); + print_template(base_path, display_path); + return 0; +} diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..81948f1ce89f0e3f05a2bd641dc2d6929fa71959 GIT binary patch literal 5304 zcmbuCdu$X%7{KSCwTN(cR@C}H53N{~ZhL@Qz-q7MvFb&UQk5W{+r2&RueqC?>(MfM- z<~QGC=9_09Se;xmBNSpXh1hj$swOF8C!$m3K3?o&5f)~KnHm~YhBmC}>|wVKtzN$| zHMn8@4L7f4Ma{|fvXW&x@HI4Bhgwl9l}0T)-OCKyw(Q?VIy;KSikM?;ce=7pA-^)FXEnQIIK3lIrn6@@ zOWgkMX`qw1EishXFf^!E=A#AG{aW4iW7}Db9mQ(A27s5;N-qLl9vhF0Jq@uG>`*hd zm|DR|R$ge2&SY$Y6KH>>J=y|8!TgLmPFAi$1y2p9#491==HK24rKI~q()~kq-;a;~ zroPOP>K=z;(mn2VXza^K`4~v5o;lT>6nxxSoUCkbKDdyZsYx0se>a1%Rf|qk*41|X z^*3}gvS+ffeurAgdivmVO8+&`Uvw1IcmEZR?7`L4!1tA)+roWM(;Wb5t_!ZgX=Km0 z+;t~>A?TB;`;+wJwEf#^q#T`!Hy2F0-`69t>jRvy`1q#Hi8~XU6L%$2?{k^zrc2il_%jOi)W-OxVE^Yk#3z>4Y~nkdi1X11R-i79~Sb0M7R55Y4`1$dh%^V#)g zsrmsJPwGFb6~3}z07>^()%}#~^-nZ)v+CDU!gKG5@b>)}y#9&uGVZrN-b1``CtqnS zQvM3`r&dYz6C910kLv4ayW+G*-;P1gcY+6)Q0V8MutXx|BhY%Vivw>UDvYG8@E8_D zAjKWY9NV7f#(yHKC{lg|S>=w?#cbBsSET$qm|pZbUr48*I6A26M{(<5pwWqYOszcA z9)|agbroSF$g#UnGiP2-7?-W1)N3v(WZv=z=*dvmS#WB!OQj+WNsi z>kmgCov}9Dwr^&CI96%u4|hD$oCtUCIV}Z8*ORjl_oZaLMWdr_<26=jk$?k z?BffB{AE6lrx=capA@9+O2Mxo42#{o-puai`PAoXUTk95Pa$4f$-m94!^iue-b&)b z=Lpzp_>n6UYF@epvPOJU08a<-LI8IH_^iq>7rY6-rQ$#DF)7*Q^P|RzNfp$}ABcqMv9ccnIOjI7R^U$PQX(MHrSv7A5iI%K-d+!h}Hb&IiWuoX0B) zPF0?~{f;{uUIT=C`}*H}3CLhVJE$Y=$o-ED=UMVKP{xGvcxp+G=PoAXXTtA<=+9jU zAxSQ9ZN$TMj(x>+zn5{2W0dxH6OQ)1^OUiQkI#X1hUrN!<70wXOx?}_!toA~_HiF! z!hYiEE%|2%Az>WOhM(m4M8t&r9Qa8t{i7Xtqt^L6(J#N9D+s4{RKd{>j#b)UN91XL zGK5n*4-q@36FZL+d1~i5B9D)M>G#C|`8SC?-j`DT9U_l+mgEzJw-G)`INohi{v_e& z6Mh~B1`@{e0{BV!1%%_BDEYO7(|Ny1aLjOBN%@ULp8DMp!1wv=$g}ZDB2WAIj89&! z|CfARuBZLP&V16(V}xHsc#Uv6-WEJ8AYt6_tsuvHKH+pdEF+w*t1RI(K067g<9&kg z81efC;R^^qAUF;K-$1gT?-6;ru0A62_@o%o zoAkSwa2o&Rgj2sU(8Yw~6;sFSOeyUsINC7ej_u`HS;GIqnUdBVjVZ&W5>spoD<~OP z;3B0}xGrrYuPLYl0-EiN6q%x1g#!Fn&lD5xBxUW*L!Hp1ZxymeHkE-3)bKj;|Gu~u za4Y*?#(e>1#kQ}v;@Utarl-#P>ZR!gzy9UWjOXZo)n5#{Xj9&oP~@pkC>uT&Jdyx*igzJsysk6%m($al0fBhMdMzYz+!^!g+a`CdHaAsxoc91`v| z^dbG@8I5T({Loc5R!ABadNIPVDElq*3}ICCL7`6>mZhHL_X##_ZvfjX^s`b>5$B;;U$+16v-+mhM!*_?_U4f1H{&01Ei(C0sE@_ SZfc}o6#XCb%+$Yr{eJ+FS7jRj literal 0 HcmV?d00001 diff --git a/src/render.c b/src/render.c new file mode 100644 index 0000000..e965b4f --- /dev/null +++ b/src/render.c @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "render.h" +#include "config.h" +#include "auth.h" +#include "fs.h" +#include "utils.h" + +extern query_params_t g_params; + +void buffer_init(buffer_t *buf) { + buf->capacity = 65536; + buf->data = malloc(buf->capacity); + buf->size = 0; +} + +void buffer_append(buffer_t *buf, const char *str) { + size_t len = strlen(str); + if (buf->size + len >= buf->capacity) { + buf->capacity *= 2; + buf->data = realloc(buf->data, buf->capacity); + } + memcpy(buf->data + buf->size, str, len); + buf->size += len; +} + +void buffer_free(buffer_t *buf) { free(buf->data); } + +void print_breadcrumb(buffer_t *buf, const char *display_path) { + buffer_append(buf, "
\n"); + buffer_append(buf, " 🏠 Главная"); + if (display_path && display_path[0]) { + char temp_path[1024] = ""; + char encoded[2048]; + char *path_copy = strdup(display_path); + char *token = strtok(path_copy, "/"); + while (token) { + buffer_append(buf, " / "); + if (temp_path[0]) strcat(temp_path, "/"); + strcat(temp_path, token); + url_encode(temp_path, encoded, sizeof(encoded)); + char safe_token[512]; + html_escape(token, safe_token, sizeof(safe_token)); + char link[4096]; + snprintf(link, sizeof(link), "%s", encoded, safe_token); + buffer_append(buf, link); + token = strtok(NULL, "/"); + } + free(path_copy); + } + buffer_append(buf, "\n
\n"); +} + +void print_password_form(buffer_t *buf, const char *folder_name) { + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
🔒
\n"); + buffer_append(buf, "

Папка защищена паролем

\n"); + buffer_append(buf, "

Введите пароль для доступа к папке "); + char safe_name[512]; + html_escape(folder_name, safe_name, sizeof(safe_name)); + buffer_append(buf, safe_name); + buffer_append(buf, "

\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "

"); + char *query_string = getenv("QUERY_STRING"); + if (query_string && strstr(query_string, "error=1")) { + buffer_append(buf, "❌ Неверный пароль! Попробуйте снова."); + } + buffer_append(buf, "

\n"); + buffer_append(buf, " ← Вернуться на главную\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); +} + +void print_content(buffer_t *buf, const char *base_path, const char *display_path) { + DIR *dir; + struct dirent *entry; + struct stat file_stat; + char full_path[1024]; + entry_t *entries = malloc(sizeof(entry_t) * g_config.max_entries); + if (!entries) { + buffer_append(buf, "
Ошибка выделения памяти
"); + return; + } + int entry_count = 0, dir_count = 0, file_count = 0; + long long total_size = 0; + int is_recursive_search = 0; + char folder_name[256] = ""; + if (display_path && display_path[0]) { + char *last_slash = strrchr(display_path, '/'); + if (last_slash) strcpy(folder_name, last_slash + 1); + else strcpy(folder_name, display_path); + char *query_string = getenv("QUERY_STRING"); + char *password = NULL; + if (query_string) { + char *pass_start = strstr(query_string, "password="); + if (pass_start) { + pass_start += 9; + char *pass_end = strchr(pass_start, '&'); + int pass_len = pass_end ? (int)(pass_end - pass_start) : (int)strlen(pass_start); + if (pass_len > 0 && pass_len < 256) { + char pass_buf[256]; + strncpy(pass_buf, pass_start, pass_len); + pass_buf[pass_len] = '\0'; + char decoded_pass[256]; + url_decode_enhanced(pass_buf, decoded_pass, sizeof(decoded_pass)); + password = decoded_pass; + } + } + } + if (is_folder_protected(folder_name)) { + if (!password || !check_folder_password(folder_name, password)) { + print_password_form(buf, folder_name); + free(entries); + return; + } + } + } + if (g_params.search[0] != '\0') { + int result_count = 0; + search_recursive(g_config.base_path, "", g_params.search, entries, &result_count, g_config.max_entries); + if (result_count == 0) { + buffer_append(buf, "
\n"); + buffer_append(buf, "
🔍
\n"); + buffer_append(buf, "

Ничего не найдено

\n"); + buffer_append(buf, "

По запросу \""); + char safe_search[512]; + html_escape(g_params.search, safe_search, sizeof(safe_search)); + buffer_append(buf, safe_search); + buffer_append(buf, "\" ничего не найдено

\n"); + buffer_append(buf, "
\n"); + free(entries); + return; + } + entry_count = result_count; + is_recursive_search = 1; + for (int i = 0; i < entry_count; i++) { + if (entries[i].is_dir) { + dir_count++; + total_size += entries[i].dir_size; + } else { + file_count++; + total_size += entries[i].size; + } + } + } else { + dir = opendir(base_path); + if (!dir) { + char alt_path[1024]; + snprintf(alt_path, sizeof(alt_path), "%s", g_config.base_path); + if (display_path[0]) { + char *encoded = strdup(display_path); + url_decode_enhanced(encoded, alt_path + strlen(alt_path), sizeof(alt_path) - strlen(alt_path)); + free(encoded); + } + dir = opendir(alt_path); + if (!dir) { + buffer_append(buf, "
\n"); + buffer_append(buf, "
📁
\n"); + buffer_append(buf, "

Ошибка открытия директории

\n"); + char error_msg[512]; + snprintf(error_msg, sizeof(error_msg), "

Путь: %s

\n", base_path); + buffer_append(buf, error_msg); + snprintf(error_msg, sizeof(error_msg), "

Ошибка: %s

\n", strerror(errno)); + buffer_append(buf, error_msg); + buffer_append(buf, "

← Вернуться на главную

\n"); + buffer_append(buf, "
\n"); + free(entries); + return; + } + } + while ((entry = readdir(dir)) != NULL && entry_count < g_config.max_entries) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + int hidden = 0; + for (int i = 0; i < g_config.hidden_dirs_count; i++) { + if (strcmp(entry->d_name, g_config.hidden_dirs[i]) == 0) { hidden = 1; break; } + } + for (int i = 0; i < g_config.hidden_files_count; i++) { + if (strcmp(entry->d_name, g_config.hidden_files[i]) == 0) { hidden = 1; break; } + } + if (entry->d_name[0] == '.') hidden = 1; + if (hidden) continue; + snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name); + if (stat(full_path, &file_stat) == 0) { + strncpy(entries[entry_count].name, entry->d_name, sizeof(entries[0].name) - 1); + entries[entry_count].name[sizeof(entries[0].name) - 1] = '\0'; + if (S_ISDIR(file_stat.st_mode)) { + entries[entry_count].is_dir = 1; + entries[entry_count].size = 0; + entries[entry_count].mtime = file_stat.st_mtime; + entries[entry_count].file_count = count_files_in_dir(full_path); + entries[entry_count].dir_size = get_dir_size(full_path); + total_size += entries[entry_count].dir_size; + if (is_folder_protected(entry->d_name)) { + strcpy(entries[entry_count].icon, "🔒"); + entries[entry_count].is_protected = 1; + } else { + strcpy(entries[entry_count].icon, "📁"); + entries[entry_count].is_protected = 0; + } + char new_path[2048]; + snprintf(new_path, sizeof(new_path), "%s%s%s", display_path, display_path[0] ? "/" : "", entries[entry_count].name); + url_encode(new_path, entries[entry_count].encoded_path, sizeof(entries[0].encoded_path)); + dir_count++; + } else if (S_ISREG(file_stat.st_mode)) { + entries[entry_count].is_dir = 0; + entries[entry_count].size = file_stat.st_size; + entries[entry_count].mtime = file_stat.st_mtime; + entries[entry_count].file_count = 0; + entries[entry_count].dir_size = 0; + strcpy(entries[entry_count].icon, get_file_icon(entry->d_name)); + entries[entry_count].is_protected = 0; + char encoded_filename[1024]; + url_encode(entry->d_name, encoded_filename, sizeof(encoded_filename)); + snprintf(entries[entry_count].file_url, sizeof(entries[0].file_url), "%s%s%s", display_path, display_path[0] ? "/" : "", encoded_filename); + total_size += file_stat.st_size; + file_count++; + } else { + continue; + } + entry_count++; + } + } + closedir(dir); + if (entry_count == 0) { + buffer_append(buf, "
\n"); + buffer_append(buf, "
📄
\n"); + buffer_append(buf, "

Здесь пусто

\n"); + buffer_append(buf, "

В этой директории нет файлов или папок

\n"); + buffer_append(buf, "
\n"); + free(entries); + return; + } + } + qsort(entries, entry_count, sizeof(entry_t), compare_entries_sorted); + char encoded_path[1024]; + url_encode(display_path, encoded_path, sizeof(encoded_path)); + char safe_search[512]; + html_escape(g_params.search, safe_search, sizeof(safe_search)); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, " \n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, " Сортировка:\n"); + buffer_append(buf, " 📝 Имя\n"); + buffer_append(buf, " 📊 Размер\n"); + buffer_append(buf, " 📅 Дата\n"); + buffer_append(buf, "
\n"); + buffer_append(buf, "
\n"); + if (is_recursive_search) { + buffer_append(buf, "
"); + buffer_append(buf, "🔍 Результаты поиска по всему сайту: "); + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%d", entry_count); + buffer_append(buf, tmp); + buffer_append(buf, " файлов/папок найдено
\n"); + } + buffer_append(buf, "\n"); + if (is_recursive_search) { + char stats[256]; + snprintf(stats, sizeof(stats), + "
\n Найдено: папок %d | файлов %d\n
\n", + dir_count, file_count); + buffer_append(buf, stats); + } else { + char total_size_str[32]; + format_size(total_size, total_size_str); + char stats[256]; + snprintf(stats, sizeof(stats), + "
\n Папки: %d | Файлы: %d | Общий размер: %s\n
\n", + dir_count, file_count, total_size_str); + buffer_append(buf, stats); + } + free(entries); +} + +void print_template(const char *base_path, const char *display_path) { + FILE *file = fopen(g_config.template_path, "r"); + if (!file) { + printf("Error: Cannot read template\n"); + return; + } + buffer_t output; + buffer_init(&output); + char line[4096]; + while (fgets(line, sizeof(line), file)) { + if (strstr(line, "")) { + print_breadcrumb(&output, display_path); + } else if (strstr(line, "")) { + print_content(&output, base_path, display_path); + } else { + buffer_append(&output, line); + } + } + fclose(file); + fwrite(output.data, 1, output.size, stdout); + buffer_free(&output); +} diff --git a/src/render.h b/src/render.h new file mode 100644 index 0000000..12a0752 --- /dev/null +++ b/src/render.h @@ -0,0 +1,17 @@ +#ifndef RENDER_H +#define RENDER_H + +#include "fs.h" + +typedef struct { + char *data; + size_t size; + size_t capacity; +} buffer_t; + +void buffer_init(buffer_t *buf); +void buffer_append(buffer_t *buf, const char *str); +void buffer_free(buffer_t *buf); +void print_template(const char *base_path, const char *display_path); + +#endif diff --git a/src/render.o b/src/render.o new file mode 100644 index 0000000000000000000000000000000000000000..b5609ba7c4f503152707eb86a93ed9f8ad82bb5f GIT binary patch literal 28136 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�z z1Ylc^0y18xfQO*FVXFfx7wmPl6UJS9S~|Im{J}>xkQU6FH``uR?`!tMeD16$EiWxA zaaI+}OY2<0vT|--YUQje$hqLGGxD}UQGAYjq0GA!&vp3)y<2nfpPQdoHvt|BSuMzcgk>?g;8;gjmbD7igz|TenVUa( z>)5&Z_Qbfk`9)iD>+;JsjjzwI>^#xK5ugdQ(8@u6b&;WGOG?+hO zY;W#}x;0F&R)Xl2vK#QzF;f^C*QJi)4ry% z(Z?+K6tzopBuMtE*|oTxI_OFq7fZ?iRgfNnQYj}q_E@DC)uL&JrC=UTfp{G{Z+q2Z?_eoVv1(0#6ThStC0ZQXe5arh>Q zr+mpjTjSF!IWW!y9m#Qb} z5eoipuCN&ahE+z{h-yoKKg@^nJV8K>FduTsuBjh{ojTu*Z_agFbk_!14DCFQ)O z$-xh=a2}tmwQHWlYc;%4%6UhVvsmJP*6`(0&Sp){4U*qS=S-nyy4N}dvi*|(BaJV{ zXRh_MhOd?UO&We1+<%p=_b!!H-vM|*Mve5xImo z;CTc8CCT3@^`QL%Tpu#aSf`WD~fP74}7lHEyfRAM7LIYkb z{wz(WRnlL3FgfIn)$pE2P52K;~l|D^#xWWe7s z;3)$>WWdjZ@jp_(UueLK40weBpJ%|YG2mVU9x>pz0#0#bGP$8e`&YQ!V&HE#;P)Ev zhYk2+2K;9R+zR>Nop-3zYn8g^mEn&Qe`erMIsR1O&vg8mi9fUOrxJgv@W&~NP#Guj zoy2ugF(-*}Qb8w`bW%|#l`W^T#GgT&8N``MrDhU7ljO{#+?kX+izLh<&McBMi!_`?8qOk_v#9JW zDm#nH&Z4rFRJM}JRuW!Gc$L6OLKWp!k>pB}TtzagNM;qutfI12LM9>3G7{k|6S75V zDpyJ6oMi-634v764Emi(_)NlQ3WSQ4lkf`4t)Scr%AHR2Os8t5Q|@%iEhjam3l2$` zP8ClVI4L}xWID@;)rqG_a5bL1o`}^IYH#udyulWq)fVZ1 z>#*0;>9fKCD&8uksCWNO_%VXD$`|nk)}RFVUo!9whc6JZRyDy@tA7>d!e=}oss}X0 z>cm|D6~<~?d{`~i-sTB-eJz$h4C3)!Qd9cnlI3mlc~_@l`RWKN>GXs=9brqn|7;5R zyj`I%eg%XNy5Sua8U)_iiP}4`&Cpa(y9pn}HsK2i%iA6d`;gMKz`b~Gox5rA{P|Zm zENfa;H`m?JWO;)fPzP!k3Hg2DCVW!~I^Kk53$5UZG|@Li@|wO1f)>c<@1Ev%AIRu} z9>6NY(34GA8R`IMQM9QEJ_rZ|o1k|+`0@^oM4t#qo2EbAX~kw)txz~@wUXjMZ3%XP zCTl}}__hbW?g)!;3b9or2y0dc9Pn{9C4Ad37{~WF{ z;c^6~s5JjY1RvF%FE_ZhyP;deH6dT1{0oeou~M?zrm#QUu8J=+a$xeKm1zacsd6TCI4*$|9!^C*rNFVZQ!3^ z{E3YJxq&|pg9s$d#%KRZ{#g>&+j}14?fcTN%E9@o`D3 z__(jag!Z`*4#kff_R{fy81>n(FP+2Qj1t203>#{>8vk?Yf`w z`MmrD!?!U0uNcn#;VSu@AN5Z#{&fuJ{v2jFkIx$=j_pNLDLrEh=l#2l;daLV36sy; z^(%%)8UHZDZ(%t8Ek7n~7w`9ChHr&DrDvnWl|L*0yjtS_0Nibi-^%!W-dWA$-^KX1 zGMwA(0VapXw;wV-pT{3({7aa8^*#mL%jd^Ej9e zU%f}r_59Sp{|l3UDbs%pF3uq7a%=|tLWyJlI^az&2;eBQs( zApa@@{%t1bGFI<(2EKa#g6+DT@!JgiumQi#fJY^c@{5@Kgn@rIcWSAVREVsauyiyMNAG~FI{8cuV(yGR&UtA|4+uB#`q@~pT~Ji&a1lJR!SW0 zR>tJC8Te}%-^uu!4g7l;znt+OHt-)~{OOGUq=Emu0snV~^Em$=!+CuEK;meJ3RdqY z2L7KJAOGS~#l0NdOhVG_JVD|pe9+QvX94YzVGVqr&ekJ2y zZ{T|vzl!nw27V{w&u08}27a#r-)g`gVmP-8NZtG-!Sms zWc(V&f6KuCBje*UH`QPGuajZY{pZGffusIc!lC#fi6ftn_gfjx?Qn?U+nJpA8Gbjz zKax1s%j3fd#t$(5DaPmVVVvB^=?jLj(VR7`}tqZ7eQ!Az{4@a40|js>F5wxyXP!n4I}c&Qt?`I^!>3{3{In`38I; zljCA?mK*ph7{8J6TMYc50l(RR_b~ZaG5IkA{|5&AhX(v{CZEU2T?YOh#^-VJMFal; z)H3<^ zF+TUVM;L!D<3GW0?uWaW9InrE2K-efhtH?KFz|oH_}rg=Yv3O-;GY`s&zXGg&tvc< z1SH+BE@U|O=VFF)J2WzUJIGV<#4B<1=OqkZ&G@`u)-asQ-^Ap6o5_hA_&+e<4>CDR znVd%r{HGWn_sjC}!_WZ3uV!*yGsyW5#^-X5Fr3RdZjdtu9|l1}dvZAi4CittOI+{Y z3WoFky^`VF{wo;H`KuVt`D-MOdM<-Q`NJ&+ew6W-GyWY0{sWAE4dee4<8#0I7lv~^ zcQZNPVRBwD@ZV*4595Etc`0p{{h3NGMvAsSSfMz2mT&p z6~p;^ll2U@Gx@hO`FyW&C9ZzK`)+7(dAPyj?dloa_00hTp^FY-0Gm z3{OZL?cihh!;H`C{RzW)y-zYZtxV3d2L1r!b3gwj<99JRzhOA{|Bo2n$M`209%lHN zli>yuws#dA${#LeIQiRHWWhTHiKGAA2Z!R%XLtw07cn_)3}4Q0Kf^aLIrlSs8^ihg z^d}h}Vf=q%^1sLM-!VRylk;^TLBe+328U|bbcS;~Kf>?_82=fGqdgyF_;ZZ^5X1K~ zocBxd`9Ok%`rHJE(r1OlQT}R%?|^Ge$mepdVEZ7BuV(TehB8XN9j-By zllR!Cm=wNE+*%vtS>Ze7{c9So{;uGZhO565Xvq;7N)G)2H$tW1^&JsUGo0arQaZP( ztB|kVQ;Pqrid72VMS85#=5W|54F&NA>CRI4be7-3m$CBJ8;;;-(eU|Y2Yyak3jdCo zuXMqp<@hhvc~=7sMf=*CTH*Uo3=jX`$qo{*i8z<=R4Z?SvY%9*U0ujCzJta-ua)=e zR9Ppk1}+z8e64`>FA&7|Q&6%R8Yg$}CSy6c?)g z{n+s=sruEq7V<_azwRPY=)8PZ7%o-&Re9W72YhU4p-mY~qBkAKKy2%YOwh-FL7=w+uK>p>ix~&7p4yM=HM)ClyGz JrsGL3|Gx`N6KVhe literal 0 HcmV?d00001 diff --git a/src/status.c b/src/status.c new file mode 100644 index 0000000..a674bdc --- /dev/null +++ b/src/status.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +long get_nginx_memory() { + long total_kb = 0; + char command[] = "ps -o rss= -C nginx 2>/dev/null"; + + FILE *ps = popen(command, "r"); + if (!ps) return 0; + + char line[64]; + while (fgets(line, sizeof(line), ps)) { + long kb; + if (sscanf(line, "%ld", &kb) == 1) { + total_kb += kb; + } + } + pclose(ps); + + return total_kb; +} + +int get_process_memory(const char *process_name, long *memory_kb) { + char command[256]; + snprintf(command, sizeof(command), "ps -o rss= -C %s 2>/dev/null | head -1", process_name); + + FILE *ps = popen(command, "r"); + if (!ps) return 0; + + int result = fscanf(ps, "%ld", memory_kb); + pclose(ps); + + return result == 1; +} + +int main() { + printf("Content-type: text/plain; charset=utf-8\n\n"); + + long busybox_kb = 0, nginx_kb = 0; + + get_process_memory("busybox", &busybox_kb); + nginx_kb = get_nginx_memory(); + + printf("BusyBox: %ld KB | Nginx: %ld MB | Всего: %.1f MB", + busybox_kb, + nginx_kb / 1024, + (busybox_kb + nginx_kb) / 1024.0); + + return 0; +} diff --git a/src/style.c b/src/style.c new file mode 100644 index 0000000..818e8c1 --- /dev/null +++ b/src/style.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +int main() { + char css_path[1024] = "/home/romkazvo/www/cgi-bin/style.css"; + struct stat st; + + if (stat(css_path, &st) != 0) { + printf("Status: 404 Not Found\n"); + printf("Content-type: text/plain\n\n"); + printf("CSS file not found\n"); + return 1; + } + + printf("Content-type: text/css\n"); + printf("Cache-Control: public, max-age=3600\n\n"); + + FILE *css_file = fopen(css_path, "r"); + if (!css_file) { + printf("Status: 500 Internal Server Error\n"); + printf("Content-type: text/plain\n\n"); + printf("Cannot open CSS file\n"); + return 1; + } + + char buffer[4096]; + size_t bytes_read; + while ((bytes_read = fread(buffer, 1, sizeof(buffer), css_file)) > 0) { + fwrite(buffer, 1, bytes_read, stdout); + } + + fclose(css_file); + return 0; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..d1ee12d --- /dev/null +++ b/src/utils.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include "utils.h" + +char* my_strcasestr(const char *haystack, const char *needle) { + if (!haystack || !needle || *needle == '\0') return (char*)haystack; + size_t needle_len = strlen(needle); + while (*haystack) { + if (strncasecmp(haystack, needle, needle_len) == 0) return (char*)haystack; + haystack++; + } + return NULL; +} + +void html_escape(const char *src, char *dst, size_t dst_size) { + if (!src || !dst || dst_size == 0) return; + char *p = dst; + size_t i = 0; + while (*src && i < dst_size - 6) { + switch (*src) { + case '<': strcpy(p, "<"); p += 4; i += 4; break; + case '>': strcpy(p, ">"); p += 4; i += 4; break; + case '"': strcpy(p, """); p += 6; i += 6; break; + case '&': strcpy(p, "&"); p += 5; i += 5; break; + default: *p++ = *src; i++; break; + } + src++; + } + *p = '\0'; +} + +void format_size(long long size, char* buffer) { + if (size < 1024) snprintf(buffer, 32, "%lld B", size); + else if (size < 1024 * 1024) snprintf(buffer, 32, "%.1f KB", size / 1024.0); + else if (size < 1024 * 1024 * 1024) snprintf(buffer, 32, "%.1f MB", size / (1024.0 * 1024.0)); + else snprintf(buffer, 32, "%.1f GB", size / (1024.0 * 1024.0 * 1024.0)); +} + +void format_date(time_t mtime, char* buffer, size_t size) { + struct tm *tm_info = localtime(&mtime); + strftime(buffer, size, "%d.%m.%Y", tm_info); +} + +void url_encode(const char *src, char *dst, size_t dst_size) { + static const char *hex = "0123456789ABCDEF"; + char *p = dst; + size_t i = 0; + while (*src && i < dst_size - 3) { + unsigned char c = (unsigned char)*src; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || strchr("-_.~", c)) { + *p++ = c; i++; + } else if (c == ' ') { + *p++ = '%'; *p++ = '2'; *p++ = '0'; i += 3; + } else { + *p++ = '%'; *p++ = hex[(c >> 4) & 0xF]; *p++ = hex[c & 0xF]; i += 3; + } + src++; + } + *p = '\0'; +} + +void url_decode_enhanced(const char *src, char *dst, size_t dst_size) { + char *p = dst; + size_t decoded_len = 0; + while (*src && decoded_len < dst_size - 1) { + if (*src == '%') { + if (src[1] && src[2] && isxdigit(src[1]) && isxdigit(src[2])) { + char hex[3] = {src[1], src[2], '\0'}; + unsigned char c = (unsigned char)strtol(hex, NULL, 16); + if (c >= 0x80 || c >= 0x20 || c == 0x0A || c == 0x0D) { + *p++ = c; + decoded_len++; + } else { + *p++ = '_'; + decoded_len++; + } + src += 3; + } else { + src++; + } + } else if (*src == '+') { + *p++ = ' '; + decoded_len++; + src++; + } else { + *p++ = *src++; + decoded_len++; + } + } + *p = '\0'; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..0301302 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,13 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +void url_encode(const char *src, char *dst, size_t dst_size); +void url_decode_enhanced(const char *src, char *dst, size_t dst_size); +void html_escape(const char *src, char *dst, size_t dst_size); +char* my_strcasestr(const char *haystack, const char *needle); +void format_size(long long size, char* buffer); +void format_date(time_t mtime, char* buffer, size_t size); + +#endif diff --git a/src/utils.o b/src/utils.o new file mode 100644 index 0000000000000000000000000000000000000000..a65a6530219bb11a34a355ffbdad8bcce8adaa03 GIT binary patch literal 4128 zcmb_feQaCR6+h2OT+@&D0&Hr^hhm{51ZdvuP?}`1QoqDbUTA^}C2R|%L^F`zY+VbppFB)guZP66cmK)4Mr6FMrR<-hwViwLQ=ar$5}7eBfb92;MKP8v0k1le@<%-Ld6X@;UI-gvR=tUbnQ*Pj-nee z3|~>!UJ<5{44zf4F~ zgV}F!qq^ttGncd{8)#Qfda*f9XJ(eZi7i~DMy~%qvl2&z4-evB60Ueo|Hbe6k&Kzv z2Uq}~nuWhMnbx5ek6FTopK0xQMFP`Wu7QP9O;3%l;9_e>YJA6d!WhFU!s6MFK|ETy zdH%dM{}Wupuyu8$bnsf(e|eIIS33`L34v^DHsi^HnZt ztrmX&ap8gy*zw$lrGc}7Tb?_sl|LP^KB=X~B3qif;${1-RWYl=AGJytT9+==Yvm=a zT<a1P_0Xrgprw6Ch!Q;kb_`dh+J= z4O^e{i-McP*T=%9b#0`St%m)7y1Bkbdp^sx&s}L{eP$`F441|fn#0*_F?VhhuqBj zyYq&J31e z-VSUIYKxVi=Td%4VB3iZxoP3Ijba%0@^l@}6qohuiw|JZ)?{+h+Yha}KjGag^r+B7 zs3-N-l-~LzbVT%7@cBC*-1X4zuI?VAe;^bd#JE!S?WtM6?5pXCQectAt- zfQduL1aFlz&f{fQzuNRtUBBur)%UCIFE$ve?}$63b{95<)S&C9o7HYa47D8@$V3mE zrMZR2`iF?6(}TkiD||hcQH!BOGL{O$&S<9R!N3w>;YG#hFE%&&Ne<0A7oze}upF z_=_9huOm)zf+7yDRm9%hfd7`@d+~Kg!s`+B3jWs1``!jP7>R-%|q1erlyOUZfg8KNF9jeST+{T#ZdwNlJPXDG(oY{3{0_9G7`_lqBC(wWU{F! zi{z#c#vzxU$xf$PLV}Y~7Kdae7EQA06b`d&f*biPx~F5ANsh&)vOvgWoDdwCil$@n zNr*&Z?7&PsG7-TL62FCzYz6D^Vwm;w-bOu>JI!#{-RhH;kViF6C2>a*#N(^ z0q(_^Bs5(yW#0cTZ*So8-X|Tny!UesTn3~2NFw70MUu~I@O50?OVD!%QY<=w8Vi%_ zDQRWn$*9ia&oj{R21G%h$mKxKW~f7SzmE4%bYnS&*DjVxrQ&Jir!y?B4?Qy0kz>)= zv&f=Q@u^568^sIse-JOmpe?2vwo6cS9uem&$DGfcJ8^(0K}it$joJ$fz7Xd}wMQn^ zK1uC81ki>y;i9}~h|5ckyb>4TWS75hDCYm_Pwyp)iC?ETiOerPkgku({89&TglwvD zyPOsCm+O>ca{W?|;sE*kBths4!r$w_WnQVDz;S8YsUH5{$Bxu&C-+(5Z@)vtl>Xfg z2RZLrH2kDTW4-f#l@1)`XiWiisU)Po+!qS(%uOyqQIJJ3NYA2e_;dPGOy}7n1n&sq ZDs^n)SPtBZW9#|1Q$iH_9Q+~ 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 YBUCuo%f3w@)QbORhw@k#3J9s<-;RF#K>z>% literal 0 HcmV?d00001