#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <stdbool.h>
#include <assert.h>
#include <sys/types.h>
#include <fcntl.h>
#include <zlib.h>
#include <errno.h>
#define MAX_THREADS 16
#define MAX_QUEUE 100000
#define PATH_MAX 512
#define CHUNK 16384
char* ignoreUUIDs = NULL;
char* base_dir = NULL;
char* cache_dir = NULL;
char* astc_bin = NULL;
typedef struct {
void (*function)(void *arg);
void *arg;
} Task;
typedef struct {
Task task_queue[MAX_QUEUE];
int front;
int rear;
int count;
int total_tasks;// 总共任务数
int done_tasks;// 完成任务数
pthread_mutex_t lock;
pthread_cond_t cond_task;
} ThreadPool;
ThreadPool pool;
int gzip_compress(const char *source, const char *out ) {
FILE *src = fopen(source, "rb");
if (!src) {
perror("打开源文件失败");
return -1;
}
// gzip 文件处理
gzFile dest_file = gzopen(out, "wb9"); // 使用最高压缩等级 '9'
if (!dest_file) {
perror("打开目的文件失败");
fclose(src);
return -1;
}
char inbuf[CHUNK];
int num_read;
while ((num_read = fread(inbuf, 1, sizeof(inbuf), src)) > 0) {
// 写入压缩文件
if (gzwrite(dest_file, inbuf, num_read) != num_read) {
perror("写入压缩文件失败");
gzclose(dest_file);
fclose(src);
return -1;
}
}
// 关闭文件
gzclose(dest_file);
fclose(src);
return 0;
}
// 添加任务到队列
void add_task(ThreadPool *pool, void (*function)(void *), void *arg) {
pthread_mutex_lock(&pool->lock);
assert(pool->count < MAX_QUEUE);
Task task;
task.function = function;
task.arg = arg;
pool->task_queue[pool->rear] = task;
pool->rear = (pool->rear + 1) % MAX_QUEUE;
pool->count++;
pthread_cond_signal(&pool->cond_task);
pthread_mutex_unlock(&pool->lock);
}
// 线程要执行的任务
void *worker(void *arg) {
while (1) {
Task task;
// 从队列取出任务时需要确保正确的锁搭配
pthread_mutex_lock(&pool.lock);
while (pool.count == 0) {
if(pool.total_tasks && pool.done_tasks >= pool.total_tasks) {
pthread_mutex_unlock(&pool.lock);
goto END;
}
pthread_cond_wait(&pool.cond_task, &pool.lock);
}
task = pool.task_queue[pool.front];
pool.front = (pool.front + 1) % MAX_QUEUE;
pool.count--;
pthread_mutex_unlock(&pool.lock);
(*(task.function))(task.arg);
pthread_mutex_lock(&pool.lock);
pool.done_tasks++;
if(pool.done_tasks >= pool.total_tasks) {
pthread_cond_broadcast(&pool.cond_task);
pthread_mutex_unlock(&pool.lock);
break;
}
pthread_mutex_unlock(&pool.lock);
}
END:
printf("worker %d: exit : %d, %d\n",*(int*)arg, pool.done_tasks, pool.total_tasks);
return NULL;
}
// 初始化线程池
void init_thread_pool(ThreadPool *pool, pthread_t threads[]) {
pool->front = 0;
pool->rear = 0;
pool->count = 0;
pool->total_tasks = 0;
pool->done_tasks = 0;
pthread_mutex_init(&pool->lock, NULL);
pthread_cond_init(&pool->cond_task, NULL);
for (int i = 0; i < MAX_THREADS; i++) {
int *arg = malloc(sizeof(*arg));
*arg = i;
pthread_create(&threads[i], NULL, worker, arg);
}
}
void task_function(void *arg) {
char* image = (char *)arg;
char imageGZ[PATH_MAX];
strcpy(imageGZ, image);
strcat(imageGZ, ".gz");
assert(gzip_compress(image, imageGZ)==0);
assert(rename(imageGZ, image)==0);
}
typedef struct {
char **files;
size_t count;
size_t capacity;
} FileList;
void init_file_list(FileList *list) {
list->count = 0;
list->capacity = 100; // 初始容量
list->files = malloc(list->capacity * sizeof(char *));
if (list->files == NULL) {
perror("Failed to allocate memory");
exit(EXIT_FAILURE);
}
}
void add_file(FileList *list, const char *file_path) {
if (list->count >= list->capacity) {
list->capacity *= 2;
list->files = realloc(list->files, list->capacity * sizeof(char *));
if (list->files == NULL) {
perror("Failed to reallocate memory");
exit(EXIT_FAILURE);
}
}
list->files[list->count] = strdup(file_path);
if (list->files[list->count] == NULL) {
perror("Failed to duplicate string");
exit(EXIT_FAILURE);
}
list->count++;
}
void free_file_list(FileList *list) {
for (size_t i = 0; i < list->count; i++) {
free(list->files[i]);
}
free(list->files);
}
int mkdir_p(const char *path) {
char tmp[512];
char *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
if (tmp[len - 1] == '/')
tmp[len - 1] = 0;
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0;
if (mkdir(tmp, S_IRWXU) != 0) {
if (errno != EEXIST) {
return -1;
}
}
*p = '/';
}
}
if (mkdir(tmp, S_IRWXU) != 0) {
if (errno != EEXIST) {
return -1;
}
}
return 0;
}
int check_file_extension(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename) {
return 0;
}
const char* extension = dot + 1;
if (strcmp(extension, "html") == 0) {
return 2;
}
return 0;
}
void find_images(const char *directory, FileList *file_list) {
DIR *dir;
struct dirent *entry;
struct stat entry_info;
if ((dir = opendir(directory)) == NULL) {
perror("Unable to open directory");
return;
}
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue; // 跳过当前目录和父目录
}
char path[1024];
snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);
if (stat(path, &entry_info) == 0) {
if (S_ISDIR(entry_info.st_mode)) {
// 如果是目录,递归调用
find_images(path, file_list);
} else if (S_ISREG(entry_info.st_mode)) {
// 如果是常规文件,检查扩展名
if (!check_file_extension(entry->d_name)) {
add_file(file_list, path);
}
}
}
}
closedir(dir);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <source_dir> \n", argv[0]);
return EXIT_FAILURE;
}
const char *source_dir = argv[1];
FileList image_files;
init_file_list(&image_files);
pthread_t threads[MAX_THREADS];
init_thread_pool(&pool, threads);
find_images(source_dir, &image_files);
pool.total_tasks = image_files.count;
if(image_files.count == 0){
goto END;
}
// 添加一些任务到队列中
for (size_t i = 0; i < image_files.count; i++) {
// printf("%s\n", image_files.files[i]);
add_task(&pool, task_function, image_files.files[i]);
}
for (int i = 0; i < MAX_THREADS; i++) {
pthread_join(threads[i], NULL);
}
free_file_list(&image_files);
// 等待线程池自己退出
pthread_mutex_lock(&pool.lock);
pthread_cond_broadcast(&pool.cond_task);
pthread_mutex_unlock(&pool.lock);
END:
printf("All tasks completed. Exiting main.\n");
return 0;
}