ICU-21386 uprv_tzname() should find the correct Olson ID when /etc/localtime is a "double" link
See #2323
diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp
index 747d37e..b8cbb9f 100644
--- a/icu4c/source/common/putil.cpp
+++ b/icu4c/source/common/putil.cpp
@@ -722,7 +722,7 @@ extern U_IMPORT char *U_TZNAME[];
#include <dirent.h> /* Needed to search through system timezone files */
#endif
static char gTimeZoneBuffer[PATH_MAX];
-static char *gTimeZoneBufferPtr = nullptr;
+static const char *gTimeZoneBufferPtr = nullptr;
#endif
#if !U_PLATFORM_USES_ONLY_WIN32_API
@@ -1171,16 +1171,16 @@ uprv_tzname(int n)
because the tzfile contents is underspecified.
This isn't guaranteed to work because it may not be a symlink.
*/
- int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1);
- if (0 < ret) {
+ char *ret = realpath(TZDEFAULT, gTimeZoneBuffer);
+ if (ret != nullptr && uprv_strcmp(TZDEFAULT, gTimeZoneBuffer) != 0) {
int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL);
- gTimeZoneBuffer[ret] = 0;
- char * tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
-
- if (tzZoneInfoTailPtr != nullptr
- && isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen))
- {
- return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
+ const char *tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
+ if (tzZoneInfoTailPtr != nullptr) {
+ tzZoneInfoTailPtr += tzZoneInfoTailLen;
+ skipZoneIDPrefix(&tzZoneInfoTailPtr);
+ if (isValidOlsonID(tzZoneInfoTailPtr)) {
+ return (gTimeZoneBufferPtr = tzZoneInfoTailPtr);
+ }
}
} else {
#if defined(SEARCH_TZFILE)
diff --git a/icu4c/source/common/uposixdefs.h b/icu4c/source/common/uposixdefs.h
index 23c3f6d..826c9bb 100644
--- a/icu4c/source/common/uposixdefs.h
+++ b/icu4c/source/common/uposixdefs.h
@@ -48,7 +48,7 @@
#endif
/*
- * Make sure things like readlink and such functions work.
+ * Make sure things like realpath and such functions work.
* Poorly upgraded Solaris machines can't have this defined.
* Cleanly installed Solaris can use this #define.
*
diff --git a/icu4c/source/test/depstest/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt
index 28a2dc7..d95e4de 100644
--- a/icu4c/source/test/depstest/dependencies.txt
+++ b/icu4c/source/test/depstest/dependencies.txt
@@ -22,7 +22,7 @@
exp_and_tanhf
stdlib_qsort
system_locale
- stdio_input stdio_output file_io readlink_function dir_io mmap_functions dlfcn
+ stdio_input stdio_output file_io realpath_function dir_io mmap_functions dlfcn
# C++
cplusplus iostream
std_mutex
@@ -110,8 +110,8 @@
# Additional symbols in an optimized build.
__xstat
-group: readlink_function
- readlink # putil.cpp uprv_tzname() calls this in a hack to get the time zone name
+group: realpath_function
+ realpath # putil.cpp uprv_tzname() calls this in a hack to get the time zone name
group: dir_io
opendir closedir readdir # for a hack to get the time zone name
@@ -869,7 +869,7 @@
PIC system_misc system_debug malloc_functions ubsan
c_strings c_string_formatting
floating_point system_locale
- stdio_input readlink_function dir_io
+ stdio_input realpath_function dir_io
dlfcn # Move related code into icuplug.c?
cplusplus
std_mutex