diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp index ca1dd445b3..d68e8da78f 100644 --- a/icu4c/source/common/putil.cpp +++ b/icu4c/source/common/putil.cpp @@ -834,7 +834,6 @@ static const char* remapShortTimeZone(const char *stdID, const char *dstID, int3 #endif #ifdef SEARCH_TZFILE -#define MAX_PATH_SIZE PATH_MAX /* Set the limit for the size of the path. */ #define MAX_READ_SIZE 512 typedef struct DefaultTZInfo { @@ -910,15 +909,19 @@ static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFil return result; } -/* - * This method recursively traverses the directory given for a matching TZ file and returns the first match. - */ + + /* dirent also lists two entries: "." and ".." that we can safely ignore. */ #define SKIP1 "." #define SKIP2 ".." -static char SEARCH_TZFILE_RESULT[MAX_PATH_SIZE] = ""; +static UBool U_CALLCONV putil_cleanup(void); +static CharString *gSearchTZFileResult = NULL; + +/* + * This method recursively traverses the directory given for a matching TZ file and returns the first match. + * This function is not thread safe - it uses a global, gSearchTZFileResult, to hold its results. + */ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) { - char curpath[MAX_PATH_SIZE]; DIR* dirp = opendir(path); DIR* subDirp = NULL; struct dirent* dirEntry = NULL; @@ -928,24 +931,40 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) { return result; } + if (gSearchTZFileResult == NULL) { + gSearchTZFileResult = new CharString; + if (gSearchTZFileResult == NULL) { + return NULL; + } + ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup); + } + /* Save the current path */ - uprv_memset(curpath, 0, MAX_PATH_SIZE); - uprv_strcpy(curpath, path); + UErrorCode status = U_ZERO_ERROR; + CharString curpath(path, -1, status); + if (U_FAILURE(status)) { + return NULL; + } /* Check each entry in the directory. */ while((dirEntry = readdir(dirp)) != NULL) { const char* dirName = dirEntry->d_name; if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0) { /* Create a newpath with the new entry to test each entry in the directory. */ - char newpath[MAX_PATH_SIZE]; - uprv_strcpy(newpath, curpath); - uprv_strcat(newpath, dirName); + CharString newpath(curpath, status); + newpath.append(dirName, -1, status); + if (U_FAILURE(status)) { + return NULL; + } - if ((subDirp = opendir(newpath)) != NULL) { + if ((subDirp = opendir(newpath.data())) != NULL) { /* If this new path is a directory, make a recursive call with the newpath. */ closedir(subDirp); - uprv_strcat(newpath, "/"); - result = searchForTZFile(newpath, tzInfo); + newpath.append('/', status); + if (U_FAILURE(status)) { + return NULL; + } + result = searchForTZFile(newpath.data(), tzInfo); /* Have to get out here. Otherwise, we'd keep looking and return the first match in the top-level directory @@ -957,11 +976,19 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) { if (result != NULL) break; } else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) { - if(compareBinaryFiles(TZDEFAULT, newpath, tzInfo)) { - const char* zoneid = newpath + (sizeof(TZZONEINFO)) - 1; + if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) { + int32_t amountToSkip = sizeof(TZZONEINFO) - 1; + if (amountToSkip > newpath.length()) { + amountToSkip = newpath.length(); + } + const char* zoneid = newpath.data() + amountToSkip; skipZoneIDPrefix(&zoneid); - uprv_strcpy(SEARCH_TZFILE_RESULT, zoneid); - result = SEARCH_TZFILE_RESULT; + gSearchTZFileResult->clear(); + gSearchTZFileResult->append(zoneid, -1, status); + if (U_FAILURE(status)) { + return NULL; + } + result = gSearchTZFileResult->data(); /* Get out after the first one found. */ break; } @@ -1150,6 +1177,9 @@ static UBool U_CALLCONV putil_cleanup(void) gTimeZoneFilesDirectory = NULL; gTimeZoneFilesInitOnce.reset(); + delete gSearchTZFileResult; + gSearchTZFileResult = NULL; + #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API if (gCorrectedPOSIXLocale) { uprv_free(gCorrectedPOSIXLocale); diff --git a/icu4c/source/tools/toolutil/filetools.cpp b/icu4c/source/tools/toolutil/filetools.cpp index 28a9b34ed1..b0d4ed81a5 100644 --- a/icu4c/source/tools/toolutil/filetools.cpp +++ b/icu4c/source/tools/toolutil/filetools.cpp @@ -6,6 +6,7 @@ ******************************************************************************* */ +#include "unicode/platform.h" #if U_PLATFORM == U_PF_MINGW // *cough* - for struct stat #ifdef __STRICT_ANSI__ @@ -15,6 +16,7 @@ #include "filetools.h" #include "filestrm.h" +#include "charstr.h" #include "cstring.h" #include "unicode/putil.h" #include "putilimp.h" @@ -29,8 +31,6 @@ #include typedef struct dirent DIRENT; -#define MAX_PATH_SIZE 4096 /* Set the limit for the size of the path. */ - #define SKIP1 "." #define SKIP2 ".." #endif @@ -58,20 +58,24 @@ isFileModTimeLater(const char *filePath, const char *checkAgainst, UBool isDir) while ((dirEntry = readdir(pDir)) != NULL) { if (uprv_strcmp(dirEntry->d_name, SKIP1) != 0 && uprv_strcmp(dirEntry->d_name, SKIP2) != 0) { - char newpath[MAX_PATH_SIZE] = ""; - uprv_strcpy(newpath, checkAgainst); - uprv_strcat(newpath, U_FILE_SEP_STRING); - uprv_strcat(newpath, dirEntry->d_name); + UErrorCode status = U_ZERO_ERROR; + icu::CharString newpath(checkAgainst, -1, status); + newpath.append(U_FILE_SEP_STRING, -1, status); + newpath.append(dirEntry->d_name, -1, status); + if (U_FAILURE(status)) { + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, u_errorName(status)); + return FALSE; + }; - if ((subDirp = opendir(newpath)) != NULL) { + if ((subDirp = opendir(newpath.data())) != NULL) { /* If this new path is a directory, make a recursive call with the newpath. */ closedir(subDirp); - isLatest = isFileModTimeLater(filePath, newpath, isDir); + isLatest = isFileModTimeLater(filePath, newpath.data(), isDir); if (!isLatest) { break; } } else { - int32_t latest = whichFileModTimeIsLater(filePath, newpath); + int32_t latest = whichFileModTimeIsLater(filePath, newpath.data()); if (latest < 0 || latest == 2) { isLatest = FALSE; break;