From fb27a633e4473c6780b80dcb7e2028a75e0e2b3b Mon Sep 17 00:00:00 2001 From: elasota <1137273+elasota@users.noreply.github.com> Date: Mon, 25 Dec 2023 21:21:20 -0500 Subject: [PATCH] Handle backslashes in paths on Windows --- lib/helper.c | 20 ++++++++++++++++++-- lib/internal.h | 1 + lib/libunshield.c | 2 +- src/unshield.c | 22 +++++++++++++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/lib/helper.c b/lib/helper.c index 25ed46a..f77772a 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -43,7 +43,7 @@ long int unshield_get_path_max(Unshield* unshield) char *unshield_get_base_directory_name(Unshield *unshield) { long int path_max = unshield_get_path_max(unshield); - char *p = strrchr(unshield->filename_pattern, '/'); + char *p = unshield_get_last_path_separator(unshield->filename_pattern); char *dirname = malloc(path_max); if (p) { @@ -95,7 +95,7 @@ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suff DIR *sourcedir = NULL; long int path_max = unshield_get_path_max(unshield); - q=strrchr(filename,'/'); + q=unshield_get_last_path_separator(filename); if (q) q++; else @@ -202,6 +202,22 @@ uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset) return NULL; } +/** + Returns the last path separator in a filesystem path + */ +char *unshield_get_last_path_separator(char *path) +{ + char *p = strrchr(path, '/'); + +#ifdef WIN32 + char *pbs = strrchr(path, '\\'); + + if (NULL != pbs && (NULL == p || pbs > p)) + return pbs; +#endif + + return p; +} static int unshield_strlen_utf16(const uint16_t* utf16) { diff --git a/lib/internal.h b/lib/internal.h index 9faf414..f9d091d 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -85,6 +85,7 @@ bool unshield_read_common_header(uint8_t** buffer, CommonHeader* common); const char* unshield_get_utf8_string(Header* header, const void* buffer); const char* unshield_header_get_string(Header* header, uint32_t offset); uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset); +char *unshield_get_last_path_separator(char *path); static inline void* unshield_fopen(Unshield* unshield, const char *filename, const char *modes) { diff --git a/lib/libunshield.c b/lib/libunshield.c index e3dd06a..7b8edf2 100644 --- a/lib/libunshield.c +++ b/lib/libunshield.c @@ -97,7 +97,7 @@ static bool unshield_create_filename_pattern(Unshield* unshield, const char* fil { char pattern[256]; char* prefix = strdup(filename); - char* p = strrchr(prefix, '/'); + char* p = unshield_get_last_path_separator(prefix); if (!p) p = prefix; diff --git a/src/unshield.c b/src/unshield.c index 470a397..62b1baf 100644 --- a/src/unshield.c +++ b/src/unshield.c @@ -96,15 +96,35 @@ static bool make_sure_directory_exists(const char* directory)/*{{{*/ p+=2; else if (0 == strncmp(p, "../", 3)) p+=3; +#ifdef WIN32 + if ('\\' == *p) + p++; + else if (0 == strncmp(p, ".\\", 2)) + p += 2; + else if (0 == strncmp(p, "..\\", 3)) + p += 3; +#endif else { + int is_win_root = 0; const char* slash = strchr(p, '/'); +#ifdef WIN32 + const char* backslash = strchr(p, '\\'); + if (NULL != backslash && (NULL == slash || backslash < slash)) + slash = backslash; +#endif + current = strdup(directory); if (slash) current[slash-directory] = '\0'; - if (stat(current, &dir_stat) < 0) +#ifdef WIN32 + if (slash - directory == 2 && current[1] == ':') + is_win_root = 1; +#endif + + if (!is_win_root && stat(current, &dir_stat) < 0) { #if defined (__MINGW32__) || defined (_WIN32) if (_mkdir(current) < 0)