| From a6d463794be51d5f48af655da22c3acb8f24fd02 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Fran=C3=A7ois=20Degros?= <fdegros@chromium.org> |
| Date: Tue, 17 Nov 2020 14:26:09 +1100 |
| Subject: [PATCH] Link and initialize chrome-icu |
| |
| Make fuse-zip work with the ChromeOS-specific version of |
| ICU (chrome-icu) on ChromeOS. |
| --- |
| Makefile | 4 +- |
| lib/Makefile | 4 +- |
| lib/fuseZipData.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++ |
| 3 files changed, 115 insertions(+), 3 deletions(-) |
| |
| diff --git a/Makefile b/Makefile |
| index e72ce52..1406e73 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -8,9 +8,9 @@ mandir=$(datarootdir)/man |
| man1dir=$(mandir)/man1 |
| manext=.1 |
| PKG_CONFIG ?= pkg-config |
| -PC_DEPS = fuse libzip icu-uc icu-i18n |
| +PC_DEPS = fuse libzip |
| PC_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PC_DEPS)) |
| -LIBS := -Llib -lfusezip $(shell $(PKG_CONFIG) --libs $(PC_DEPS)) |
| +LIBS := -Llib -lfusezip -licui18n-chrome -licuuc-chrome $(shell $(PKG_CONFIG) --libs $(PC_DEPS)) |
| COMMON_CXXFLAGS = -Wall -Wextra -Wconversion -Wno-sign-compare -Wlogical-op -Wshadow -pedantic -std=c++17 |
| CXXFLAGS = -g -O0 $(COMMON_CXXFLAGS) |
| RELEASE_CXXFLAGS = -O2 $(COMMON_CXXFLAGS) |
| diff --git a/lib/Makefile b/lib/Makefile |
| index 4e4b23a..8c2d098 100644 |
| --- a/lib/Makefile |
| +++ b/lib/Makefile |
| @@ -1,7 +1,9 @@ |
| DEST=libfusezip.a |
| PKG_CONFIG ?= pkg-config |
| -PC_DEPS = fuse libzip icu-uc icu-i18n |
| +PC_DEPS = fuse libzip |
| PC_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PC_DEPS)) |
| +PC_CFLAGS += -I"$(SYSROOT)/usr/include/icu-chrome/common" |
| +PC_CFLAGS += -I"$(SYSROOT)/usr/include/icu-chrome/i18n" |
| COMMON_CXXFLAGS = -Wall -Wextra -Wconversion -Wno-sign-compare -Wlogical-op -Wshadow -pedantic -std=c++17 |
| CXXFLAGS = -g -O0 $(COMMON_CXXFLAGS) |
| RELEASE_CXXFLAGS = -O2 $(COMMON_CXXFLAGS) |
| diff --git a/lib/fuseZipData.cpp b/lib/fuseZipData.cpp |
| index 9639a8e..6666d6e 100644 |
| --- a/lib/fuseZipData.cpp |
| +++ b/lib/fuseZipData.cpp |
| @@ -25,10 +25,18 @@ |
| #include <stdexcept> |
| #include <functional> |
| #include <memory> |
| +#include <system_error> |
| |
| +#include <fcntl.h> |
| #include <syslog.h> |
| +#include <sys/mman.h> |
| +#include <sys/stat.h> |
| +#include <sys/types.h> |
| +#include <unicode/putil.h> |
| +#include <unicode/uclean.h> |
| #include <unicode/ucnv.h> |
| #include <unicode/ucsdet.h> |
| +#include <unicode/udata.h> |
| |
| #include "fuseZipData.h" |
| #include "extraField.h" |
| @@ -60,6 +68,105 @@ static void SetPassword(zip_t *const archive) { |
| |
| namespace { |
| |
| +[[noreturn]] void ThrowSystemError(const char *const reason) { |
| + throw std::system_error(errno, std::system_category(), reason); |
| +} |
| + |
| +// A scoped file handle. |
| +class ScopedFile { |
| + public: |
| + // Closes the file. |
| + ~ScopedFile() { |
| + if (close(fd_) < 0) |
| + perror("Cannot close file"); |
| + } |
| + |
| + explicit ScopedFile(int fd) : fd_(fd) {} |
| + |
| + // No copy. |
| + ScopedFile(const ScopedFile &) = delete; |
| + ScopedFile &operator=(const ScopedFile &) = delete; |
| + |
| + private: |
| + const int fd_; |
| +}; |
| + |
| +// A file mapping to memory. |
| +class FileMapping { |
| + public: |
| + // Removes the memory mapping. |
| + ~FileMapping() { |
| + if (munmap(data_, size_) < 0) |
| + perror("Cannot unmap file"); |
| + } |
| + |
| + // Maps a file to memory in read-only mode. |
| + // Throws a runtime_error in case of error. |
| + explicit FileMapping(const char *const path) { |
| + // Open file in read-only mode. |
| + const int fd = open(path, O_RDONLY); |
| + if (fd < 0) |
| + ThrowSystemError("Cannot open file"); |
| + |
| + // Ensure file will be closed. |
| + const ScopedFile guard(fd); |
| + |
| + // Get file size. |
| + struct stat st; |
| + if (fstat(fd, &st) < 0) |
| + ThrowSystemError("Cannot fstat file"); |
| + |
| + size_ = static_cast<size_t>(st.st_size); |
| + if (size_ != st.st_size) |
| + throw std::runtime_error("File too big to be memory-mapped"); |
| + |
| + // Map file to memory. |
| + data_ = mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd, 0); |
| + if (data_ == MAP_FAILED) |
| + ThrowSystemError("Cannot mmap file"); |
| + } |
| + |
| + // No copy. |
| + FileMapping(const FileMapping &) = delete; |
| + FileMapping &operator=(const FileMapping &) = delete; |
| + |
| + // Start of the memory mapping. |
| + const void *data() const { return data_; } |
| + |
| + private: |
| + void *data_; |
| + size_t size_; |
| +}; |
| + |
| +// Initializes and cleans up the ICU library. |
| +class IcuGuard { |
| + public: |
| + // Initializes the ICU library. |
| + // Throws an runtime_error in case of error. |
| + IcuGuard() { |
| + UErrorCode error = U_ZERO_ERROR; |
| + udata_setCommonData(mappedDataFile.data(), &error); |
| + // Never try to load ICU data from files. |
| + udata_setFileAccess(UDATA_ONLY_PACKAGES, &error); |
| + u_init(&error); |
| + if (U_FAILURE(error)) { |
| + std::string msg = "Cannot initialize ICU: "; |
| + msg += u_errorName(error); |
| + throw std::runtime_error(std::move(msg)); |
| + } |
| + } |
| + |
| + // Cleans up the ICU library. |
| + ~IcuGuard() { u_cleanup(); } |
| + |
| + // No copy. |
| + IcuGuard(const IcuGuard &) = delete; |
| + IcuGuard &operator=(const IcuGuard &) = delete; |
| + |
| + private: |
| + const FileMapping mappedDataFile{"/opt/google/chrome/icudtl.dat"}; |
| +}; |
| + |
| struct Closer { |
| void operator()(UConverter *const conv) const { ucnv_close(conv); } |
| void operator()(UCharsetDetector *const csd) const { ucsdet_close(csd); } |
| @@ -236,6 +343,9 @@ void FuseZipData::build_tree(bool readonly) { |
| } |
| } |
| |
| + // Initialize ICU library and ensure it will be cleaned up. |
| + const IcuGuard guard; |
| + |
| // Detect filename encoding. |
| const std::string encoding = DetectEncoding(allNames); |
| allNames.clear(); |
| -- |
| 2.29.2.576.ga3fc446d84-goog |
| |