Merge "Move early_hal start to late-fs trigger action"
diff --git a/base/Android.bp b/base/Android.bp
index 121da42..3af7686 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -98,6 +98,7 @@
"parseint_test.cpp",
"parsenetaddress_test.cpp",
"quick_exit_test.cpp",
+ "scopeguard_test.cpp",
"stringprintf_test.cpp",
"strings_test.cpp",
"test_main.cpp",
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
new file mode 100644
index 0000000..abcf4bc
--- /dev/null
+++ b/base/include/android-base/scopeguard.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source 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.
+ */
+
+#ifndef ANDROID_BASE_SCOPEGUARD_H
+#define ANDROID_BASE_SCOPEGUARD_H
+
+#include <utility> // for std::move
+
+namespace android {
+namespace base {
+
+template <typename F>
+class ScopeGuard {
+ public:
+ ScopeGuard(F f) : f_(f), active_(true) {}
+
+ ScopeGuard(ScopeGuard&& that) : f_(std::move(that.f_)), active_(that.active_) {
+ that.active_ = false;
+ }
+
+ ~ScopeGuard() {
+ if (active_) f_();
+ }
+
+ ScopeGuard() = delete;
+ ScopeGuard(const ScopeGuard&) = delete;
+ void operator=(const ScopeGuard&) = delete;
+ void operator=(ScopeGuard&& that) = delete;
+
+ void Disable() { active_ = false; }
+
+ bool active() const { return active_; }
+
+ private:
+ F f_;
+ bool active_;
+};
+
+template <typename T>
+ScopeGuard<T> make_scope_guard(T f) {
+ return ScopeGuard<T>(f);
+}
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_SCOPEGUARD_H
diff --git a/base/scopeguard_test.cpp b/base/scopeguard_test.cpp
new file mode 100644
index 0000000..e11154a
--- /dev/null
+++ b/base/scopeguard_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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 "android-base/scopeguard.h"
+
+#include <utility>
+
+#include <gtest/gtest.h>
+
+TEST(scopeguard, normal) {
+ bool guarded_var = true;
+ {
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ }
+ ASSERT_FALSE(guarded_var);
+}
+
+TEST(scopeguard, disabled) {
+ bool guarded_var = true;
+ {
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ scopeguard.Disable();
+ }
+ ASSERT_TRUE(guarded_var);
+}
+
+TEST(scopeguard, moved) {
+ int guarded_var = true;
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ { decltype(scopeguard) new_guard(std::move(scopeguard)); }
+ EXPECT_FALSE(scopeguard.active());
+ ASSERT_FALSE(guarded_var);
+}
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 45266de..929b8ae 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -116,14 +116,25 @@
// Use NativeBridgeIsSupported() instead in non-namespace scenario.
bool NativeBridgeIsPathSupported(const char* path);
-// Initializes public and anonymous namespace at native bridge side.
+// Initializes anonymous namespace.
+// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
+//
+// The anonymous namespace is used in the case when a NativeBridge implementation
+// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
+// by dynamic linker; for example calls from the mono-compiled code.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
-bool NativeBridgeInitNamespace(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
-// Create a namespace and pass the key of related namespaces to native bridge.
+// Create new namespace in which native libraries will be loaded.
+// NativeBridge's peer of android_create_namespace() of dynamic linker.
+//
+// The libraries in the namespace are searched by folowing order:
+// 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+// 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+// 3. deault_library_path (This of this as namespace-local default library path)
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@@ -134,7 +145,17 @@
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
+// Creates a link which shares some libraries from one namespace to another.
+// NativeBridge's peer of android_link_namespaces() of dynamic linker.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames);
+
// Load a shared library with namespace key that is supported by the native bridge.
+// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
+// extension.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
@@ -152,7 +173,7 @@
// Parameters:
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
// Returns:
- // true iff initialization was successful.
+ // true if initialization was successful.
bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
const char* instruction_set);
@@ -194,10 +215,10 @@
// instruction set.
//
// Parameters:
- // instruction_set [IN] the instruction set of the app
+ // instruction_set [IN] the instruction set of the app
// Returns:
- // NULL if not supported by native bridge.
- // Otherwise, return all environment values to be set after fork.
+ // NULL if not supported by native bridge.
+ // Otherwise, return all environment values to be set after fork.
const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
// Added callbacks in version 2.
@@ -206,9 +227,9 @@
// forwards- or backwards-compatible, and libnativebridge will then stop using it.
//
// Parameters:
- // bridge_version [IN] the version of libnativebridge.
+ // bridge_version [IN] the version of libnativebridge.
// Returns:
- // true iff the native bridge supports the given version of libnativebridge.
+ // true if the native bridge supports the given version of libnativebridge.
bool (*isCompatibleWith)(uint32_t bridge_version);
// A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
@@ -217,12 +238,12 @@
// that will potentially lead to cycles.
//
// Parameters:
- // signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
+ // signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
// supported by the runtime.
// Returns:
- // NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
- // runtime.
- // Otherwise, a pointer to the signal handler.
+ // NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
+ // runtime.
+ // Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
// Added callbacks in version 3.
@@ -231,7 +252,7 @@
// to zero then the dynamic library is unloaded.
//
// Parameters:
- // handle [IN] the handler of a dynamic library.
+ // handle [IN] the handler of a dynamic library.
//
// Returns:
// 0 on success, and nonzero on error.
@@ -257,33 +278,36 @@
// Use isSupported instead in non-namespace scenario.
bool (*isPathSupported)(const char* library_path);
- // Initializes anonymous namespace at native bridge side and pass the key of
- // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+ // Initializes anonymous namespace at native bridge side.
+ // NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
+ //
+ // The anonymous namespace is used in the case when a NativeBridge implementation
+ // cannot identify the caller of dlopen/dlsym which happens for the code not loaded
+ // by dynamic linker; for example calls from the mono-compiled code.
//
// Parameters:
- // public_ns_sonames [IN] the name of "public" libraries.
- // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+ // public_ns_sonames [IN] the name of "public" libraries.
+ // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
// Returns:
- // true if the pass is ok.
- // Otherwise, false.
+ // true if the pass is ok.
+ // Otherwise, false.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
- bool (*initNamespace)(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+ bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
-
- // Create a namespace and pass the key of releated namespaces to native bridge.
+ // Create new namespace in which native libraries will be loaded.
+ // NativeBridge's peer of android_create_namespace() of dynamic linker.
//
// Parameters:
- // name [IN] the name of the namespace.
- // ld_library_path [IN] the first set of library search paths of the namespace.
- // default_library_path [IN] the second set of library search path of the namespace.
- // type [IN] the attribute of the namespace.
- // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
- // parent_ns [IN] the pointer of the parent namespace to be inherited from.
+ // name [IN] the name of the namespace.
+ // ld_library_path [IN] the first set of library search paths of the namespace.
+ // default_library_path [IN] the second set of library search path of the namespace.
+ // type [IN] the attribute of the namespace.
+ // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+ // parent_ns [IN] the pointer of the parent namespace to be inherited from.
// Returns:
- // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+ // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@@ -294,7 +318,25 @@
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
+ // Creates a link which shares some libraries from one namespace to another.
+ // NativeBridge's peer of android_link_namespaces() of dynamic linker.
+ //
+ // Parameters:
+ // from [IN] the namespace where libraries are accessed.
+ // to [IN] the namespace where libraries are loaded.
+ // shared_libs_sonames [IN] the libraries to be shared.
+ //
+ // Returns:
+ // Whether successed or not.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ bool (*linkNamespaces)(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames);
+
// Load a shared library within a namespace.
+ // NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
+ // extension.
//
// Parameters:
// libpath [IN] path to the shared library
diff --git a/include/system b/include/system
new file mode 120000
index 0000000..91d45be
--- /dev/null
+++ b/include/system
@@ -0,0 +1 @@
+../libsystem/include/system/
\ No newline at end of file
diff --git a/include/ziparchive/zip_writer.h b/include/ziparchive/zip_writer.h
index 41ca2e1..08ead48 100644
--- a/include/ziparchive/zip_writer.h
+++ b/include/ziparchive/zip_writer.h
@@ -75,7 +75,8 @@
uint32_t uncompressed_size;
uint16_t last_mod_time;
uint16_t last_mod_date;
- uint32_t local_file_header_offset;
+ uint32_t padding_length;
+ off64_t local_file_header_offset;
};
static const char* ErrorCodeString(int32_t error_code);
@@ -172,6 +173,7 @@
};
FILE* file_;
+ bool seekable_;
off64_t current_offset_;
State state_;
std::vector<FileEntry> files_;
diff --git a/init/Android.mk b/init/Android.mk
index 1ca88d7..730ffc4 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -62,6 +62,7 @@
action.cpp \
capabilities.cpp \
descriptors.cpp \
+ devices.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
@@ -81,7 +82,6 @@
LOCAL_SRC_FILES:= \
bootchart.cpp \
builtins.cpp \
- devices.cpp \
init.cpp \
keychords.cpp \
property_service.cpp \
@@ -138,6 +138,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
+ devices_test.cpp \
init_parser_test.cpp \
property_service_test.cpp \
util_test.cpp \
diff --git a/init/action.cpp b/init/action.cpp
index 2ccf0bc..347edb0 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -16,16 +16,11 @@
#include "action.h"
-#include <errno.h>
-
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include "builtins.h"
-#include "error.h"
-#include "init_parser.h"
-#include "log.h"
#include "util.h"
using android::base::Join;
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index beabea1..825603a 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -17,7 +17,6 @@
#include "bootchart.h"
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -31,9 +30,7 @@
#include <condition_variable>
#include <memory>
#include <mutex>
-#include <string>
#include <thread>
-#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 64c00e9..7298dff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -19,33 +19,28 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <linux/loop.h>
+#include <linux/module.h>
#include <mntent.h>
#include <net/if.h>
-#include <signal.h>
#include <sched.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/system_properties.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <linux/loop.h>
-#include <linux/module.h>
-
-#include <string>
-#include <thread>
-
-#include <selinux/android.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -55,14 +50,14 @@
#include <ext4_utils/ext4_crypt.h>
#include <ext4_utils/ext4_crypt_init_extensions.h>
#include <fs_mgr.h>
-#include <logwrap/logwrap.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "action.h"
#include "bootchart.h"
-#include "devices.h"
#include "init.h"
#include "init_parser.h"
-#include "log.h"
#include "property_service.h"
#include "reboot.h"
#include "service.h"
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 6e457cd..bc6bc8d 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -19,16 +19,15 @@
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
#include "init.h"
-#include "log.h"
#include "util.h"
DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
diff --git a/init/devices.cpp b/init/devices.cpp
index 405f92e..760e0f5 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -19,41 +19,37 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <linux/netlink.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <linux/netlink.h>
-
#include <memory>
#include <thread>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#include <selinux/android.h>
-#include <selinux/avc.h>
-
-#include <private/android_filesystem_config.h>
-
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+#include <selinux/avc.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "devices.h"
#include "ueventd_parser.h"
#include "util.h"
-#include "log.h"
#define SYSFS_PREFIX "/sys"
static const char *firmware_dirs[] = { "/etc/firmware",
@@ -286,8 +282,7 @@
}
}
-static void add_platform_device(const char *path)
-{
+void add_platform_device(const char* path) {
int path_len = strlen(path);
struct platform_node *bus;
const char *name = path;
@@ -329,8 +324,7 @@
return NULL;
}
-static void remove_platform_device(const char *path)
-{
+void remove_platform_device(const char* path) {
struct listnode *node;
struct platform_node *bus;
@@ -473,8 +467,7 @@
}
}
-static char **get_character_device_symlinks(struct uevent *uevent)
-{
+char** get_character_device_symlinks(struct uevent* uevent) {
const char *parent;
const char *slash;
char **links;
@@ -526,8 +519,24 @@
return NULL;
}
-static char **get_block_device_symlinks(struct uevent *uevent)
-{
+// replaces any unacceptable characters with '_', the
+// length of the resulting string is equal to the input string
+void sanitize_partition_name(char* s) {
+ const char* accept =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_-.";
+
+ if (!s) return;
+
+ while (*s) {
+ s += strspn(s, accept);
+ if (*s) *s++ = '_';
+ }
+}
+
+char** get_block_device_symlinks(struct uevent* uevent) {
const char *device;
struct platform_node *pdev;
const char *slash;
@@ -562,7 +571,7 @@
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
- sanitize(p);
+ sanitize_partition_name(p);
if (strcmp(uevent->partition_name, p)) {
LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
}
diff --git a/init/devices.h b/init/devices.h
index 26a064b..abf1e7c 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,9 +17,10 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
-#include <functional>
#include <sys/stat.h>
+#include <functional>
+
enum coldboot_action_t {
// coldboot continues without creating the device for the uevent
COLDBOOT_CONTINUE = 0,
@@ -55,4 +56,11 @@
unsigned short wildcard);
int get_device_fd();
-#endif /* _INIT_DEVICES_H */
+// Exposed for testing
+void add_platform_device(const char* path);
+void remove_platform_device(const char* path);
+char** get_character_device_symlinks(uevent* uevent);
+char** get_block_device_symlinks(struct uevent* uevent);
+void sanitize_partition_name(char* s);
+
+#endif /* _INIT_DEVICES_H */
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
new file mode 100644
index 0000000..f79c96d
--- /dev/null
+++ b/init/devices_test.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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 "devices.h"
+
+#include <string>
+#include <vector>
+
+#include <android-base/scopeguard.h>
+#include <gtest/gtest.h>
+
+template <char** (*Function)(uevent*)>
+void test_get_symlinks(const std::string& platform_device_name, uevent* uevent,
+ const std::vector<std::string> expected_links) {
+ add_platform_device(platform_device_name.c_str());
+ auto platform_device_remover = android::base::make_scope_guard(
+ [&platform_device_name]() { remove_platform_device(platform_device_name.c_str()); });
+
+ char** result = Function(uevent);
+ auto result_freer = android::base::make_scope_guard([result]() {
+ if (result) {
+ for (int i = 0; result[i]; i++) {
+ free(result[i]);
+ }
+ free(result);
+ }
+ });
+
+ auto expected_size = expected_links.size();
+ if (expected_size == 0) {
+ ASSERT_EQ(nullptr, result);
+ } else {
+ ASSERT_NE(nullptr, result);
+ // First assert size is equal, so we don't overrun expected_links
+ unsigned int size = 0;
+ while (result[size]) ++size;
+ ASSERT_EQ(expected_size, size);
+
+ for (unsigned int i = 0; i < size; ++i) {
+ EXPECT_EQ(expected_links[i], result[i]);
+ }
+ }
+}
+
+TEST(devices, get_character_device_symlinks_success) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/name/tty2-1:1.0",
+ .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result{"/dev/usb/ttyname"};
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_pdev_match) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/device/name/tty2-1:1.0", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_nothing_after_platform_device) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_usb_found) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/bad/bad/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_roothub) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_usb_device) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_final_slash) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/name", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_final_name) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device//", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform) {
+ // These are actual paths from bullhead
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition) {
+ // These are actual paths from bullhead
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = "modem",
+ .partition_num = 1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-name/modem",
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-num/p1",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition_only_num) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = nullptr,
+ .partition_num = 1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-num/p1",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition_only_name) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = "modem",
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-name/modem",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_pci) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_vbd) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/vbd-1234/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_no_matches) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/not_the_device/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, sanitize_null) {
+ sanitize_partition_name(nullptr);
+}
+
+TEST(devices, sanitize_empty) {
+ std::string empty;
+ sanitize_partition_name(&empty[0]);
+ EXPECT_EQ(0u, empty.size());
+}
+
+TEST(devices, sanitize_allgood) {
+ std::string good =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_-.";
+ std::string good_copy = good;
+ sanitize_partition_name(&good[0]);
+ EXPECT_EQ(good_copy, good);
+}
+
+TEST(devices, sanitize_somebad) {
+ std::string string = "abc!@#$%^&*()";
+ sanitize_partition_name(&string[0]);
+ EXPECT_EQ("abc__________", string);
+}
+
+TEST(devices, sanitize_allbad) {
+ std::string string = "!@#$%^&*()";
+ sanitize_partition_name(&string[0]);
+ EXPECT_EQ("__________", string);
+}
+
+TEST(devices, sanitize_onebad) {
+ std::string string = ")";
+ sanitize_partition_name(&string[0]);
+ EXPECT_EQ("_", string);
+}
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index d52247b..8a2bcc2 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -16,12 +16,8 @@
#include "import_parser.h"
-#include "errno.h"
+#include <android-base/logging.h>
-#include <string>
-#include <vector>
-
-#include "log.h"
#include "util.h"
bool ImportParser::ParseSection(const std::vector<std::string>& args,
diff --git a/init/init.cpp b/init/init.cpp
index e14034f..023d727 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "init.h"
+
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -42,6 +44,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -59,7 +62,6 @@
#include "devices.h"
#include "fs_mgr.h"
#include "import_parser.h"
-#include "init.h"
#include "init_parser.h"
#include "keychords.h"
#include "log.h"
@@ -716,14 +718,18 @@
return false;
}
std::string actual_plat_id;
- if (!read_first_line("/system/etc/selinux/plat_sepolicy.cil.sha256", &actual_plat_id)) {
- PLOG(INFO) << "Failed to read /system/etc/selinux/plat_sepolicy.cil.sha256";
+ if (!read_first_line("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256",
+ &actual_plat_id)) {
+ PLOG(INFO) << "Failed to read "
+ "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
return false;
}
std::string precompiled_plat_id;
- if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat.sha256",
+ if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat_and_mapping.sha256",
&precompiled_plat_id)) {
- PLOG(INFO) << "Failed to read /vendor/etc/selinux/precompiled_sepolicy.plat.sha256";
+ PLOG(INFO) << "Failed to read "
+ "/vendor/etc/selinux/"
+ "precompiled_sepolicy.plat_and_mapping.sha256";
return false;
}
if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
@@ -795,7 +801,7 @@
"-M", "true",
// Target the highest policy language version supported by the kernel
"-c", std::to_string(max_policy_version).c_str(),
- "/vendor/etc/selinux/mapping_sepolicy.cil",
+ "/system/etc/selinux/mapping_sepolicy.cil",
"/vendor/etc/selinux/nonplat_sepolicy.cil",
"-o", compiled_sepolicy,
// We don't care about file_contexts output by the compiler
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index a192862..53e670b 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -14,18 +14,17 @@
* limitations under the License.
*/
+#include "init_parser.h"
+
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
#include "action.h"
-#include "init_parser.h"
-#include "log.h"
#include "parser.h"
#include "service.h"
-#include "util.h"
-
-#include <android-base/stringprintf.h>
Parser::Parser() {
}
diff --git a/init/init_parser.h b/init/init_parser.h
index f66ba52..6935fdf 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -18,6 +18,7 @@
#define _INIT_INIT_PARSER_H_
#include <map>
+#include <memory>
#include <string>
#include <vector>
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index 52aaa37..d8fd2ba 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -18,9 +18,7 @@
#include "init.h"
#include "service.h"
-#include "util.h"
-#include <errno.h>
#include <gtest/gtest.h>
#include <string>
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 5801ea8..c572cee 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/keychord.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include "init.h"
-#include "log.h"
#include "service.h"
static struct input_keychord *keychords = 0;
diff --git a/init/log.cpp b/init/log.cpp
index 6b32526..ee6489b 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -17,9 +17,10 @@
#include "log.h"
#include <fcntl.h>
+#include <linux/audit.h>
#include <string.h>
-#include <linux/audit.h>
+#include <android-base/logging.h>
#include <netlink/netlink.h>
#include <selinux/selinux.h>
diff --git a/init/log.h b/init/log.h
index 8fa6d74..29a27af 100644
--- a/init/log.h
+++ b/init/log.h
@@ -17,7 +17,7 @@
#ifndef _INIT_LOG_H_
#define _INIT_LOG_H_
-#include <android-base/logging.h>
+#include <sys/cdefs.h>
void InitKernelLogging(char* argv[]);
diff --git a/init/parser.cpp b/init/parser.cpp
index 45862b7..5953a88 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -4,7 +4,7 @@
#include <stdio.h>
#include <string.h>
-#include "log.h"
+#include <android-base/logging.h>
void parse_error(struct parse_state *state, const char *fmt, ...)
{
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a4d8b5f..2aa89ff 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -14,46 +14,45 @@
* limitations under the License.
*/
+#include "property_service.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
+#include <sys/mman.h>
#include <sys/poll.h>
-
-#include <memory>
-#include <vector>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/mman.h>
+#include <memory>
+#include <vector>
-#include <selinux/android.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
-#include <fs_mgr.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include "bootimg.h"
+#include <bootimg.h>
+#include <fs_mgr.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
-#include "property_service.h"
#include "init.h"
#include "util.h"
-#include "log.h"
using android::base::StringPrintf;
diff --git a/init/property_service.h b/init/property_service.h
index 994da63..9a5b6f6 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,9 +17,8 @@
#ifndef _INIT_PROPERTY_H
#define _INIT_PROPERTY_H
-#include <stddef.h>
#include <sys/socket.h>
-#include <sys/system_properties.h>
+
#include <string>
struct property_audit_data {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 62e5c85..53bdeb1 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include "reboot.h"
+
#include <dirent.h>
#include <fcntl.h>
#include <mntent.h>
@@ -27,11 +30,11 @@
#include <memory>
#include <set>
-#include <string>
#include <thread>
#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -41,11 +44,8 @@
#include <fs_mgr.h>
#include <logwrap/logwrap.h>
-#include "log.h"
#include "property_service.h"
-#include "reboot.h"
#include "service.h"
-#include "util.h"
using android::base::StringPrintf;
diff --git a/init/reboot.h b/init/reboot.h
index 3956249..6432fa5 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -17,6 +17,8 @@
#ifndef _INIT_REBOOT_H
#define _INIT_REBOOT_H
+#include <string>
+
/* Reboot / shutdown the system.
* cmd ANDROID_RB_* as defined in android_reboot.h
* reason Reason string like "reboot", "userrequested"
diff --git a/init/service.cpp b/init/service.cpp
index e89de9a..4adbbf0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -24,28 +24,23 @@
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/system_properties.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
-#include <selinux/selinux.h>
-
-#include <android-base/chrono_utils.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <processgroup/processgroup.h>
+#include <selinux/selinux.h>
#include <system/thread_defs.h>
-#include <processgroup/processgroup.h>
-
-#include "action.h"
#include "init.h"
-#include "init_parser.h"
-#include "log.h"
#include "property_service.h"
#include "util.h"
diff --git a/init/service.h b/init/service.h
index d84ce02..5e89b9f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -19,14 +19,13 @@
#include <sys/types.h>
-#include <cutils/iosched_policy.h>
-
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <android-base/chrono_utils.h>
+#include <cutils/iosched_policy.h>
#include "action.h"
#include "capabilities.h"
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 5e3acac..4d56d84 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -14,22 +14,17 @@
* limitations under the License.
*/
-#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
-#include <stdio.h>
+#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include "action.h"
#include "init.h"
-#include "log.h"
#include "service.h"
-#include "util.h"
static int signal_write_fd = -1;
static int signal_read_fd = -1;
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index ba53e47..ea767a8 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "ueventd.h"
+
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
@@ -24,17 +26,15 @@
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <selinux/selinux.h>
-#include "ueventd.h"
-#include "log.h"
-#include "util.h"
#include "devices.h"
+#include "log.h"
#include "ueventd_parser.h"
+#include "util.h"
int ueventd_main(int argc, char **argv)
{
diff --git a/init/ueventd.h b/init/ueventd.h
index d12d7fe..d44d1ca 100644
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -17,9 +17,10 @@
#ifndef _INIT_UEVENTD_H_
#define _INIT_UEVENTD_H_
-#include <cutils/list.h>
#include <sys/types.h>
+#include <cutils/list.h>
+
enum devname_src_t {
DEVNAME_UNKNOWN = 0,
DEVNAME_UEVENT_DEVNAME,
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 554c1e3..510d7bb 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -14,18 +14,18 @@
* limitations under the License.
*/
+#include "ueventd_parser.h"
+
#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
-#include "ueventd.h"
-#include "ueventd_parser.h"
+#include <android-base/logging.h>
+
#include "parser.h"
-#include "log.h"
#include "util.h"
static list_declare(subsystem_list);
diff --git a/init/util.cpp b/init/util.cpp
index bf4109c..bbc59cb 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,26 +14,21 @@
* limitations under the License.
*/
+#include "util.h"
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <ftw.h>
#include <pwd.h>
#include <stdarg.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <time.h>
#include <unistd.h>
-#include <selinux/android.h>
-#include <selinux/label.h>
-
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
#include <thread>
#include <android-base/file.h>
@@ -42,15 +37,13 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-
#include <cutils/android_reboot.h>
-/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
#include "init.h"
-#include "log.h"
#include "reboot.h"
-#include "util.h"
using android::base::boot_clock;
@@ -235,27 +228,6 @@
return 0;
}
-/*
- * replaces any unacceptable characters with '_', the
- * length of the resulting string is equal to the input string
- */
-void sanitize(char *s)
-{
- const char* accept =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789"
- "_-.";
-
- if (!s)
- return;
-
- while (*s) {
- s += strspn(s, accept);
- if (*s) *s++ = '_';
- }
-}
-
int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
boot_clock::time_point timeout_time = boot_clock::now() + timeout;
while (boot_clock::now() < timeout_time) {
diff --git a/init/util.h b/init/util.h
index 1034c9b..38a7bdb 100644
--- a/init/util.h
+++ b/init/util.h
@@ -61,7 +61,6 @@
unsigned int decode_uid(const char *s);
int mkdir_recursive(const char *pathname, mode_t mode);
-void sanitize(char *p);
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index b196147..21c1e5b 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -16,11 +16,12 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/watchdog.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <linux/watchdog.h>
+#include <android-base/logging.h>
#include "log.h"
#include "util.h"
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index b26827c..5fc2386 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -227,25 +227,24 @@
/* clang-format on */
};
+static size_t strip(const char* path, size_t len, const char suffix[]) {
+ if (len < strlen(suffix)) return len;
+ if (strncmp(path + len - strlen(suffix), suffix, strlen(suffix))) return len;
+ return len - strlen(suffix);
+}
+
static int fs_config_open(int dir, int which, const char* target_out_path) {
int fd = -1;
if (target_out_path && *target_out_path) {
/* target_out_path is the path to the directory holding content of
* system partition but as we cannot guarantee it ends with '/system'
- * or a trailing slash or not, we need to strip them off. */
+ * or with or without a trailing slash, need to strip them carefully. */
char* name = NULL;
- int target_out_path_len = strlen(target_out_path);
-
- while ((target_out_path_len > 0) &&
- (target_out_path[target_out_path_len - strlen("/")] == '/')) {
- --target_out_path_len;
- }
- if ((target_out_path_len >= (int)strlen("/system")) &&
- !strcmp(target_out_path + target_out_path_len - strlen("/system"), "/system")) {
- target_out_path_len -= strlen("/system");
- }
- if (asprintf(&name, "%.*s%s", target_out_path_len, target_out_path, conf[which][dir]) != -1) {
+ size_t len = strlen(target_out_path);
+ len = strip(target_out_path, len, "/");
+ len = strip(target_out_path, len, "/system");
+ if (asprintf(&name, "%.*s%s", (int)len, target_out_path, conf[which][dir]) != -1) {
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
free(name);
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bb8c3af..bc262db 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -107,14 +107,16 @@
license: "NOTICE",
}
-cc_library_headers {
- name: "liblog_vndk_headers",
- export_include_dirs: ["include_vndk"],
-}
-
ndk_library {
name: "liblog.ndk",
symbol_file: "liblog.map.txt",
first_version: "9",
unversioned_until: "current",
}
+
+llndk_library {
+ name: "liblog.llndk",
+ symbol_file: "liblog.map.txt",
+ unversioned: true,
+ export_include_dirs: ["include_vndk"],
+}
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 599dc90..c00f2a0 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -1,6 +1,10 @@
LIBLOG {
global:
+ android_name_to_log_id; # vndk
+ android_log_id_to_name; # vndk
__android_log_assert;
+ __android_log_buf_print; # vndk
+ __android_log_buf_write; # vndk
__android_log_print;
__android_log_vprint;
__android_log_write;
@@ -8,8 +12,27 @@
*;
};
+LIBLOG_L {
+ global:
+ android_logger_clear; # vndk
+ android_logger_get_id; # vndk
+ android_logger_get_log_readable_size; # vndk
+ android_logger_get_log_version; # vndk
+ android_logger_get_log_size; # vndk
+ android_logger_list_alloc; # vndk
+ android_logger_list_alloc_time; # vndk
+ android_logger_list_free; # vndk
+ android_logger_list_open; # vndk
+ android_logger_list_read; # vndk
+ android_logger_open; # vndk
+ android_logger_set_log_size; # vndk
+};
+
LIBLOG_M {
global:
+ android_logger_get_prune_list; # vndk
+ android_logger_set_prune_list; # vndk
+ android_logger_get_statistics; # vndk
__android_log_is_loggable;
};
diff --git a/liblog/properties.c b/liblog/properties.c
index 0b0ef52..adf1900 100644
--- a/liblog/properties.c
+++ b/liblog/properties.c
@@ -95,7 +95,7 @@
/* calculate the size of our key temporary buffer */
const size_t taglen = tag ? len : 0;
/* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+ char key[sizeof(log_namespace) + taglen];
char* kp;
size_t i;
char c = 0;
@@ -108,7 +108,8 @@
* Where the missing tag matches all tags and becomes the
* system global default. We do not support ro.log.tag* .
*/
- static char last_tag[PROP_NAME_MAX];
+ static char* last_tag;
+ static size_t last_tag_len;
static uint32_t global_serial;
/* some compilers erroneously see uninitialized use. !not_locked */
uint32_t current_global_serial = 0;
@@ -147,25 +148,29 @@
if (taglen) {
int local_change_detected = change_detected;
if (!not_locked) {
- if (!last_tag[0] || (last_tag[0] != tag[0]) ||
- strncmp(
- last_tag + 1, tag + 1,
- (len < sizeof(last_tag)) ? (len - 1) : (sizeof(last_tag) - 1)) ||
- ((len < sizeof(last_tag)) && last_tag[len])) {
+ if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
+ strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {
/* invalidate log.tag.<tag> cache */
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
tag_cache[i].cache.pinfo = NULL;
tag_cache[i].c = '\0';
}
- last_tag[0] = '\0';
+ if (last_tag) last_tag[0] = '\0';
local_change_detected = 1;
}
- if (!last_tag[0]) {
- if (len < sizeof(last_tag)) {
+ if (!last_tag || !last_tag[0]) {
+ if (!last_tag) {
+ last_tag = calloc(1, len + 1);
+ last_tag_len = 0;
+ if (last_tag) last_tag_len = len + 1;
+ } else if (len >= last_tag_len) {
+ last_tag = realloc(last_tag, len + 1);
+ last_tag_len = 0;
+ if (last_tag) last_tag_len = len + 1;
+ }
+ if (last_tag) {
strncpy(last_tag, tag, len);
last_tag[len] = '\0';
- } else {
- strncpy(last_tag, tag, sizeof(last_tag));
}
}
}
@@ -435,7 +440,7 @@
int flag) {
struct cache_property property = { { NULL, -1 }, { 0 } };
if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
- char newkey[PROP_NAME_MAX];
+ char newkey[strlen("persist.") + strlen(key) + 1];
snprintf(newkey, sizeof(newkey), "ro.%s", key);
refresh_cache_property(&property, newkey);
property.cache.pinfo = NULL;
@@ -600,8 +605,8 @@
evaluate_property_get_size
/* clang-format on */
};
- char key_persist[PROP_NAME_MAX];
- char key_ro[PROP_NAME_MAX];
+ char key_persist[strlen(global_tunable) + strlen(".security") + 1];
+ char key_ro[strlen(global_default) + strlen(".security") + 1];
struct cache2_property_size local = {
/* clang-format off */
PTHREAD_MUTEX_INITIALIZER, 0,
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 83f35b1..050373a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -573,11 +573,11 @@
return false;
}
-bool NativeBridgeInitNamespace(const char* public_ns_sonames,
- const char* anon_ns_library_path) {
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
- return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+ return callbacks->initAnonymousNamespace(public_ns_sonames, anon_ns_library_path);
} else {
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
}
@@ -608,6 +608,19 @@
return nullptr;
}
+bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->linkNamespaces(from, to, shared_libs_sonames);
+ } else {
+ ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+ }
+ }
+
+ return false;
+}
+
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 4c3e862..c9468f0 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -24,7 +24,7 @@
NativeBridge3UnloadLibrary_test.cpp \
NativeBridge3GetError_test.cpp \
NativeBridge3IsPathSupported_test.cpp \
- NativeBridge3InitNamespace_test.cpp \
+ NativeBridge3InitAnonymousNamespace_test.cpp \
NativeBridge3CreateNamespace_test.cpp \
NativeBridge3LoadLibraryExt_test.cpp
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
index 13fce85..4ef1c82 100644
--- a/libnativebridge/tests/DummyNativeBridge3.cpp
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -76,8 +76,8 @@
return true;
}
-extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
- const char* /* anon_ns_library_path */) {
+extern "C" bool native_bridge3_initAnonymousNamespace(const char* /* public_ns_sonames */,
+ const char* /* anon_ns_library_path */) {
return true;
}
@@ -91,30 +91,34 @@
return nullptr;
}
+extern "C" bool native_bridge3_linkNamespaces(android::native_bridge_namespace_t* /* from */,
+ android::native_bridge_namespace_t* /* to */,
+ const char* /* shared_libs_soname */) {
+ return true;
+}
+
extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
int /* flag */,
android::native_bridge_namespace_t* /* ns */) {
return nullptr;
}
-
-android::NativeBridgeCallbacks NativeBridgeItf {
- // v1
- .version = 3,
- .initialize = &native_bridge3_initialize,
- .loadLibrary = &native_bridge3_loadLibrary,
- .getTrampoline = &native_bridge3_getTrampoline,
- .isSupported = &native_bridge3_isSupported,
- .getAppEnv = &native_bridge3_getAppEnv,
- // v2
- .isCompatibleWith = &native_bridge3_isCompatibleWith,
- .getSignalHandler = &native_bridge3_getSignalHandler,
- // v3
- .unloadLibrary = &native_bridge3_unloadLibrary,
- .getError = &native_bridge3_getError,
- .isPathSupported = &native_bridge3_isPathSupported,
- .initNamespace = &native_bridge3_initNamespace,
- .createNamespace = &native_bridge3_createNamespace,
- .loadLibraryExt = &native_bridge3_loadLibraryExt
-};
-
+android::NativeBridgeCallbacks NativeBridgeItf{
+ // v1
+ .version = 3,
+ .initialize = &native_bridge3_initialize,
+ .loadLibrary = &native_bridge3_loadLibrary,
+ .getTrampoline = &native_bridge3_getTrampoline,
+ .isSupported = &native_bridge3_isSupported,
+ .getAppEnv = &native_bridge3_getAppEnv,
+ // v2
+ .isCompatibleWith = &native_bridge3_isCompatibleWith,
+ .getSignalHandler = &native_bridge3_getSignalHandler,
+ // v3
+ .unloadLibrary = &native_bridge3_unloadLibrary,
+ .getError = &native_bridge3_getError,
+ .isPathSupported = &native_bridge3_isPathSupported,
+ .initAnonymousNamespace = &native_bridge3_initAnonymousNamespace,
+ .createNamespace = &native_bridge3_createNamespace,
+ .linkNamespaces = &native_bridge3_linkNamespaces,
+ .loadLibraryExt = &native_bridge3_loadLibraryExt};
diff --git a/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp
new file mode 100644
index 0000000..b0d6b09
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitAnonymousNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeInitAnonymousNamespace(nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
deleted file mode 100644
index ae0fd2b..0000000
--- a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source 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 "NativeBridgeTest.h"
-
-namespace android {
-
-constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
-
-TEST_F(NativeBridgeTest, V3_InitNamespace) {
- // Init
- ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
- ASSERT_TRUE(NativeBridgeAvailable());
- ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
- ASSERT_TRUE(NativeBridgeAvailable());
- ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
- ASSERT_TRUE(NativeBridgeAvailable());
-
- ASSERT_EQ(3U, NativeBridgeGetVersion());
- ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
-
- // Clean-up code_cache
- ASSERT_EQ(0, rmdir(kCodeCache));
-}
-
-} // namespace android
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 74f2f1d..f3391d1 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -183,6 +183,11 @@
return false;
}
+ if (!NativeBridgeLinkNamespaces(ns, nullptr, public_libraries_.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return false;
+ }
+
native_loader_ns = NativeLoaderNamespace(ns);
}
@@ -324,8 +329,8 @@
// and now initialize native bridge namespaces if necessary.
if (NativeBridgeInitialized()) {
- initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
- is_native_bridge ? library_path : nullptr);
+ initialized_ = NativeBridgeInitAnonymousNamespace(public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
new file mode 100644
index 0000000..4d076d5
--- /dev/null
+++ b/libsystem/Android.bp
@@ -0,0 +1,4 @@
+cc_library_headers {
+ name: "libsystem_headers",
+ export_include_dirs: ["include"],
+}
diff --git a/include/system/camera.h b/libsystem/include/system/camera.h
similarity index 100%
rename from include/system/camera.h
rename to libsystem/include/system/camera.h
diff --git a/include/system/graphics.h b/libsystem/include/system/graphics.h
similarity index 100%
rename from include/system/graphics.h
rename to libsystem/include/system/graphics.h
diff --git a/include/system/qemu_pipe.h b/libsystem/include/system/qemu_pipe.h
similarity index 100%
rename from include/system/qemu_pipe.h
rename to libsystem/include/system/qemu_pipe.h
diff --git a/include/system/radio.h b/libsystem/include/system/radio.h
similarity index 100%
rename from include/system/radio.h
rename to libsystem/include/system/radio.h
diff --git a/include/system/thread_defs.h b/libsystem/include/system/thread_defs.h
similarity index 100%
rename from include/system/thread_defs.h
rename to libsystem/include/system/thread_defs.h
diff --git a/include/system/window.h b/libsystem/include/system/window.h
similarity index 100%
rename from include/system/window.h
rename to libsystem/include/system/window.h
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ee646de..e35593f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -54,6 +54,7 @@
"ElfInterfaceArm.cpp",
"Log.cpp",
"Regs.cpp",
+ "Maps.cpp",
"Memory.cpp",
"Symbols.cpp",
],
@@ -97,6 +98,7 @@
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",
"tests/LogFake.cpp",
+ "tests/MapsTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
new file mode 100644
index 0000000..b369c43
--- /dev/null
+++ b/libunwindstack/Maps.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Maps.h"
+
+MapInfo* Maps::Find(uint64_t pc) {
+ if (maps_.empty()) {
+ return nullptr;
+ }
+ size_t first = 0;
+ size_t last = maps_.size();
+ while (first < last) {
+ size_t index = (first + last) / 2;
+ MapInfo* cur = &maps_[index];
+ if (pc >= cur->start && pc < cur->end) {
+ return cur;
+ } else if (pc < cur->start) {
+ last = index;
+ } else {
+ first = index + 1;
+ }
+ }
+ return nullptr;
+}
+
+bool Maps::ParseLine(const char* line, MapInfo* map_info) {
+ char permissions[5];
+ int name_pos;
+ // Linux /proc/<pid>/maps lines:
+ // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*x:%*x %*d %n", &map_info->start,
+ &map_info->end, permissions, &map_info->offset, &name_pos) != 4) {
+ return false;
+ }
+ map_info->flags = PROT_NONE;
+ if (permissions[0] == 'r') {
+ map_info->flags |= PROT_READ;
+ }
+ if (permissions[1] == 'w') {
+ map_info->flags |= PROT_WRITE;
+ }
+ if (permissions[2] == 'x') {
+ map_info->flags |= PROT_EXEC;
+ }
+
+ map_info->name = &line[name_pos];
+ size_t length = map_info->name.length() - 1;
+ if (map_info->name[length] == '\n') {
+ map_info->name.erase(length);
+ }
+ // Mark a device map in /dev/and not in /dev/ashmem/ specially.
+ if (!map_info->name.empty() && map_info->name.substr(0, 5) == "/dev/" &&
+ map_info->name.substr(5, 7) != "ashmem/") {
+ map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ }
+
+ return true;
+}
+
+bool Maps::Parse() {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
+ if (!fp) {
+ return false;
+ }
+
+ bool valid = true;
+ char* line = nullptr;
+ size_t line_len;
+ while (getline(&line, &line_len, fp.get()) > 0) {
+ MapInfo map_info;
+ if (!ParseLine(line, &map_info)) {
+ valid = false;
+ break;
+ }
+
+ maps_.push_back(map_info);
+ }
+ free(line);
+
+ return valid;
+}
+
+Maps::~Maps() {
+ for (auto& map : maps_) {
+ delete map.elf;
+ map.elf = nullptr;
+ }
+}
+
+bool BufferMaps::Parse() {
+ const char* start_of_line = buffer_;
+ do {
+ std::string line;
+ const char* end_of_line = strchr(start_of_line, '\n');
+ if (end_of_line == nullptr) {
+ line = start_of_line;
+ } else {
+ end_of_line++;
+ line = std::string(start_of_line, end_of_line - start_of_line);
+ }
+
+ MapInfo map_info;
+ if (!ParseLine(line.c_str(), &map_info)) {
+ return false;
+ }
+ maps_.push_back(map_info);
+
+ start_of_line = end_of_line;
+ } while (start_of_line != nullptr && *start_of_line != '\0');
+ return true;
+}
+
+const std::string RemoteMaps::GetMapsFile() const {
+ return "/proc/" + std::to_string(pid_) + "/maps";
+}
+
+bool OfflineMaps::Parse() {
+ // Format of maps information:
+ // <uint64_t> StartOffset
+ // <uint64_t> EndOffset
+ // <uint64_t> offset
+ // <uint16_t> flags
+ // <uint16_t> MapNameLength
+ // <VariableLengthValue> MapName
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_.c_str(), O_RDONLY)));
+ if (fd == -1) {
+ return false;
+ }
+
+ std::vector<char> name;
+ while (true) {
+ MapInfo map_info;
+ ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
+ if (bytes == 0) {
+ break;
+ }
+ if (bytes == -1 || bytes != sizeof(map_info.start)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
+ if (bytes == -1 || bytes != sizeof(map_info.end)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
+ if (bytes == -1 || bytes != sizeof(map_info.offset)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
+ if (bytes == -1 || bytes != sizeof(map_info.flags)) {
+ return false;
+ }
+ uint16_t len;
+ bytes = TEMP_FAILURE_RETRY(read(fd, &len, sizeof(len)));
+ if (bytes == -1 || bytes != sizeof(len)) {
+ return false;
+ }
+ if (len > 0) {
+ name.resize(len);
+ bytes = TEMP_FAILURE_RETRY(read(fd, name.data(), len));
+ if (bytes == -1 || bytes != len) {
+ return false;
+ }
+ map_info.name = std::string(name.data(), len);
+ }
+ maps_.push_back(map_info);
+ }
+ return true;
+}
diff --git a/libunwindstack/Maps.h b/libunwindstack/Maps.h
new file mode 100644
index 0000000..239b64a
--- /dev/null
+++ b/libunwindstack/Maps.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MAPS_H
+#define _LIBUNWINDSTACK_MAPS_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "Elf.h"
+#include "MapInfo.h"
+
+// Special flag to indicate a map is in /dev/. However, a map in
+// /dev/ashmem/... does not set this flag.
+static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000;
+
+class Maps {
+ public:
+ Maps() = default;
+ virtual ~Maps();
+
+ MapInfo* Find(uint64_t pc);
+
+ bool ParseLine(const char* line, MapInfo* map_info);
+
+ virtual bool Parse();
+
+ virtual const std::string GetMapsFile() const { return ""; }
+
+ typedef std::vector<MapInfo>::iterator iterator;
+ iterator begin() { return maps_.begin(); }
+ iterator end() { return maps_.end(); }
+
+ typedef std::vector<MapInfo>::const_iterator const_iterator;
+ const_iterator begin() const { return maps_.begin(); }
+ const_iterator end() const { return maps_.end(); }
+
+ size_t Total() { return maps_.size(); }
+
+ protected:
+ std::vector<MapInfo> maps_;
+};
+
+class RemoteMaps : public Maps {
+ public:
+ RemoteMaps(pid_t pid) : pid_(pid) {}
+ virtual ~RemoteMaps() = default;
+
+ virtual const std::string GetMapsFile() const override;
+
+ private:
+ pid_t pid_;
+};
+
+class LocalMaps : public RemoteMaps {
+ public:
+ LocalMaps() : RemoteMaps(getpid()) {}
+ virtual ~LocalMaps() = default;
+};
+
+class BufferMaps : public Maps {
+ public:
+ BufferMaps(const char* buffer) : buffer_(buffer) {}
+ virtual ~BufferMaps() = default;
+
+ bool Parse() override;
+
+ private:
+ const char* buffer_;
+};
+
+class FileMaps : public Maps {
+ public:
+ FileMaps(const std::string& file) : file_(file) {}
+ virtual ~FileMaps() = default;
+
+ const std::string GetMapsFile() const override { return file_; }
+
+ protected:
+ const std::string file_;
+};
+
+class OfflineMaps : public FileMaps {
+ public:
+ OfflineMaps(const std::string& file) : FileMaps(file) {}
+ virtual ~OfflineMaps() = default;
+
+ bool Parse() override;
+};
+
+#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
new file mode 100644
index 0000000..7eb9bae
--- /dev/null
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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 <sys/mman.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "Maps.h"
+
+TEST(MapsTest, parse_permissions) {
+ BufferMaps maps(
+ "1000-2000 ---- 00000000 00:00 0\n"
+ "2000-3000 r--- 00000000 00:00 0\n"
+ "3000-4000 -w-- 00000000 00:00 0\n"
+ "4000-5000 --x- 00000000 00:00 0\n"
+ "5000-6000 rwx- 00000000 00:00 0\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(5U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(PROT_NONE, it->flags);
+ ASSERT_EQ(0x1000U, it->start);
+ ASSERT_EQ(0x2000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_READ, it->flags);
+ ASSERT_EQ(0x2000U, it->start);
+ ASSERT_EQ(0x3000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_WRITE, it->flags);
+ ASSERT_EQ(0x3000U, it->start);
+ ASSERT_EQ(0x4000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_EXEC, it->flags);
+ ASSERT_EQ(0x4000U, it->start);
+ ASSERT_EQ(0x5000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, it->flags);
+ ASSERT_EQ(0x5000U, it->start);
+ ASSERT_EQ(0x6000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, parse_name) {
+ BufferMaps maps(
+ "720b29b000-720b29e000 rw-p 00000000 00:00 0\n"
+ "720b29e000-720b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "720b29f000-720b2a0000 rw-p 00000000 00:00 0");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(3U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ("", it->name);
+ ASSERT_EQ(0x720b29b000U, it->start);
+ ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ASSERT_EQ(0x720b29e000U, it->start);
+ ASSERT_EQ(0x720b29f000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ("", it->name);
+ ASSERT_EQ(0x720b29f000U, it->start);
+ ASSERT_EQ(0x720b2a0000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, parse_offset) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(2U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(0xa000U, it->start);
+ ASSERT_EQ(0xe000U, it->end);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(0xa12345U, it->offset);
+ ASSERT_EQ(0xe000U, it->start);
+ ASSERT_EQ(0xf000U, it->end);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(maps.end(), it);
+}
+
+TEST(MapsTest, device) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /dev/\n"
+ "f000-f100 rw-p 00000000 00:00 0 /dev/does_not_exist\n"
+ "f100-f200 rw-p 00000000 00:00 0 /dev/ashmem/does_not_exist\n"
+ "f200-f300 rw-p 00000000 00:00 0 /devsomething/does_not_exist\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(4U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_TRUE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/", it->name);
+ ++it;
+ ASSERT_TRUE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/does_not_exist", it->name);
+ ++it;
+ ASSERT_FALSE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/ashmem/does_not_exist", it->name);
+ ++it;
+ ASSERT_FALSE(it->flags & 0x8000);
+ ASSERT_EQ("/devsomething/does_not_exist", it->name);
+}
+
+TEST(MapsTest, file_smoke) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_TRUE(
+ android::base::WriteStringToFile("720b29b000-720b29e000 r-xp a0000000 00:00 0 /fake.so\n"
+ "720b2b0000-720b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
+ "720b2e0000-720b2f0000 r-xp c0000000 00:00 0 /fake3.so\n",
+ tf.path, 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(3U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(0x720b29b000U, it->start);
+ ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0xa0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(0x720b2b0000U, it->start);
+ ASSERT_EQ(0x720b2e0000U, it->end);
+ ASSERT_EQ(0xb0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake2.so", it->name);
+ ++it;
+ ASSERT_EQ(0x720b2e0000U, it->start);
+ ASSERT_EQ(0x720b2f0000U, it->end);
+ ASSERT_EQ(0xc0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake3.so", it->name);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, find) {
+ BufferMaps maps(
+ "1000-2000 r--p 00000010 00:00 0 /system/lib/fake1.so\n"
+ "3000-4000 -w-p 00000020 00:00 0 /system/lib/fake2.so\n"
+ "6000-8000 --xp 00000030 00:00 0 /system/lib/fake3.so\n"
+ "a000-b000 rw-p 00000040 00:00 0 /system/lib/fake4.so\n"
+ "e000-f000 rwxp 00000050 00:00 0 /system/lib/fake5.so\n");
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(5U, maps.Total());
+
+ ASSERT_TRUE(maps.Find(0x500) == nullptr);
+ ASSERT_TRUE(maps.Find(0x2000) == nullptr);
+ ASSERT_TRUE(maps.Find(0x5010) == nullptr);
+ ASSERT_TRUE(maps.Find(0x9a00) == nullptr);
+ ASSERT_TRUE(maps.Find(0xf000) == nullptr);
+ ASSERT_TRUE(maps.Find(0xf010) == nullptr);
+
+ MapInfo* info = maps.Find(0x1000);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x1000U, info->start);
+ ASSERT_EQ(0x2000U, info->end);
+ ASSERT_EQ(0x10U, info->offset);
+ ASSERT_EQ(PROT_READ, info->flags);
+ ASSERT_EQ("/system/lib/fake1.so", info->name);
+
+ info = maps.Find(0x3020);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x3000U, info->start);
+ ASSERT_EQ(0x4000U, info->end);
+ ASSERT_EQ(0x20U, info->offset);
+ ASSERT_EQ(PROT_WRITE, info->flags);
+ ASSERT_EQ("/system/lib/fake2.so", info->name);
+
+ info = maps.Find(0x6020);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x6000U, info->start);
+ ASSERT_EQ(0x8000U, info->end);
+ ASSERT_EQ(0x30U, info->offset);
+ ASSERT_EQ(PROT_EXEC, info->flags);
+ ASSERT_EQ("/system/lib/fake3.so", info->name);
+
+ info = maps.Find(0xafff);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0xa000U, info->start);
+ ASSERT_EQ(0xb000U, info->end);
+ ASSERT_EQ(0x40U, info->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, info->flags);
+ ASSERT_EQ("/system/lib/fake4.so", info->name);
+
+ info = maps.Find(0xe500);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0xe000U, info->start);
+ ASSERT_EQ(0xf000U, info->end);
+ ASSERT_EQ(0x50U, info->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+ ASSERT_EQ("/system/lib/fake5.so", info->name);
+}
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 7600528..2edf224 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -18,6 +18,7 @@
#include <cstdio>
#include <sys/param.h>
+#include <sys/stat.h>
#include <zlib.h>
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
@@ -84,11 +85,19 @@
delete stream;
}
-ZipWriter::ZipWriter(FILE* f) : file_(f), current_offset_(0), state_(State::kWritingZip),
- z_stream_(nullptr, DeleteZStream), buffer_(kBufSize) {
+ZipWriter::ZipWriter(FILE* f) : file_(f), seekable_(false), current_offset_(0),
+ state_(State::kWritingZip), z_stream_(nullptr, DeleteZStream),
+ buffer_(kBufSize) {
+ // Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
+ // will fail as well.
+ struct stat file_stats;
+ if (fstat(fileno(f), &file_stats) == 0) {
+ seekable_ = S_ISREG(file_stats.st_mode);
+ }
}
ZipWriter::ZipWriter(ZipWriter&& writer) : file_(writer.file_),
+ seekable_(writer.seekable_),
current_offset_(writer.current_offset_),
state_(writer.state_),
files_(std::move(writer.files_)),
@@ -100,6 +109,7 @@
ZipWriter& ZipWriter::operator=(ZipWriter&& writer) {
file_ = writer.file_;
+ seekable_ = writer.seekable_;
current_offset_ = writer.current_offset_;
state_ = writer.state_;
files_ = std::move(writer.files_);
@@ -159,6 +169,30 @@
*out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
}
+static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
+ LocalFileHeader* dst) {
+ dst->lfh_signature = LocalFileHeader::kSignature;
+ if (use_data_descriptor) {
+ // Set this flag to denote that a DataDescriptor struct will appear after the data,
+ // containing the crc and size fields.
+ dst->gpb_flags |= kGPBDDFlagMask;
+
+ // The size and crc fields must be 0.
+ dst->compressed_size = 0u;
+ dst->uncompressed_size = 0u;
+ dst->crc32 = 0u;
+ } else {
+ dst->compressed_size = src.compressed_size;
+ dst->uncompressed_size = src.uncompressed_size;
+ dst->crc32 = src.crc32;
+ }
+ dst->compression_method = src.compression_method;
+ dst->last_mod_time = src.last_mod_time;
+ dst->last_mod_date = src.last_mod_date;
+ dst->file_name_length = src.path.size();
+ dst->extra_field_length = src.padding_length;
+}
+
int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags,
time_t time, uint32_t alignment) {
if (state_ != State::kWritingZip) {
@@ -173,66 +207,58 @@
return kInvalidAlignment;
}
- current_file_entry_ = {};
- current_file_entry_.path = path;
- current_file_entry_.local_file_header_offset = current_offset_;
+ FileEntry file_entry = {};
+ file_entry.local_file_header_offset = current_offset_;
+ file_entry.path = path;
- if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(current_file_entry_.path.data()),
- current_file_entry_.path.size())) {
+ if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
+ file_entry.path.size())) {
return kInvalidEntryName;
}
- LocalFileHeader header = {};
- header.lfh_signature = LocalFileHeader::kSignature;
-
- // Set this flag to denote that a DataDescriptor struct will appear after the data,
- // containing the crc and size fields.
- header.gpb_flags |= kGPBDDFlagMask;
-
if (flags & ZipWriter::kCompress) {
- current_file_entry_.compression_method = kCompressDeflated;
+ file_entry.compression_method = kCompressDeflated;
int32_t result = PrepareDeflate();
if (result != kNoError) {
return result;
}
} else {
- current_file_entry_.compression_method = kCompressStored;
+ file_entry.compression_method = kCompressStored;
}
- header.compression_method = current_file_entry_.compression_method;
- ExtractTimeAndDate(time, ¤t_file_entry_.last_mod_time, ¤t_file_entry_.last_mod_date);
- header.last_mod_time = current_file_entry_.last_mod_time;
- header.last_mod_date = current_file_entry_.last_mod_date;
+ ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
- header.file_name_length = current_file_entry_.path.size();
-
- off64_t offset = current_offset_ + sizeof(header) + current_file_entry_.path.size();
+ off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
std::vector<char> zero_padding;
if (alignment != 0 && (offset & (alignment - 1))) {
// Pad the extra field so the data will be aligned.
uint16_t padding = alignment - (offset % alignment);
- header.extra_field_length = padding;
+ file_entry.padding_length = padding;
offset += padding;
- zero_padding.resize(padding);
- memset(zero_padding.data(), 0, zero_padding.size());
+ zero_padding.resize(padding, 0);
}
+ LocalFileHeader header = {};
+ // Always start expecting a data descriptor. When the data has finished being written,
+ // if it is possible to seek back, the GPB flag will reset and the sizes written.
+ CopyFromFileEntry(file_entry, true /*use_data_descriptor*/, &header);
+
if (fwrite(&header, sizeof(header), 1, file_) != 1) {
return HandleError(kIoError);
}
- if (fwrite(path, sizeof(*path), current_file_entry_.path.size(), file_)
- != current_file_entry_.path.size()) {
+ if (fwrite(path, sizeof(*path), file_entry.path.size(), file_) != file_entry.path.size()) {
return HandleError(kIoError);
}
- if (header.extra_field_length != 0 &&
- fwrite(zero_padding.data(), 1, header.extra_field_length, file_)
- != header.extra_field_length) {
+ if (file_entry.padding_length != 0 &&
+ fwrite(zero_padding.data(), 1, file_entry.padding_length, file_)
+ != file_entry.padding_length) {
return HandleError(kIoError);
}
+ current_file_entry_ = std::move(file_entry);
current_offset_ = offset;
state_ = State::kWritingEntry;
return kNoError;
@@ -405,23 +431,41 @@
}
}
- const uint32_t sig = DataDescriptor::kOptSignature;
- if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
- state_ = State::kError;
- return kIoError;
- }
+ if ((current_file_entry_.compression_method & kCompressDeflated) || !seekable_) {
+ // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
+ // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
+ const uint32_t sig = DataDescriptor::kOptSignature;
+ if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
- DataDescriptor dd = {};
- dd.crc32 = current_file_entry_.crc32;
- dd.compressed_size = current_file_entry_.compressed_size;
- dd.uncompressed_size = current_file_entry_.uncompressed_size;
- if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
- return HandleError(kIoError);
+ DataDescriptor dd = {};
+ dd.crc32 = current_file_entry_.crc32;
+ dd.compressed_size = current_file_entry_.compressed_size;
+ dd.uncompressed_size = current_file_entry_.uncompressed_size;
+ if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
+ current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
+ } else {
+ // Seek back to the header and rewrite to include the size.
+ if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
+ return HandleError(kIoError);
+ }
+
+ LocalFileHeader header = {};
+ CopyFromFileEntry(current_file_entry_, false /*use_data_descriptor*/, &header);
+
+ if (fwrite(&header, sizeof(header), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
+
+ if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
+ return HandleError(kIoError);
+ }
}
files_.emplace_back(std::move(current_file_entry_));
-
- current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
state_ = State::kWritingZip;
return kNoError;
}
@@ -431,7 +475,7 @@
return kInvalidState;
}
- off64_t startOfCdr = current_offset_;
+ off_t startOfCdr = current_offset_;
for (FileEntry& file : files_) {
CentralDirectoryRecord cdr = {};
cdr.record_signature = CentralDirectoryRecord::kSignature;
@@ -443,7 +487,7 @@
cdr.compressed_size = file.compressed_size;
cdr.uncompressed_size = file.uncompressed_size;
cdr.file_name_length = file.path.size();
- cdr.local_file_header_offset = file.local_file_header_offset;
+ cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
return HandleError(kIoError);
}
@@ -473,7 +517,7 @@
// Since we can BackUp() and potentially finish writing at an offset less than one we had
// already written at, we must truncate the file.
- if (ftruncate64(fileno(file_), current_offset_) != 0) {
+ if (ftruncate(fileno(file_), current_offset_) != 0) {
return HandleError(kIoError);
}
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 30f4950..5b526a4 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -64,6 +64,7 @@
ZipEntry data;
ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
EXPECT_EQ(kCompressStored, data.method);
+ EXPECT_EQ(0u, data.has_data_descriptor);
EXPECT_EQ(strlen(expected), data.compressed_length);
ASSERT_EQ(strlen(expected), data.uncompressed_length);
ASSERT_TRUE(AssertFileEntryContentsEq(expected, handle, &data));