[RecursiveBrowser] Make implementation not recursive.

Do stat when DT_UNKNOWN is given back when reading directory.

Issue: #1954
This commit is contained in:
Qball Cow 2024-05-12 13:41:32 +02:00
parent 5b9939b287
commit 9580c4a191
1 changed files with 127 additions and 73 deletions

View File

@ -178,81 +178,134 @@ static void recursive_browser_mode_init_current_dir(Mode *sw) {
} }
static void scan_dir(FileBrowserModePrivateData *pd, GFile *path) { static void scan_dir(FileBrowserModePrivateData *pd, GFile *path) {
char *cdir = g_file_get_path(path); GQueue *dirs_to_scan = g_queue_new();
DIR *dir = opendir(cdir); g_queue_push_tail(dirs_to_scan, g_object_ref(path));
if (dir) { GFile *dir_to_scan = NULL;
struct dirent *rd = NULL; while ( (dir_to_scan = g_queue_pop_head(dirs_to_scan)) != NULL) {
while (pd->end_thread == FALSE && (rd = readdir(dir)) != NULL) { char *cdir = g_file_get_path(dir_to_scan);
if (g_strcmp0(rd->d_name, "..") == 0) { DIR *dir = opendir(cdir);
continue; g_object_unref(dir_to_scan);
} if (dir) {
if (g_strcmp0(rd->d_name, ".") == 0) { struct dirent *rd = NULL;
continue; while (pd->end_thread == FALSE && (rd = readdir(dir)) != NULL) {
} if (g_strcmp0(rd->d_name, "..") == 0) {
if (pd->filter_regex && continue;
g_regex_match(pd->filter_regex, rd->d_name, 0, NULL)) { }
continue; if (g_strcmp0(rd->d_name, ".") == 0) {
} continue;
switch (rd->d_type) { }
case DT_BLK: if (pd->filter_regex &&
case DT_CHR: g_regex_match(pd->filter_regex, rd->d_name, 0, NULL)) {
case DT_FIFO: continue;
case DT_UNKNOWN: }
case DT_SOCK: switch (rd->d_type) {
default: case DT_BLK:
break; case DT_CHR:
case DT_REG: { case DT_FIFO:
FBFile *f = g_malloc0(sizeof(FBFile)); case DT_SOCK:
// Rofi expects utf-8, so lets convert the filename. default:
f->path = g_build_filename(cdir, rd->d_name, NULL); break;
f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL); case DT_REG: {
if (f->name == NULL) { FBFile *f = g_malloc0(sizeof(FBFile));
f->name = rofi_force_utf8(rd->d_name, -1); // Rofi expects utf-8, so lets convert the filename.
} f->path = g_build_filename(cdir, rd->d_name, NULL);
f->type = (rd->d_type == DT_DIR) ? DIRECTORY : RFILE; f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL);
f->icon_fetch_uid = 0; if (f->name == NULL) {
f->icon_fetch_size = 0; f->name = rofi_force_utf8(rd->d_name, -1);
f->link = FALSE; }
if (f->name == NULL) {
f->name = g_strdup("n/a");
}
f->type = (rd->d_type == DT_DIR) ? DIRECTORY : RFILE;
f->icon_fetch_uid = 0;
f->icon_fetch_size = 0;
f->link = FALSE;
g_async_queue_push(pd->async_queue, f); g_async_queue_push(pd->async_queue, f);
if (g_async_queue_length(pd->async_queue) > 10000) { if (g_async_queue_length(pd->async_queue) > 10000) {
write(pd->pipefd2[1], "r", 1); write(pd->pipefd2[1], "r", 1);
} }
break; break;
} }
case DT_DIR: { case DT_DIR: {
char *d = g_build_filename(cdir, rd->d_name, NULL); char *d = g_build_filename(cdir, rd->d_name, NULL);
GFile *dirp = g_file_new_for_path(d); GFile *dirp = g_file_new_for_path(d);
scan_dir(pd, dirp); g_queue_push_tail(dirs_to_scan, dirp);
g_object_unref(dirp); g_free(d);
g_free(d); break;
break; }
} case DT_UNKNOWN:
case DT_LNK: { case DT_LNK: {
FBFile *f = g_malloc0(sizeof(FBFile)); FBFile *f = g_malloc0(sizeof(FBFile));
// Rofi expects utf-8, so lets convert the filename. // Rofi expects utf-8, so lets convert the filename.
f->path = g_build_filename(cdir, rd->d_name, NULL); f->path = g_build_filename(cdir, rd->d_name, NULL);
f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL); f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL);
if (f->name == NULL) { if (f->name == NULL) {
f->name = rofi_force_utf8(rd->d_name, -1); f->name = rofi_force_utf8(rd->d_name, -1);
} }
f->icon_fetch_uid = 0; if (f->name == NULL) {
f->icon_fetch_size = 0; f->name = g_strdup("n/a");
f->link = TRUE; }
// Default to file. f->icon_fetch_uid = 0;
f->type = RFILE; f->icon_fetch_size = 0;
g_async_queue_push(pd->async_queue, f); // Default to file.
if (g_async_queue_length(pd->async_queue) > 10000) { f->type = RFILE;
write(pd->pipefd2[1], "r", 1); if (rd->d_type == DT_LNK) {
} f->link = TRUE;
break; } else {
} f->link = FALSE;
} }
} {
closedir(dir); // If we have link, use a stat to fine out what it is, if we fail, we
// mark it as file.
// TODO have a 'broken link' mode?
// Convert full path to right encoding.
// DD: Path should be in file encoding, not utf-8
// char *file =
// g_filename_from_utf8(pd->array[pd->array_length].path,
// -1, NULL, NULL, NULL);
// TODO: How to handle loops in links.
if (f->path) {
GStatBuf statbuf;
if (g_stat(f->path, &statbuf) == 0) {
if (S_ISDIR(statbuf.st_mode)) {
char *new_full_path = g_build_filename(cdir, rd->d_name, NULL);
g_free(f->path);
g_free(f->name);
g_free(f);
f = NULL;
GFile *dirp = g_file_new_for_path(new_full_path);
g_queue_push_tail(dirs_to_scan, dirp);
g_free(new_full_path);
break;
} else if (S_ISREG(statbuf.st_mode)) {
f->type = RFILE;
}
} else {
g_warning("Failed to stat file: %s, %s", f->path,
strerror(errno));
}
// g_free(file);
}
}
if (f != NULL) {
g_async_queue_push(pd->async_queue, f);
if (g_async_queue_length(pd->async_queue) > 10000) {
write(pd->pipefd2[1], "r", 1);
}
}
break;
}
}
}
closedir(dir);
}
g_free(cdir);
} }
g_free(cdir); g_queue_free(dirs_to_scan);
} }
static gpointer recursive_browser_input_thread(gpointer userdata) { static gpointer recursive_browser_input_thread(gpointer userdata) {
FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)userdata; FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)userdata;
@ -335,7 +388,8 @@ static unsigned int recursive_browser_mode_get_num_entries(const Mode *sw) {
return pd->array_length; return pd->array_length;
} }
static ModeMode recursive_browser_mode_result(Mode *sw, int mretv, G_GNUC_UNUSED char **input, static ModeMode recursive_browser_mode_result(Mode *sw, int mretv,
G_GNUC_UNUSED char **input,
unsigned int selected_line) { unsigned int selected_line) {
ModeMode retv = MODE_EXIT; ModeMode retv = MODE_EXIT;
FileBrowserModePrivateData *pd = FileBrowserModePrivateData *pd =