Revert "Revert "Do not look for tzdata file in /data.""

This reverts commit 4e013233b85ad14b3e23dcbe15c1b7130ccce527.

Issue was in unexpected returned fd and errno value combination.
See comments in bionic.cpp and time_test.cpp.

Bug: 236967833
Fix: 236967833

Test: atest CtsBionicTestCases
Test: atest toybox-tests

Change-Id: I51b3e1527ff16b2a6ea4d6fedf8102019f7fd896
diff --git a/libc/tzcode/bionic.cpp b/libc/tzcode/bionic.cpp
index e134aaa..d2b5d80 100644
--- a/libc/tzcode/bionic.cpp
+++ b/libc/tzcode/bionic.cpp
@@ -190,6 +190,18 @@
     // Give up now, and don't try fallback tzdata files. We don't log here
     // because for all we know the given olson id was nonsense.
     close(fd);
+    // This file descriptor (-1) is passed to localtime.c. In invalid fd case
+    // upstream passes errno value around methods and having 0 there will
+    // indicate that time zone was found and read successfully and localtime's
+    // internal state was properly initialized (which wasn't as we couldn't find
+    // requested time zone in the tzdata file).
+    // If we reached this point errno is unlikely to be touched. It is only
+    // close(fd) which can do it, but that is very unlikely to happen. And
+    // even if it happens we can't extract any useful insights from it.
+    // We are overriding it to ENOENT as it matches upstream expectations -
+    // time zone is absent in the tzdata file == there is no TZif file in
+    // /usr/share/zoneinfo.
+    errno = ENOENT;
     return -1;
   }
 
@@ -206,24 +218,14 @@
 int __bionic_open_tzdata(const char* olson_id, int32_t* entry_length) {
   int fd;
 
-  // Try the three locations for the tzdata file in a strict order:
-  // 1: The O-MR1 time zone updates via APK update mechanism. This is
-  //    tried first because it allows us to test that the time zone updates
-  //    via APK mechanism still works even on devices with the time zone
-  //    module.
-  //    TODO: remove this when those devices are no longer supported.
-  // 2: The time zone data module which contains the main copy. This is the
+  // Try the two locations for the tzdata file in a strict order:
+  // 1: The time zone data module which contains the main copy. This is the
   //    common case for current devices.
-  // 3: The ultimate fallback: the non-updatable copy in /system.
+  // 2: The ultimate fallback: the non-updatable copy in /system.
 
 #if defined(__ANDROID__)
   // On Android devices, bionic has to work even if exec takes place without
   // environment variables set. So, all paths are hardcoded here.
-
-  fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/current/tzdata",
-                                 olson_id, entry_length);
-  if (fd >= -1) return fd;
-
   fd = __bionic_open_tzdata_path("/apex/com.android.tzdata/etc/tz/tzdata",
                                  olson_id, entry_length);
   if (fd >= -1) return fd;
@@ -233,16 +235,10 @@
   if (fd >= -1) return fd;
 #else
   // On the host, we don't expect the hard-coded locations above to exist, and
-  // we're not worried about security so we trust $ANDROID_DATA,
-  // $ANDROID_TZDATA_ROOT, and $ANDROID_ROOT to point us in the right direction
-  // instead.
+  // we're not worried about security so we trust $ANDROID_TZDATA_ROOT, and
+  // $ANDROID_ROOT to point us in the right direction instead.
 
-  char* path = make_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata");
-  fd = __bionic_open_tzdata_path(path, olson_id, entry_length);
-  free(path);
-  if (fd >= -1) return fd;
-
-  path = make_path("ANDROID_TZDATA_ROOT", "/etc/tz/tzdata");
+  char* path = make_path("ANDROID_TZDATA_ROOT", "/etc/tz/tzdata");
   fd = __bionic_open_tzdata_path(path, olson_id, entry_length);
   free(path);
   if (fd >= -1) return fd;
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 983a823..d86550d 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -84,6 +84,16 @@
   ASSERT_EQ(1970, broken_down->tm_year + 1900);
 }
 
+TEST(time, mktime_TZ_as_UTC_and_offset) {
+  struct tm tm = {.tm_year = 70, .tm_mon = 0, .tm_mday = 1};
+
+  // This TZ value is not a valid Olson ID and is not present in tzdata file,
+  // but is a valid TZ string according to POSIX standard.
+  setenv("TZ", "UTC+08:00:00", 1);
+  tzset();
+  ASSERT_EQ(static_cast<time_t>(8 * 60 * 60), mktime(&tm));
+}
+
 static void* gmtime_no_stack_overflow_14313703_fn(void*) {
   const char* original_tz = getenv("TZ");
   // Ensure we'll actually have to enter tzload by using a time zone that doesn't exist.