444 lines
14 KiB
C
444 lines
14 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <dirent.h>
|
||
#include <sys/stat.h>
|
||
#include <string.h>
|
||
#include <errno.h>
|
||
#include <locale.h>
|
||
|
||
#include <ctype.h>
|
||
|
||
#include <pthread.h>
|
||
|
||
#include "cJSON/cJSON.h"
|
||
|
||
|
||
#ifdef USE_JEMALLOC
|
||
const char *je_malloc_conf = "narenas:2,lg_chunk:20,stats_print:false";
|
||
#include <jemalloc/jemalloc.h>
|
||
#else
|
||
#define je_malloc(size) malloc(size)
|
||
#define je_calloc(nmemb, size) calloc((nmemb), (size))
|
||
#define je_realloc(ptr, size) realloc((ptr), (size))
|
||
#define je_free(ptr) free((ptr))
|
||
#include <stdint.h>
|
||
#endif
|
||
|
||
unsigned narenas = 4;
|
||
#define bool unsigned char
|
||
|
||
|
||
|
||
#define DEBUG 0
|
||
#define jemalloc 1
|
||
|
||
#if defined(DEBUG) && DEBUG > 1
|
||
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \
|
||
__FILE__, __LINE__, __func__, ##args)
|
||
#elif DEBUG == 1
|
||
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %d:%s(): " fmt, \
|
||
__LINE__, __func__, ##args)
|
||
#else
|
||
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
|
||
#endif
|
||
|
||
|
||
struct opts_struct{
|
||
int recursion;
|
||
int json;
|
||
char* dir;
|
||
};
|
||
struct opts_struct opts;
|
||
struct tred_pizdec{
|
||
char* name;
|
||
long int* size;
|
||
};
|
||
|
||
|
||
struct dir_list_struct{
|
||
struct metadata* top;
|
||
struct metadata* file;
|
||
struct dir_list_struct* next;
|
||
};
|
||
typedef struct metadata {
|
||
char* name;
|
||
bool tipe_dir;
|
||
long int size;
|
||
struct dir_list_struct* dir_list;
|
||
struct metadata* top;
|
||
struct dir_list_struct* jamp;
|
||
} stack_element;
|
||
|
||
#include "file.h"
|
||
#include "args_parser.h"
|
||
|
||
|
||
void dir_list_struct_init(struct dir_list_struct* dir_list_struct){
|
||
dir_list_struct->top = NULL;
|
||
dir_list_struct->file = NULL;
|
||
dir_list_struct->next = NULL;
|
||
}
|
||
void meta_data_init(struct metadata* metadata){
|
||
metadata->name = NULL;
|
||
metadata->dir_list = NULL;
|
||
metadata->top = NULL;
|
||
metadata->jamp = NULL;
|
||
}
|
||
|
||
// Функция для получения размера файла
|
||
long get_file_size(char* size) {
|
||
struct stat st;
|
||
DEBUG_PRINT("get_file_size START!\n");
|
||
DEBUG_PRINT("name: %s!\n", size);
|
||
if (stat(size, &st) == 0) {
|
||
return st.st_size;
|
||
}
|
||
return 0;
|
||
}
|
||
void* get_file_size_multi_tred(void *arg) {
|
||
struct tred_pizdec* mata = (struct tred_pizdec*) arg;
|
||
struct stat st;
|
||
DEBUG_PRINT("get_file_size START!\n");
|
||
DEBUG_PRINT("mata->name: %s!\n", mata->name);
|
||
if (stat(mata->name, &st) == 0) {
|
||
//return st.st_size;
|
||
*mata->size = st.st_size;
|
||
}
|
||
//DEBUG_PRINT("mata->size: %li!\n", *mata->size);
|
||
free(mata);
|
||
DEBUG_PRINT("СВОБОДА!!!\n");
|
||
return NULL;
|
||
}
|
||
|
||
void format_size(unsigned long long bytes, char *output, size_t output_size) {
|
||
const double KB = 1024.0;
|
||
const double MB = 1024.0 * KB;
|
||
const double GB = 1024.0 * MB;
|
||
const double TB = 1024.0 * GB;
|
||
|
||
if (bytes >= TB) {
|
||
snprintf(output, output_size, "%.2f TiB", bytes / TB);
|
||
} else if (bytes >= GB) {
|
||
snprintf(output, output_size, "%.2f GiB", bytes / GB);
|
||
} else if (bytes >= MB) {
|
||
snprintf(output, output_size, "%.2f MiB", bytes / MB);
|
||
} else if (bytes >= KB) {
|
||
snprintf(output, output_size, "%.2f KiB", bytes / KB);
|
||
} else {
|
||
snprintf(output, output_size, "%llu B", bytes);
|
||
}
|
||
}
|
||
|
||
struct metadata* metadata_create(bool tipe_dir,char* path, struct metadata* top){
|
||
DEBUG_PRINT("Пред mata malloc\n");
|
||
struct metadata* mata = je_malloc(sizeof(struct metadata));
|
||
meta_data_init(mata);
|
||
DEBUG_PRINT("После mata malloc\n");
|
||
mata->name = path;
|
||
mata->tipe_dir = tipe_dir;
|
||
mata->top = top;
|
||
if (tipe_dir){
|
||
mata->size = 0;
|
||
}
|
||
else{
|
||
mata->name = path;
|
||
mata->size = mata->size;
|
||
|
||
//struct metadata* mata_2 = mata;
|
||
/*
|
||
struct tred_pizdec* mata_2 = je_malloc(sizeof(struct tred_pizdec));
|
||
mata_2->name = path;
|
||
mata_2->size = &mata->size;
|
||
pthread_t thread;
|
||
pthread_create(&thread, NULL, get_file_size_multi_tred, (void*)mata_2);
|
||
pthread_join(thread, NULL);
|
||
*/
|
||
|
||
mata->size = get_file_size(path);
|
||
DEBUG_PRINT("Объём:%li - %s\n", mata->size, mata->name);
|
||
}
|
||
return mata;
|
||
}
|
||
|
||
void scanning(struct metadata *mata){
|
||
struct dirent *entry = NULL;
|
||
DIR *dp;
|
||
bool AAA = 1;
|
||
dp = opendir(mata->name);
|
||
DEBUG_PRINT("%i\n", errno);
|
||
/*
|
||
if (errno == 2){
|
||
printf("Нет такого файла или каталога!\n");
|
||
//printf("%s\n", strerror(errno));
|
||
printf("file: %s\n", mata->name);
|
||
}
|
||
else if (errno == 22){
|
||
printf("Недопустимый аргумент!\n");
|
||
//printf("%s\n", strerror(errno));
|
||
printf("file: %s\n", mata->name);
|
||
}
|
||
*/
|
||
if (errno == 13){
|
||
printf("Отказ в доступе!\n");
|
||
//printf("%s\n", strerror(errno));
|
||
}
|
||
else{
|
||
entry = readdir(dp);
|
||
}
|
||
|
||
//printf("TEST: %s\n", mata->name);
|
||
DEBUG_PRINT("TEST: %s\n", mata->name);
|
||
struct dir_list_struct* put_2;
|
||
|
||
|
||
//printf("%s\n", strerror(errno));
|
||
while(entry != NULL){
|
||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0){
|
||
entry = readdir(dp);
|
||
continue;
|
||
}
|
||
DEBUG_PRINT("mata->name: %s\n", mata->name);
|
||
DEBUG_PRINT("entry->d_name: %s\n", entry->d_name);
|
||
DEBUG_PRINT("Сум обём: %li\n", (strlen(mata->name) * sizeof(char) + strlen(entry->d_name) * sizeof(char) + sizeof(char)));
|
||
DEBUG_PRINT("mata->name обём: %li\n",(strlen(mata->name) * sizeof(char)));
|
||
DEBUG_PRINT("entry->d_name обём: %li\n",(strlen(entry->d_name) * sizeof(char)));
|
||
|
||
char* putaa = je_malloc(strlen(mata->name) + (strlen(entry->d_name)) + 2);
|
||
//snprintf(putaa, path_len, "%s/%s", mata->name, entry->d_name);
|
||
|
||
//char* putaa = malloc(sizeof(mata->name) + sizeof(entry->d_name) + sizeof(char));
|
||
DEBUG_PRINT("putaa готов! \n");
|
||
sprintf(putaa, "%s/%s",mata->name,entry->d_name);
|
||
DEBUG_PRINT("putaa обединён! \n");
|
||
struct metadata* SAS;
|
||
if (entry->d_type == DT_DIR){
|
||
SAS = metadata_create(1, putaa, mata);
|
||
}
|
||
else{
|
||
SAS = metadata_create(0, putaa, mata);
|
||
}
|
||
DEBUG_PRINT("SAS готов! \n");
|
||
if (AAA){
|
||
put_2 = je_malloc(sizeof(struct dir_list_struct));
|
||
dir_list_struct_init(put_2);
|
||
DEBUG_PRINT("put_2 1 готов!\n");
|
||
mata->dir_list = put_2;
|
||
AAA = 0;
|
||
}
|
||
else{
|
||
put_2->next = je_malloc(sizeof(struct dir_list_struct));
|
||
dir_list_struct_init(put_2->next);
|
||
DEBUG_PRINT("put_2 2 готов! \n");
|
||
put_2 = put_2->next;
|
||
}
|
||
put_2->top = mata;
|
||
put_2->file = SAS;
|
||
entry = readdir(dp);
|
||
}
|
||
closedir(dp);
|
||
DEBUG_PRINT("XXXXXXXXXXXXXs_3!\n");
|
||
}
|
||
|
||
void sum_dir(struct metadata* meta_data){
|
||
DEBUG_PRINT("Пред вычисляю объём!\n");
|
||
meta_data->size = 0;
|
||
if (meta_data->dir_list == NULL) return;
|
||
DEBUG_PRINT("Вычисляю объём!\n");
|
||
struct dir_list_struct* list = meta_data->dir_list;
|
||
while (list != NULL){
|
||
meta_data->size += list->file->size;
|
||
list = list->next;
|
||
|
||
}
|
||
DEBUG_PRINT("Объём готов!\n");
|
||
}
|
||
// Функция для сохранения кеша на диск
|
||
void save_cache(struct metadata** cache, int cache_size) {
|
||
FILE* file = fopen("cache.dat", "wb");
|
||
if (file != NULL) {
|
||
for (int i = 0; i < cache_size; i++) {
|
||
fwrite(cache[i], sizeof(struct metadata), 1, file);
|
||
}
|
||
fclose(file);
|
||
}
|
||
}
|
||
|
||
// Функция для загрузки кеша с диска
|
||
void load_cache(struct metadata** cache, int* cache_size) {
|
||
FILE* file = fopen("cache.dat", "rb");
|
||
if (file != NULL) {
|
||
struct metadata info;
|
||
while (fread(&info, sizeof(struct metadata), 1, file) == 1) {
|
||
(*cache_size)++;
|
||
cache[*cache_size] = malloc(sizeof(struct metadata));
|
||
memcpy(cache[*cache_size], &info, sizeof(struct metadata));
|
||
}
|
||
fclose(file);
|
||
}
|
||
}
|
||
|
||
void json_create(cJSON *main_Array, char* name, long int volume, cJSON *content_Array){
|
||
cJSON *main_ob = cJSON_CreateObject();
|
||
cJSON_AddItemToArray(main_Array, main_ob);
|
||
cJSON *name_js = cJSON_CreateString(name);
|
||
cJSON_AddItemToObject(main_ob, "name", name_js);
|
||
cJSON *volume_js = cJSON_CreateNumber(volume);
|
||
cJSON_AddItemToObject(main_ob, "volume", volume_js);
|
||
cJSON_AddItemToObject(main_ob, "content", content_Array);
|
||
|
||
}
|
||
|
||
void scan_dir(struct metadata *mata){
|
||
struct metadata *meta_data, *meta_data_tmp;
|
||
meta_data = mata;
|
||
if (meta_data->dir_list == NULL)
|
||
meta_data->jamp = meta_data->dir_list;
|
||
struct dir_list_struct* global_dir_list = meta_data->dir_list;
|
||
while(1){
|
||
//printf("%s%s",global_dir_list->file->name ,"\n");
|
||
DEBUG_PRINT("Цикол!\n");
|
||
//else if (meta_data->jamp->next != NULL)
|
||
// global_dir_list = meta_data->jamp->next;
|
||
while(global_dir_list != NULL){
|
||
DEBUG_PRINT("%s" ,"while global_dir_list\n");
|
||
if (global_dir_list->file->tipe_dir){
|
||
DEBUG_PRINT("Выполняю прыжок вниз!\n");
|
||
scanning(global_dir_list->file);
|
||
DEBUG_PRINT("%s%s",global_dir_list->file->name ," AAA \n");
|
||
meta_data_tmp = global_dir_list->file;
|
||
DEBUG_PRINT("%s --- dd\n", global_dir_list->file->name);
|
||
meta_data_tmp->jamp = global_dir_list;
|
||
meta_data = meta_data_tmp;
|
||
global_dir_list = meta_data->dir_list;
|
||
break;
|
||
}
|
||
else{
|
||
DEBUG_PRINT("Нaйден файл: %s\n",global_dir_list->file->name);
|
||
global_dir_list = global_dir_list->next;
|
||
DEBUG_PRINT("Прыгаю вперёд!\n");
|
||
}
|
||
//if (){}
|
||
|
||
}
|
||
if (global_dir_list == NULL){
|
||
DEBUG_PRINT("Глобальный список закончен, прыгаю верх за контрольную точку!\n");
|
||
//if (meta_data->jamp->next == NULL) printf("XXXXXXXX!\n");
|
||
if (meta_data->jamp != NULL && meta_data->jamp->next != NULL ){
|
||
if(meta_data->tipe_dir) sum_dir(meta_data);
|
||
global_dir_list = meta_data->jamp->next;
|
||
meta_data = meta_data->jamp->next->file;
|
||
}
|
||
else{
|
||
DEBUG_PRINT("Контлоьные точки закончелись, поднимаюсь!\n");
|
||
if(meta_data->tipe_dir)sum_dir(meta_data);
|
||
if (meta_data->top == NULL){
|
||
DEBUG_PRINT("Подём отменён!\n");
|
||
break;
|
||
}
|
||
DEBUG_PRINT("Подём!\n");
|
||
meta_data = meta_data->top;
|
||
}
|
||
}
|
||
}
|
||
DEBUG_PRINT("Готово!\n");
|
||
}
|
||
bool js_logok, int_depth=0;
|
||
|
||
cJSON *print_statistik(cJSON *main_Array, struct dir_list_struct* list, char* output, int i){
|
||
//cJSON *main_Array = cJSON_CreateArray();
|
||
cJSON *content_Array;
|
||
do{
|
||
format_size(list->file->size, output, sizeof(output));
|
||
printf("%s\t%li\t%s\n", output, list->file->size, list->file->name);
|
||
DEBUG_PRINT("%s\t%li\t%s\n", output, list->file->size, list->file->name);
|
||
if (js_logok){
|
||
DEBUG_PRINT("int_depth: %i\n", int_depth);
|
||
if (list->file->tipe_dir && (list->file->dir_list != NULL) && (int_depth != i)){
|
||
DEBUG_PRINT("Рекурсируем!\n");
|
||
DEBUG_PRINT("Каталог вниз: %s!\n", list->file->name);
|
||
DEBUG_PRINT("Глубина: %i!\n", i);
|
||
cJSON *main_Array_2 = cJSON_CreateArray();
|
||
content_Array = print_statistik(main_Array_2, list->file->dir_list, output, i + 1);
|
||
DEBUG_PRINT("AA: %s\n", cJSON_Print(content_Array));
|
||
DEBUG_PRINT("Верх!\n");
|
||
}
|
||
else{
|
||
DEBUG_PRINT("Конец рекурсии!\n");
|
||
content_Array = cJSON_CreateArray();
|
||
}
|
||
DEBUG_PRINT("json_create main_Array!\n");
|
||
DEBUG_PRINT("Имя: %s!\n", list->file->name);
|
||
DEBUG_PRINT("До: %s\n", cJSON_Print(main_Array));
|
||
json_create(main_Array, list->file->name, list->file->size, content_Array);
|
||
DEBUG_PRINT("После: %s\n", cJSON_Print(main_Array));
|
||
|
||
}
|
||
DEBUG_PRINT("прыгаем_1!\n");
|
||
list = list->next;
|
||
DEBUG_PRINT("прыгаем_2!\n");
|
||
}while(list != NULL);
|
||
return main_Array;
|
||
}
|
||
|
||
int main(int argc, char *argv[]){
|
||
//mallctl("opt.narenas", NULL, NULL, &narenas, sizeof(narenas));
|
||
char *path;
|
||
setlocale(LC_ALL, "");
|
||
//printf("Your locale is: %s\n", setlocale(LC_CTYPE, NULL));
|
||
opts.json=0;
|
||
args_pars(&argc, argv);
|
||
/*
|
||
Options opts;
|
||
if (!parse_args(argc, argv, &opts)) {
|
||
return 1;
|
||
}
|
||
*/
|
||
|
||
printf("Путь: %s\n", opts.dir);
|
||
printf("Флаг -j: %s\n", opts.json ? "да" : "нет");
|
||
if (opts.recursion) {
|
||
printf("Флаг -r: да, значение: %d\n", opts.recursion);
|
||
} else {
|
||
printf("Флаг -r: нет\n");
|
||
}
|
||
js_logok = opts.json;
|
||
int_depth = opts.recursion;
|
||
path = opts.dir;
|
||
|
||
struct metadata * mata = je_malloc(sizeof(stack_element));
|
||
meta_data_init(mata);
|
||
mata->name = path;
|
||
mata->tipe_dir = 1;
|
||
scanning(mata);
|
||
scan_dir(mata);
|
||
/*
|
||
struct metadata * mata = je_malloc(sizeof(stack_element));
|
||
nanaaa_2(mata);
|
||
printf("AAAA0: %s\n", mata->name);
|
||
printf("AAAA1: %s\n", mata->dir_list->file->name);
|
||
printf("tipe_dir: %i\n", mata->dir_list->file->tipe_dir);
|
||
printf("size: %li\n", mata->dir_list->file->size);
|
||
if (mata->dir_list->next == NULL) printf("SUKA\n");
|
||
//printf("AAAA2: %s\n", mata->dir_list->next->file->name);
|
||
//printf("AAAA2: %s\n", mata->dir_list->file->dir_list->file->name);
|
||
*/
|
||
|
||
char output[64];
|
||
struct dir_list_struct* list = mata->dir_list;
|
||
cJSON *main_Array = cJSON_CreateArray();
|
||
main_Array = print_statistik(main_Array, list, output, 0);
|
||
//while(list->next != NULL);
|
||
//save_cache(mata, int cache_size)
|
||
DEBUG_PRINT("ПППП!\n");
|
||
char *string = cJSON_Print(main_Array);
|
||
DEBUG_PRINT("ччччч!\n");
|
||
printf("AA: %s\n", string);
|
||
printf("%s","bye.\n");
|
||
|
||
//file_weit(mata);
|
||
|
||
nanaaa(mata);
|
||
|
||
|
||
return 0;
|
||
}
|