487 lines
15 KiB
Diff
Executable File
487 lines
15 KiB
Diff
Executable File
From 07654f80f1dc979b825c8c26c45e683547d20941 Mon Sep 17 00:00:00 2001
|
|
From: s00478819 <sunjianye@huawei.com>
|
|
Date: Mon, 25 Oct 2021 17:38:14 +0800
|
|
Subject: [PATCH 1/4] 8273111: Default timezone should return zone ID if
|
|
/etc/localtime is valid but not canonicalization on linux
|
|
|
|
---
|
|
jdk/make/lib/ServiceabilityLibraries.gmk | 1 +
|
|
.../solaris/native/java/io/canonicalize_md.c | 144 +--------------
|
|
jdk/src/solaris/native/java/io/path_util.c | 166 ++++++++++++++++++
|
|
jdk/src/solaris/native/java/io/path_util.h | 31 ++++
|
|
.../solaris/native/java/util/TimeZone_md.c | 61 +++----
|
|
5 files changed, 230 insertions(+), 173 deletions(-)
|
|
create mode 100644 jdk/src/solaris/native/java/io/path_util.c
|
|
create mode 100644 jdk/src/solaris/native/java/io/path_util.h
|
|
|
|
diff --git a/jdk/make/lib/ServiceabilityLibraries.gmk b/jdk/make/lib/ServiceabilityLibraries.gmk
|
|
index 36b6c6811..2c80ffc00 100644
|
|
--- a/jdk/make/lib/ServiceabilityLibraries.gmk
|
|
+++ b/jdk/make/lib/ServiceabilityLibraries.gmk
|
|
@@ -225,6 +225,7 @@ LIBINSTRUMENT_FILES := \
|
|
PathCharsValidator.c \
|
|
Reentrancy.c \
|
|
Utilities.c \
|
|
+ path_util.c \
|
|
canonicalize_md.c
|
|
|
|
LIBINSTRUMENT_DIR := $(JDK_OUTPUTDIR)/objs/libinstrument
|
|
diff --git a/jdk/src/solaris/native/java/io/canonicalize_md.c b/jdk/src/solaris/native/java/io/canonicalize_md.c
|
|
index cb8ce69c8..2bd1ef2cd 100644
|
|
--- a/jdk/src/solaris/native/java/io/canonicalize_md.c
|
|
+++ b/jdk/src/solaris/native/java/io/canonicalize_md.c
|
|
@@ -33,154 +33,12 @@
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
-#if !defined(_ALLBSD_SOURCE)
|
|
-#include <alloca.h>
|
|
-#endif
|
|
+#include "path_util.h"
|
|
|
|
|
|
/* Note: The comments in this file use the terminology
|
|
defined in the java.io.File class */
|
|
|
|
-
|
|
-/* Check the given name sequence to see if it can be further collapsed.
|
|
- Return zero if not, otherwise return the number of names in the sequence. */
|
|
-
|
|
-static int
|
|
-collapsible(char *names)
|
|
-{
|
|
- char *p = names;
|
|
- int dots = 0, n = 0;
|
|
-
|
|
- while (*p) {
|
|
- if ((p[0] == '.') && ((p[1] == '\0')
|
|
- || (p[1] == '/')
|
|
- || ((p[1] == '.') && ((p[2] == '\0')
|
|
- || (p[2] == '/'))))) {
|
|
- dots = 1;
|
|
- }
|
|
- n++;
|
|
- while (*p) {
|
|
- if (*p == '/') {
|
|
- p++;
|
|
- break;
|
|
- }
|
|
- p++;
|
|
- }
|
|
- }
|
|
- return (dots ? n : 0);
|
|
-}
|
|
-
|
|
-
|
|
-/* Split the names in the given name sequence,
|
|
- replacing slashes with nulls and filling in the given index array */
|
|
-
|
|
-static void
|
|
-splitNames(char *names, char **ix)
|
|
-{
|
|
- char *p = names;
|
|
- int i = 0;
|
|
-
|
|
- while (*p) {
|
|
- ix[i++] = p++;
|
|
- while (*p) {
|
|
- if (*p == '/') {
|
|
- *p++ = '\0';
|
|
- break;
|
|
- }
|
|
- p++;
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
-/* Join the names in the given name sequence, ignoring names whose index
|
|
- entries have been cleared and replacing nulls with slashes as needed */
|
|
-
|
|
-static void
|
|
-joinNames(char *names, int nc, char **ix)
|
|
-{
|
|
- int i;
|
|
- char *p;
|
|
-
|
|
- for (i = 0, p = names; i < nc; i++) {
|
|
- if (!ix[i]) continue;
|
|
- if (i > 0) {
|
|
- p[-1] = '/';
|
|
- }
|
|
- if (p == ix[i]) {
|
|
- p += strlen(p) + 1;
|
|
- } else {
|
|
- char *q = ix[i];
|
|
- while ((*p++ = *q++));
|
|
- }
|
|
- }
|
|
- *p = '\0';
|
|
-}
|
|
-
|
|
-
|
|
-/* Collapse "." and ".." names in the given path wherever possible.
|
|
- A "." name may always be eliminated; a ".." name may be eliminated if it
|
|
- follows a name that is neither "." nor "..". This is a syntactic operation
|
|
- that performs no filesystem queries, so it should only be used to cleanup
|
|
- after invoking the realpath() procedure. */
|
|
-
|
|
-static void
|
|
-collapse(char *path)
|
|
-{
|
|
- char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
|
|
- int nc;
|
|
- char **ix;
|
|
- int i, j;
|
|
- char *p, *q;
|
|
-
|
|
- nc = collapsible(names);
|
|
- if (nc < 2) return; /* Nothing to do */
|
|
- ix = (char **)alloca(nc * sizeof(char *));
|
|
- splitNames(names, ix);
|
|
-
|
|
- for (i = 0; i < nc; i++) {
|
|
- int dots = 0;
|
|
-
|
|
- /* Find next occurrence of "." or ".." */
|
|
- do {
|
|
- char *p = ix[i];
|
|
- if (p[0] == '.') {
|
|
- if (p[1] == '\0') {
|
|
- dots = 1;
|
|
- break;
|
|
- }
|
|
- if ((p[1] == '.') && (p[2] == '\0')) {
|
|
- dots = 2;
|
|
- break;
|
|
- }
|
|
- }
|
|
- i++;
|
|
- } while (i < nc);
|
|
- if (i >= nc) break;
|
|
-
|
|
- /* At this point i is the index of either a "." or a "..", so take the
|
|
- appropriate action and then continue the outer loop */
|
|
- if (dots == 1) {
|
|
- /* Remove this instance of "." */
|
|
- ix[i] = 0;
|
|
- }
|
|
- else {
|
|
- /* If there is a preceding name, remove both that name and this
|
|
- instance of ".."; otherwise, leave the ".." as is */
|
|
- for (j = i - 1; j >= 0; j--) {
|
|
- if (ix[j]) break;
|
|
- }
|
|
- if (j < 0) continue;
|
|
- ix[j] = 0;
|
|
- ix[i] = 0;
|
|
- }
|
|
- /* i will be incremented at the top of the loop */
|
|
- }
|
|
-
|
|
- joinNames(names, nc, ix);
|
|
-}
|
|
-
|
|
-
|
|
/* Convert a pathname to canonical form. The input path is assumed to contain
|
|
no duplicate slashes. On Solaris we can use realpath() to do most of the
|
|
work, though once that's done we still must collapse any remaining "." and
|
|
diff --git a/jdk/src/solaris/native/java/io/path_util.c b/jdk/src/solaris/native/java/io/path_util.c
|
|
new file mode 100644
|
|
index 000000000..8a533f812
|
|
--- /dev/null
|
|
+++ b/jdk/src/solaris/native/java/io/path_util.c
|
|
@@ -0,0 +1,166 @@
|
|
+/*
|
|
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
|
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
+ *
|
|
+ * This code is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 only, as
|
|
+ * published by the Free Software Foundation. Oracle designates this
|
|
+ * particular file as subject to the "Classpath" exception as provided
|
|
+ * by Oracle in the LICENSE file that accompanied this code.
|
|
+ *
|
|
+ * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
+ * version 2 for more details (a copy is included in the LICENSE file that
|
|
+ * accompanied this code).
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License version
|
|
+ * 2 along with this work; if not, write to the Free Software Foundation,
|
|
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *
|
|
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
+ * or visit www.oracle.com if you need additional information or have any
|
|
+ * questions.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#if !defined(_ALLBSD_SOURCE)
|
|
+#include <alloca.h>
|
|
+#endif
|
|
+#include "path_util.h"
|
|
+
|
|
+/* Check the given name sequence to see if it can be further collapsed.
|
|
+ Return zero if not, otherwise return the number of names in the sequence. */
|
|
+
|
|
+static int
|
|
+collapsible(char *names)
|
|
+{
|
|
+ char *p = names;
|
|
+ int dots = 0, n = 0;
|
|
+
|
|
+ while (*p) {
|
|
+ if ((p[0] == '.') && ((p[1] == '\0')
|
|
+ || (p[1] == '/')
|
|
+ || ((p[1] == '.') && ((p[2] == '\0')
|
|
+ || (p[2] == '/'))))) {
|
|
+ dots = 1;
|
|
+ }
|
|
+ n++;
|
|
+ while (*p) {
|
|
+ if (*p == '/') {
|
|
+ p++;
|
|
+ break;
|
|
+ }
|
|
+ p++;
|
|
+ }
|
|
+ }
|
|
+ return (dots ? n : 0);
|
|
+}
|
|
+
|
|
+/* Split the names in the given name sequence,
|
|
+ replacing slashes with nulls and filling in the given index array */
|
|
+
|
|
+static void
|
|
+splitNames(char *names, char **ix)
|
|
+{
|
|
+ char *p = names;
|
|
+ int i = 0;
|
|
+
|
|
+ while (*p) {
|
|
+ ix[i++] = p++;
|
|
+ while (*p) {
|
|
+ if (*p == '/') {
|
|
+ *p++ = '\0';
|
|
+ break;
|
|
+ }
|
|
+ p++;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Join the names in the given name sequence, ignoring names whose index
|
|
+ entries have been cleared and replacing nulls with slashes as needed */
|
|
+
|
|
+static void
|
|
+joinNames(char *names, int nc, char **ix)
|
|
+{
|
|
+ int i;
|
|
+ char *p;
|
|
+
|
|
+ for (i = 0, p = names; i < nc; i++) {
|
|
+ if (!ix[i]) continue;
|
|
+ if (i > 0) {
|
|
+ p[-1] = '/';
|
|
+ }
|
|
+ if (p == ix[i]) {
|
|
+ p += strlen(p) + 1;
|
|
+ } else {
|
|
+ char *q = ix[i];
|
|
+ while ((*p++ = *q++));
|
|
+ }
|
|
+ }
|
|
+ *p = '\0';
|
|
+}
|
|
+
|
|
+/* Collapse "." and ".." names in the given path wherever possible.
|
|
+ A "." name may always be eliminated; a ".." name may be eliminated if it
|
|
+ follows a name that is neither "." nor "..". This is a syntactic operation
|
|
+ that performs no filesystem queries, so it should only be used to cleanup
|
|
+ after invoking the realpath() procedure. */
|
|
+
|
|
+void
|
|
+collapse(char *path)
|
|
+{
|
|
+ char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
|
|
+ int nc;
|
|
+ char **ix;
|
|
+ int i, j;
|
|
+ char *p, *q;
|
|
+
|
|
+ nc = collapsible(names);
|
|
+ if (nc < 2) return; /* Nothing to do */
|
|
+ ix = (char **)alloca(nc * sizeof(char *));
|
|
+ splitNames(names, ix);
|
|
+
|
|
+ for (i = 0; i < nc; i++) {
|
|
+ int dots = 0;
|
|
+
|
|
+ /* Find next occurrence of "." or ".." */
|
|
+ do {
|
|
+ char *p = ix[i];
|
|
+ if (p[0] == '.') {
|
|
+ if (p[1] == '\0') {
|
|
+ dots = 1;
|
|
+ break;
|
|
+ }
|
|
+ if ((p[1] == '.') && (p[2] == '\0')) {
|
|
+ dots = 2;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ i++;
|
|
+ } while (i < nc);
|
|
+ if (i >= nc) break;
|
|
+
|
|
+ /* At this point i is the index of either a "." or a "..", so take the
|
|
+ appropriate action and then continue the outer loop */
|
|
+ if (dots == 1) {
|
|
+ /* Remove this instance of "." */
|
|
+ ix[i] = 0;
|
|
+ }
|
|
+ else {
|
|
+ /* If there is a preceding name, remove both that name and this
|
|
+ instance of ".."; otherwise, leave the ".." as is */
|
|
+ for (j = i - 1; j >= 0; j--) {
|
|
+ if (ix[j]) break;
|
|
+ }
|
|
+ if (j < 0) continue;
|
|
+ ix[j] = 0;
|
|
+ ix[i] = 0;
|
|
+ }
|
|
+ /* i will be incremented at the top of the loop */
|
|
+ }
|
|
+
|
|
+ joinNames(names, nc, ix);
|
|
+}
|
|
diff --git a/jdk/src/solaris/native/java/io/path_util.h b/jdk/src/solaris/native/java/io/path_util.h
|
|
new file mode 100644
|
|
index 000000000..7b0fd5eb1
|
|
--- /dev/null
|
|
+++ b/jdk/src/solaris/native/java/io/path_util.h
|
|
@@ -0,0 +1,31 @@
|
|
+/*
|
|
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
|
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
+ *
|
|
+ * This code is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 only, as
|
|
+ * published by the Free Software Foundation. Oracle designates this
|
|
+ * particular file as subject to the "Classpath" exception as provided
|
|
+ * by Oracle in the LICENSE file that accompanied this code.
|
|
+ *
|
|
+ * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
+ * version 2 for more details (a copy is included in the LICENSE file that
|
|
+ * accompanied this code).
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License version
|
|
+ * 2 along with this work; if not, write to the Free Software Foundation,
|
|
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *
|
|
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
+ * or visit www.oracle.com if you need additional information or have any
|
|
+ * questions.
|
|
+ */
|
|
+
|
|
+#ifndef PATH_UTIL_H
|
|
+#define PATH_UTIL_H
|
|
+
|
|
+void collapse(char *path);
|
|
+
|
|
+#endif
|
|
diff --git a/jdk/src/solaris/native/java/util/TimeZone_md.c b/jdk/src/solaris/native/java/util/TimeZone_md.c
|
|
index c183a723d..df1450e03 100644
|
|
--- a/jdk/src/solaris/native/java/util/TimeZone_md.c
|
|
+++ b/jdk/src/solaris/native/java/util/TimeZone_md.c
|
|
@@ -41,6 +41,7 @@
|
|
|
|
#include "jvm.h"
|
|
#include "TimeZone_md.h"
|
|
+#include "path_util.h"
|
|
|
|
static char *isFileIdentical(char* buf, size_t size, char *pathname);
|
|
|
|
@@ -77,6 +78,33 @@ static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
|
|
|
|
#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
|
|
|
|
+/*
|
|
+ * remove repeated path separators ('/') in the given 'path'.
|
|
+ */
|
|
+static void
|
|
+removeDuplicateSlashes(char *path)
|
|
+{
|
|
+ char *left = path;
|
|
+ char *right = path;
|
|
+ char *end = path + strlen(path);
|
|
+
|
|
+ for (; right < end; right++) {
|
|
+ // Skip sequence of multiple path-separators.
|
|
+ while (*right == '/' && *(right + 1) == '/') {
|
|
+ right++;
|
|
+ }
|
|
+
|
|
+ while (*right != '\0' && !(*right == '/' && *(right + 1) == '/')) {
|
|
+ *left++ = *right++;
|
|
+ }
|
|
+
|
|
+ if (*right == '\0') {
|
|
+ *left = '\0';
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Returns a pointer to the zone ID portion of the given zoneinfo file
|
|
* name, or NULL if the given string doesn't contain "zoneinfo/".
|
|
@@ -319,36 +347,9 @@ getPlatformTimeZoneID()
|
|
return NULL;
|
|
}
|
|
linkbuf[len] = '\0';
|
|
-
|
|
- /* linkbuf may be a relative symlink or has more than one characters, like '.' and '/' ,
|
|
- * which will cause the function call getZoneName return to an abnormal timeZone name.
|
|
- * For example, linkbuf is "../usr/share/zoneinfo//Asia/Shanghai", then the call of
|
|
- * getZoneName(linkbuf) will get "/Asia/Shanghai", not "Asia/Shanghai".
|
|
- * So we covert it to an absolute path by adding the file's (which is define by macro
|
|
- * DEFAULT_ZONEINFO_FILE) dirname and then call glibc's realpath API to canonicalize
|
|
- * the path.
|
|
- */
|
|
- char abslinkbuf[2 * (PATH_MAX + 1)];
|
|
- if (linkbuf[0] != '/') {
|
|
- if (sprintf(abslinkbuf, "%s/%s", DEFAULT_ZONEINFO_FILE_DIRNAME, linkbuf) < 0) {
|
|
- jio_fprintf(stderr, (const char *) "failed to generate absolute path\n");
|
|
- return NULL;
|
|
- }
|
|
- } else {
|
|
- strncpy(abslinkbuf, linkbuf, len + 1);
|
|
- }
|
|
-
|
|
- /* canonicalize the path */
|
|
- char resolvedpath[PATH_MAX + 1];
|
|
- resolvedpath[PATH_MAX] = '\0';
|
|
- char *path = realpath(abslinkbuf, resolvedpath);
|
|
- if (path == NULL) {
|
|
- jio_fprintf(stderr, (const char *) "failed to get real path, symlink is %s\n",
|
|
- abslinkbuf);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- tz = getZoneName(resolvedpath);
|
|
+ removeDuplicateSlashes(linkbuf);
|
|
+ collapse(linkbuf);
|
|
+ tz = getZoneName(linkbuf);
|
|
if (tz != NULL) {
|
|
tz = strdup(tz);
|
|
return tz;
|
|
--
|
|
2.22.0
|
|
|