Progress.
This commit is contained in:
parent
ffec86df05
commit
e80e835939
173
main.c
173
main.c
@ -5,6 +5,7 @@
|
|||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -13,7 +14,6 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *path;
|
char *path;
|
||||||
@ -419,7 +419,8 @@ void rzf_sort_files(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rzf_draw_file_preview(WINDOW *win, const char *filepath) {
|
void rzf_draw_file_preview(WINDOW *win, const char *filepath) {
|
||||||
if (!win) return;
|
if (!win)
|
||||||
|
return;
|
||||||
werase(win);
|
werase(win);
|
||||||
box(win, 0, 0);
|
box(win, 0, 0);
|
||||||
|
|
||||||
@ -581,11 +582,17 @@ void *rzf_indexing_worker_func(void *arg) {
|
|||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
if (lstat(path, &statbuf) == 0) {
|
if (lstat(path, &statbuf) == 0) {
|
||||||
int is_dir = S_ISDIR(statbuf.st_mode);
|
int is_dir = S_ISDIR(statbuf.st_mode);
|
||||||
|
char real[PATH_MAX];
|
||||||
|
if (realpath(path, real) == NULL) /* canonical, absolute path */
|
||||||
|
continue;
|
||||||
local_batch[local_count].path = strdup(path);
|
local_batch[local_count].path = strdup(path);
|
||||||
local_batch[local_count].lower_path = rzf_to_lower(path);
|
local_batch[local_count].lower_path = rzf_to_lower(path);
|
||||||
if (!local_batch[local_count].path || !local_batch[local_count].lower_path) {
|
if (!local_batch[local_count].path ||
|
||||||
if (local_batch[local_count].path) free(local_batch[local_count].path);
|
!local_batch[local_count].lower_path) {
|
||||||
if (local_batch[local_count].lower_path) free(local_batch[local_count].lower_path);
|
if (local_batch[local_count].path)
|
||||||
|
free(local_batch[local_count].path);
|
||||||
|
if (local_batch[local_count].lower_path)
|
||||||
|
free(local_batch[local_count].lower_path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
local_batch[local_count].size = statbuf.st_size;
|
local_batch[local_count].size = statbuf.st_size;
|
||||||
@ -714,7 +721,7 @@ int rzf_recursive_delete(const char *path) {
|
|||||||
struct stat path_stat;
|
struct stat path_stat;
|
||||||
if (lstat(path, &path_stat) != 0)
|
if (lstat(path, &path_stat) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!S_ISDIR(path_stat.st_mode)) {
|
if (!S_ISDIR(path_stat.st_mode)) {
|
||||||
return remove(path);
|
return remove(path);
|
||||||
}
|
}
|
||||||
@ -762,7 +769,8 @@ void rzf_draw_help_window(int height, int width) {
|
|||||||
int start_y = (height - h) / 2;
|
int start_y = (height - h) / 2;
|
||||||
int start_x = (width - w) / 2;
|
int start_x = (width - w) / 2;
|
||||||
WINDOW *win = newwin(h, w, start_y, start_x);
|
WINDOW *win = newwin(h, w, start_y, start_x);
|
||||||
if (!win) return;
|
if (!win)
|
||||||
|
return;
|
||||||
box(win, 0, 0);
|
box(win, 0, 0);
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
mvwprintw(win, 1, (w - 10) / 2, "Shortcuts");
|
mvwprintw(win, 1, (w - 10) / 2, "Shortcuts");
|
||||||
@ -795,11 +803,13 @@ void rzf_draw_help_window(int height, int width) {
|
|||||||
|
|
||||||
bool rzf_show_confirmation(int height, int width, const char *message) {
|
bool rzf_show_confirmation(int height, int width, const char *message) {
|
||||||
int h = 3, w = strlen(message) + 8;
|
int h = 3, w = strlen(message) + 8;
|
||||||
if (w > width - 4) w = width - 4;
|
if (w > width - 4)
|
||||||
|
w = width - 4;
|
||||||
int start_y = (height - h) / 2;
|
int start_y = (height - h) / 2;
|
||||||
int start_x = (width - w) / 2;
|
int start_x = (width - w) / 2;
|
||||||
WINDOW *win = newwin(h, w, start_y, start_x);
|
WINDOW *win = newwin(h, w, start_y, start_x);
|
||||||
if (!win) return false;
|
if (!win)
|
||||||
|
return false;
|
||||||
box(win, 0, 0);
|
box(win, 0, 0);
|
||||||
mvwprintw(win, 1, 2, "%.*s (y/n)", w - 8, message);
|
mvwprintw(win, 1, 2, "%.*s (y/n)", w - 8, message);
|
||||||
wrefresh(win);
|
wrefresh(win);
|
||||||
@ -820,11 +830,13 @@ bool rzf_show_confirmation(int height, int width, const char *message) {
|
|||||||
|
|
||||||
char *rzf_prompt_for_command(int height, int width) {
|
char *rzf_prompt_for_command(int height, int width) {
|
||||||
int h = 3, w = 60;
|
int h = 3, w = 60;
|
||||||
if (w > width - 4) w = width - 4;
|
if (w > width - 4)
|
||||||
|
w = width - 4;
|
||||||
int start_y = (height - h) / 2;
|
int start_y = (height - h) / 2;
|
||||||
int start_x = (width - w) / 2;
|
int start_x = (width - w) / 2;
|
||||||
WINDOW *win = newwin(h, w, start_y, start_x);
|
WINDOW *win = newwin(h, w, start_y, start_x);
|
||||||
if (!win) return NULL;
|
if (!win)
|
||||||
|
return NULL;
|
||||||
box(win, 0, 0);
|
box(win, 0, 0);
|
||||||
mvwprintw(win, 1, 2, "Command: ");
|
mvwprintw(win, 1, 2, "Command: ");
|
||||||
wrefresh(win);
|
wrefresh(win);
|
||||||
@ -952,12 +964,75 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
pthread_mutex_lock(&files_mutex);
|
pthread_mutex_lock(&files_mutex);
|
||||||
int file_idx = filtered_indices[selected_index];
|
int file_idx = filtered_indices[selected_index];
|
||||||
if (file_idx < file_count) {
|
if (file_idx < file_count) {
|
||||||
*selected_file_path = strdup(files[file_idx].path);
|
if (files[file_idx].is_dir) {
|
||||||
command = strdup(files[file_idx].is_dir ? "xdg-open" : "vim");
|
// Navigate into directory
|
||||||
|
char *dir_path = strdup(files[file_idx].path);
|
||||||
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
|
||||||
|
if (dir_path && chdir(dir_path) == 0) {
|
||||||
|
// Clear the queue
|
||||||
|
pthread_mutex_lock(&queue_mutex);
|
||||||
|
for (int i = 0; i < queue_count; i++) {
|
||||||
|
int idx = (queue_head + i) % DIR_QUEUE_CAPACITY;
|
||||||
|
if (dir_queue[idx]) {
|
||||||
|
free(dir_queue[idx]);
|
||||||
|
dir_queue[idx] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queue_head = 0;
|
||||||
|
queue_tail = 0;
|
||||||
|
queue_count = 0;
|
||||||
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
|
||||||
|
// Clear files
|
||||||
|
pthread_mutex_lock(&files_mutex);
|
||||||
|
if (files) {
|
||||||
|
for (int i = 0; i < file_count; i++) {
|
||||||
|
free(files[i].path);
|
||||||
|
free(files[i].lower_path);
|
||||||
|
}
|
||||||
|
free(files);
|
||||||
|
}
|
||||||
|
files = NULL;
|
||||||
|
file_count = 0;
|
||||||
|
file_capacity = 0;
|
||||||
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
|
||||||
|
// Cancel and restart indexing
|
||||||
|
if (indexing_started && !indexing_complete) {
|
||||||
|
pthread_cancel(indexing_thread);
|
||||||
|
pthread_join(indexing_thread, NULL);
|
||||||
|
}
|
||||||
|
indexing_complete = false;
|
||||||
|
indexing_started = false;
|
||||||
|
producer_finished = false;
|
||||||
|
active_workers = 0;
|
||||||
|
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func, NULL);
|
||||||
|
|
||||||
|
search_query[0] = '\0';
|
||||||
|
selected_index = 0;
|
||||||
|
scroll_offset = 0;
|
||||||
|
}
|
||||||
|
if (dir_path) free(dir_path);
|
||||||
|
} else {
|
||||||
|
// Open file
|
||||||
|
char abs[PATH_MAX];
|
||||||
|
if (realpath(files[file_idx].path, abs))
|
||||||
|
*selected_file_path = strdup(abs); /* always absolute */
|
||||||
|
else /* fallback (shouldn't)*/
|
||||||
|
*selected_file_path = strdup(files[file_idx].path);
|
||||||
|
|
||||||
|
command = strdup("vim");
|
||||||
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
goto end_loop;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pthread_mutex_unlock(&files_mutex);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&files_mutex);
|
|
||||||
}
|
}
|
||||||
goto end_loop;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 27:
|
case 27:
|
||||||
case 3:
|
case 3:
|
||||||
goto end_loop;
|
goto end_loop;
|
||||||
@ -988,13 +1063,10 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
|
|
||||||
if (dot) {
|
if (dot) {
|
||||||
snprintf(backup_path, sizeof(backup_path), "%.*s/.%.*s%s%s.bak",
|
snprintf(backup_path, sizeof(backup_path), "%.*s/.%.*s%s%s.bak",
|
||||||
(int)dir_len, path,
|
(int)dir_len, path, (int)(dot - fname), fname, dt, dot);
|
||||||
(int)(dot - fname), fname,
|
|
||||||
dt, dot);
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(backup_path, sizeof(backup_path), "%.*s/.%s%s.bak",
|
snprintf(backup_path, sizeof(backup_path), "%.*s/.%s%s.bak",
|
||||||
(int)dir_len, path,
|
(int)dir_len, path, fname, dt);
|
||||||
fname, dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char cmd[PATH_MAX * 2 + 10];
|
char cmd[PATH_MAX * 2 + 10];
|
||||||
@ -1090,21 +1162,22 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
}
|
}
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
if (selected_count > 0) {
|
if (selected_count > 0) {
|
||||||
char **paths_to_delete = malloc(selected_count * sizeof(char*));
|
char **paths_to_delete = malloc(selected_count * sizeof(char *));
|
||||||
int *is_dir_flags = malloc(selected_count * sizeof(int));
|
int *is_dir_flags = malloc(selected_count * sizeof(int));
|
||||||
int delete_count = 0;
|
int delete_count = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&files_mutex);
|
pthread_mutex_lock(&files_mutex);
|
||||||
for (int i = 0; i < selected_count; i++) {
|
for (int i = 0; i < selected_count; i++) {
|
||||||
if (selected_indices[i] < file_count) {
|
if (selected_indices[i] < file_count) {
|
||||||
paths_to_delete[delete_count] = strdup(files[selected_indices[i]].path);
|
paths_to_delete[delete_count] =
|
||||||
|
strdup(files[selected_indices[i]].path);
|
||||||
is_dir_flags[delete_count] = files[selected_indices[i]].is_dir;
|
is_dir_flags[delete_count] = files[selected_indices[i]].is_dir;
|
||||||
if (paths_to_delete[delete_count])
|
if (paths_to_delete[delete_count])
|
||||||
delete_count++;
|
delete_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&files_mutex);
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
|
||||||
for (int i = 0; i < delete_count; i++) {
|
for (int i = 0; i < delete_count; i++) {
|
||||||
if (is_dir_flags[i])
|
if (is_dir_flags[i])
|
||||||
rzf_recursive_delete(paths_to_delete[i]);
|
rzf_recursive_delete(paths_to_delete[i]);
|
||||||
@ -1129,7 +1202,7 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&queue_mutex);
|
pthread_mutex_lock(&queue_mutex);
|
||||||
for (int i = 0; i < queue_count; i++) {
|
for (int i = 0; i < queue_count; i++) {
|
||||||
int idx = (queue_head + i) % DIR_QUEUE_CAPACITY;
|
int idx = (queue_head + i) % DIR_QUEUE_CAPACITY;
|
||||||
@ -1142,7 +1215,7 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
queue_tail = 0;
|
queue_tail = 0;
|
||||||
queue_count = 0;
|
queue_count = 0;
|
||||||
pthread_mutex_unlock(&queue_mutex);
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
|
||||||
pthread_mutex_lock(&files_mutex);
|
pthread_mutex_lock(&files_mutex);
|
||||||
if (files) {
|
if (files) {
|
||||||
for (int i = 0; i < file_count; i++) {
|
for (int i = 0; i < file_count; i++) {
|
||||||
@ -1155,7 +1228,7 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
file_count = 0;
|
file_count = 0;
|
||||||
file_capacity = 0;
|
file_capacity = 0;
|
||||||
pthread_mutex_unlock(&files_mutex);
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
|
||||||
if (indexing_started && !indexing_complete) {
|
if (indexing_started && !indexing_complete) {
|
||||||
pthread_cancel(indexing_thread);
|
pthread_cancel(indexing_thread);
|
||||||
pthread_join(indexing_thread, NULL);
|
pthread_join(indexing_thread, NULL);
|
||||||
@ -1164,7 +1237,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
indexing_started = false;
|
indexing_started = false;
|
||||||
producer_finished = false;
|
producer_finished = false;
|
||||||
active_workers = 0;
|
active_workers = 0;
|
||||||
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func, NULL);
|
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1222,7 +1296,7 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
queue_tail = 0;
|
queue_tail = 0;
|
||||||
queue_count = 0;
|
queue_count = 0;
|
||||||
pthread_mutex_unlock(&queue_mutex);
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
|
||||||
pthread_mutex_lock(&files_mutex);
|
pthread_mutex_lock(&files_mutex);
|
||||||
if (files) {
|
if (files) {
|
||||||
for (int i = 0; i < file_count; i++) {
|
for (int i = 0; i < file_count; i++) {
|
||||||
@ -1235,7 +1309,7 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
file_count = 0;
|
file_count = 0;
|
||||||
file_capacity = 0;
|
file_capacity = 0;
|
||||||
pthread_mutex_unlock(&files_mutex);
|
pthread_mutex_unlock(&files_mutex);
|
||||||
|
|
||||||
if (indexing_started && !indexing_complete) {
|
if (indexing_started && !indexing_complete) {
|
||||||
pthread_cancel(indexing_thread);
|
pthread_cancel(indexing_thread);
|
||||||
pthread_join(indexing_thread, NULL);
|
pthread_join(indexing_thread, NULL);
|
||||||
@ -1244,7 +1318,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
indexing_started = false;
|
indexing_started = false;
|
||||||
producer_finished = false;
|
producer_finished = false;
|
||||||
active_workers = 0;
|
active_workers = 0;
|
||||||
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func, NULL);
|
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func,
|
||||||
|
NULL);
|
||||||
search_query[0] = '\0';
|
search_query[0] = '\0';
|
||||||
selected_index = 0;
|
selected_index = 0;
|
||||||
scroll_offset = 0;
|
scroll_offset = 0;
|
||||||
@ -1280,7 +1355,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
free(fp);
|
free(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cmd) free(cmd);
|
if (cmd)
|
||||||
|
free(cmd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 22:
|
case 22:
|
||||||
@ -1312,7 +1388,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
current_file_count = file_count;
|
current_file_count = file_count;
|
||||||
if (current_file_count > filtered_capacity) {
|
if (current_file_count > filtered_capacity) {
|
||||||
filtered_capacity = current_file_count * 2;
|
filtered_capacity = current_file_count * 2;
|
||||||
int *new_filtered = realloc(filtered_indices, filtered_capacity * sizeof(int));
|
int *new_filtered =
|
||||||
|
realloc(filtered_indices, filtered_capacity * sizeof(int));
|
||||||
if (!new_filtered) {
|
if (!new_filtered) {
|
||||||
pthread_mutex_unlock(&files_mutex);
|
pthread_mutex_unlock(&files_mutex);
|
||||||
continue;
|
continue;
|
||||||
@ -1324,7 +1401,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
char search_pattern[256];
|
char search_pattern[256];
|
||||||
if (filter_start) {
|
if (filter_start) {
|
||||||
size_t len = filter_start - search_query;
|
size_t len = filter_start - search_query;
|
||||||
if (len >= sizeof(search_pattern)) len = sizeof(search_pattern) - 1;
|
if (len >= sizeof(search_pattern))
|
||||||
|
len = sizeof(search_pattern) - 1;
|
||||||
strncpy(search_pattern, search_query, len);
|
strncpy(search_pattern, search_query, len);
|
||||||
search_pattern[len] = '\0';
|
search_pattern[len] = '\0';
|
||||||
} else {
|
} else {
|
||||||
@ -1379,7 +1457,8 @@ char *rzf_run_interface(char **selected_file_path) {
|
|||||||
for (int i = 0; i < list_height && (i + scroll_offset) < filtered_count;
|
for (int i = 0; i < list_height && (i + scroll_offset) < filtered_count;
|
||||||
++i) {
|
++i) {
|
||||||
int current_index = i + scroll_offset;
|
int current_index = i + scroll_offset;
|
||||||
if (current_index >= filtered_count) continue;
|
if (current_index >= filtered_count)
|
||||||
|
continue;
|
||||||
int file_idx = filtered_indices[current_index];
|
int file_idx = filtered_indices[current_index];
|
||||||
if (file_idx >= file_count)
|
if (file_idx >= file_count)
|
||||||
continue;
|
continue;
|
||||||
@ -1500,7 +1579,7 @@ int main() {
|
|||||||
signal(SIGINT, rzf_cleanup_terminal);
|
signal(SIGINT, rzf_cleanup_terminal);
|
||||||
signal(SIGTERM, rzf_cleanup_terminal);
|
signal(SIGTERM, rzf_cleanup_terminal);
|
||||||
signal(SIGHUP, rzf_cleanup_terminal);
|
signal(SIGHUP, rzf_cleanup_terminal);
|
||||||
|
|
||||||
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func, NULL);
|
pthread_create(&indexing_thread, NULL, rzf_indexing_thread_func, NULL);
|
||||||
char *file_to_open = NULL;
|
char *file_to_open = NULL;
|
||||||
char *command = rzf_run_interface(&file_to_open);
|
char *command = rzf_run_interface(&file_to_open);
|
||||||
@ -1508,7 +1587,7 @@ int main() {
|
|||||||
pthread_cancel(indexing_thread);
|
pthread_cancel(indexing_thread);
|
||||||
}
|
}
|
||||||
pthread_join(indexing_thread, NULL);
|
pthread_join(indexing_thread, NULL);
|
||||||
|
|
||||||
pthread_mutex_lock(&queue_mutex);
|
pthread_mutex_lock(&queue_mutex);
|
||||||
for (int i = 0; i < queue_count; i++) {
|
for (int i = 0; i < queue_count; i++) {
|
||||||
int idx = (queue_head + i) % DIR_QUEUE_CAPACITY;
|
int idx = (queue_head + i) % DIR_QUEUE_CAPACITY;
|
||||||
@ -1518,13 +1597,18 @@ int main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&queue_mutex);
|
pthread_mutex_unlock(&queue_mutex);
|
||||||
|
|
||||||
if (command && file_to_open) {
|
if (command && file_to_open) {
|
||||||
reset_shell_mode();
|
reset_shell_mode();
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
execlp(command, command, file_to_open, NULL);
|
char abs_path[PATH_MAX];
|
||||||
perror("execlp failed");
|
if (realpath(file_to_open, abs_path)) {
|
||||||
|
execlp("vim", "vim", abs_path, (char *)NULL);
|
||||||
|
perror("execlp failed");
|
||||||
|
} else
|
||||||
|
perror("realpath");
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
wait(NULL);
|
wait(NULL);
|
||||||
@ -1533,8 +1617,9 @@ int main() {
|
|||||||
}
|
}
|
||||||
free(file_to_open);
|
free(file_to_open);
|
||||||
}
|
}
|
||||||
if (command) free(command);
|
if (command)
|
||||||
|
free(command);
|
||||||
|
|
||||||
rzf_free_files();
|
rzf_free_files();
|
||||||
rzf_free_bookmarks();
|
rzf_free_bookmarks();
|
||||||
pthread_mutex_destroy(&files_mutex);
|
pthread_mutex_destroy(&files_mutex);
|
||||||
|
Loading…
Reference in New Issue
Block a user