From ac130613ce3f8c3353dfc002ebf8b6b831536af6 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Mon, 8 Jul 2024 03:44:46 +0200 Subject: [PATCH] crnlib: additional way to test if a file is a directory For some unknown reasons open() fails at this point on macOS if the file is on a network file system and it is not in the current directory, same with `stat()` and variants. But opendir() works if the path is a directory, so let's assume what is not a directory is a regular file. This assumption may be wrong, this is why this guess is only done if two other implementations failed to detect the file type first. --- crnlib/crn_find_files.cpp | 42 ++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/crnlib/crn_find_files.cpp b/crnlib/crn_find_files.cpp index 0746c32c..bd14746b 100644 --- a/crnlib/crn_find_files.cpp +++ b/crnlib/crn_find_files.cpp @@ -206,24 +206,52 @@ bool find_files::find_internal(const char* pBasepath, const char* pRelpath, cons if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) continue; - bool is_directory = 0; - bool is_file = 0; + bool is_directory = false; + bool is_file = false; + bool guessed = false; - if ( ep->d_type != 0 ) { + if (ep->d_type != 0) { is_directory = (ep->d_type & DT_DIR) != 0; is_file = (ep->d_type & DT_REG) != 0; - } else { + guessed = true; + } + + /* Not all filesystems implement d_type. + See https://github.com/DaemonEngine/crunch/issues/37 */ + if (!guessed) { struct stat s; if (stat(ep->d_name, &s) == 0) { is_directory = S_ISDIR(s.st_mode); is_file = S_ISREG(s.st_mode); + guessed = true; } - else { - console::error("Cannot detect if given path is a file or a directory"); - return false; + } + + /* On macOS fails to open the file on a network file system + if the file is not in the current directory when running crunch. + See https://github.com/DaemonEngine/crunch/issues/63 */ + if (!guessed) { + DIR* df = opendir(ep->d_name); + if (df) { + is_directory = true; + guessed = true; + } else if (errno == ENOTDIR) { + // HACK: Assume it is a regular file if not a directory. + is_file = true; + guessed = true; } } + if (!guessed) { + console::error("Cannot detect if the given path is a file or a directory"); + return false; + } + + if (!is_file && !is_directory) { + console::error("The given path is not a file neither a directory"); + return false; + } + dynamic_string filename(ep->d_name); if (is_directory) {