From 59bfde6c0a2d0c225016950fb80011f4e4d41d61 Mon Sep 17 00:00:00 2001 From: rapperskull Date: Thu, 29 Feb 2024 23:22:16 +0100 Subject: [PATCH] Replace dirent implementation with one capable of detecting symlinks Now symlinks are skipped on Windows too --- .gitmodules | 3 + CMakeLists.txt | 6 ++ deps/dirent | 1 + extract-xiso.c | 79 +++++++++++++++----- win32/dirent.c | 195 ------------------------------------------------- 5 files changed, 70 insertions(+), 214 deletions(-) create mode 160000 deps/dirent delete mode 100644 win32/dirent.c diff --git a/.gitmodules b/.gitmodules index c273dc2..0be85d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "deps/asprintf"] path = deps/asprintf url = https://github.com/eiszapfen2000/asprintf.git +[submodule "deps/dirent"] + path = deps/dirent + url = https://github.com/tronkko/dirent.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 521a39f..d521dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCE_FILES ) set(DEPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps) +set(DIRENT_DIR ${DEPS_DIR}/dirent) set(GETOPT_DIR ${DEPS_DIR}/getopt_port) set(ASPRINTF_DIR ${DEPS_DIR}/asprintf) @@ -36,6 +37,11 @@ set_property(TARGET extract-xiso PROPERTY C_STANDARD 99) set_property(TARGET extract-xiso PROPERTY C_EXTENSIONS OFF) if(WIN32) + add_library(dirent INTERFACE) + target_include_directories(dirent INTERFACE ${DIRENT_DIR}/include) + + target_link_libraries(extract-xiso dirent) + add_library(getopt STATIC ${GETOPT_DIR}/getopt.c) target_sources(getopt PUBLIC ${GETOPT_DIR}/getopt.h) target_include_directories(getopt PUBLIC ${GETOPT_DIR}) diff --git a/deps/dirent b/deps/dirent new file mode 160000 index 0000000..57ff230 --- /dev/null +++ b/deps/dirent @@ -0,0 +1 @@ +Subproject commit 57ff23098eca49db016b8f66a12d31713f1c45d5 diff --git a/extract-xiso.c b/extract-xiso.c index cdaea0e..c5711ba 100644 --- a/extract-xiso.c +++ b/extract-xiso.c @@ -242,24 +242,14 @@ #if defined(__GNUC__) #define _GNU_SOURCE - #define unused __attribute__((__unused__)) #elif defined(_MSC_VER) #pragma warning(disable: 4706) // C4706: assignment within conditional expression - #define unused __pragma(warning(suppress:4100)) /* This unfortunately disables the warning for the whole line and the next one */ -#else - #define unused #endif #ifndef DEBUG #define DEBUG 0 #endif -#if DEBUG - #define unused_release -#else - #define unused_release unused -#endif - #include #include #include @@ -272,6 +262,7 @@ #include #include #include +#include /* Provided by CMake on Windows */ #include #include #include "cp1252/cp1252.c" @@ -283,10 +274,8 @@ #if defined(_WIN32) #include #include - #include "win32/dirent.c" #include /* Provided by CMake */ #else - #include #include #include #endif @@ -337,9 +326,6 @@ #define exiso_target "Windows" #if defined(_MSC_VER) - #define S_ISDIR(x) ((x) & _S_IFDIR) - #define S_ISREG(x) ((x) & _S_IFREG) - typedef SSIZE_T ssize_t; #define strcasecmp _stricmp #define strncasecmp _strnicmp @@ -353,7 +339,6 @@ #define lseek _lseeki64 #define mkdir(a, b) _mkdir(a) #define stat _stat64 - #define lstat _stat64 #define realpath(a, b) _fullpath(b, a, _MAX_PATH) #define bswap_16(x) _byteswap_ushort(x) @@ -425,6 +410,21 @@ typedef int64_t file_time_t; #define max(a, b) ( (a) > (b) ? (a) : (b) ) #endif +/* These definitions need to be after all the includes */ +#if defined(__GNUC__) + #define unused __attribute__((__unused__)) +#elif defined(_MSC_VER) + #define unused __pragma(warning(suppress:4100)) /* This unfortunately disables the warning for the whole line and the next one */ +#else + #define unused +#endif + +#if DEBUG + #define unused_release +#else + #define unused_release unused +#endif + #define exiso_version "2.7.1 (01.11.14)" #define VERSION_LENGTH 16 @@ -619,6 +619,9 @@ int calculate_directory_offsets( dir_node_avl *in_avl, uint32_t *io_context, int int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io_context, int in_depth ); int write_volume_descriptors( int in_xiso, uint32_t in_total_sectors ); +static int is_lnk_lstat(struct dirent* p, bool* lnk); +static int is_lnk(struct dirent* p, bool* lnk); + #if DEBUG void write_sector( int in_xiso, xoff_t in_start, const char *in_name, const char *in_extension ); #endif @@ -2014,6 +2017,41 @@ int calculate_directory_size( dir_node_avl *in_avl, uint32_t *out_size, int in_d return 0; } +static int is_lnk_lstat(struct dirent* p, bool* lnk) { + if (p == NULL || lnk == NULL) { + errno = EFAULT; + return -1; + } +#if !defined(_WIN32) + struct stat sb = { 0 }; + if (lstat(p->d_name, &sb) == -1) { + return -1; + } + *lnk = S_ISLNK(sb.st_mode); +#else + *lnk = false; +#endif // _WIN32 + return 0; +} + +static int is_lnk(struct dirent* p, bool* lnk) { + if (p == NULL || lnk == NULL) { + errno = EFAULT; + return -1; + } +#if defined(_DIRENT_HAVE_D_TYPE) + if (p->d_type == DT_UNKNOWN) { + return is_lnk_lstat(p, lnk); + } + else { + *lnk = (p->d_type == DT_LNK); + return 0; + } +#else + return is_lnk_lstat(p, lnk); +#endif // _DIRENT_HAVE_D_TYPE +} + int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { struct dirent *p = NULL; @@ -2021,7 +2059,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { dir_node_avl *avl = NULL; DIR *dir = NULL; int err = 0, i = 0, j = 0; - bool empty_dir = true; + bool empty_dir = true, lnk; if ( ( dir = opendir( "." ) ) == NULL ) mem_err(); @@ -2034,8 +2072,11 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { for ( j = i; j < *io_n; ++j ) exiso_log( "\b" ); *io_n = i; flush(); + + if (is_lnk(p, &lnk) == -1) read_err(); + else if (lnk) continue; - if ( ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == NULL ) mem_err(); + if (!err && ( avl = (dir_node_avl *) calloc( 1, sizeof(dir_node_avl) ) ) == NULL ) mem_err(); if (!err && (avl->filename = strdup(p->d_name)) == NULL) mem_err(); if (!err) { if (s_cp1252) { @@ -2043,7 +2084,7 @@ int generate_avl_tree_local( dir_node_avl **out_root, int *io_n ) { avl->filename = NULL; } else if ((avl->filename_cp1252 = getCP1252String(p->d_name)) == NULL) mem_err(); } - if ( ! err && lstat( p->d_name, &sb ) == -1 ) read_err(); + if ( ! err && stat( p->d_name, &sb ) == -1 ) read_err(); if ( ! err ) { if ( S_ISDIR( sb.st_mode ) ) { empty_dir = false; diff --git a/win32/dirent.c b/win32/dirent.c deleted file mode 100644 index 7accefc..0000000 --- a/win32/dirent.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - - Implementation of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifndef DIRENT_INCLUDED -#define DIRENT_INCLUDED - -/* - - Declaration of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct DIR DIR; - -struct dirent -{ - char *d_name; -}; - -DIR *opendir(const char *); -int closedir(DIR *); -struct dirent *readdir(DIR *); -void rewinddir(DIR *); - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#include -#include /* _findfirst and _findnext set errno iff they return -1 */ -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -struct DIR -{ - intptr_t handle; /* -1 for failed rewind */ - struct _finddata_t info; - struct dirent result; /* d_name null iff first time */ - char *name; /* null-terminated char string */ -}; - -DIR *opendir(const char *name) -{ - DIR *dir = 0; - - if(name && name[0]) - { - size_t base_length = strlen(name); - const char *all = /* search pattern must end with suitable wildcard */ - strchr("/\\", name[base_length - 1]) ? "*" : "/*"; - - if((dir = (DIR *) malloc(sizeof *dir)) != 0 && - (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) - { - strcat(strcpy(dir->name, name), all); - - if((dir->handle = _findfirst(dir->name, &dir->info)) != -1) - { - dir->result.d_name = 0; - } - else /* rollback */ - { - free(dir->name); - free(dir); - dir = 0; - } - } - else /* rollback */ - { - free(dir); - dir = 0; - errno = ENOMEM; - } - } - else - { - errno = EINVAL; - } - - return dir; -} - -int closedir(DIR *dir) -{ - int result = -1; - - if(dir) - { - if(dir->handle != -1) - { - result = _findclose(dir->handle); - } - - free(dir->name); - free(dir); - } - - if(result == -1) /* map all errors to EBADF */ - { - errno = EBADF; - } - - return result; -} - -struct dirent *readdir(DIR *dir) -{ - struct dirent *result = 0; - - if(dir && dir->handle != -1) - { - if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) - { - result = &dir->result; - result->d_name = dir->info.name; - } - } - else - { - errno = EBADF; - } - - return result; -} - -void rewinddir(DIR *dir) -{ - if(dir && dir->handle != -1) - { - _findclose(dir->handle); - dir->handle = _findfirst(dir->name, &dir->info); - dir->result.d_name = 0; - } - else - { - errno = EBADF; - } -} - -#ifdef __cplusplus -} -#endif - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/