From 12123dffb829086ebb1b07d81ef01522519ed657 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 24 Feb 2016 15:09:28 +0000 Subject: Update timezone data to 2016a Changes affecting future time stamps America/Cayman will not observe daylight saving this year after all. Revert our guess that it would. (Thanks to Matt Johnson.) Asia/Chita switches from +0800 to +0900 on 2016-03-27 at 02:00. (Thanks to Alexander Krivenyshev.) Asia/Tehran now has DST predictions for the year 2038 and later, to be March 21 00:00 to September 21 00:00. This is likely better than predicting no DST, albeit off by a day every now and then. Changes affecting past and future time stamps America/Metlakatla switched from PST all year to AKST/AKDT on 2015-11-01 at 02:00. (Thanks to Steffen Thorsen.) America/Santa_Isabel has been removed, and replaced with a backward compatibility link to America/Tijuana. Its contents were apparently based on a misreading of Mexican legislation. Changes affecting past time stamps Asia/Karachi's two transition times in 2002 were off by a minute. (Thanks to Matt Johnson.) Bug: 26833368 Change-Id: I5af1d69f8ca767369f1cbc4aa863280b960777e0 --- libc/zoneinfo/tzdata | Bin 494261 -> 491711 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata index c464f46..d2cc535 100644 Binary files a/libc/zoneinfo/tzdata and b/libc/zoneinfo/tzdata differ -- cgit v1.1 From 98ea0860a43eb4d830f44062fd1130a68f8fc59c Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Fri, 1 Apr 2016 14:57:21 -0700 Subject: bionic: Teach fnmatch(3) to handle UTF-8 characters in patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is NOT comprehensive UTF-8 support. It is just a quick hack to make alternation work in bracket expressions so that the system file manager can find files with non-ASCII names in root mode. Bracket expressions that contain non-ASCII ranges are explicitly avoided to avoid the complexities of unicode collation rules. Things like the following will now work: fnmatch("те[с][т].jpg", "тест.jpg", 0); fnmatch("test[αβγ].txt", "testβ.txt", 0); Things like the following will still fail: fnmatch("тес[а-я].txt", "тест.txt", 0); Jira: CYNGNOS-2336 Change-Id: If38dc6692bc22d20128b0cd8a7632754a496d7fb --- libc/upstream-openbsd/lib/libc/gen/fnmatch.c | 114 +++++++++++++++++++++------ 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c index 2c860f7..62c58f8 100644 --- a/libc/upstream-openbsd/lib/libc/gen/fnmatch.c +++ b/libc/upstream-openbsd/lib/libc/gen/fnmatch.c @@ -90,12 +90,72 @@ #include #include +#include + #include "charclass.h" #define RANGE_MATCH 1 #define RANGE_NOMATCH 0 #define RANGE_ERROR (-1) +static unsigned int +utf8_len(const char *s) +{ + const unsigned char *b = (const unsigned char *)s; + unsigned int len = 1; + unsigned char c; + + if ((b[0] & 0xc0) != 0xc0) { + return 1; + } + c = b[0] << 1; + while (len < 6 && (c & 0x80)) { + if ((b[len] & 0xc0) != 0x80) { + return 1; + } + c <<= 1; + ++len; + } + + return len; +} + +static void +utf8_inc(const char **s) +{ + *s += utf8_len(*s); +} + +static uint32_t +utf8_get_inc(const char **s) +{ + unsigned int len = utf8_len(*s); + const unsigned char *b = (const unsigned char *)(*s); + unsigned int n; + uint32_t ch; + + *s += len; + + if (len == 1) { + return b[0]; + } + + ch = b[0] & (0xff >> len); + for (n = 1; n < len; ++n) { + ch <<= 6; + ch |= (b[n] & 0x3f); + } + + return ch; +} + +static uint32_t +utf8_get(const char *s) +{ + const char *tmp = s; + return utf8_get_inc(&tmp); +} + static int classmatch(const char *pattern, char test, int foldcase, const char **ep) { @@ -150,7 +210,7 @@ static int fnmatch_ch(const char **pattern, const char **string, int flags) const int escape = !(flags & FNM_NOESCAPE); const int slash = !!(flags & FNM_PATHNAME); int result = FNM_NOMATCH; - const char *startch; + uint32_t startch, endch, compch; int negate; if (**pattern == '[') @@ -171,7 +231,7 @@ static int fnmatch_ch(const char **pattern, const char **string, int flags) if (**pattern == ']') { ++*pattern; /* XXX: Fix for MBCS character width */ - ++*string; + utf8_inc(string); return (result ^ negate); } @@ -199,10 +259,13 @@ leadingclosebrace: * "x-]" is not allowed unless escaped ("x-\]") * XXX: Fix for locale/MBCS character width */ - if (((*pattern)[1] == '-') && ((*pattern)[2] != ']')) + startch = utf8_get_inc(pattern); + compch = utf8_get(*string); + if (((*pattern)[0] == '-') && ((*pattern)[1] != ']')) { - startch = *pattern; - *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2; + *pattern += 1; + if (escape && **pattern == '\\') + *pattern += 1; /* NOT a properly balanced [expr] pattern, EOS terminated * or ranges containing a slash in FNM_PATHNAME mode pattern @@ -211,32 +274,35 @@ leadingclosebrace: if (!**pattern || (slash && (**pattern == '/'))) break; + endch = utf8_get_inc(pattern); + + /* Refuse to attempt collation for non-ASCII chars */ + if (startch >= 0x80 || endch >= 0x80) + continue; + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ - if ((**string >= *startch) && (**string <= **pattern)) + if ((compch >= startch) && (compch <= endch)) result = 0; - else if (nocase && (isupper((unsigned char)**string) || - isupper((unsigned char)*startch) || - isupper((unsigned char)**pattern)) - && (tolower((unsigned char)**string) >= - tolower((unsigned char)*startch)) - && (tolower((unsigned char)**string) <= - tolower((unsigned char)**pattern))) + else if (nocase && (isupper(compch) || + isupper(startch) || + isupper(endch)) + && (tolower(compch) >= + tolower(startch)) + && (tolower(compch) <= + tolower(endch))) result = 0; - ++*pattern; continue; } /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ - if ((**string == **pattern)) + if (compch == startch) result = 0; - else if (nocase && (isupper((unsigned char)**string) || - isupper((unsigned char)**pattern)) - && (tolower((unsigned char)**string) == - tolower((unsigned char)**pattern))) + else if (nocase && (isupper(compch) || + isupper(startch)) + && (tolower(compch) == + tolower(startch))) result = 0; - - ++*pattern; } /* NOT a properly balanced [expr] pattern; Rewind @@ -257,7 +323,7 @@ leadingclosebrace: } /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */ - if (**string == **pattern) + if (utf8_get(*string) == utf8_get(*pattern)) result = 0; else if (nocase && (isupper((unsigned char)**string) || isupper((unsigned char)**pattern)) @@ -271,8 +337,8 @@ leadingclosebrace: return result; fnmatch_ch_success: - ++*pattern; - ++*string; + utf8_inc(pattern); + utf8_inc(string); return result; } -- cgit v1.1 From e87a5b3d6fd488965c3c8927816db70497e88e65 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Sat, 30 Apr 2016 19:50:10 -0700 Subject: bionic: Use a more simple strrchr for arm64 * Current version seems like overkill, and it doesn't compile with Clang. Use a simplified version from ARM. Change-Id: I2fe5467b6a504ea04b5f28a08d92e7c2306772d0 --- libc/arch-arm64/generic/bionic/strrchr.S | 159 ++++--------------------------- 1 file changed, 21 insertions(+), 138 deletions(-) diff --git a/libc/arch-arm64/generic/bionic/strrchr.S b/libc/arch-arm64/generic/bionic/strrchr.S index 46b5031..409bc71 100644 --- a/libc/arch-arm64/generic/bionic/strrchr.S +++ b/libc/arch-arm64/generic/bionic/strrchr.S @@ -25,147 +25,30 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/* Assumptions: - * - * ARMv8-a, AArch64 - * Neon Available. - */ + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ #include -/* Arguments and results. */ -#define srcin x0 -#define chrin w1 - -#define result x0 - -#define src x2 -#define tmp1 x3 -#define wtmp2 w4 -#define tmp3 x5 -#define src_match x6 -#define src_offset x7 -#define const_m1 x8 -#define tmp4 x9 -#define nul_match x10 -#define chr_match x11 - -#define vrepchr v0 -#define vdata1 v1 -#define vdata2 v2 -#define vhas_nul1 v3 -#define vhas_nul2 v4 -#define vhas_chr1 v5 -#define vhas_chr2 v6 -#define vrepmask_0 v7 -#define vrepmask_c v16 -#define vend1 v17 -#define vend2 v18 - -/* Core algorithm. - - For each 32-byte hunk we calculate a 64-bit syndrome value, with - two bits per byte (LSB is always in bits 0 and 1, for both big - and little-endian systems). For each tuple, bit 0 is set iff - the relevant byte matched the requested character; bit 1 is set - iff the relevant byte matched the NUL end of string (we trigger - off bit0 for the special case of looking for NUL). Since the bits - in the syndrome reflect exactly the order in which things occur - in the original string a count_trailing_zeros() operation will - identify exactly which byte is causing the termination, and why. */ - -/* Locals and temporaries. */ - +/* + * Find the last occurrence of a character in a string. + * + * Parameters: + * x0 - str + * x1 - c + * Returns: + * x0 - address of last occurrence of 'c' or 0 + */ ENTRY(strrchr) - /* Magic constant 0x40100401 to allow us to identify which lane - matches the requested byte. Magic constant 0x80200802 used - similarly for NUL termination. */ - mov wtmp2, #0x0401 - movk wtmp2, #0x4010, lsl #16 - dup vrepchr.16b, chrin - bic src, srcin, #31 /* Work with aligned 32-byte hunks. */ - dup vrepmask_c.4s, wtmp2 - mov src_offset, #0 - ands tmp1, srcin, #31 - add vrepmask_0.4s, vrepmask_c.4s, vrepmask_c.4s /* equiv: lsl #1 */ - b.eq .Laligned - - /* Input string is not 32-byte aligned. Rather than forcing - the padding bytes to a safe value, we calculate the syndrome - for all the bytes, but then mask off those bits of the - syndrome that are related to the padding. */ - ld1 {vdata1.16b, vdata2.16b}, [src], #32 - neg tmp1, tmp1 - cmeq vhas_nul1.16b, vdata1.16b, #0 - cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b - cmeq vhas_nul2.16b, vdata2.16b, #0 - cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b - and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b - and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b - and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b - and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b - addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128 - addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128 - addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b // 128->64 - addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64 - mov nul_match, vhas_nul1.2d[0] - lsl tmp1, tmp1, #1 - mov const_m1, #~0 - mov chr_match, vhas_chr1.2d[0] - lsr tmp3, const_m1, tmp1 - - bic nul_match, nul_match, tmp3 // Mask padding bits. - bic chr_match, chr_match, tmp3 // Mask padding bits. - cbnz nul_match, .Ltail - -.Lloop: - cmp chr_match, #0 - csel src_match, src, src_match, ne - csel src_offset, chr_match, src_offset, ne -.Laligned: - ld1 {vdata1.16b, vdata2.16b}, [src], #32 - cmeq vhas_nul1.16b, vdata1.16b, #0 - cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b - cmeq vhas_nul2.16b, vdata2.16b, #0 - cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b - addp vend1.16b, vhas_nul1.16b, vhas_nul2.16b // 256->128 - and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b - and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b - addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr2.16b // 256->128 - addp vend1.16b, vend1.16b, vend1.16b // 128->64 - addp vhas_chr1.16b, vhas_chr1.16b, vhas_chr1.16b // 128->64 - mov nul_match, vend1.2d[0] - mov chr_match, vhas_chr1.2d[0] - cbz nul_match, .Lloop - - and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b - and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b - addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul2.16b - addp vhas_nul1.16b, vhas_nul1.16b, vhas_nul1.16b - mov nul_match, vhas_nul1.2d[0] - -.Ltail: - /* Work out exactly where the string ends. */ - sub tmp4, nul_match, #1 - eor tmp4, tmp4, nul_match - ands chr_match, chr_match, tmp4 - /* And pick the values corresponding to the last match. */ - csel src_match, src, src_match, ne - csel src_offset, chr_match, src_offset, ne - - /* Count down from the top of the syndrome to find the last match. */ - clz tmp3, src_offset - /* Src_match points beyond the word containing the match, so we can - simply subtract half the bit-offset into the syndrome. Because - we are counting down, we need to go back one more character. */ - add tmp3, tmp3, #2 - sub result, src_match, tmp3, lsr #1 - /* But if the syndrome shows no match was found, then return NULL. */ - cmp src_offset, #0 - csel result, result, xzr, ne - + mov x3, #0 + and w1, w1, #0xff +1: ldrb w2, [x0], #1 + cbz w2, 2f + cmp w2, w1 + b.ne 1b + sub x3, x0, #1 + b 1b +2: mov x0, x3 ret - END(strrchr) -- cgit v1.1 From 2a016b8808633cd56962d8024c51941bcd649706 Mon Sep 17 00:00:00 2001 From: Kyle Repinski Date: Tue, 28 Apr 2015 13:39:41 -0500 Subject: cortex-a9: Fix reference to __memcpy_base_aligned. With a different memcpy, __memcpy_base_aligned ceased to exist. Instead, point to the name defined by whatever includes memcpy_base.S Change-Id: I242cf49cbada35337ba155d7f170e86a905ff55f --- libc/arch-arm/cortex-a9/bionic/memcpy_base.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S index 6ab5a69..966b9b3 100644 --- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S +++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S @@ -44,7 +44,7 @@ ENTRY_PRIVATE(MEMCPY_BASE) /* check if buffers are aligned. If so, run arm-only version */ eor r3, r0, r1 ands r3, r3, #0x3 - beq __memcpy_base_aligned + beq MEMCPY_BASE_ALIGNED /* Check the upper size limit for Neon unaligned memory access in memcpy */ cmp r2, #224 -- cgit v1.1 From 02972e7101291409121a085b104d3f7451a2e1d7 Mon Sep 17 00:00:00 2001 From: Junichi Uekawa Date: Wed, 18 Nov 2015 10:18:59 +0900 Subject: Do not depend on host bits to get the right size to write. x86_64 32-bit or 64-bit relocations do not depend on ELF bit size, they are 32-bit or 64-bit respectively. Known compiler that emits such code is nacl-clang which emits R_X86_64_PC32 which should write 32 bits but ended up writing 64 bits. Change-Id: Ibb6b484c0fea6a7e291362148e8ac749d6674529 --- linker/linker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index bc40cf1..6019c91 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2208,14 +2208,14 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast(reloc), static_cast(sym_addr), sym_name); - *reinterpret_cast(reloc) = sym_addr + addend; + *reinterpret_cast(reloc) = sym_addr + addend; break; case R_X86_64_64: count_relocation(kRelocRelative); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast(reloc), static_cast(sym_addr), sym_name); - *reinterpret_cast(reloc) = sym_addr + addend; + *reinterpret_cast(reloc) = sym_addr + addend; break; case R_X86_64_PC32: count_relocation(kRelocRelative); @@ -2223,7 +2223,7 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s", static_cast(reloc), static_cast(sym_addr - reloc), static_cast(sym_addr), static_cast(reloc), sym_name); - *reinterpret_cast(reloc) = sym_addr + addend - reloc; + *reinterpret_cast(reloc) = sym_addr + addend - reloc; break; #elif defined(__arm__) case R_ARM_ABS32: -- cgit v1.1 From 0a143d038f08d595d2678839e7f5f5dafc92c78d Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Fri, 1 Jul 2016 08:45:04 -0700 Subject: libc: Fix invalid offset warning with Clang Change-Id: I71274a6f592356a259ccdbe9c09383bc75e2d26b --- libc/arch-arm64/kryo/bionic/memcpy_base.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/arch-arm64/kryo/bionic/memcpy_base.S b/libc/arch-arm64/kryo/bionic/memcpy_base.S index 0096bb7..ee0757d 100644 --- a/libc/arch-arm64/kryo/bionic/memcpy_base.S +++ b/libc/arch-arm64/kryo/bionic/memcpy_base.S @@ -170,8 +170,8 @@ kryo_bb_prime_pump: add x10, x1, #(PLDOFFS*PLDSIZE) bic x10, x10, #0x7F sub x12, x12, #PLDOFFS - prfm PLDL1KEEP, [x10, #(-1*PLDSIZE)] - prfm PLDL1KEEP, [x10, #(-1*PLDSIZE+64)] + prfm PLDL1KEEP, [x10, #((PLDOFFS-1)*PLDSIZE)] + prfm PLDL1KEEP, [x10, #((PLDOFFS-1)*PLDSIZE)+64] cmp x12, #(448*1024/128) bhi kryo_bb_copy_128_loop_ddr -- cgit v1.1 From 4e646507b980f2a1cd5dd8dee3e9e70e8880ce54 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Mon, 24 Aug 2015 17:52:56 +0100 Subject: Move tzdata scripts from bionic to external/icu The scripts affect files in external/icu, bionic and the generated files affect libcore. The files must be updated together so there is no "obvious" home. OEM developers seem to want to update ICU themselves and have been asking how. Moving the scripts to external/icu and splitting the ICU generation code into a sub-script they can run makes some sense. Bug: 23419215 Change-Id: Ia26fa526fd2b560a79f36d327a10e262a85db752 --- libc/tools/zoneinfo/ZoneCompactor.java | 192 ------------------------ libc/tools/zoneinfo/update-tzdata.py | 262 --------------------------------- 2 files changed, 454 deletions(-) delete mode 100644 libc/tools/zoneinfo/ZoneCompactor.java delete mode 100755 libc/tools/zoneinfo/update-tzdata.py diff --git a/libc/tools/zoneinfo/ZoneCompactor.java b/libc/tools/zoneinfo/ZoneCompactor.java deleted file mode 100644 index 2d598fe..0000000 --- a/libc/tools/zoneinfo/ZoneCompactor.java +++ /dev/null @@ -1,192 +0,0 @@ - -import java.io.*; -import java.util.*; - -// usage: java ZoneCompiler -// -// Compile a set of tzfile-formatted files into a single file containing an index. -// -// The compilation is controlled by a setup file, which is provided as a -// command-line argument. The setup file has the form: -// -// Link -// ... -// -// ... -// -// Note that the links must be declared prior to the zone names. -// A zone name is a filename relative to the source directory such as -// 'GMT', 'Africa/Dakar', or 'America/Argentina/Jujuy'. -// -// Use the 'zic' command-line tool to convert from flat files -// (such as 'africa' or 'northamerica') to a directory -// hierarchy suitable for this tool (containing files such as 'data/Africa/Abidjan'). -// - -public class ZoneCompactor { - // Maximum number of characters in a zone name, including '\0' terminator. - private static final int MAXNAME = 40; - - // Zone name synonyms. - private Map links = new HashMap(); - - // File offsets by zone name. - private Map offsets = new HashMap(); - - // File lengths by zone name. - private Map lengths = new HashMap(); - - // Concatenate the contents of 'inFile' onto 'out'. - private static void copyFile(File inFile, OutputStream out) throws Exception { - byte[] ret = new byte[0]; - - InputStream in = new FileInputStream(inFile); - byte[] buf = new byte[8192]; - while (true) { - int nbytes = in.read(buf); - if (nbytes == -1) { - break; - } - out.write(buf, 0, nbytes); - - byte[] nret = new byte[ret.length + nbytes]; - System.arraycopy(ret, 0, nret, 0, ret.length); - System.arraycopy(buf, 0, nret, ret.length, nbytes); - ret = nret; - } - out.flush(); - } - - public ZoneCompactor(String setupFile, String dataDirectory, String zoneTabFile, String outputDirectory, String version) throws Exception { - // Read the setup file and concatenate all the data. - ByteArrayOutputStream allData = new ByteArrayOutputStream(); - BufferedReader reader = new BufferedReader(new FileReader(setupFile)); - String s; - int offset = 0; - while ((s = reader.readLine()) != null) { - s = s.trim(); - if (s.startsWith("Link")) { - StringTokenizer st = new StringTokenizer(s); - st.nextToken(); - String to = st.nextToken(); - String from = st.nextToken(); - links.put(from, to); - } else { - String link = links.get(s); - if (link == null) { - File sourceFile = new File(dataDirectory, s); - long length = sourceFile.length(); - offsets.put(s, offset); - lengths.put(s, (int) length); - - offset += length; - copyFile(sourceFile, allData); - } - } - } - reader.close(); - - // Fill in fields for links. - Iterator it = links.keySet().iterator(); - while (it.hasNext()) { - String from = it.next(); - String to = links.get(from); - - offsets.put(from, offsets.get(to)); - lengths.put(from, lengths.get(to)); - } - - // Create/truncate the destination file. - RandomAccessFile f = new RandomAccessFile(new File(outputDirectory, "tzdata"), "rw"); - f.setLength(0); - - // Write the header. - - // byte[12] tzdata_version -- 'tzdata2012f\0' - // int index_offset -- so we can slip in extra header fields in a backwards-compatible way - // int data_offset - // int zonetab_offset - - // tzdata_version - f.write(toAscii(new byte[12], version)); - - // Write dummy values for the three offsets, and remember where we need to seek back to later - // when we have the real values. - int index_offset_offset = (int) f.getFilePointer(); - f.writeInt(0); - int data_offset_offset = (int) f.getFilePointer(); - f.writeInt(0); - int zonetab_offset_offset = (int) f.getFilePointer(); - f.writeInt(0); - - int index_offset = (int) f.getFilePointer(); - - // Write the index. - ArrayList sortedOlsonIds = new ArrayList(); - sortedOlsonIds.addAll(offsets.keySet()); - Collections.sort(sortedOlsonIds); - it = sortedOlsonIds.iterator(); - while (it.hasNext()) { - String zoneName = it.next(); - if (zoneName.length() >= MAXNAME) { - throw new RuntimeException("zone filename too long: " + zoneName.length()); - } - - // Follow the chain of links to work out where the real data for this zone lives. - String actualZoneName = zoneName; - while (links.get(actualZoneName) != null) { - actualZoneName = links.get(actualZoneName); - } - - f.write(toAscii(new byte[MAXNAME], zoneName)); - f.writeInt(offsets.get(actualZoneName)); - f.writeInt(lengths.get(actualZoneName)); - f.writeInt(0); // Used to be raw GMT offset. No longer used. - } - - int data_offset = (int) f.getFilePointer(); - - // Write the data. - f.write(allData.toByteArray()); - - int zonetab_offset = (int) f.getFilePointer(); - - // Copy the zone.tab. - reader = new BufferedReader(new FileReader(zoneTabFile)); - while ((s = reader.readLine()) != null) { - if (!s.startsWith("#")) { - f.writeBytes(s); - f.write('\n'); - } - } - reader.close(); - - // Go back and fix up the offsets in the header. - f.seek(index_offset_offset); - f.writeInt(index_offset); - f.seek(data_offset_offset); - f.writeInt(data_offset); - f.seek(zonetab_offset_offset); - f.writeInt(zonetab_offset); - - f.close(); - } - - private static byte[] toAscii(byte[] dst, String src) { - for (int i = 0; i < src.length(); ++i) { - if (src.charAt(i) > '~') { - throw new RuntimeException("non-ASCII string: " + src); - } - dst[i] = (byte) src.charAt(i); - } - return dst; - } - - public static void main(String[] args) throws Exception { - if (args.length != 5) { - System.err.println("usage: java ZoneCompactor "); - System.exit(0); - } - new ZoneCompactor(args[0], args[1], args[2], args[3], args[4]); - } -} diff --git a/libc/tools/zoneinfo/update-tzdata.py b/libc/tools/zoneinfo/update-tzdata.py deleted file mode 100755 index 68a5ff5..0000000 --- a/libc/tools/zoneinfo/update-tzdata.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/python - -"""Updates the timezone data held in bionic and ICU.""" - -import ftplib -import glob -import httplib -import os -import re -import shutil -import subprocess -import sys -import tarfile -import tempfile - -regions = ['africa', 'antarctica', 'asia', 'australasia', - 'etcetera', 'europe', 'northamerica', 'southamerica', - # These two deliberately come last so they override what came - # before (and each other). - 'backward', 'backzone' ] - -def CheckDirExists(dir, dirname): - if not os.path.isdir(dir): - print "Couldn't find %s (%s)!" % (dirname, dir) - sys.exit(1) - -bionic_libc_tools_zoneinfo_dir = os.path.realpath(os.path.dirname(sys.argv[0])) - -# Find the bionic directory, searching upward from this script. -bionic_dir = os.path.realpath('%s/../../..' % bionic_libc_tools_zoneinfo_dir) -bionic_libc_zoneinfo_dir = '%s/libc/zoneinfo' % bionic_dir -CheckDirExists(bionic_libc_zoneinfo_dir, 'bionic/libc/zoneinfo') -CheckDirExists(bionic_libc_tools_zoneinfo_dir, 'bionic/libc/tools/zoneinfo') -print 'Found bionic in %s ...' % bionic_dir - -# Find the icu directory. -icu_dir = os.path.realpath('%s/../external/icu' % bionic_dir) -icu4c_dir = os.path.realpath('%s/icu4c/source' % icu_dir) -icu4j_dir = os.path.realpath('%s/icu4j' % icu_dir) -CheckDirExists(icu4c_dir, 'external/icu/icu4c/source') -CheckDirExists(icu4j_dir, 'external/icu/icu4j') -print 'Found icu in %s ...' % icu_dir - - -def GetCurrentTzDataVersion(): - return open('%s/tzdata' % bionic_libc_zoneinfo_dir).read().split('\x00', 1)[0] - - -def WriteSetupFile(): - """Writes the list of zones that ZoneCompactor should process.""" - links = [] - zones = [] - for region in regions: - for line in open('extracted/%s' % region): - fields = line.split() - if fields: - if fields[0] == 'Link': - links.append('%s %s %s' % (fields[0], fields[1], fields[2])) - zones.append(fields[2]) - elif fields[0] == 'Zone': - zones.append(fields[1]) - zones.sort() - - setup = open('setup', 'w') - for link in sorted(set(links)): - setup.write('%s\n' % link) - for zone in sorted(set(zones)): - setup.write('%s\n' % zone) - setup.close() - - -def SwitchToNewTemporaryDirectory(): - tmp_dir = tempfile.mkdtemp('-tzdata') - os.chdir(tmp_dir) - print 'Created temporary directory "%s"...' % tmp_dir - - -def FtpRetrieveFile(ftp, filename): - ftp.retrbinary('RETR %s' % filename, open(filename, 'wb').write) - - -def FtpRetrieveFileAndSignature(ftp, data_filename): - """Downloads and repackages the given data from the given FTP server.""" - print 'Downloading data...' - FtpRetrieveFile(ftp, data_filename) - - print 'Downloading signature...' - signature_filename = '%s.asc' % data_filename - FtpRetrieveFile(ftp, signature_filename) - - -def HttpRetrieveFile(http, path, output_filename): - http.request("GET", path) - f = open(output_filename, 'wb') - f.write(http.getresponse().read()) - f.close() - - -def HttpRetrieveFileAndSignature(http, data_filename): - """Downloads and repackages the given data from the given HTTP server.""" - path = "/time-zones/repository/releases/%s" % data_filename - - print 'Downloading data...' - HttpRetrieveFile(http, path, data_filename) - - print 'Downloading signature...' - signature_filename = '%s.asc' % data_filename - HttpRetrievefile(http, "%s.asc" % path, signature_filename) - - -def BuildIcuToolsAndData(data_filename): - # Keep track of the original cwd so we can go back to it at the end. - original_working_dir = os.getcwd() - - # Create a directory to run 'make' from. - icu_working_dir = '%s/icu' % original_working_dir - os.mkdir(icu_working_dir) - os.chdir(icu_working_dir) - - # Build the ICU tools. - print 'Configuring ICU tools...' - subprocess.check_call(['%s/runConfigureICU' % icu4c_dir, 'Linux']) - - # Run the ICU tools. - os.chdir('tools/tzcode') - - # The tz2icu tool only picks up icuregions and icuzones in they are in the CWD - for icu_data_file in [ 'icuregions', 'icuzones']: - icu_data_file_source = '%s/tools/tzcode/%s' % (icu4c_dir, icu_data_file) - icu_data_file_symlink = './%s' % icu_data_file - os.symlink(icu_data_file_source, icu_data_file_symlink) - - shutil.copyfile('%s/%s' % (original_working_dir, data_filename), data_filename) - print 'Making ICU data...' - # The Makefile assumes the existence of the bin directory. - os.mkdir('%s/bin' % icu_working_dir) - subprocess.check_call(['make']) - - # Copy the source file to its ultimate destination. - icu_txt_data_dir = '%s/data/misc' % icu4c_dir - print 'Copying zoneinfo64.txt to %s ...' % icu_txt_data_dir - shutil.copy('zoneinfo64.txt', icu_txt_data_dir) - - # Regenerate the .dat file. - os.chdir(icu_working_dir) - subprocess.check_call(['make', 'INCLUDE_UNI_CORE_DATA=1', '-j32']) - - # Copy the .dat file to its ultimate destination. - icu_dat_data_dir = '%s/stubdata' % icu4c_dir - datfiles = glob.glob('data/out/tmp/icudt??l.dat') - if len(datfiles) != 1: - print 'ERROR: Unexpectedly found %d .dat files (%s). Halting.' % (len(datfiles), datfiles) - sys.exit(1) - datfile = datfiles[0] - print 'Copying %s to %s ...' % (datfile, icu_dat_data_dir) - shutil.copy(datfile, icu_dat_data_dir) - - # Generate the ICU4J .jar files - os.chdir('%s/data' % icu_working_dir) - subprocess.check_call(['make', 'icu4j-data']) - - # Copy the ICU4J .jar files to their ultimate destination. - icu_jar_data_dir = '%s/main/shared/data' % icu4j_dir - jarfiles = glob.glob('out/icu4j/*.jar') - if len(jarfiles) != 2: - print 'ERROR: Unexpectedly found %d .jar files (%s). Halting.' % (len(jarfiles), jarfiles) - sys.exit(1) - for jarfile in jarfiles: - print 'Copying %s to %s ...' % (jarfile, icu_jar_data_dir) - shutil.copy(jarfile, icu_jar_data_dir) - - # Switch back to the original working cwd. - os.chdir(original_working_dir) - - -def CheckSignature(data_filename): - signature_filename = '%s.asc' % data_filename - print 'Verifying signature...' - # If this fails for you, you probably need to import Paul Eggert's public key: - # gpg --recv-keys ED97E90E62AA7E34 - subprocess.check_call(['gpg', '--trusted-key=ED97E90E62AA7E34', '--verify', - signature_filename, data_filename]) - - -def BuildBionicToolsAndData(data_filename): - new_version = re.search('(tzdata.+)\\.tar\\.gz', data_filename).group(1) - - print 'Extracting...' - os.mkdir('extracted') - tar = tarfile.open(data_filename, 'r') - tar.extractall('extracted') - - print 'Calling zic(1)...' - os.mkdir('data') - zic_inputs = [ 'extracted/%s' % x for x in regions ] - zic_cmd = ['zic', '-d', 'data' ] - zic_cmd.extend(zic_inputs) - subprocess.check_call(zic_cmd) - - WriteSetupFile() - - print 'Calling ZoneCompactor to update bionic to %s...' % new_version - subprocess.check_call(['javac', '-d', '.', - '%s/ZoneCompactor.java' % bionic_libc_tools_zoneinfo_dir]) - subprocess.check_call(['java', 'ZoneCompactor', - 'setup', 'data', 'extracted/zone.tab', - bionic_libc_zoneinfo_dir, new_version]) - - -# Run with no arguments from any directory, with no special setup required. -# See http://www.iana.org/time-zones/ for more about the source of this data. -def main(): - print 'Looking for new tzdata...' - - tzdata_filenames = [] - - # The FTP server lets you download intermediate releases, and also lets you - # download the signatures for verification, so it's your best choice. - use_ftp = True - - if use_ftp: - ftp = ftplib.FTP('ftp.iana.org') - ftp.login() - ftp.cwd('tz/releases') - for filename in ftp.nlst(): - if filename.startswith('tzdata20') and filename.endswith('.tar.gz'): - tzdata_filenames.append(filename) - tzdata_filenames.sort() - else: - http = httplib.HTTPConnection('www.iana.org') - http.request("GET", "/time-zones") - index_lines = http.getresponse().read().split('\n') - for line in index_lines: - m = re.compile('.*href="/time-zones/repository/releases/(tzdata20\d\d\c\.tar\.gz)".*').match(line) - if m: - tzdata_filenames.append(m.group(1)) - - # If you're several releases behind, we'll walk you through the upgrades - # one by one. - current_version = GetCurrentTzDataVersion() - current_filename = '%s.tar.gz' % current_version - for filename in tzdata_filenames: - if filename > current_filename: - print 'Found new tzdata: %s' % filename - SwitchToNewTemporaryDirectory() - if use_ftp: - FtpRetrieveFileAndSignature(ftp, filename) - else: - HttpRetrieveFileAndSignature(http, filename) - - CheckSignature(filename) - BuildIcuToolsAndData(filename) - BuildBionicToolsAndData(filename) - print 'Look in %s and %s for new data files' % (bionic_dir, icu_dir) - sys.exit(0) - - print 'You already have the latest tzdata (%s)!' % current_version - sys.exit(0) - - -if __name__ == '__main__': - main() -- cgit v1.1 From 545862d54af2b210bba725cc655857f7d7068ad9 Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Fri, 17 Jun 2016 16:38:12 -0700 Subject: bionic: Sort and cache hosts file data for fast lookup The hosts file is normally searched linearly. This is very slow when the file is large. To mitigate this, read the hosts file and sort the entries in an in-memory cache. When an address is requested via gethostbyname or getaddrinfo, binary search the cache. In case where the cache is not available, return a suitable error code and fall back to the existing lookup code. This has been written to behave as much like the existing lookup code as possible. But note bionic and glibc differ in behavior for some corner cases. Choose the most standard compliant behavior for these where possible. Otherwise choose the behavior that seems most reasonable. Change-Id: I3b322883cbc48b0d76a0ce9d149b59faaac1dc58 --- libc/dns/net/getaddrinfo.c | 10 + libc/dns/net/hosts_cache.c | 524 +++++++++++++++++++++++++++++++++++++++++++++ libc/dns/net/hosts_cache.h | 23 ++ libc/dns/net/sethostent.c | 7 + 4 files changed, 564 insertions(+) create mode 100644 libc/dns/net/hosts_cache.c create mode 100644 libc/dns/net/hosts_cache.h diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c index cc8b8b4..269be56 100644 --- a/libc/dns/net/getaddrinfo.c +++ b/libc/dns/net/getaddrinfo.c @@ -108,6 +108,8 @@ #include #include "nsswitch.h" +#include "hosts_cache.h" + #ifdef ANDROID_CHANGES #include #endif /* ANDROID_CHANGES */ @@ -2107,6 +2109,14 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap) name = va_arg(ap, char *); pai = va_arg(ap, struct addrinfo *); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + int gai_error = hc_getaddrinfo(name, NULL, pai, &cur); + if (gai_error != EAI_SYSTEM) { + *((struct addrinfo **)rv) = sentinel.ai_next; + return (gai_error == 0 ? NS_SUCCESS : NS_NOTFOUND); + } + // fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c new file mode 100644 index 0000000..deafb78 --- /dev/null +++ b/libc/dns/net/hosts_cache.c @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hostent.h" +#include "resolv_private.h" + +#define MAX_ADDRLEN (INET6_ADDRSTRLEN - (1 + 5)) +#define MAX_HOSTLEN MAXHOSTNAMELEN + +#define ESTIMATED_LINELEN 32 +#define HCFILE_ALLOC_SIZE 256 + +/* From sethostent.c */ +#define ALIGNBYTES (sizeof(uintptr_t) - 1) +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) + +/* + * Host cache entry for hcfile.c_data. + * Offsets are into hcfile.h_data. + * Strings are *not* terminated by NULL, but by whitespace (isspace) or '#'. + * Use hstr* functions with these. + */ +struct hcent +{ + uint32_t addr; + uint32_t name; +}; + +/* + * Overall host cache file state. + */ +struct hcfile +{ + int h_fd; + struct stat h_st; + char *h_data; + + uint32_t c_alloc; + uint32_t c_len; + struct hcent *c_data; +}; +static struct hcfile hcfile; +static pthread_mutex_t hclock = PTHREAD_MUTEX_INITIALIZER; + +static size_t hstrlen(const char *s) +{ + const char *p = s; + while (*p && *p != '#' && !isspace(*p)) + ++p; + return p - s; +} + +static int hstrcmp(const char *a, const char *b) +{ + size_t alen = hstrlen(a); + size_t blen = hstrlen(b); + int res = strncmp(a, b, MIN(alen, blen)); + if (res == 0) + res = alen - blen; + return res; +} + +static char *hstrcpy(char *dest, const char *src) +{ + size_t len = hstrlen(src); + memcpy(dest, src, len); + dest[len] = '\0'; + return dest; +} + +static char *hstrdup(const char *s) +{ + size_t len = hstrlen(s); + char *dest = (char *)malloc(len + 1); + if (!dest) + return NULL; + memcpy(dest, s, len); + dest[len] = '\0'; + return dest; +} + +static int cmp_hcent_name(const void *a, const void *b) +{ + struct hcent *ea = (struct hcent *)a; + const char *na = hcfile.h_data + ea->name; + struct hcent *eb = (struct hcent *)b; + const char *nb = hcfile.h_data + eb->name; + + return hstrcmp(na, nb); +} + +static struct hcent *_hcfindname(const char *name) +{ + size_t first, last, mid; + struct hcent *cur = NULL; + int cmp; + + if (hcfile.c_len == 0) + return NULL; + + first = 0; + last = hcfile.c_len - 1; + mid = (first + last) / 2; + while (first <= last) { + cur = hcfile.c_data + mid; + cmp = hstrcmp(hcfile.h_data + cur->name, name); + if (cmp == 0) + goto found; + if (cmp < 0) + first = mid + 1; + else { + if (mid > 0) + last = mid - 1; + else + return NULL; + } + mid = (first + last) / 2; + } + return NULL; + +found: + while (cur > hcfile.c_data) { + struct hcent *prev = cur - 1; + cmp = cmp_hcent_name(cur, prev); + if (cmp) + break; + cur = prev; + } + + return cur; +} + +/* + * Find next name on line, if any. + * + * Assumes that line is terminated by LF. + */ +static const char *_hcnextname(const char *name) +{ + while (!isspace(*name)) { + if (*name == '#') + return NULL; + ++name; + } + while (isspace(*name)) { + if (*name == '\n') + return NULL; + ++name; + } + if (*name == '#') + return NULL; + return name; +} + +static int _hcfilemmap(void) +{ + struct stat st; + int h_fd; + char *h_addr; + const char *p, *pend; + uint32_t c_alloc; + + h_fd = open(_PATH_HOSTS, O_RDONLY); + if (h_fd < 0) + return -1; + if (flock(h_fd, LOCK_EX) != 0) { + close(h_fd); + return -1; + } + + if (hcfile.h_data) { + memset(&st, 0, sizeof(st)); + if (fstat(h_fd, &st) == 0) { + if (st.st_size == hcfile.h_st.st_size && + st.st_mtime == hcfile.h_st.st_mtime) { + flock(h_fd, LOCK_UN); + close(h_fd); + return 0; + } + } + free(hcfile.c_data); + munmap(hcfile.h_data, hcfile.h_st.st_size); + close(hcfile.h_fd); + memset(&hcfile, 0, sizeof(struct hcfile)); + } + + if (fstat(h_fd, &st) != 0) { + flock(h_fd, LOCK_UN); + close(h_fd); + return -1; + } + h_addr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, h_fd, 0); + if (h_addr == MAP_FAILED) { + flock(h_fd, LOCK_UN); + close(h_fd); + return -1; + } + + hcfile.h_fd = h_fd; + hcfile.h_st = st; + hcfile.h_data = h_addr; + + c_alloc = 0; + /* + * Do an initial allocation if the file is "large". Estimate + * 32 bytes per line and define "large" as more than half of + * the alloc growth size (256 entries). + */ + if (st.st_size >= ESTIMATED_LINELEN * HCFILE_ALLOC_SIZE / 2) { + c_alloc = st.st_size / ESTIMATED_LINELEN; + hcfile.c_data = malloc(c_alloc * sizeof(struct hcent)); + if (!hcfile.c_data) { + goto oom; + } + } + + p = (const char *)h_addr; + pend = p + st.st_size; + while (p < pend) { + const char *eol, *addr, *name; + size_t len; + addr = p; + eol = memchr(p, '\n', pend - p); + if (!eol) + break; + p = eol + 1; + if (*addr == '#' || *addr == '\n') + continue; + len = hstrlen(addr); + if (len > MAX_ADDRLEN) + continue; + name = addr + len; + while (name < eol && isspace(*name)) + ++name; + while (name < eol) { + len = hstrlen(name); + if (len == 0) + break; + if (len < MAX_HOSTLEN) { + struct hcent *ent; + if (c_alloc <= hcfile.c_len) { + struct hcent *c_data; + c_alloc += HCFILE_ALLOC_SIZE; + c_data = realloc(hcfile.c_data, c_alloc * sizeof(struct hcent)); + if (!c_data) { + goto oom; + } + hcfile.c_data = c_data; + } + ent = hcfile.c_data + hcfile.c_len; + ent->addr = addr - h_addr; + ent->name = name - h_addr; + ++hcfile.c_len; + } + name += len; + while (name < eol && isspace(*name)) + ++name; + } + } + + qsort(hcfile.c_data, hcfile.c_len, + sizeof(struct hcent), cmp_hcent_name); + + flock(h_fd, LOCK_UN); + + return 0; + +oom: + free(hcfile.c_data); + munmap(hcfile.h_data, hcfile.h_st.st_size); + flock(hcfile.h_fd, LOCK_UN); + close(hcfile.h_fd); + memset(&hcfile, 0, sizeof(struct hcfile)); + return -1; +} + +/* + * Caching version of getaddrinfo. + * + * If we find the requested host name in the cache, use getaddrinfo to + * populate the result for each address we find. + * + * Note glibc and bionic differ in the handling of ai_canonname. POSIX + * says that ai_canonname is only populated in the first result entry. + * glibc does this. bionic populates ai_canonname in all result entries. + * We choose the POSIX/glibc way here. + */ +int hc_getaddrinfo(const char *host, const char *service, + const struct addrinfo *hints, + struct addrinfo **result) +{ + int ret = 0; + struct hcent *ent, *cur; + struct addrinfo *ai; + struct addrinfo rhints; + struct addrinfo *last; + int canonname = 0; + int cmp; + + if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL) + return EAI_SYSTEM; + + /* Avoid needless work and recursion */ + if (hints && (hints->ai_flags & AI_NUMERICHOST)) + return EAI_SYSTEM; + if (!host) + return EAI_SYSTEM; + + pthread_mutex_lock(&hclock); + + if (_hcfilemmap() != 0) { + ret = EAI_SYSTEM; + goto out; + } + ent = _hcfindname(host); + if (!ent) { + ret = EAI_NONAME; + goto out; + } + + if (hints) { + canonname = (hints->ai_flags & AI_CANONNAME); + memcpy(&rhints, hints, sizeof(rhints)); + rhints.ai_flags &= ~AI_CANONNAME; + } + else { + memset(&rhints, 0, sizeof(rhints)); + } + rhints.ai_flags |= AI_NUMERICHOST; + + last = NULL; + cur = ent; + do { + char addrstr[MAX_ADDRLEN]; + struct addrinfo *res; + + hstrcpy(addrstr, hcfile.h_data + cur->addr); + + if (getaddrinfo(addrstr, service, &rhints, &res) == 0) { + if (!last) + (*result)->ai_next = res; + else + last->ai_next = res; + last = res; + while (last->ai_next) + last = last->ai_next; + } + + if(cur + 1 >= hcfile.c_data + hcfile.c_len) + break; + cmp = cmp_hcent_name(cur, cur + 1); + cur = cur + 1; + } + while (!cmp); + + if (last == NULL) { + /* This check is equivalent to (*result)->ai_next == NULL */ + ret = EAI_NODATA; + goto out; + } + + if (canonname) { + ai = (*result)->ai_next; + free(ai->ai_canonname); + ai->ai_canonname = hstrdup(hcfile.h_data + ent->name); + } + +out: + pthread_mutex_unlock(&hclock); + return ret; +} + +/* + * Caching version of gethtbyname. + * + * Note glibc and bionic differ in the handling of aliases. glibc returns + * all aliases for all entries, regardless of whether they match h_addrtype. + * bionic returns only the aliases for the first hosts entry. We return all + * aliases for all IPv4 entries. + * + * Additionally, if an alias is IPv6 and the primary name for an alias also + * has an IPv4 entry, glibc will return the IPv4 address(es), but bionic + * will not. Neither do we. + */ +int hc_gethtbyname(const char *host, int af, struct getnamaddr *info) +{ + int ret = NETDB_SUCCESS; + struct hcent *ent, *cur; + int cmp; + size_t addrlen; + unsigned int naliases = 0; + char *aliases[MAXALIASES]; + unsigned int naddrs = 0; + char *addr_ptrs[MAXADDRS]; + unsigned int n; + + if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL) + return NETDB_INTERNAL; + + switch (af) { + case AF_INET: addrlen = NS_INADDRSZ; break; + case AF_INET6: addrlen = NS_IN6ADDRSZ; break; + default: + return NETDB_INTERNAL; + } + + pthread_mutex_lock(&hclock); + + if (_hcfilemmap() != 0) { + ret = NETDB_INTERNAL; + goto out; + } + + ent = _hcfindname(host); + if (!ent) { + ret = HOST_NOT_FOUND; + goto out; + } + + cur = ent; + do { + char addr[16]; + char addrstr[MAX_ADDRLEN]; + char namestr[MAX_HOSTLEN]; + const char *name; + + hstrcpy(addrstr, hcfile.h_data + cur->addr); + if (inet_pton(af, addrstr, &addr) == 1) { + char *aligned; + /* First match is considered the official hostname */ + if (naddrs == 0) { + hstrcpy(namestr, hcfile.h_data + cur->name); + HENT_SCOPY(info->hp->h_name, namestr, info->buf, info->buflen); + } + for (name = hcfile.h_data + cur->name; name; name = _hcnextname(name)) { + if (!hstrcmp(name, host)) + continue; + hstrcpy(namestr, name); + HENT_SCOPY(aliases[naliases], namestr, info->buf, info->buflen); + ++naliases; + if (naliases >= MAXALIASES) + goto nospc; + } + aligned = (char *)ALIGN(info->buf); + if (info->buf != aligned) { + if ((ptrdiff_t)info->buflen < (aligned - info->buf)) + goto nospc; + info->buflen -= (aligned - info->buf); + info->buf = aligned; + } + HENT_COPY(addr_ptrs[naddrs], addr, addrlen, info->buf, info->buflen); + ++naddrs; + if (naddrs >= MAXADDRS) + goto nospc; + } + + if(cur + 1 >= hcfile.c_data + hcfile.c_len) + break; + cmp = cmp_hcent_name(cur, cur + 1); + cur = cur + 1; + } + while (!cmp); + + if (naddrs == 0) { + ret = HOST_NOT_FOUND; + goto out; + } + + addr_ptrs[naddrs++] = NULL; + aliases[naliases++] = NULL; + + /* hp->h_name already populated */ + HENT_ARRAY(info->hp->h_aliases, naliases, info->buf, info->buflen); + for (n = 0; n < naliases; ++n) { + info->hp->h_aliases[n] = aliases[n]; + } + info->hp->h_addrtype = af; + info->hp->h_length = addrlen; + HENT_ARRAY(info->hp->h_addr_list, naddrs, info->buf, info->buflen); + for (n = 0; n < naddrs; ++n) { + info->hp->h_addr_list[n] = addr_ptrs[n]; + } + +out: + pthread_mutex_unlock(&hclock); + *info->he = ret; + return ret; + +nospc: + ret = NETDB_INTERNAL; + goto out; +} diff --git a/libc/dns/net/hosts_cache.h b/libc/dns/net/hosts_cache.h new file mode 100644 index 0000000..fa5488f --- /dev/null +++ b/libc/dns/net/hosts_cache.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +struct getnamaddr; + +int hc_getaddrinfo(const char *host, const char *service, + const struct addrinfo *hints, + struct addrinfo **result); + +int hc_gethtbyname(const char *host, int af, struct getnamaddr *info); diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c index 916421e..be29621 100644 --- a/libc/dns/net/sethostent.c +++ b/libc/dns/net/sethostent.c @@ -55,6 +55,8 @@ __RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $"); #include "hostent.h" #include "resolv_private.h" +#include "hosts_cache.h" + #define ALIGNBYTES (sizeof(uintptr_t) - 1) #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) @@ -99,6 +101,11 @@ _hf_gethtbyname(void *rv, void *cb_data, va_list ap) /* NOSTRICT skip string len */(void)va_arg(ap, int); af = va_arg(ap, int); + int rc = hc_gethtbyname(name, af, info); + if (rc != NETDB_INTERNAL) { + return (rc == NETDB_SUCCESS ? NS_SUCCESS : NS_NOTFOUND); + } + #if 0 { res_state res = __res_get_state(); -- cgit v1.1 From 92595081575c82ace07201a3ea32004eba968c0b Mon Sep 17 00:00:00 2001 From: Marcin Chojnacki Date: Sun, 10 Nov 2013 13:59:47 +0100 Subject: linker: Avoid logcat spam with some blobs Many of pre-kitkat blobs would emit a "text relocations" warning which makes logcat completely unreadable. This commit will hide this warning to prevent it. Change-Id: I8f32b5bbfea33d732320b3ac29da6b0027fbd521 Reworked-by: Caio Oliveira --- linker/linker.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linker/linker.cpp b/linker/linker.cpp index 6019c91..99c02d8 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -3023,7 +3023,11 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t& #endif // Make segments writable to allow text relocations to work properly. We will later call // phdr_table_protect_segments() after all of them are applied and all constructors are run. +#if defined(USE_LEGACY_BLOBS) + DEBUG("%s has text relocations. This is wasting memory and prevents " +#else DL_WARN("%s has text relocations. This is wasting memory and prevents " +#endif "security hardening. Please fix.", get_realpath()); if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { DL_ERR("can't unprotect loadable segments for \"%s\": %s", -- cgit v1.1