From a2f8c65d2a7b646e2682fb7ff996da7dc1267007 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Mon, 25 Jan 2021 17:18:05 +0900 Subject: [PATCH] Refactor Preference API Change-Id: I8d2d28dbdc046c0aa9becd3042fa6d71b89aa1be Signed-off-by: Hwankyu Jhun --- CMakeLists.txt | 59 +- cmake/Modules/ApplyPkgConfig.cmake | 35 + include/app_preference_internal.h | 143 -- include/app_preference_log.h | 93 - packaging/capi-appfw-preference.spec | 6 +- preference/CMakeLists.txt | 33 + preference/backend-interface.hh | 47 + .../capi-appfw-preference.pc.in | 0 preference/data-event-interface.hh | 37 + preference/data-internal.cc | 75 + preference/data-internal.hh | 94 + preference/file-backend-internal.cc | 239 +++ preference/file-backend-internal.hh | 63 + preference/file-internal.cc | 291 +++ preference/file-internal.hh | 82 + preference/log-internal.hh | 37 + preference/path-internal.cc | 60 + preference/path-internal.hh | 34 + preference/preference-internal.cc | 137 ++ preference/preference-internal.hh | 73 + preference/stub.cc | 347 ++++ src/CMakeLists.txt | 66 - src/preference.c | 1638 ----------------- src/preference_db.c | 795 -------- src/preference_inoti.c | 444 ----- src/tool/CMakeLists.txt | 31 - src/tool/preference_tool.c | 1145 ------------ tool/CMakeLists.txt | 25 + tool/log-private.hh | 37 + {src/tool => tool}/pref_dump.sh | 2 +- tool/preference_tool.cc | 411 +++++ unittests/CMakeLists.txt | 34 +- unittests/main.cc | 36 + unittests/mock/common_mock.cc | 6 +- unittests/mock/common_mock.h | 9 +- unittests/mock/mock_hook.h | 6 +- unittests/mock/module_mock.h | 6 +- unittests/mock/test_fixture.cc | 2 +- unittests/mock/test_fixture.h | 8 +- unittests/preference_test.cc | 68 +- unittests/preference_unittest.cc | 275 +++ 41 files changed, 2587 insertions(+), 4442 deletions(-) create mode 100644 cmake/Modules/ApplyPkgConfig.cmake delete mode 100644 include/app_preference_internal.h delete mode 100644 include/app_preference_log.h create mode 100644 preference/CMakeLists.txt create mode 100644 preference/backend-interface.hh rename capi-appfw-preference.pc.in => preference/capi-appfw-preference.pc.in (100%) create mode 100644 preference/data-event-interface.hh create mode 100644 preference/data-internal.cc create mode 100644 preference/data-internal.hh create mode 100644 preference/file-backend-internal.cc create mode 100644 preference/file-backend-internal.hh create mode 100644 preference/file-internal.cc create mode 100644 preference/file-internal.hh create mode 100644 preference/log-internal.hh create mode 100644 preference/path-internal.cc create mode 100644 preference/path-internal.hh create mode 100644 preference/preference-internal.cc create mode 100644 preference/preference-internal.hh create mode 100644 preference/stub.cc delete mode 100644 src/CMakeLists.txt delete mode 100644 src/preference.c delete mode 100644 src/preference_db.c delete mode 100644 src/preference_inoti.c delete mode 100644 src/tool/CMakeLists.txt delete mode 100644 src/tool/preference_tool.c create mode 100644 tool/CMakeLists.txt create mode 100644 tool/log-private.hh rename {src/tool => tool}/pref_dump.sh (87%) create mode 100644 tool/preference_tool.cc create mode 100644 unittests/main.cc create mode 100644 unittests/preference_unittest.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 919c4a3..6d194f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,53 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -SET(INC_DIR include) +PROJECT(capi-appfw-preference C CXX) -ADD_SUBDIRECTORY(src) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin") +SET(LIBDIR ${LIB_INSTALL_DIR}) +SET(INCDIR "\${prefix}/include") +SET(EXEC_PREFIX "\${prefix}") -INSTALL( - DIRECTORY ${INC_DIR}/ DESTINATION include/appfw - FILES_MATCHING - PATTERN "*_private.h" EXCLUDE - PATTERN "${INC_DIR}/*.h" - ) +## Compile flags +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-zdefs -fvisibility=hidden -g -Wall -Werror -fpic") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") -ADD_SUBDIRECTORY(unittests) \ No newline at end of file +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} -std=c++14") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") + +## Target +SET(TARGET_PREFERENCE "capi-appfw-preference") +SET(TARGET_TOOL "preference_tool") + +ENABLE_TESTING() +SET(TARGET_UNIT_TESTS "preference-unit-tests") + +INCLUDE(FindPkgConfig) +INCLUDE(ApplyPkgConfig) + +PKG_CHECK_MODULES(CAPI_APPFW_APP_COMMON_DEPS REQUIRED capi-appfw-app-common) +PKG_CHECK_MODULES(CAPI_BASE_COMMON_DEPS REQUIRED capi-base-common) +PKG_CHECK_MODULES(DLOG_DEPS REQUIRED dlog) +PKG_CHECK_MODULES(GLIB_DEPS REQUIRED glib-2.0) +PKG_CHECK_MODULES(GMOCK_DEPS REQUIRED gmock) +PKG_CHECK_MODULES(LIBTZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config) +PKG_CHECK_MODULES(SQLITE3_DEPS REQUIRED sqlite3) +PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info) + +INSTALL(DIRECTORY include/ + DESTINATION include/appfw + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "include/*.h" +) + +ADD_SUBDIRECTORY(preference) +ADD_SUBDIRECTORY(tool) +ADD_SUBDIRECTORY(unittests) diff --git a/cmake/Modules/ApplyPkgConfig.cmake b/cmake/Modules/ApplyPkgConfig.cmake new file mode 100644 index 0000000..9b84be3 --- /dev/null +++ b/cmake/Modules/ApplyPkgConfig.cmake @@ -0,0 +1,35 @@ +# Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# +# This function applies external (out of source tree) dependencies +# to given target. Arguments are: +# TARGET - valid cmake target +# PRIVACY - dependency can be inherited by dependent targets or not: +# PUBLIC - this should be used by default, cause compile/link flags passing +# PRIVATE - do not passes any settings to dependent targets, +# may be usefull for static libraries from the inside of the project +# Argument ARGV2 and following are supposed to be names of checked pkg config +# packages. This function will use variables created by check_pkg_modules(). +# - ${DEP_NAME}_LIBRARIES +# - ${DEP_NAME}_INCLUDE_DIRS +# - ${DEP_NAME}_CFLAGS +# +FUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY) + MATH(EXPR DEST_INDEX "${ARGC}-1") + FOREACH(I RANGE 2 ${DEST_INDEX}) + IF(NOT ${ARGV${I}}_FOUND) + MESSAGE(FATAL_ERROR "Not found dependency - ${ARGV${I}}_FOUND") + ENDIF(NOT ${ARGV${I}}_FOUND) + TARGET_LINK_LIBRARIES(${TARGET} ${PRIVACY} "${${ARGV${I}}_LIBRARIES}") + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${PRIVACY} SYSTEM "${${ARGV${I}}_INCLUDE_DIRS}") + STRING(REPLACE ";" " " CFLAGS_STR "${${ARGV${I}}_CFLAGS}") + SET(CFLAGS_LIST ${CFLAGS_STR}) + SEPARATE_ARGUMENTS(CFLAGS_LIST) + FOREACH(OPTION ${CFLAGS_LIST}) + TARGET_COMPILE_OPTIONS(${TARGET} ${PRIVACY} ${OPTION}) + ENDFOREACH(OPTION) + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES SKIP_BUILD_RPATH true) + ENDFOREACH(I RANGE 2 ${DEST_INDEX}) +ENDFUNCTION(APPLY_PKG_CONFIG TARGET PRIVACY) diff --git a/include/app_preference_internal.h b/include/app_preference_internal.h deleted file mode 100644 index 0221c20..0000000 --- a/include/app_preference_internal.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2011 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 __TIZEN_APPFW_PREFERENCE_INTERNAL_H__ -#define __TIZEN_APPFW_PREFERENCE_INTERNAL_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "app_preference_log.h" -#include "linux/limits.h" - -#define BUF_LEN (4096) -#define PREF_DIR ".pref/" - -#define PREFERENCE_KEY_PATH_LEN 1024 -#define ERR_LEN 1024 - -#define PREF_DB_NAME ".pref.db" -#define PREF_TBL_NAME "pref" -#define PREF_F_KEY_NAME "pref_key" -#define PREF_F_TYPE_NAME "pref_type" -#define PREF_F_DATA_NAME "pref_data" - -/* ASCII VALUE */ -#define PREF_KEYNAME_C_PAD '=' -#define PREF_KEYNAME_C_PLUS '+' -#define PREF_KEYNAME_C_SLASH '/' - -#define PREF_KEYNAME_C_DOT '.' -#define PREF_KEYNAME_C_UNDERSCORE '_' -#define PREF_KEYNAME_C_HYPHEN '-' - -/** - * @brief Definition for PREFERENCE_ERROR_WRONG_PREFIX. - */ -#define PREFERENCE_ERROR_WRONG_PREFIX -2 - -/** - * @brief Definition for PREFERENCE_ERROR_WRONG_TYPE. - */ -#define PREFERENCE_ERROR_WRONG_TYPE -3 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_OPEN. - */ -#define PREFERENCE_ERROR_FILE_OPEN -21 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_FREAD. - */ -#define PREFERENCE_ERROR_FILE_FREAD -22 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_FGETS. - */ -#define PREFERENCE_ERROR_FILE_FGETS -23 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_WRITE. - */ -#define PREFERENCE_ERROR_FILE_WRITE -24 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_SYNC. - */ -#define PREFERENCE_ERROR_FILE_SYNC -25 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_CHMOD. - */ -#define PREFERENCE_ERROR_FILE_CHMOD -28 - -/** - * @brief Definition for PREFERENCE_ERROR_FILE_LOCK. - */ -#define PREFERENCE_ERROR_FILE_LOCK -29 - -typedef struct _pref_changed_cb_node_t { - char *key; - preference_changed_cb cb; - void *user_data; - struct _pref_changed_cb_node_t *prev; - struct _pref_changed_cb_node_t *next; -} pref_changed_cb_node_t; - -typedef struct _keynode_t { - char *keyname; /**< Keyname for keynode */ - int type; /**< Keynode type */ - union { - int i; /**< Integer type */ - int b; /**< Bool type */ - double d; /**< Double type */ - char *s; /**< String type */ - } value; /**< Value for keynode */ - struct _keynode_t *next; /**< Next keynode */ -} keynode_t; - -/** - * @brief The structure type for opaque type. It must be used via accessor functions. - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif - */ -typedef struct _keylist_t { - int num; /**< Number of list */ - keynode_t *head; /**< Head node */ - keynode_t *cursor; /**< Cursor node */ -} keylist_t; - - -int _preference_kdb_add_notify - (keynode_t *keynode, preference_changed_cb cb, void *data); -int _preference_kdb_del_notify - (keynode_t *keynode); - -int _preference_get_key_path(keynode_t *keynode, char *path); -int _preference_get_key(keynode_t *keynode); - -int _preference_keynode_set_keyname(keynode_t *keynode, const char *keyname); -__attribute__ ((gnu_inline)) inline keynode_t *_preference_keynode_new(void); -__attribute__ ((gnu_inline)) inline void _preference_keynode_free(keynode_t *keynode); - - -#ifdef __cplusplus -} -#endif - -#endif /* __TIZEN_APPFW_PREFERENCE_INTERNAL_H__ */ - diff --git a/include/app_preference_log.h b/include/app_preference_log.h deleted file mode 100644 index 5aa8144..0000000 --- a/include/app_preference_log.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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. - */ - -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "CAPI_APPFW_APPLICATION_PREFERENCE" -#define DBG_MODE (1) - -#ifndef __PREFERENCE_LOG_H__ -#define __PREFERENCE_LOG_H__ - -#include -#include -#include -#include - - -#define INFO(fmt, arg...) -#define DBG(fmt, arg...) SECURE_SLOGI(fmt, ##arg) -#define ERR(fmt, arg...) LOGE(fmt, ##arg) -#define SECURE_ERR(fmt, arg...) SECURE_SLOGE(fmt, ##arg) -#define FATAL(fmt, arg...) SECURE_SLOGF(fmt, ##arg) -#define WARN(fmt, arg...) SECURE_SLOGW(fmt, ##arg) - - -/************** Return ***************/ -#define ret_if(expr) \ - do { \ - if (expr) { \ - ERR("(%s) -> %s() return", #expr, __FUNCTION__); \ - return; \ - } \ - } while (0) -#define retv_if(expr, val) \ - do { \ - if (expr) { \ - ERR("(%s) -> %s() return", #expr, __FUNCTION__); \ - return (val); \ - } \ - } while (0) -#define retm_if(expr, fmt, arg...) \ - do { \ - if (expr) { \ - ERR(fmt, ##arg); \ - return; \ - } \ - } while (0) -#define retvm_if(expr, val, fmt, arg...) \ - do { \ - if (expr) { \ - ERR(fmt, ##arg); \ - return (val); \ - } \ - } while (0) -#define retex_if(expr, fmt, arg...) \ - do { \ - if (expr) { \ - ERR(fmt, ##arg); \ - goto CATCH; \ - } \ - } while (0) - - -/************** TimeCheck ***************/ -#ifdef PREFERENCE_TIMECHECK -#define START_TIME_CHECK \ - init_time();\ - startT = set_start_time(); -#define END_TIME_CHECK \ - PREFERENCE_DEBUG("time = %f ms\n", exec_time(startT)); -#else -#define START_TIME_CHECK -#define END_TIME_CHECK -#endif - - -#endif /* __PREFERENCE_LOG_H__ */ - diff --git a/packaging/capi-appfw-preference.spec b/packaging/capi-appfw-preference.spec index 800a9ad..c9617fd 100644 --- a/packaging/capi-appfw-preference.spec +++ b/packaging/capi-appfw-preference.spec @@ -14,6 +14,7 @@ BuildRequires: pkgconfig(gmock) BuildRequires: pkgconfig(capi-appfw-app-common) BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(pkgmgr-info) %if 0%{?gcov:1} BuildRequires: lcov BuildRequires: zip @@ -71,7 +72,7 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj %check cd unittests -LD_LIBRARY_PATH=../src ctest -V +LD_LIBRARY_PATH=../preference ctest -V %if 0%{?gcov:1} cd ../src lcov -c --ignore-errors graph --no-external -d . -o preference.info @@ -88,13 +89,12 @@ install -m 0644 preference.zip %{buildroot}%{_datadir}/gcov/ %{_libdir}/libcapi-appfw-preference.so.* %attr(0700,root,root) %{_bindir}/preference_tool %attr(755,root,root) /opt/etc/dump.d/module.d/pref_dump.sh +%attr(755,root,root) %{_bindir}/preference-unit-tests %license LICENSE %files devel %manifest %{name}.manifest %{_includedir}/appfw/app_preference.h -%{_includedir}/appfw/app_preference_internal.h -%{_includedir}/appfw/app_preference_log.h %{_libdir}/pkgconfig/capi-appfw-preference.pc %{_libdir}/libcapi-appfw-preference.so diff --git a/preference/CMakeLists.txt b/preference/CMakeLists.txt new file mode 100644 index 0000000..68e0318 --- /dev/null +++ b/preference/CMakeLists.txt @@ -0,0 +1,33 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} PREFERENCE_SRCS) + +ADD_LIBRARY(${TARGET_PREFERENCE} SHARED ${PREFERENCE_SRCS}) + +SET_TARGET_PROPERTIES(${TARGET_PREFERENCE} PROPERTIES SOVERSION ${MAJORVER}) +SET_TARGET_PROPERTIES(${TARGET_PREFERENCE} PROPERTIES VERSION ${FULLVER}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_PREFERENCE} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../include/) + +APPLY_PKG_CONFIG(${TARGET_PREFERENCE} PUBLIC + CAPI_APPFW_APP_COMMON_DEPS + CAPI_BASE_COMMON_DEPS + DLOG_DEPS + GLIB_DEPS +) + +INSTALL(TARGETS ${TARGET_PREFERENCE} + DESTINATION ${LIBDIR} + COMPONENT RuntimeLibraries +) + +SET(PC_NAME ${TARGET_PREFERENCE}) +SET(PC_REQUIRED "capi-base-common") +SET(PC_LD_FLAGS -l${TARGET_PREFERENCE}) + +# pkg-config file +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/capi-appfw-preference.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/capi-appfw-preference.pc @ONLY) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/capi-appfw-preference.pc + DESTINATION ${LIBDIR}/pkgconfig) diff --git a/preference/backend-interface.hh b/preference/backend-interface.hh new file mode 100644 index 0000000..f533307 --- /dev/null +++ b/preference/backend-interface.hh @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_BACKEND_INTERFACE_HH_ +#define PREFERENCE_BACKEND_INTERFACE_HH_ + +#include +#include +#include + +#include "preference/data-event-interface.hh" +#include "preference/data-internal.hh" + +namespace preference { +namespace internal { + +class IBackend { + public: + virtual ~IBackend() { } + + virtual int Set(const Data& data) = 0; + virtual std::shared_ptr Get(const std::string& key) = 0; + virtual int Remove(const std::string& key) = 0; + virtual int RemoveAll() = 0; + virtual int AddWatch(const std::string& key, IDataEvent* listener) = 0; + virtual int RemoveWatch(const std::string& key) = 0; + virtual std::vector GetKeys() = 0; + virtual bool IsExisting(const std::string& key) = 0; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_BACKEND_INTERFACE_HH_ diff --git a/capi-appfw-preference.pc.in b/preference/capi-appfw-preference.pc.in similarity index 100% rename from capi-appfw-preference.pc.in rename to preference/capi-appfw-preference.pc.in diff --git a/preference/data-event-interface.hh b/preference/data-event-interface.hh new file mode 100644 index 0000000..42e712e --- /dev/null +++ b/preference/data-event-interface.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_DATA_EVENT_INTERFACE_HH_ +#define PREFERENCE_DATA_EVENT_INTERFACE_HH_ + +#include + +namespace preference { +namespace internal { + +class IDataEvent { + public: + virtual ~IDataEvent() { } + + virtual void OnDataCreated(const std::string& key) = 0; + virtual void OnDataUpdated(const std::string& key) = 0; + virtual void OnDataDeleted(const std::string& key) = 0; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_DATA_EVENT_INTERFACE_HH_ diff --git a/preference/data-internal.cc b/preference/data-internal.cc new file mode 100644 index 0000000..15bbaa3 --- /dev/null +++ b/preference/data-internal.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/data-internal.hh" + +namespace preference { +namespace internal { + +Data::Data(std::string key) : key_(std::move(key)) { +} + +const std::string& Data::GetKey() const { + return key_; +} + +void Data::SetString(const char* str) { + size_t len = std::strlen(str) + 1; + value_.clear(); + std::copy(str, str + len, std::back_inserter(value_)); + SetType(str); +} + +void Data::SetInt(int i) { + Set(i); + SetType(i); +} + +void Data::SetDouble(double d) { + Set(d); + SetType(d); +} + +void Data::SetBoolean(bool b) { + Set(b); + SetType(b); +} + +const char* Data::GetString() const { + const char* str = reinterpret_cast(&value_[0]); + return str; +} + +int Data::GetInt() const { + return Get(); +} + +double Data::GetDouble() const { + return Get(); +} + +bool Data::GetBoolean() const { + return Get(); +} + +const Data::Type Data::GetType() const { + return type_; +} + +} // namespace internal +} // namespace preference diff --git a/preference/data-internal.hh b/preference/data-internal.hh new file mode 100644 index 0000000..0cd70fb --- /dev/null +++ b/preference/data-internal.hh @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_DATA_INTERNAL_HH_ +#define PREFERENCE_DATA_INTERNAL_HH_ + +#include +#include +#include + +namespace preference { +namespace internal { + +class Data { + public: + enum class Type : int { + NONE = 0, + STRING, + INT, + DOUBLE, + BOOLEAN, + }; + + Data(std::string key); + ~Data() = default; + + const std::string& GetKey() const; + void SetString(const char* value); + void SetInt(int value); + void SetDouble(double value); + void SetBoolean(bool value); + const char* GetString() const; + int GetInt() const; + double GetDouble() const; + bool GetBoolean() const; + const Type GetType() const; + + const std::vector& GetRaw() const { + return value_; + } + + private: + template + void SetType(T d) { + if (typeid(T) == typeid(const char*)) + type_ = Type::STRING; + else if (typeid(T) == typeid(int)) + type_ = Type::INT; + else if (typeid(T) == typeid(double)) + type_ = Type::DOUBLE; + else if (typeid(T) == typeid(bool)) + type_ = Type::BOOLEAN; + else + type_ = Type::NONE; + } + + template + void Set(T d) { + value_.clear(); + uint8_t* p = reinterpret_cast(&d); + std::copy(p, p + sizeof(T), std::back_inserter(value_)); + } + + template + T Get() const { + T d; + uint8_t* p = reinterpret_cast(&d); + std::copy(value_.begin(), value_.begin() + sizeof(T), p); + return d; + } + + private: + std::string key_; + std::vector value_; + Type type_ = Type::NONE; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_DATA_INTERNAL_HH_ diff --git a/preference/file-backend-internal.cc b/preference/file-backend-internal.cc new file mode 100644 index 0000000..b487da8 --- /dev/null +++ b/preference/file-backend-internal.cc @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/file-backend-internal.hh" +#include "preference/file-internal.hh" +#include "preference/log-internal.hh" +#include "preference/path-internal.hh" + +namespace preference { +namespace internal { + +FileBackend::FileBackend() { +} + +FileBackend::~FileBackend() { + RemoveWatch(); +} + +int FileBackend::Set(const Data& data) { + File file(data.GetKey(), false); + file.SetData(data); + return file.Write(); +} + +std::shared_ptr FileBackend::Get(const std::string& key) { + File file(key, false); + if (file.Read() < 0) + return nullptr; + + return std::make_shared(file.GetData()); +} + +int FileBackend::Remove(const std::string& key) { + File file(key, false); + return file.Delete(); +} + +int FileBackend::RemoveAll() { + DIR* dir = opendir(Path::Get().c_str()); + if (dir == nullptr) { + _E("Failed to open directory. errno(%d)", errno); + return -1; + } + + int ret = 0; + int retry_count = 7; + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + if (entry->d_name[0] == '.') + continue; + + do { + File file(entry->d_name, true); + if (file.Delete() < 0) { + _E("Failed to delete file. errno(%d)", errno); + ret = -1; + } else { + ret = 0; + break; + } + } while (retry_count--); + retry_count = 7; + } + closedir(dir); + return ret; +} + +int FileBackend::AddWatch(const std::string& key, IDataEvent* listener) { + if (AddWatch() < 0) + return -1; + + File file(key); + key_map_[file.GetName()] = key; + watch_map_[file.GetName()] = listener; + return 0; +} + +int FileBackend::RemoveWatch(const std::string& key) { + File file(key); + auto i = key_map_.find(file.GetName()); + if (i == key_map_.end()) + return -1; + + key_map_.erase(file.GetName()); + watch_map_.erase(file.GetName()); + return 0; +} + +std::vector FileBackend::GetKeys() { + std::vector keys; + DIR* dir = opendir(Path::Get().c_str()); + if (dir == nullptr) { + _E("Failed to open directory. errno(%d)", errno); + return {}; + } + + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + if (entry->d_name[0] == '.') + continue; + + auto key = GetKey(entry->d_name); + if (key.empty()) + continue; + + keys.push_back(key); + } + closedir(dir); + + return keys; +} + +bool FileBackend::IsExisting(const std::string& key) { + File file(key, false); + return file.IsExisting(); +} + +int FileBackend::AddWatch() { + if (tag_ != 0) + return 0; + + fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (fd_ < 0) { + _E("Failed to initilaize inotify. errno(%d)", errno); + return -1; + } + + wd_ = inotify_add_watch(fd_, Path::Get().c_str(), + (IN_CREATE | IN_CLOSE_WRITE | IN_DELETE)); + if (wd_ < 0) { + _E("Failed to add watch. errno(%d)", errno); + RemoveWatch(); + return -1; + } + + channel_ = g_io_channel_unix_new(fd_); + if (channel_ == nullptr) { + _E("Failed to create GIO channel"); + RemoveWatch(); + return -1; + } + + tag_ = g_io_add_watch(channel_, G_IO_IN, GIOFunc, this); + if (tag_ == 0) { + _E("Failed to add watch"); + RemoveWatch(); + return -1; + } + + return 0; +} + +void FileBackend::RemoveWatch() { + if (tag_) { + g_source_remove(tag_); + tag_ = 0; + } + + if (channel_) { + g_io_channel_unref(channel_); + channel_ = nullptr; + } + + if (wd_ > 0) { + inotify_rm_watch(fd_, wd_); + wd_ = 0; + } + + if (fd_ > 0) { + close(fd_); + fd_ = 0; + } +} + +gboolean FileBackend::GIOFunc(GIOChannel* channel, GIOCondition cond, + gpointer user_data) { + FileBackend* backend = static_cast(user_data); + char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); + char* ptr; + ssize_t len; + struct inotify_event* event; + + int fd = g_io_channel_unix_get_fd(channel); + while ((len = read(fd, buf, sizeof(buf))) > 0) { + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + event->len) { + event = reinterpret_cast(ptr); + char* nptr = ptr + sizeof(struct inotify_event) + event->len; + if (nptr > buf + len) + break; + + if (event->len) { + if (event->mask & IN_CREATE) { + auto i = backend->watch_map_.find(event->name); + if (i != backend->watch_map_.end()) + i->second->OnDataCreated(backend->key_map_[event->name]); + } else if (event->mask & IN_CLOSE_WRITE) { + auto i = backend->watch_map_.find(event->name); + if (i != backend->watch_map_.end()) + i->second->OnDataUpdated(backend->key_map_[event->name]); + } else if (event->mask & IN_DELETE) { + auto i = backend->watch_map_.find(event->name); + if (i != backend->watch_map_.end()) + i->second->OnDataDeleted(backend->key_map_[event->name]); + } + } + } + } + + return G_SOURCE_CONTINUE; +} + +std::string FileBackend::GetKey(const std::string& file_name) { + File file(file_name, true); + if (file.Read() < 0) + return std::string(""); + + auto data = file.GetData(); + return data.GetKey(); +} + +} // namespace internal +} // namespace preference diff --git a/preference/file-backend-internal.hh b/preference/file-backend-internal.hh new file mode 100644 index 0000000..53f53f4 --- /dev/null +++ b/preference/file-backend-internal.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_FILE_BACKEND_INTERNAL_HH_ +#define PREFERENCE_FILE_BACKEND_INTERNAL_HH_ + +#include +#include + +#include + +#include "preference/backend-interface.hh" + +namespace preference { +namespace internal { + +class FileBackend : public IBackend { + public: + FileBackend(); + virtual ~FileBackend(); + + int Set(const Data& data) override; + std::shared_ptr Get(const std::string& key) override; + int Remove(const std::string& key) override; + int RemoveAll() override; + int AddWatch(const std::string& key, IDataEvent* listener) override; + int RemoveWatch(const std::string& key) override; + std::vector GetKeys() override; + bool IsExisting(const std::string& key) override; + + private: + std::string GetKey(const std::string& file_name); + static gboolean GIOFunc(GIOChannel* channel, GIOCondition cond, + gpointer user_data); + int AddWatch(); + void RemoveWatch(); + + private: + int fd_ = -1; + int wd_ = -1; + GIOChannel* channel_ = nullptr; + guint tag_ = 0; + std::map key_map_; + std::map watch_map_; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_FILE_BACKEND_INTERNAL_HH_ diff --git a/preference/file-internal.cc b/preference/file-internal.cc new file mode 100644 index 0000000..dd653ca --- /dev/null +++ b/preference/file-internal.cc @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/file-internal.hh" +#include "preference/log-internal.hh" +#include "preference/path-internal.hh" + +namespace preference { +namespace internal { +namespace { + +const int RETRY_COUNT = 7; +const int RETRY_SLEEP_UTIME = 10000; + +} // namespace + +File::File(std::string name, bool is_checksum) { + if (!is_checksum) { + char* checksum = g_compute_checksum_for_string(G_CHECKSUM_SHA1, + name.c_str(), name.length()); + name_ = std::string(checksum); + g_free(checksum); + } else { + name_ = std::move(name); + } + path_ = Path::Get(name_); +} + +File::File(std::string name, std::string pref_path, bool is_checksum) { + if (!is_checksum) { + char* checksum = g_compute_checksum_for_string(G_CHECKSUM_SHA1, + name.c_str(), name.length()); + name_ = std::string(checksum); + g_free(checksum); + } else { + name_ = std::move(name); + } + path_ = pref_path + "/" + name_; +} + +File::~File() { + Close(); +} + +void File::SetData(const Data& data) { + raw_data_.clear(); + + int key_length = data.GetKey().length(); + uint8_t* p = reinterpret_cast(&key_length); + std::copy(p, p + sizeof(int), std::back_inserter(raw_data_)); + + std::copy(data.GetKey().begin(), data.GetKey().end(), + std::back_inserter(raw_data_)); + + int type = static_cast(data.GetType()); + p = reinterpret_cast(&type); + std::copy(p, p + sizeof(int), std::back_inserter(raw_data_)); + + std::copy(data.GetRaw().begin(), data.GetRaw().end(), + std::back_inserter(raw_data_)); +} + +Data File::GetData() { + int index = 0; + int key_length = 0; + uint8_t* p = reinterpret_cast(&key_length); + std::copy(&raw_data_[index], &raw_data_[index] + sizeof(int), p); + index += sizeof(int); + + std::string key; + std::copy(&raw_data_[index], &raw_data_[index] + key_length, + std::back_inserter(key)); + index += key_length; + + int type = 0; + p = reinterpret_cast(&type); + std::copy(&raw_data_[index], &raw_data_[index] + sizeof(int), p); + index += sizeof(int); + + Data data(key); + + Data::Type data_type = static_cast(type); + if (data_type == Data::Type::STRING) { + const char* str = reinterpret_cast(&raw_data_[index]); + data.SetString(str); + } else if (data_type == Data::Type::INT) { + int i = 0; + p = reinterpret_cast(&i); + std::copy(&raw_data_[index], &raw_data_[index] + sizeof(int), p); + data.SetInt(i); + } else if (data_type == Data::Type::DOUBLE) { + double d = 0; + p = reinterpret_cast(&d); + std::copy(&raw_data_[index], &raw_data_[index] + sizeof(double), p); + data.SetDouble(d); + } else if (data_type == Data::Type::BOOLEAN) { + bool b = 0; + p = reinterpret_cast(&b); + std::copy(&raw_data_[index], &raw_data_[index] + sizeof(bool), p); + data.SetBoolean(b); + } + + return data; +} + +int File::Write() { + int retry_count = 0; + int ret = TryWrite(); + while (ret != 0 && retry_count < RETRY_COUNT) { + retry_count++; + usleep(retry_count * RETRY_SLEEP_UTIME); + ret = TryWrite(); + } + + return ret; +} + +int File::Read() { + int retry_count = 0; + int ret = TryRead(); + while (ret != 0 && retry_count < RETRY_COUNT) { + retry_count++; + usleep(retry_count * RETRY_SLEEP_UTIME); + ret = TryRead(); + } + + return ret; +} + +int File::Delete() { + int retry_count = 0; + int ret = TryDelete(); + while (ret != 0 && retry_count < RETRY_COUNT) { + retry_count++; + usleep(retry_count * RETRY_SLEEP_UTIME); + ret = TryDelete(); + } + + return ret; +} + +bool File::IsExisting() { + if (access(path_.c_str(), F_OK) == 0) + return true; + + return false; +} + +int File::Open(bool readonly) { + if (readonly) + fd_ = open(path_.c_str(), O_RDONLY); + else + fd_ = open(path_.c_str(), (O_CREAT | O_WRONLY | O_TRUNC), 0644); + if (fd_ < 0) { + _E("Failed to open %s. errno(%d)", path_.c_str(), errno); + return -1; + } + + return 0; +} + +void File::Close() { + if (fd_ > 0) { + close(fd_); + fd_ = 0; + } +} + +int File::Sync() { + int ret = fdatasync(fd_); + if (ret < 0) { + _E("Failed to synchronize a file. errno(%d)", errno); + return static_cast(Error::ERROR_FILE_SYNC); + } + + return 0; +} + +bool File::Lock(bool readonly) { + struct flock lock; + + lock.l_type = readonly ? F_RDLCK : F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + if (fcntl(fd_, F_SETLK, &lock) < 0) + return false; + + return true; +} + +void File::Unlock() { + struct flock lock; + + lock.l_type = F_UNLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + fcntl(fd_, F_SETLK, &lock); +} + +int File::TryWrite() { + int ret = Open(false); + if (ret < 0) + return static_cast(Error::ERROR_FILE_OPEN); + + if (!Lock(false)) { + Close(); + return static_cast(Error::ERROR_FILE_LOCK); + } + + ssize_t bytes_written; + ssize_t size = raw_data_.size(); + uint8_t* buffer = static_cast(&raw_data_[0]); + + bytes_written = write(fd_, buffer, size); + if (bytes_written <= 0) { + _E("Failed to write to a fd(%d). errno(%d)", fd_, errno); + ret = static_cast(Error::ERROR_FILE_WRITE); + } else { + ret = Sync(); + } + + Unlock(); + Close(); + return ret; +} + +int File::TryRead() { + int ret = Open(); + if (ret < 0) + return static_cast(Error::ERROR_FILE_OPEN); + + if (!Lock()) { + Close(); + return static_cast(Error::ERROR_FILE_LOCK); + } + + ssize_t total_size = 0; + ssize_t bytes_read; + uint8_t buffer[4096] = { 0, }; + + raw_data_.clear(); + while ((bytes_read = read(fd_, buffer, sizeof(buffer))) > 0) { + std::copy(buffer, buffer + bytes_read, std::back_inserter(raw_data_)); + total_size += bytes_read; + } + + if (total_size == 0) { + _E("Total size is zero"); + ret = static_cast(Error::ERROR_FILE_READ); + } + + Unlock(); + Close(); + return ret; +} + +int File::TryDelete() { + int ret = unlink(path_.c_str()); + if (ret != 0) { + _E("Failed to delete %s. errno(%d)", path_.c_str(), errno); + return -1; + } + return 0; +} + +} // namespace internal +} // namespace preference diff --git a/preference/file-internal.hh b/preference/file-internal.hh new file mode 100644 index 0000000..0386cec --- /dev/null +++ b/preference/file-internal.hh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_FILE_INTERNAL_HH_ +#define PREFERENCE_FILE_INTERNAL_HH_ + +#include +#include +#include + +#include "preference/data-internal.hh" + +namespace preference { +namespace internal { + +class File { + public: + enum class Error : int { + ERROR_WRONG_PREFIX = -2, + ERROR_WRONG_TYPE = -3, + ERROR_FILE_OPEN = -21, + ERROR_FILE_READ = -22, + ERROR_FILE_WRITE = -23, + ERROR_FILE_SYNC = -24, + ERROR_FILE_CHMOD = -25, + ERROR_FILE_LOCK = -26, + }; + + File(std::string name, bool is_checksum = false); + File(std::string name, std::string pref_path, bool is_checksum = false); + ~File(); + + const std::string& GetName() { + return name_; + } + + const std::string& GetPath() { + return path_; + } + + void SetData(const Data& data); + Data GetData(); + + int Write(); + int Read(); + int Delete(); + bool IsExisting(); + void Close(); + + private: + int Open(bool readonly = true); + int Sync(); + bool Lock(bool readonly = true); + void Unlock(); + int TryWrite(); + int TryRead(); + int TryDelete(); + + private: + std::string name_; + std::string path_; + std::vector raw_data_; + int fd_ = 0; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_FILE_INTERNAL_HH_ diff --git a/preference/log-internal.hh b/preference/log-internal.hh new file mode 100644 index 0000000..4f8bb9a --- /dev/null +++ b/preference/log-internal.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_LOG_INTERNAL_HH_ +#define PREFERENCE_LOG_INTERNAL_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "CAPI_APPFW_PREFERENCE" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // PREFERENCE_LOG_INTERNAL_HH_ diff --git a/preference/path-internal.cc b/preference/path-internal.cc new file mode 100644 index 0000000..d6c63e8 --- /dev/null +++ b/preference/path-internal.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/log-internal.hh" +#include "preference/path-internal.hh" + +namespace preference { +namespace internal { + +std::string Path::Get() { + static std::string path; + if (!path.empty()) + return path; + + char* data_path = app_get_data_path(); + if (data_path != nullptr) { + path = std::string(data_path) + ".pref/"; + free(data_path); + } else { + path = "/tmp/." + std::to_string(getpid()) + "_pref/"; + } + + if (access(path.c_str(), F_OK) != 0) { + int ret = mkdir(path.c_str(), + (S_IRWXU | S_IRGRP | S_IXGRP | S_ISGID | S_IROTH | S_IXOTH)); + if (ret != 0) { + _E("mkdir(%s) is failed. errno(%d)", path.c_str(), errno); + path = ""; + } + } + + return path; +} + +std::string Path::Get(const std::string& file_name) { + return Get() + file_name; +} + +} // namespace internal +} // namespace preference diff --git a/preference/path-internal.hh b/preference/path-internal.hh new file mode 100644 index 0000000..e250a6b --- /dev/null +++ b/preference/path-internal.hh @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_PATH_INTERNAL_HH_ +#define PREFERENCE_PATH_INTERNAL_HH_ + +#include + +namespace preference { +namespace internal { + +class Path { + public: + static std::string Get(); + static std::string Get(const std::string& file_name); +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_PATH_INTERNAL_HH_ diff --git a/preference/preference-internal.cc b/preference/preference-internal.cc new file mode 100644 index 0000000..2363331 --- /dev/null +++ b/preference/preference-internal.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/preference-internal.hh" + +namespace preference { +namespace internal { + +Preference::Preference(IEventListener* listener) + : backend_(new FileBackend()), + listener_(listener) { +} + +int Preference::SetInt(const std::string& key, int value) { + Data d(key); + d.SetInt(value); + return backend_->Set(d); +} + +int Preference::SetDouble(const std::string& key, double value) { + Data d(key); + d.SetDouble(value); + return backend_->Set(d); +} + +int Preference::SetString(const std::string& key, const char* value) { + Data d(key); + d.SetString(value); + return backend_->Set(d); +} + +int Preference::SetBoolean(const std::string& key, bool value) { + Data d(key); + d.SetBoolean(value); + return backend_->Set(d); +} + +int Preference::GetInt(const std::string& key) { + auto d = backend_->Get(key); + if (d == nullptr) + return -1; + + return d->GetInt(); +} + +double Preference::GetDouble(const std::string& key) { + auto d = backend_->Get(key); + if (d == nullptr) + return -1; + + return d->GetDouble(); +} + +std::string Preference::GetString(const std::string& key) { + auto d = backend_->Get(key); + if (d == nullptr) + return std::string(""); + + return d->GetString(); +} + +bool Preference::GetBoolean(const std::string& key) { + auto d = backend_->Get(key); + if (d == nullptr) + return false; + + return d->GetBoolean(); +} + +int Preference::GetType(const std::string& key) { + auto d = backend_->Get(key); + if (d == nullptr) + return 0; + + return static_cast(d->GetType()); +} + +bool Preference::IsExisting(const std::string& key) { + return backend_->IsExisting(key); +} + +int Preference::Remove(const std::string& key) { + return backend_->Remove(key); +} + +int Preference::RemoveAll() { + return backend_->RemoveAll(); +} + +std::vector Preference::GetKeys() { + return backend_->GetKeys(); +} + +int Preference::AddWatch(const std::string& key) { + return backend_->AddWatch(key, this); +} + +int Preference::RemoveWatch(const std::string& key) { + return backend_->RemoveWatch(key); +} + +void Preference::OnDataCreated(const std::string& key) { + if (listener_ == nullptr) + return; + + listener_->OnCreated(key); +} + +void Preference::OnDataUpdated(const std::string& key) { + if (listener_ == nullptr) + return; + + listener_->OnUpdated(key); +} + +void Preference::OnDataDeleted(const std::string& key) { + if (listener_ == nullptr) + return; + + listener_->OnDeleted(key); +} + +} // namespace internal +} // namespace preference diff --git a/preference/preference-internal.hh b/preference/preference-internal.hh new file mode 100644 index 0000000..394373a --- /dev/null +++ b/preference/preference-internal.hh @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 PREFERENCE_PREFERENCE_INTERNAL_HH_ +#define PREFERENCE_PREFERENCE_INTERNAL_HH_ + +#include +#include +#include + +#include "preference/file-backend-internal.hh" + +namespace preference { +namespace internal { + +class Preference : private IDataEvent { + public: + class IEventListener { + public: + virtual void OnCreated(const std::string& key) = 0; + virtual void OnUpdated(const std::string& key) = 0; + virtual void OnDeleted(const std::string& key) = 0; + }; + + Preference(IEventListener* listener); + ~Preference() = default; + + int SetInt(const std::string& key, int value); + int SetDouble(const std::string& key, double value); + int SetString(const std::string& key, const char* value); + int SetBoolean(const std::string& key, bool value); + + int GetInt(const std::string& key); + double GetDouble(const std::string& key); + std::string GetString(const std::string& key); + bool GetBoolean(const std::string& key); + int GetType(const std::string& key); + + bool IsExisting(const std::string& key); + int Remove(const std::string& key); + int RemoveAll(); + std::vector GetKeys(); + + int AddWatch(const std::string& key); + int RemoveWatch(const std::string& key); + + private: + void OnDataCreated(const std::string& key) override; + void OnDataUpdated(const std::string& key) override; + void OnDataDeleted(const std::string& key) override; + + private: + std::unique_ptr backend_; + IEventListener* listener_ = nullptr; +}; + +} // namespace internal +} // namespace preference + +#endif // PREFERENCE_PREFERENCE_INTERNAL_HH_ diff --git a/preference/stub.cc b/preference/stub.cc new file mode 100644 index 0000000..39d71b7 --- /dev/null +++ b/preference/stub.cc @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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/app_preference.h" +#include "preference/log-internal.hh" +#include "preference/preference-internal.hh" + +#undef API +#define API __attribute__ ((visibility("default"))) + +namespace { + +template +class Event { + public: + Event(T cb, void* user_data) : cb_(cb), user_data_(user_data) {} + + T cb_; + void* user_data_; +}; + +class PrefExt : public preference::internal::Preference, + public preference::internal::Preference::IEventListener { + public: + PrefExt() : Preference(this) { + } + + int AddWatch(const char* key, preference_changed_cb cb, void* user_data) { + std::lock_guard lock(GetMutex()); + if (Preference::AddWatch(key) < 0) + return -1; + + map_[std::string(key)] = std::unique_ptr>( + new Event(cb, user_data)); + + return 0; + } + + int RemoveWatch(const char* key) { + std::lock_guard lock(GetMutex()); + auto i = map_.find(key); + if (i == map_.end()) + return -1; + + map_.erase(key); + Preference::RemoveWatch(std::string(key)); + return 0; + } + + private: + std::recursive_mutex& GetMutex() const { + return mutex_; + } + + void OnCreated(const std::string& key) override { + SECURE_LOGD("key(%s)", key.c_str()); + } + + void OnUpdated(const std::string& key) override { + SECURE_LOGD("key(%s)", key.c_str()); + std::lock_guard lock(GetMutex()); + auto i = map_.find(key); + if (i != map_.end()) { + auto& ev = i->second; + ev->cb_(key.c_str(), ev->user_data_); + } + } + + void OnDeleted(const std::string& key) override { + SECURE_LOGD("key(%s)", key.c_str()); + std::lock_guard lock(GetMutex()); + auto i = map_.find(key); + if (i == map_.end()) + return; + + map_.erase(key); + Preference::RemoveWatch(key); + } + + private: + std::map>> map_; + mutable std::recursive_mutex mutex_; +}; + +PrefExt pref; + +} // namespace + +extern "C" API int preference_set_int(const char* key, int intval) { + if (key == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + int ret = pref.SetInt(key, intval); + if (ret < 0) { + _E("Failed to set integer value"); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("key(%s), value(%d)", key, intval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_set_boolean(const char* key, bool boolval) { + if (key == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + int ret = pref.SetBoolean(key, boolval); + if (ret < 0) { + _E("Failed to set boolean value"); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("key(%s), value(%d)", key, boolval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_set_double(const char* key, double dblval) { + if (key == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + int ret = pref.SetDouble(key, dblval); + if (ret < 0) { + _E("Failed to set double value"); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("key(%s), value(%lf)", key, dblval); + + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_set_string(const char* key, const char* strval) { + if (key == nullptr || strval == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + int ret = pref.SetString(key, strval); + if (ret < 0) { + _E("Failed to set string value"); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("key(%s), value(%s)", key, strval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_get_int(const char* key, int* intval) { + if (key == nullptr || intval == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) + return PREFERENCE_ERROR_NO_KEY; + + *intval = pref.GetInt(key); + SECURE_LOGD("key(%s), value(%d)", key, *intval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_get_boolean(const char* key, bool* boolval) { + if (key == nullptr || boolval == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) + return PREFERENCE_ERROR_NO_KEY; + + *boolval = pref.GetBoolean(key); + SECURE_LOGD("key(%s), value(%d)", key, *boolval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_get_double(const char* key, double* dblval) { + if (key == nullptr || dblval == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) + return PREFERENCE_ERROR_NO_KEY; + + *dblval = pref.GetDouble(key); + SECURE_LOGD("key(%s), value(%lf)", key, *dblval); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_get_string(const char* key, char** value) { + if (key == nullptr || value == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) + return PREFERENCE_ERROR_NO_KEY; + + *value = strdup(pref.GetString(key).c_str()); + SECURE_LOGD("key(%s), value(%s)", key, *value); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_remove(const char* key) { + if (key == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) { + _E("%s doesn't exist", key); + return PREFERENCE_ERROR_NO_KEY; + } + + int ret = pref.Remove(key); + if (ret < 0) { + _E("Failed to remove key(%s)", key); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("key(%s)", key); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_is_existing(const char* key, bool* exist) { + if (key == nullptr || exist == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + *exist = pref.IsExisting(key); + SECURE_LOGD("key(%s), existence(%d)", key, *exist); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_remove_all(void) { + int ret = pref.RemoveAll(); + if (ret < 0) { + _E("Failed to delete all keys"); + return PREFERENCE_ERROR_IO_ERROR; + } + + SECURE_LOGD("RemoveAll"); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_set_changed_cb(const char* key, + preference_changed_cb callback, void* user_data) { + if (key == nullptr || callback == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) { + _E("Failed to find key(%s)", key); + return PREFERENCE_ERROR_NO_KEY; + } + + int ret = pref.AddWatch(key, callback, user_data); + if (ret < 0) { + _E("Failed to add watch"); + return PREFERENCE_ERROR_OUT_OF_MEMORY; + } + + SECURE_LOGD("key(%s)", key); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_unset_changed_cb(const char* key) { + if (key == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) { + _E("Failed to find key(%s)", key); + return PREFERENCE_ERROR_NO_KEY; + } + + int ret = pref.RemoveWatch(key); + if (ret < 0) { + _E("Failed to remove watch"); + return PREFERENCE_ERROR_NO_KEY; + } + + SECURE_LOGD("key(%s)", key); + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_foreach_item(preference_item_cb callback, + void* user_data) { + if (callback == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + auto keys = pref.GetKeys(); + for (auto& i : keys) { + if (!callback(i.c_str(), user_data)) + break; + } + + return PREFERENCE_ERROR_NONE; +} + +extern "C" API int preference_get_type(const char* key, + preference_type_e* type) { + if (key == nullptr || type == nullptr) { + _E("Invalid parameter"); + return PREFERENCE_ERROR_INVALID_PARAMETER; + } + + if (!pref.IsExisting(key)) { + *type = PREFERENCE_TYPE_NONE; + return PREFERENCE_ERROR_NONE; + } + + *type = static_cast(pref.GetType(key)); + SECURE_LOGD("key(%s), type(%d)", key, *type); + return PREFERENCE_ERROR_NONE; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index b3a18e8..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -SET(fw_name "capi-appfw-preference") - -PROJECT(${fw_name}) - -SET(CMAKE_INSTALL_PREFIX /usr) -SET(PREFIX ${CMAKE_INSTALL_PREFIX}) - -SET(INC_DIR ${CMAKE_SOURCE_DIR}/include) -INCLUDE_DIRECTORIES(${INC_DIR}) - -SET(requires "dlog capi-base-common sqlite3 glib-2.0 capi-appfw-app-common") -SET(pc_requires "capi-base-common") - -INCLUDE(FindPkgConfig) -pkg_check_modules(${fw_name} REQUIRED ${requires}) -FOREACH(flag ${${fw_name}_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) - -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror") -SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") - -IF("${ARCH}" STREQUAL "arm") - ADD_DEFINITIONS("-DTARGET") -ENDIF("${ARCH}" STREQUAL "arm") - -ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") -ADD_DEFINITIONS("-DSLP_DEBUG") - -SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") - -add_library(${fw_name} SHARED - preference.c - preference_inoti.c - ) - -TARGET_LINK_LIBRARIES(${fw_name} capi-appfw-app-common ${${fw_name}_LDFLAGS}) - -SET_TARGET_PROPERTIES(${fw_name} - PROPERTIES - VERSION ${FULLVER} - SOVERSION ${MAJORVER} - CLEAN_DIRECT_OUTPUT 1 -) - -INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) -INSTALL( - DIRECTORY ${INC_DIR}/ DESTINATION include/appfw - FILES_MATCHING - PATTERN "*_private.h" EXCLUDE - PATTERN "${INC_DIR}/*.h" - ) - -SET(PC_NAME ${fw_name}) -SET(PC_REQUIRED ${pc_requires}) -SET(PC_LDFLAGS -l${fw_name}) - -CONFIGURE_FILE( - ${CMAKE_SOURCE_DIR}/${fw_name}.pc.in - ${CMAKE_SOURCE_DIR}/${fw_name}.pc - @ONLY -) -INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) - -ADD_SUBDIRECTORY(tool) diff --git a/src/preference.c b/src/preference.c deleted file mode 100644 index 4547d5f..0000000 --- a/src/preference.c +++ /dev/null @@ -1,1638 +0,0 @@ -/* - * Copyright (c) 2011 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 - -#ifdef PREFERENCE_TIMECHECK -#include -#endif - -#ifndef API -#define API __attribute__ ((visibility("default"))) -#endif - -#define PREFERENCE_ERROR_RETRY_CNT 7 -#define PREFERENCE_ERROR_RETRY_SLEEP_UTIME 10000 - -#define DELIMITER 29 - -static int g_posix_errno; -static int g_preference_errno; -static char *g_pref_dir_path = NULL; - -enum preference_op_t { - PREFERENCE_OP_GET = 0, - PREFERENCE_OP_SET = 1 -}; - -#ifdef PREFERENCE_TIMECHECK -double correction, startT; - -double set_start_time(void) -{ - struct timeval tv; - double curtime; - - gettimeofday(&tv, NULL); - curtime = tv.tv_sec * 1000 + (double)tv.tv_usec / 1000; - return curtime; -} - -double exec_time(double start) -{ - double end = set_start_time(); - return (end - start - correction); -} - -int init_time(void) -{ - double temp_t; - temp_t = set_start_time(); - correction = exec_time(temp_t); - - return 0; -} -#endif - -char *_preference_get_pref_dir_path() -{ - char *app_data_path = NULL; - - if (!g_pref_dir_path) { - g_pref_dir_path = (char *)malloc(PREFERENCE_KEY_PATH_LEN + 1); - if (!g_pref_dir_path) { - ERR("Out of memory"); - return NULL; - } - - if ((app_data_path = app_get_data_path()) == NULL) { - /* LCOV_EXCL_START */ - ERR("IO_ERROR(0x%08x) : fail to get data directory", PREFERENCE_ERROR_IO_ERROR); - free(g_pref_dir_path); - g_pref_dir_path = NULL; - return NULL; - /* LCOV_EXCL_STOP */ - } - - snprintf(g_pref_dir_path, PREFERENCE_KEY_PATH_LEN, "%s%s", app_data_path, PREF_DIR); - INFO("pref_dir_path: %s", g_pref_dir_path); - free(app_data_path); - } - return g_pref_dir_path; -} - -int _preference_keynode_set_keyname(keynode_t *keynode, const char *keyname) -{ - if (keynode->keyname) free(keynode->keyname); - keynode->keyname = strndup(keyname, PREFERENCE_KEY_PATH_LEN); - retvm_if(keynode->keyname == NULL, PREFERENCE_ERROR_IO_ERROR, "strndup Fails"); - return PREFERENCE_ERROR_NONE; -} - -static inline void _preference_keynode_set_value_int(keynode_t *keynode, const int value) -{ - keynode->type = PREFERENCE_TYPE_INT; - keynode->value.i = value; -} - -static inline void _preference_keynode_set_value_boolean(keynode_t *keynode, const int value) -{ - keynode->type = PREFERENCE_TYPE_BOOLEAN; - keynode->value.b = !!value; -} - -static inline void _preference_keynode_set_value_double(keynode_t *keynode, const double value) -{ - keynode->type = PREFERENCE_TYPE_DOUBLE; - keynode->value.d = value; -} - -static inline void _preference_keynode_set_value_string(keynode_t *keynode, const char *value) -{ - keynode->type = PREFERENCE_TYPE_STRING; - keynode->value.s = strdup(value); -} - -__attribute__ ((gnu_inline)) inline keynode_t *_preference_keynode_new(void) -{ - keynode_t *keynode; - keynode = calloc(1, sizeof(keynode_t)); - - return keynode; -} - -__attribute__ ((gnu_inline)) inline void _preference_keynode_free(keynode_t *keynode) -{ - if (keynode) { - if (keynode->keyname) - free(keynode->keyname); - if (keynode->type == PREFERENCE_TYPE_STRING && keynode->value.s) - free(keynode->value.s); - free(keynode); - } -} - -int _preference_get_key_name(const char *path, char **keyname) -{ - int read_size = 0; - size_t keyname_len = 0; - char *convert_key = NULL; - FILE *fp = NULL; - - if ((fp = fopen(path, "r")) == NULL) - return PREFERENCE_ERROR_FILE_OPEN; - - read_size = fread((void *)&keyname_len, sizeof(int), 1, fp); - if (read_size <= 0 || keyname_len > PREFERENCE_KEY_PATH_LEN) { - fclose(fp); - return PREFERENCE_ERROR_FILE_FREAD; - } - - convert_key = (char *)calloc(1, keyname_len+1); - if (convert_key == NULL) { - LOGE("memory alloc failed"); - fclose(fp); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - - read_size = fread((void *)convert_key, keyname_len, 1, fp); - if (read_size <= 0) { - free(convert_key); - fclose(fp); - return PREFERENCE_ERROR_FILE_FREAD; - } - - *keyname = convert_key; - - fclose(fp); - - return PREFERENCE_ERROR_NONE; -} - -int _preference_get_key_path(keynode_t *keynode, char *path) -{ - const char *key = NULL; - char *pref_dir_path = NULL; - gchar *convert_key; - char *keyname = keynode->keyname; - - if (!keyname) { - LOGE("keyname is null"); - return PREFERENCE_ERROR_WRONG_PREFIX; - } - - pref_dir_path = _preference_get_pref_dir_path(); - if (!pref_dir_path) { - LOGE("_preference_get_pref_dir_path() failed."); - return PREFERENCE_ERROR_IO_ERROR; - } - - convert_key = g_compute_checksum_for_string(G_CHECKSUM_SHA1, - keyname, - strlen(keyname)); - if (convert_key == NULL) { - LOGE("fail to convert"); - return PREFERENCE_ERROR_IO_ERROR; - } - - key = (const char *)convert_key; - - snprintf(path, PATH_MAX-1, "%s%s", pref_dir_path, key); - - g_free(convert_key); - - return PREFERENCE_ERROR_NONE; -} - -static int _preference_set_key_check_pref_dir() -{ - char *pref_dir_path = NULL; - mode_t dir_mode = 0664 | 0111; - char err_buf[ERR_LEN] = {0,}; - - pref_dir_path = _preference_get_pref_dir_path(); - if (!pref_dir_path) { - LOGE("_preference_get_pref_dir_path() failed."); - return PREFERENCE_ERROR_IO_ERROR; - } - - if (access(pref_dir_path, F_OK) < 0) { - if (mkdir(pref_dir_path, dir_mode) < 0) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("mkdir() failed(%d/%s)", errno, err_buf); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - return PREFERENCE_ERROR_NONE; -} - -static int _preference_set_key_creation(const char *path) -{ - int fd; - mode_t temp; - char err_buf[ERR_LEN] = {0,}; - - temp = umask(0000); - fd = open(path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); - umask(temp); - - if (fd == -1) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("open(rdwr,create) error: %d(%s)", errno, err_buf); - return PREFERENCE_ERROR_IO_ERROR; - } - close(fd); - - return PREFERENCE_ERROR_NONE; -} - -static int _preference_set_file_lock(int fd, short type) -{ - struct flock l; - - l.l_type = type; - l.l_start = 0; /*Start at begin*/ - l.l_whence = SEEK_SET; - l.l_len = 0; /*Do it with whole file*/ - - return fcntl(fd, F_SETLK, &l); -} - -/* LCOV_EXCL_START */ -static int _preference_get_pid_of_file_lock_owner(int fd, short type) -{ - struct flock l; - - l.l_type = type; - l.l_start = 0; /*Start at begin*/ - l.l_whence = SEEK_SET; - l.l_len = 0; /*Do it with whole file*/ - - if (fcntl(fd, F_GETLK, &l) < 0) { - WARN("error in getting lock info"); - return -1; - } - - if (l.l_type == F_UNLCK) - return 0; - else - return l.l_pid; -} -/* LCOV_EXCL_STOP */ - -static int _preference_set_read_lock(int fd) -{ - return _preference_set_file_lock(fd, F_RDLCK); -} - -static int _preference_set_write_lock(int fd) -{ - return _preference_set_file_lock(fd, F_WRLCK); -} - -static int _preference_set_unlock(int fd) -{ - return _preference_set_file_lock(fd, F_UNLCK); -} - -/* LCOV_EXCL_START */ -static void _preference_log_subject_label(void) -{ - int fd; - int ret; - char smack_label[256] = {0,}; - char curren_path[256] = {0,}; - int tid; - char err_buf[ERR_LEN] = {0,}; - - tid = (int)syscall(SYS_gettid); - snprintf(curren_path, sizeof(curren_path)-1, "/proc/%d/attr/current", tid); - fd = open(curren_path, O_RDONLY); - if (fd < 0) { - strerror_r(errno, err_buf, sizeof(err_buf)); - LOGE("fail to open self current attr (err: %s)", err_buf); - return; - } - - ret = read(fd, smack_label, sizeof(smack_label)-1); - if (ret < 0) { - close(fd); - strerror_r(errno, err_buf, sizeof(err_buf)); - LOGE("fail to open self current attr (err: %s)", err_buf); - return; - } - - ERR("current(%d) subject label : %s", tid, smack_label); - - close(fd); -} -/* LCOV_EXCL_STOP */ - -static int _preference_check_retry_err(keynode_t *keynode, int preference_errno, int io_errno, int op_type) -{ - int is_busy_err = 0; - int rc = 0; - char path[PATH_MAX] = {0,}; - char err_buf[ERR_LEN] = {0,}; - - if (preference_errno == PREFERENCE_ERROR_FILE_OPEN) { - switch (io_errno) { - case ENOENT: - if (op_type == PREFERENCE_OP_SET) { - rc = _preference_get_key_path(keynode, path); - if (rc != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("_preference_get_key_path error"); - _preference_log_subject_label(); - break; - /* LCOV_EXCL_STOP */ - } - - rc = _preference_set_key_check_pref_dir(); - if (rc != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("_preference_set_key_check_pref_dir() failed."); - _preference_log_subject_label(); - break; - /* LCOV_EXCL_STOP */ - } - - rc = _preference_set_key_creation(path); - if (rc != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("_preference_set_key_creation error : %s", path); - _preference_log_subject_label(); - break; - /* LCOV_EXCL_STOP */ - } - INFO("%s key is created", keynode->keyname); - - is_busy_err = 1; - } - break; - case EACCES: - _preference_log_subject_label(); - break; - case EAGAIN: - case EMFILE: - case ENFILE: - case ETXTBSY: - is_busy_err = 1; - } - } else if (preference_errno == PREFERENCE_ERROR_FILE_CHMOD) { - switch (io_errno) { - case EINTR: - case EBADF: - is_busy_err = 1; - } - } else if (preference_errno == PREFERENCE_ERROR_FILE_LOCK) { - switch (io_errno) { - case EBADF: - case EAGAIN: - case ENOLCK: - is_busy_err = 1; - } - } else if (preference_errno == PREFERENCE_ERROR_FILE_WRITE) { - switch (io_errno) { - case 0: - case EAGAIN: - case EINTR: - case EIO: - case ENOMEM: - is_busy_err = 1; - } - } else if (preference_errno == PREFERENCE_ERROR_FILE_FREAD) { - switch (io_errno) { - case EAGAIN: - case EINTR: - case EIO: - is_busy_err = 1; - } - } else { - is_busy_err = 0; - } - - if (is_busy_err == 1) { - return 1; - } else { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("key(%s), check retry err: %d/(%d/%s).", keynode->keyname, preference_errno, io_errno, err_buf); - return 0; - } -} - -static int _preference_set_key_filesys(keynode_t *keynode, int *io_errno) -{ - char path[PATH_MAX] = {0,}; - FILE *fp = NULL; - int ret = -1; - int func_ret = PREFERENCE_ERROR_NONE; - int err_no = 0; - char err_buf[100] = { 0, }; - int is_write_error = 0; - int retry_cnt = 0; - size_t keyname_len = 0; - -retry_open: - errno = 0; - err_no = 0; - func_ret = PREFERENCE_ERROR_NONE; - - ret = _preference_get_key_path(keynode, path); - retv_if(ret != PREFERENCE_ERROR_NONE, ret); - - if ((fp = fopen(path, "w+")) == NULL) { - func_ret = PREFERENCE_ERROR_FILE_OPEN; - err_no = errno; - goto out_return; - } - -retry: - errno = 0; - err_no = 0; - func_ret = PREFERENCE_ERROR_NONE; - - ret = _preference_set_write_lock(fileno(fp)); - if (ret == -1) { - /* LCOV_EXCL_START */ - func_ret = PREFERENCE_ERROR_FILE_LOCK; - err_no = errno; - ERR("file(%s) lock owner(%d)", - keynode->keyname, - _preference_get_pid_of_file_lock_owner(fileno(fp), F_WRLCK)); - goto out_return; - /* LCOV_EXCL_STOP */ - } - - /* write keyname and size */ - keyname_len = strlen(keynode->keyname); - - ret = fwrite((void *)&keyname_len, sizeof(int), 1, fp); - if (ret <= 0) { - /* LCOV_EXCL_START */ - if (!errno) { - LOGW("number of written items is 0. try again"); - errno = EAGAIN; - } - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_WRITE; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - ret = fwrite((void *)keynode->keyname, keyname_len, 1, fp); - if (ret <= 0) { - /* LCOV_EXCL_START */ - if (!errno) { - LOGW("number of written items is 0. try again"); - errno = EAGAIN; - } - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_WRITE; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - /* write key type */ - ret = fwrite((void *)&(keynode->type), sizeof(int), 1, fp); - if (ret <= 0) { - /* LCOV_EXCL_START */ - if (!errno) { - LOGW("number of written items is 0. try again"); - errno = EAGAIN; - } - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_WRITE; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - /* write key value */ - switch (keynode->type) { - case PREFERENCE_TYPE_INT: - ret = fwrite((void *)&(keynode->value.i), sizeof(int), 1, fp); - if (ret <= 0) is_write_error = 1; - break; - case PREFERENCE_TYPE_DOUBLE: - ret = fwrite((void *)&(keynode->value.d), sizeof(double), 1, fp); - if (ret <= 0) is_write_error = 1; - break; - case PREFERENCE_TYPE_BOOLEAN: - ret = fwrite((void *)&(keynode->value.b), sizeof(int), 1, fp); - if (ret <= 0) is_write_error = 1; - break; - case PREFERENCE_TYPE_STRING: - ret = fprintf(fp, "%s", keynode->value.s); - if (ret < strlen(keynode->value.s)) - is_write_error = 1; - break; - default: - func_ret = PREFERENCE_ERROR_WRONG_TYPE; - goto out_unlock; - } - - if (is_write_error) { - /* LCOV_EXCL_START */ - if (!errno) { - LOGW("number of written items is 0. try again"); - errno = EAGAIN; - } - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_WRITE; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - fflush(fp); - -out_unlock: - ret = _preference_set_unlock(fileno(fp)); - if (ret == -1) { - func_ret = PREFERENCE_ERROR_FILE_LOCK; - err_no = errno; - goto out_return; - } - -out_return: - if (func_ret != PREFERENCE_ERROR_NONE) { - strerror_r(err_no, err_buf, 100); - if (_preference_check_retry_err(keynode, func_ret, err_no, PREFERENCE_OP_SET)) { - if (retry_cnt < PREFERENCE_ERROR_RETRY_CNT) { - WARN("_preference_set_key_filesys(%d-%s) step(%d) failed(%d / %s) retry(%d)", keynode->type, keynode->keyname, func_ret, err_no, err_buf, retry_cnt); - retry_cnt++; - usleep((retry_cnt)*PREFERENCE_ERROR_RETRY_SLEEP_UTIME); - - if (fp) - goto retry; - else - goto retry_open; - } else { - ERR("_preference_set_key_filesys(%d-%s) step(%d) faild(%d / %s) over the retry count.", - keynode->type, keynode->keyname, func_ret, err_no, err_buf); - } - } else { - ERR("_preference_set_key_filesys(%d-%s) step(%d) failed(%d / %s)\n", keynode->type, keynode->keyname, func_ret, err_no, err_buf); - } - } else if (retry_cnt > 0) { - DBG("_preference_set_key_filesys ok with retry cnt(%d)", retry_cnt); - } - - if (fp) { - if (func_ret == PREFERENCE_ERROR_NONE) { - ret = fdatasync(fileno(fp)); - if (ret == -1) { - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_SYNC; - } - } - fclose(fp); - } - *io_errno = err_no; - - return func_ret; -} - -static int _preference_set_key(keynode_t *keynode) -{ - int ret = 0; - int io_errno = 0; - char err_buf[100] = { 0, }; - - ret = _preference_set_key_filesys(keynode, &io_errno); - if (ret == PREFERENCE_ERROR_NONE) { - g_posix_errno = PREFERENCE_ERROR_NONE; - g_preference_errno = PREFERENCE_ERROR_NONE; - } else { - /* LCOV_EXCL_START */ - strerror_r(io_errno, err_buf, 100); - ERR("_preference_set_key(%s) step(%d) failed(%d / %s)", keynode->keyname, ret, io_errno, err_buf); - g_posix_errno = io_errno; - g_preference_errno = ret; - /* LCOV_EXCL_STOP */ - } - - return ret; -} - - -/* - * This function set the integer value of given key - * @param[in] key key - * @param[in] intval integer value to set - * @return 0 on success, -1 on error - */ -API int preference_set_int(const char *key, int intval) -{ - int func_ret = PREFERENCE_ERROR_NONE; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - _preference_keynode_set_value_int(pKeyNode, intval); - - if (_preference_set_key(pKeyNode) != PREFERENCE_ERROR_NONE) { - ERR("preference_set_int(%d) : key(%s/%d) error", getpid(), key, intval); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } else { - INFO("%s(%d) success", key, intval); - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* -* This function set the boolean value of given key -* @param[in] key key -* @param[in] boolval boolean value to set - (Integer value 1 is 'True', and 0 is 'False') -* @return 0 on success, -1 on error -*/ -API int preference_set_boolean(const char *key, bool boolval) -{ - int func_ret = PREFERENCE_ERROR_NONE; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - _preference_keynode_set_value_boolean(pKeyNode, boolval); - - if (_preference_set_key(pKeyNode) != PREFERENCE_ERROR_NONE) { - ERR("preference_set_boolean(%d) : key(%s/%d) error", getpid(), key, boolval); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } else { - INFO("%s(%d) success", key, boolval); - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function set the double value of given key - * @param[in] key key - * @param[in] dblval double value to set - * @return 0 on success, -1 on error - */ -API int preference_set_double(const char *key, double dblval) -{ - int func_ret = PREFERENCE_ERROR_NONE; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - _preference_keynode_set_value_double(pKeyNode, dblval); - - if (_preference_set_key(pKeyNode) != PREFERENCE_ERROR_NONE) { - ERR("preference_set_double(%d) : key(%s/%f) error", getpid(), key, dblval); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } else { - INFO("%s(%f) success", key, dblval); - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function set the string value of given key - * @param[in] key key - * @param[in] strval string value to set - * @return 0 on success, -1 on error - */ -API int preference_set_string(const char *key, const char *strval) -{ - int func_ret = PREFERENCE_ERROR_NONE; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL"); - retvm_if(strval == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: value is NULL"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - _preference_keynode_set_value_string(pKeyNode, strval); - - if (_preference_set_key(pKeyNode) != PREFERENCE_ERROR_NONE) { - ERR("preference_set_string(%d) : key(%s/%s) error", getpid(), key, strval); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } else { - INFO("%s(%s) success", key, strval); - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -static int _preference_get_key_filesys(keynode_t *keynode, int* io_errno) -{ - char path[PATH_MAX] = {0,}; - int ret = -1; - int func_ret = PREFERENCE_ERROR_NONE; - char err_buf[100] = { 0, }; - int err_no = 0; - int type = 0; - FILE *fp = NULL; - int retry_cnt = 0; - int read_size = 0; - size_t keyname_len = 0; - int value_int = 0; - double value_dbl = 0; - char file_buf[BUF_LEN] = {0,}; - char *value = NULL; - char *tmp_value; - int value_size = 0; - int tmp_value_size = 0; - -retry_open: - errno = 0; - func_ret = PREFERENCE_ERROR_NONE; - - ret = _preference_get_key_path(keynode, path); - retv_if(ret != PREFERENCE_ERROR_NONE, ret); - - if ((fp = fopen(path, "r")) == NULL) { - func_ret = PREFERENCE_ERROR_FILE_OPEN; - err_no = errno; - goto out_return; - } - -retry: - err_no = 0; - func_ret = PREFERENCE_ERROR_NONE; - - ret = _preference_set_read_lock(fileno(fp)); - if (ret == -1) { - /* LCOV_EXCL_START */ - func_ret = PREFERENCE_ERROR_FILE_LOCK; - err_no = errno; - goto out_return; - /* LCOV_EXCL_STOP */ - } - - read_size = fread((void *)&keyname_len, sizeof(int), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - errno = ENODATA; - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - ret = fseek(fp, keyname_len, SEEK_CUR); - if (ret) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - errno = ENODATA; - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - read_size = fread((void *)&type, sizeof(int), 1, fp); - if (read_size <= 0) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - errno = ENODATA; - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } - - /* read data value */ - switch (type) { - case PREFERENCE_TYPE_INT: - read_size = fread((void *)&value_int, sizeof(int), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - LOGW("number of read items for value is wrong. err : %d", errno); - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } else { - _preference_keynode_set_value_int(keynode, value_int); - } - - break; - case PREFERENCE_TYPE_DOUBLE: - read_size = fread((void *)&value_dbl, sizeof(double), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(double))) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - LOGW("number of read items for value is wrong. err : %d", errno); - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } else { - _preference_keynode_set_value_double(keynode, value_dbl); - } - - break; - case PREFERENCE_TYPE_BOOLEAN: - read_size = fread((void *)&value_int, sizeof(int), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - /* LCOV_EXCL_START */ - if (!ferror(fp)) - LOGW("number of read items for value is wrong. err : %d", errno); - - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FREAD; - goto out_unlock; - /* LCOV_EXCL_STOP */ - } else { - _preference_keynode_set_value_boolean(keynode, value_int); - } - - break; - case PREFERENCE_TYPE_STRING: - while (fgets(file_buf, sizeof(file_buf), fp)) { - if (value) { - tmp_value_size = value_size + sizeof(file_buf); - tmp_value = (char *) realloc(value, tmp_value_size); - if (tmp_value == NULL) { - func_ret = PREFERENCE_ERROR_OUT_OF_MEMORY; - free(value); - value = NULL; - break; - } - - memset(tmp_value + value_size , 0x00, sizeof(file_buf)); - strncat(tmp_value, file_buf, tmp_value_size - strlen(tmp_value)); - value = tmp_value; - - value_size = tmp_value_size; - memset(file_buf, 0x00, sizeof(file_buf)); - } else { - value_size = sizeof(file_buf) + 1; - value = (char *)malloc(value_size); - if (value == NULL) { - func_ret = PREFERENCE_ERROR_OUT_OF_MEMORY; - break; - } - memset(value, 0x00, value_size); - strncpy(value, file_buf, value_size - 1); - } - } - - if (ferror(fp)) { - err_no = errno; - func_ret = PREFERENCE_ERROR_FILE_FGETS; - } else { - if (value) - _preference_keynode_set_value_string(keynode, value); - else - _preference_keynode_set_value_string(keynode, ""); - } - if (value) - free(value); - - break; - default: - func_ret = PREFERENCE_ERROR_WRONG_TYPE; - } - -out_unlock: - ret = _preference_set_unlock(fileno(fp)); - if (ret == -1) { - func_ret = PREFERENCE_ERROR_FILE_LOCK; - err_no = errno; - goto out_return; - } - - -out_return: - if (func_ret != PREFERENCE_ERROR_NONE) { - strerror_r(err_no, err_buf, 100); - - if (_preference_check_retry_err(keynode, func_ret, err_no, PREFERENCE_OP_GET)) { - /* LCOV_EXCL_START */ - if (retry_cnt < PREFERENCE_ERROR_RETRY_CNT) { - retry_cnt++; - usleep((retry_cnt)*PREFERENCE_ERROR_RETRY_SLEEP_UTIME); - - if (fp) - goto retry; - else - goto retry_open; - } else { - ERR("_preference_get_key_filesys(%s) step(%d) faild(%d / %s) over the retry count.", - keynode->keyname, func_ret, err_no, err_buf); - } - /* LCOV_EXCL_STOP */ - } - } - - if (fp) - fclose(fp); - - *io_errno = err_no; - - return func_ret; -} - -int _preference_get_key(keynode_t *keynode) -{ - int ret = 0; - int io_errno = 0; - char err_buf[100] = {0,}; - - ret = _preference_get_key_filesys(keynode, &io_errno); - if (ret == PREFERENCE_ERROR_NONE) { - g_posix_errno = PREFERENCE_ERROR_NONE; - g_preference_errno = PREFERENCE_ERROR_NONE; - } else { - if (io_errno == ENOENT) - ret = PREFERENCE_ERROR_NO_KEY; - else - ret = PREFERENCE_ERROR_IO_ERROR; - - strerror_r(io_errno, err_buf, 100); - ERR("_preference_get_key(%s) step(%d) failed(%d / %s)\n", keynode->keyname, ret, io_errno, err_buf); - g_posix_errno = io_errno; - g_preference_errno = ret; - } - - return ret; -} - - -/* - * This function get the integer value of given key - * @param[in] key key - * @param[out] intval output buffer - * @return 0 on success, -1 on error - */ -API int preference_get_int(const char *key, int *intval) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(intval == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: output buffer is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_get_key(pKeyNode); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("preference_get_int(%d) : key(%s) error", getpid(), key); - } else { - *intval = pKeyNode->value.i; - if (pKeyNode->type == PREFERENCE_TYPE_INT) { - INFO("%s(%d) success", key, *intval); - func_ret = PREFERENCE_ERROR_NONE; - } else { - ERR("The type(%d) of keynode(%s) is not INT", pKeyNode->type, pKeyNode->keyname); - func_ret = PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function get the boolean value of given key - * @param[in] key key - * @param[out] boolval output buffer - * @return 0 on success, -1 on error - */ -API int preference_get_boolean(const char *key, bool *boolval) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(boolval == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: output buffer is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_get_key(pKeyNode); - - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("preference_get_boolean(%d) : %s error", getpid(), key); - } else { - *boolval = !!(pKeyNode->value.b); - if (pKeyNode->type == PREFERENCE_TYPE_BOOLEAN) { - INFO("%s(%d) success", key, *boolval); - func_ret = PREFERENCE_ERROR_NONE; - } else { - ERR("The type(%d) of keynode(%s) is not BOOL", pKeyNode->type, pKeyNode->keyname); - func_ret = PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function get the double value of given key - * @param[in] key key - * @param[out] dblval output buffer - * @return 0 on success, -1 on error - */ -API int preference_get_double(const char *key, double *dblval) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(dblval == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: output buffer is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_get_key(pKeyNode); - - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("preference_get_double(%d) : %s error", getpid(), key); - } else { - *dblval = pKeyNode->value.d; - if (pKeyNode->type == PREFERENCE_TYPE_DOUBLE) { - INFO("%s(%f) success", key, *dblval); - func_ret = PREFERENCE_ERROR_NONE; - } else { - ERR("The type(%d) of keynode(%s) is not DBL", pKeyNode->type, pKeyNode->keyname); - func_ret = PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function get the string value of given key - * @param[in] key key - * @param[out] value output buffer - * @return 0 on success, -1 on error - */ -API int preference_get_string(const char *key, char **value) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - char *tempstr = NULL; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(value == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: output buffer is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_get_key(pKeyNode); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("preference_get_string(%d) : %s error", getpid(), key); - } else { - if (pKeyNode->type == PREFERENCE_TYPE_STRING) { - tempstr = pKeyNode->value.s; - } else { - ERR("The type(%d) of keynode(%s) is not STR", pKeyNode->type, pKeyNode->keyname); - func_ret = PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (tempstr) { - *value = strdup(tempstr); - INFO("%s(%s) success", key, value); - } - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -/* - * This function unset given key - * @param[in] key key - * @return 0 on success, -1 on error - */ -API int preference_remove(const char *key) -{ - char path[PATH_MAX] = {0,}; - int ret = -1; - int err_retry = PREFERENCE_ERROR_RETRY_CNT; - int func_ret = PREFERENCE_ERROR_NONE; - char err_buf[ERR_LEN] = {0,}; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - - keynode_t *pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - ret = _preference_keynode_set_keyname(pKeyNode, key); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = _preference_get_key_path(pKeyNode, path); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("Invalid argument: key is not valid"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (access(path, F_OK) == -1) { - ERR("Error : key(%s) is not exist", key); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_NO_KEY; - } - - do { - ret = remove(path); - if (ret == -1) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("preference_remove() failed. ret=%d(%s), key(%s)", errno, err_buf, key); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } else { - func_ret = PREFERENCE_ERROR_NONE; - break; - } - } while (err_retry--); - - END_TIME_CHECK; - - _preference_keynode_free(pKeyNode); - - return func_ret; -} - -API int preference_remove_all(void) -{ - int ret = -1; - int err_retry = PREFERENCE_ERROR_RETRY_CNT; - int func_ret = PREFERENCE_ERROR_NONE; - DIR *dir; - struct dirent *dent = NULL; - char *pref_dir_path = NULL; - char err_buf[ERR_LEN] = {0,}; - const char *entry; - char *keyname = NULL; - char path[PATH_MAX] = {0,}; - - START_TIME_CHECK - - pref_dir_path = _preference_get_pref_dir_path(); - if (!pref_dir_path) { - LOGE("_preference_get_pref_dir_path() failed."); - return PREFERENCE_ERROR_IO_ERROR; - } - - dir = opendir(pref_dir_path); - if (dir == NULL) { - if (errno == ENOENT) - return PREFERENCE_ERROR_NONE; - strerror_r(errno, err_buf, sizeof(err_buf)); - LOGE("opendir() failed. pref_path: %s, error: %d(%s)", pref_dir_path, errno, err_buf); - return PREFERENCE_ERROR_IO_ERROR; - } - - keynode_t *pKeyNode = _preference_keynode_new(); - if (pKeyNode == NULL) { - ERR("key malloc fail"); - closedir(dir); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - - while ((dent = readdir(dir)) != NULL) { - entry = dent->d_name; - if (entry[0] == '.') - continue; - - snprintf(path, PATH_MAX-1, "%s%s", pref_dir_path, entry); - - ret = _preference_get_key_name(path, &keyname); - if (ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - ERR("_preference_get_key_name() failed(%d)", ret); - _preference_keynode_free(pKeyNode); - closedir(dir); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - - ret = preference_unset_changed_cb(keyname); - if (ret != PREFERENCE_ERROR_NONE) { - /* LCOV_EXCL_START */ - if (ret == PREFERENCE_ERROR_NO_KEY) { - ERR("can't find %s's cb()", keyname); - } else { - ERR("preference_unset_changed_cb() failed(%d)", ret); - _preference_keynode_free(pKeyNode); - closedir(dir); - free(keyname); - return PREFERENCE_ERROR_IO_ERROR; - } - /* LCOV_EXCL_STOP */ - } - - do { - ret = remove(path); - if (ret == -1) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("preference_remove_all error: %d(%s)", errno, err_buf); - func_ret = PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } else { - func_ret = PREFERENCE_ERROR_NONE; - break; - } - } while (err_retry--); - - free(keyname); - } - - _preference_keynode_free(pKeyNode); - closedir(dir); - - END_TIME_CHECK - - return func_ret; -} - -int preference_is_existing(const char *key, bool *exist) -{ - char path[PATH_MAX] = {0,}; - int ret = -1; - int func_ret = PREFERENCE_ERROR_NONE; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(exist == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - ret = _preference_keynode_set_keyname(pKeyNode, key); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = _preference_get_key_path(pKeyNode, path); - if (ret != PREFERENCE_ERROR_NONE) { - _preference_keynode_free(pKeyNode); - return ret; - } - - ret = access(path, F_OK); - if (ret == -1) { - if (errno != ENOENT) { - ERR("Failed to access key(%s) node. errno(%d)", - key, errno); - } - *exist = 0; - } else { - *exist = 1; - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return func_ret; -} - -API int preference_set_changed_cb(const char *key, preference_changed_cb callback, void *user_data) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - retvm_if(callback == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: cb(%p)", callback); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_kdb_add_notify(pKeyNode, callback, user_data); - if (func_ret != PREFERENCE_ERROR_NONE) { - if (func_ret == PREFERENCE_ERROR_NO_KEY) { - LOGE("NO_KEY(0x%08x) : fail to find given key(%s)", PREFERENCE_ERROR_NO_KEY, key); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_NO_KEY; - } else if (errno != 0) { - ERR("preference_notify_key_changed : key(%s) add notify fail", key); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - } - INFO("%s noti is added", key); - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return PREFERENCE_ERROR_NONE; -} - -API int preference_unset_changed_cb(const char *key) -{ - int func_ret = PREFERENCE_ERROR_IO_ERROR; - keynode_t *pKeyNode; - char err_buf[ERR_LEN] = {0,}; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - func_ret = _preference_keynode_set_keyname(pKeyNode, key); - if (func_ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - - func_ret = _preference_kdb_del_notify(pKeyNode); - if (func_ret != PREFERENCE_ERROR_NONE) { - if (func_ret == PREFERENCE_ERROR_NO_KEY) { - LOGE("NO_KEY(0x%08x) : fail to find given key(%s)", PREFERENCE_ERROR_NO_KEY, key); - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_NO_KEY; - } else { - if (errno != 0) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("preference_unset_changed_cb() failed: key(%s) error(%d:%s)", - key, errno, err_buf); - } else { - ERR("preference_unset_changed_cb() failed: key(%s)", key); - } - _preference_keynode_free(pKeyNode); - return PREFERENCE_ERROR_IO_ERROR; - } - } - INFO("%s noti removed", key); - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return PREFERENCE_ERROR_NONE; -} - - -API int preference_foreach_item(preference_item_cb callback, void *user_data) -{ - int ret = 0; - DIR *dir; - struct dirent *dent = NULL; - char *pref_dir_path = NULL; - char err_buf[ERR_LEN] = {0,}; - const char *entry; - char *keyname = NULL; - char path[PATH_MAX] = {0,}; - - - START_TIME_CHECK - retvm_if(callback == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: cb(%p)", callback); - - pref_dir_path = _preference_get_pref_dir_path(); - if (!pref_dir_path) { - LOGE("_preference_get_pref_dir_path() failed."); - return PREFERENCE_ERROR_IO_ERROR; - } - - dir = opendir(pref_dir_path); - if (dir == NULL) { - if (errno == ENOENT) - return PREFERENCE_ERROR_NONE; - strerror_r(errno, err_buf, sizeof(err_buf)); - LOGE("opendir() failed. path: %s, error: %d(%s)", pref_dir_path, errno, err_buf); - return PREFERENCE_ERROR_IO_ERROR; - } - - while ((dent = readdir(dir)) != NULL) { - entry = dent->d_name; - if (entry[0] == '.') - continue; - - snprintf(path, PATH_MAX-1, "%s%s", pref_dir_path, entry); - - ret = _preference_get_key_name(path, &keyname); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("_preference_get_key_name() failed(%d)", ret); - closedir(dir); - return PREFERENCE_ERROR_IO_ERROR; - } - - callback(keyname, user_data); - free(keyname); - } - - closedir(dir); - END_TIME_CHECK - - return PREFERENCE_ERROR_NONE; -} - -/* - * This function get the type of given key - * @param[in] key key - * @param[out] type output buffer - * @return 0 on success, -value on error - */ -API int preference_get_type(const char *key, preference_type_e *type) -{ - int ret; - keynode_t *pKeyNode; - - START_TIME_CHECK - - retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, - "Invalid argument: key is null"); - retvm_if(type == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, - "Invalid argument: output buffer is null"); - - pKeyNode = _preference_keynode_new(); - retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail"); - - ret = _preference_keynode_set_keyname(pKeyNode, key); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("set key name error"); - _preference_keynode_free(pKeyNode); - return ret; - } - - ret = _preference_get_key(pKeyNode); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("preference_get_int(%d) : key(%s) error", getpid(), key); - *type = PREFERENCE_TYPE_NONE; - } else { - *type = pKeyNode->type; - } - - _preference_keynode_free(pKeyNode); - - END_TIME_CHECK - - return ret; -} diff --git a/src/preference_db.c b/src/preference_db.c deleted file mode 100644 index e87b34a..0000000 --- a/src/preference_db.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 - -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "CAPI_APPFW_APPLICATION_PREFERENCE" -#define DBG_MODE (1) - -static sqlite3 *pref_db = NULL; -static bool is_update_hook_registered = false; -static pref_changed_cb_node_t *head = NULL; - -static void _finish(void *data) -{ - if (pref_db != NULL) { - sqlite3_close(pref_db); - pref_db = NULL; - } -} - -static int _busy_handler(void *pData, int count) -{ - if (5 - count > 0) { - LOGD("Busy Handler Called! : PID(%d) / CNT(%d)\n", getpid(), count + 1); - usleep((count + 1) * 100000); - return 1; - } else { - LOGD("Busy Handler will be returned SQLITE_BUSY error : PID(%d) \n", getpid()); - return 0; - } -} - -static int _initialize(void) -{ - char *data_path = NULL; - char db_path[TIZEN_PATH_MAX] = {0, }; - int ret; - char *errmsg; - - if ((data_path = app_get_data_path()) == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to get data directory", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - snprintf(db_path, sizeof(db_path), "%s/%s", data_path, PREF_DB_NAME); - free(data_path); - - ret = sqlite3_open(db_path, &pref_db); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to open db(%s)", PREFERENCE_ERROR_IO_ERROR, sqlite3_errmsg(pref_db)); - pref_db = NULL; - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_busy_handler(pref_db, _busy_handler, NULL); - if (ret != SQLITE_OK) - LOGW("IO_ERROR(0x%08x) : fail to register busy handler(%s)\n", PREFERENCE_ERROR_IO_ERROR, sqlite3_errmsg(pref_db)); - - ret = sqlite3_exec(pref_db, "CREATE TABLE IF NOT EXISTS pref ( pref_key TEXT PRIMARY KEY, pref_type TEXT, pref_data TEXT)", - NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to create db table(%s)", PREFERENCE_ERROR_IO_ERROR, errmsg); - sqlite3_free(errmsg); - sqlite3_close(pref_db); - pref_db = NULL; - return PREFERENCE_ERROR_IO_ERROR; - } - - app_finalizer_add(_finish, NULL); - - return PREFERENCE_ERROR_NONE; -} - -static int _write_data(const char *key, const char *type, const char *data) -{ - int ret; - char *buf = NULL; - bool exist = false; - sqlite3_stmt *stmt; - - if (key == NULL || key[0] == '\0' || data == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - /* insert data or update data if data already exist */ - ret = preference_is_existing(key, &exist); - if (ret != PREFERENCE_ERROR_NONE) - return ret; - - /* to use sqlite3_update_hook, we have to use INSERT/UPDATE operation instead of REPLACE operation */ - if (exist) - buf = sqlite3_mprintf("UPDATE %s SET %s=?, %s=? WHERE %s=?;", - PREF_TBL_NAME, PREF_F_TYPE_NAME, PREF_F_DATA_NAME, PREF_F_KEY_NAME); - else - buf = sqlite3_mprintf("INSERT INTO %s (%s, %s, %s) values (?, ?, ?);", - PREF_TBL_NAME, PREF_F_KEY_NAME, PREF_F_TYPE_NAME, PREF_F_DATA_NAME); - - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_prepare(pref_db, buf, strlen(buf), &stmt, NULL); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to prepare query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - return PREFERENCE_ERROR_IO_ERROR; - } - - if (exist) { - ret = sqlite3_bind_text(stmt, 1, type, strlen(type), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(1) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - ret = sqlite3_bind_text(stmt, 2, data, strlen(data), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(2) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - ret = sqlite3_bind_text(stmt, 3, key, strlen(key), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(3) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - } else { - ret = sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(1) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - ret = sqlite3_bind_text(stmt, 2, type, strlen(type), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(2) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - ret = sqlite3_bind_text(stmt, 3, data, strlen(data), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(3) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - ret = sqlite3_step(stmt); - if (ret != SQLITE_DONE) { - LOGE("IO_ERROR(0x%08x): fail to write data(%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - - sqlite3_finalize(stmt); - if (buf) { - sqlite3_free(buf); - buf = NULL; - } - - return PREFERENCE_ERROR_NONE; -} - -/* static int _read_data(const char *key, preference_type_e *type, char *data) */ -static int _read_data(const char *key, char *type, char *data) -{ - int ret; - char *buf; - char **result; - int rows; - int columns; - char *errmsg; - - if (key == NULL || key[0] == '\0' || data == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (pref_db == NULL) { - if (_initialize() != PREFERENCE_ERROR_NONE) { - LOGE("IO_ERROR(0x%08x) : fail to initialize db", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - buf = sqlite3_mprintf("SELECT %s, %s, %s FROM %s WHERE %s=%Q;", - PREF_F_KEY_NAME, PREF_F_TYPE_NAME, PREF_F_DATA_NAME, PREF_TBL_NAME, PREF_F_KEY_NAME, key); - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_get_table(pref_db, buf, &result, &rows, &columns, &errmsg); - sqlite3_free(buf); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to read data (%s)", PREFERENCE_ERROR_IO_ERROR, errmsg); - sqlite3_free(errmsg); - return PREFERENCE_ERROR_IO_ERROR; - } - - if (rows == 0) { - LOGE("NO_KEY(0x%08x) : fail to find given key(%s)", PREFERENCE_ERROR_NO_KEY, key); - sqlite3_free_table(result); - return PREFERENCE_ERROR_NO_KEY; - } - - snprintf(type, 2, "%s", result[4]); /* get type value */ - snprintf(data, BUF_LEN, "%s", result[5]); /* get data value */ - - sqlite3_free_table(result); - - return PREFERENCE_ERROR_NONE; -} - - -int preference_set_int(const char *key, int value) -{ - char type[2]; - char data[BUF_LEN]; - snprintf(type, 2, "%d", PREFERENCE_TYPE_INT); - snprintf(data, BUF_LEN, "%d", value); - return _write_data(key, type, data); -} - -int preference_get_int(const char *key, int *value) -{ - char type[2]; - char data[BUF_LEN]; - int ret; - - if (value == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - ret = _read_data(key, type, data); - if (ret == PREFERENCE_ERROR_NONE) { - if (atoi(type) == PREFERENCE_TYPE_INT) - *value = atoi(data); - else { - LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)", PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type)); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - return ret; -} - -int preference_set_double(const char *key, double value) -{ - char type[2]; - char data[BUF_LEN]; - - locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL); - uselocale(loc); - - snprintf(type, 2, "%d", PREFERENCE_TYPE_DOUBLE); - snprintf(data, BUF_LEN, "%f", value); - - freelocale(loc); - uselocale(LC_GLOBAL_LOCALE); - - return _write_data(key, type, data); -} - -int preference_get_double(const char *key, double *value) -{ - char type[2]; - char data[BUF_LEN]; - int ret; - - if (value == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - ret = _read_data(key, type, data); - if (ret == PREFERENCE_ERROR_NONE) { - if (atoi(type) == PREFERENCE_TYPE_DOUBLE) { - locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL); - uselocale(loc); - - *value = atof(data); - - freelocale(loc); - uselocale(LC_GLOBAL_LOCALE); - } else { - LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)", PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type)); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - return ret; -} - -int preference_set_string(const char *key, const char *value) -{ - char type[2]; - - snprintf(type, 2, "%d", PREFERENCE_TYPE_STRING); - if (strlen(value) > (BUF_LEN-1)) { - LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)", PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type)); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - return _write_data(key, type, value); -} - -int preference_get_string(const char *key, char **value) -{ - char type[2]; - char data[BUF_LEN]; - int ret; - - if (value == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - ret = _read_data(key, type, data); - if (ret == PREFERENCE_ERROR_NONE) { - if (atoi(type) == PREFERENCE_TYPE_STRING) { - *value = strdup(data); - if (value == NULL) { - LOGE("OUT_OF_MEMORY(0x%08x)", PREFERENCE_ERROR_OUT_OF_MEMORY); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - } else { - LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)", PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type)); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - return ret; -} - -int preference_set_boolean(const char *key, bool value) -{ - char type[2]; - char data[BUF_LEN]; - - snprintf(type, 2, "%d", PREFERENCE_TYPE_BOOLEAN); - snprintf(data, BUF_LEN, "%d", value); - - return _write_data(key, type, data); -} - -int preference_get_boolean(const char *key, bool *value) -{ - char type[2]; - char data[BUF_LEN]; - int ret; - - if (value == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - ret = _read_data(key, type, data); - if (ret == PREFERENCE_ERROR_NONE) { - if (atoi(type) == PREFERENCE_TYPE_BOOLEAN) - *value = (bool)atoi(data); - else { - LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)", PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type)); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - } - - return ret; -} - -/* TODO: below operation is too heavy, let's find the light way to check. */ -int preference_is_existing(const char *key, bool *exist) -{ - int ret; - char *buf; - char **result; - int rows; - int columns; - char *errmsg; - - if (key == NULL || key[0] == '\0' || exist == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (pref_db == NULL) { - if (_initialize() != PREFERENCE_ERROR_NONE) { - LOGE("IO_ERROR(0x%08x) : fail to initialize db", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - /* check data is exist */ - buf = sqlite3_mprintf("SELECT %s FROM %s WHERE %s=%Q;", PREF_F_KEY_NAME, PREF_TBL_NAME, PREF_F_KEY_NAME, key); - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_get_table(pref_db, buf, &result, &rows, &columns, &errmsg); - sqlite3_free(buf); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to read data(%s)", PREFERENCE_ERROR_IO_ERROR, errmsg); - sqlite3_free(errmsg); - return PREFERENCE_ERROR_IO_ERROR; - } - - if (rows > 0) - *exist = true; - else - *exist = false; - - sqlite3_free_table(result); - return PREFERENCE_ERROR_NONE; -} - -static pref_changed_cb_node_t *_find_node(const char *key) -{ - pref_changed_cb_node_t *tmp_node; - - if (key == NULL || key[0] == '\0') - return NULL; - - tmp_node = head; - while (tmp_node) { - if (strcmp(tmp_node->key, key) == 0) - break; - - tmp_node = tmp_node->next; - } - - return tmp_node; -} - -static int _add_node(const char *key, preference_changed_cb cb, void *user_data) -{ - pref_changed_cb_node_t *tmp_node; - - if (key == NULL || key[0] == '\0' || cb == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - tmp_node = _find_node(key); - if (tmp_node != NULL) { - tmp_node->cb = cb; - tmp_node->user_data = user_data; - } else { - tmp_node = (pref_changed_cb_node_t *)malloc(sizeof(pref_changed_cb_node_t)); - if (tmp_node == NULL) { - LOGE("OUT_OF_MEMORY(0x%08x)", PREFERENCE_ERROR_OUT_OF_MEMORY); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - - tmp_node->key = strdup(key); - if (tmp_node->key == NULL) { - free(tmp_node); - LOGE("OUT_OF_MEMORY(0x%08x)", PREFERENCE_ERROR_OUT_OF_MEMORY); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - - if (head != NULL) - head->prev = tmp_node; - tmp_node->cb = cb; - tmp_node->user_data = user_data; - tmp_node->prev = NULL; - tmp_node->next = head; - head = tmp_node; - } - - return PREFERENCE_ERROR_NONE; -} - -static int _remove_node(const char *key) -{ - pref_changed_cb_node_t *tmp_node; - - if (key == NULL || key[0] == '\0') { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - tmp_node = _find_node(key); - if (tmp_node == NULL) - return PREFERENCE_ERROR_NONE; - - if (tmp_node->prev != NULL) - tmp_node->prev->next = tmp_node->next; - else - head = tmp_node->next; - - if (tmp_node->next != NULL) - tmp_node->next->prev = tmp_node->prev; - - if (tmp_node->key) - free(tmp_node->key); - - free(tmp_node); - - return PREFERENCE_ERROR_NONE; -} - -static void _remove_all_node(void) -{ - pref_changed_cb_node_t *tmp_node; - - while (head) { - tmp_node = head; - head = tmp_node->next; - - if (tmp_node->key) - free(tmp_node->key); - - free(tmp_node); - } -} - -static void _update_cb(void *data, int action, char const *db_name, char const *table_name, sqlite_int64 rowid) -{ - int ret; - char *buf; - char **result; - int rows; - int columns; - char *errmsg; - pref_changed_cb_node_t *tmp_node; - - /* skip INSERT/DELETE event */ - if (action != SQLITE_UPDATE) - return; - - if (strcmp(table_name, PREF_TBL_NAME) != 0) { - SECURE_LOGE("given table name (%s) is not same", table_name); - return; - } - - buf = sqlite3_mprintf("SELECT %s FROM %s WHERE rowid='%lld';", PREF_F_KEY_NAME, PREF_TBL_NAME, rowid); - if (buf == NULL) - return; - - ret = sqlite3_get_table(pref_db, buf, &result, &rows, &columns, &errmsg); - sqlite3_free(buf); - if (ret != SQLITE_OK) { - LOGI("fail to read data(%s)", errmsg); - sqlite3_free(errmsg); - return; - } - - if (rows == 0) { - sqlite3_free_table(result); - return; - } - - tmp_node = _find_node(result[1]); - if (tmp_node != NULL && tmp_node->cb != NULL) - tmp_node->cb(result[1], tmp_node->user_data); - - sqlite3_free_table(result); -} - -int preference_remove(const char *key) -{ - int ret; - char *buf; - bool exist; - sqlite3_stmt *stmt; - - ret = preference_is_existing(key, &exist); - if (ret != PREFERENCE_ERROR_NONE) - return ret; - - if (!exist) - return PREFERENCE_ERROR_NO_KEY; - - /* insert data or update data if data already exist */ - buf = sqlite3_mprintf("DELETE FROM %s WHERE %s = ?", - PREF_TBL_NAME, PREF_F_KEY_NAME, key); - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_prepare(pref_db, buf, strlen(buf), &stmt, NULL); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to prepare query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_bind_text(stmt, 1, key, strlen(key), SQLITE_STATIC); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to bind(1) query (%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_step(stmt); - if (ret != SQLITE_DONE) { - LOGE("IO_ERROR(0x%08x): fail to delete data(%d/%s)", - PREFERENCE_ERROR_IO_ERROR, - sqlite3_extended_errcode(pref_db), - sqlite3_errmsg(pref_db)); - sqlite3_finalize(stmt); - return PREFERENCE_ERROR_IO_ERROR; - } - - sqlite3_finalize(stmt); - if (buf) { - sqlite3_free(buf); - buf = NULL; - } - - /* if exist, remove changed cb */ - _remove_node(key); - - return PREFERENCE_ERROR_NONE; -} - -int preference_remove_all(void) -{ - int ret; - char *buf; - char *errmsg; - - if (pref_db == NULL) { - if (_initialize() != PREFERENCE_ERROR_NONE) { - LOGE("IO_ERROR(0x%08x) : fail to initialize db", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - /* insert data or update data if data already exist */ - buf = sqlite3_mprintf("DELETE FROM %s;", PREF_TBL_NAME); - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_exec(pref_db, buf, NULL, NULL, &errmsg); - sqlite3_free(buf); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to delete data (%s)", PREFERENCE_ERROR_IO_ERROR, errmsg); - sqlite3_free(errmsg); - return PREFERENCE_ERROR_IO_ERROR; - } - - /* if exist, remove changed cb */ - _remove_all_node(); - - return PREFERENCE_ERROR_NONE; -} - -int preference_set_changed_cb(const char *key, preference_changed_cb callback, void *user_data) -{ - int ret; - bool exist; - - ret = preference_is_existing(key, &exist); - if (ret != PREFERENCE_ERROR_NONE) - return ret; - - if (!exist) { - LOGE("NO_KEY(0x%08x) : fail to find given key(%s)", PREFERENCE_ERROR_NO_KEY, key); - return PREFERENCE_ERROR_NO_KEY; - } - - if (!is_update_hook_registered) { - sqlite3_update_hook(pref_db, _update_cb, NULL); - is_update_hook_registered = true; - } - - return _add_node(key, callback, user_data); -} - -int preference_unset_changed_cb(const char *key) -{ - int ret; - bool exist; - - ret = preference_is_existing(key, &exist); - if (ret != PREFERENCE_ERROR_NONE) - return ret; - - if (!exist) { - LOGE("NO_KEY(0x%08x) : fail to find given key(%s)", PREFERENCE_ERROR_NO_KEY, key); - return PREFERENCE_ERROR_NO_KEY; - } - - return _remove_node(key); -} - -int preference_foreach_item(preference_item_cb callback, void *user_data) -{ - int ret; - char *buf; - char **result; - int rows; - int columns; - char *errmsg; - int i; - - if (callback == NULL) { - LOGE("INVALID_PARAMETER(0x%08x)", PREFERENCE_ERROR_INVALID_PARAMETER); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (pref_db == NULL) { - if (_initialize() != PREFERENCE_ERROR_NONE) { - LOGE("IO_ERROR(0x%08x) : fail to initialize db", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - } - - buf = sqlite3_mprintf("SELECT %s FROM %s;", PREF_F_KEY_NAME, PREF_TBL_NAME); - if (buf == NULL) { - LOGE("IO_ERROR(0x%08x) : fail to create query string", PREFERENCE_ERROR_IO_ERROR); - return PREFERENCE_ERROR_IO_ERROR; - } - - ret = sqlite3_get_table(pref_db, buf, &result, &rows, &columns, &errmsg); - sqlite3_free(buf); - if (ret != SQLITE_OK) { - LOGE("IO_ERROR(0x%08x) : fail to read data (%s)", PREFERENCE_ERROR_IO_ERROR, errmsg); - sqlite3_free(errmsg); - return PREFERENCE_ERROR_IO_ERROR; - } - - for (i = 1; i <= rows; i++) { - if (callback(result[i], user_data) != true) - break; - } - - sqlite3_free_table(result); - - return PREFERENCE_ERROR_NONE; -} - diff --git a/src/preference_inoti.c b/src/preference_inoti.c deleted file mode 100644 index 9fc8cfe..0000000 --- a/src/preference_inoti.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 - -#define INOTY_EVENT_MASK (IN_CLOSE_WRITE | IN_DELETE_SELF) - -/* inotify */ -struct noti_node { - int wd; - char *keyname; - preference_changed_cb cb; - void *cb_data; - struct noti_node *next; -}; -typedef struct noti_node noti_node_s; -static GList *g_notilist; - -static int _preference_inoti_comp_with_wd(gconstpointer a, gconstpointer b) -{ - int r; - - noti_node_s *key1 = (noti_node_s *) a; - noti_node_s *key2 = (noti_node_s *) b; - - r = key1->wd - key2->wd; - return r; -} - -static int _kdb_inoti_fd; - -static pthread_mutex_t _kdb_inoti_fd_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t _kdb_g_ns_mutex = PTHREAD_MUTEX_INITIALIZER; - -static GSource *_kdb_handler; - -static GList *_preference_copy_noti_list(GList *orig_notilist) -{ - GList *copy_notilist = NULL; - struct noti_node *n = NULL; - struct noti_node *t = NULL; - char err_buf[ERR_LEN] = {0,}; - - if (!orig_notilist) - return NULL; - - orig_notilist = g_list_first(orig_notilist); - if (!orig_notilist) - return NULL; - - while (orig_notilist) { - do { - t = orig_notilist->data; - if (t == NULL) { - WARN("noti item data is null"); - break; - } - - if ((t->keyname == NULL) || (strlen(t->keyname) == 0)) { - WARN("noti item data key name is null"); - break; - } - - n = calloc(1, sizeof(noti_node_s)); - if (n == NULL) { - ERR("_preference_copy_noti_list : calloc failed. memory full"); - break; - } - - n->keyname = strndup(t->keyname, PREFERENCE_KEY_PATH_LEN); - if (n->keyname == NULL) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("The memory is insufficient, errno: %d (%s)", errno, err_buf); - free(n); - break; - /* LCOV_EXCL_STOP */ - } - n->wd = t->wd; - n->cb_data = t->cb_data; - n->cb = t->cb; - - copy_notilist = g_list_append(copy_notilist, n); - } while (0); - - orig_notilist = g_list_next(orig_notilist); - } - return copy_notilist; -} - -static void _preference_free_noti_node(gpointer data) -{ - struct noti_node *n = (struct noti_node *)data; - g_free(n->keyname); - g_free(n); -} - -static void _preference_free_noti_list(GList *noti_list) -{ - g_list_free_full(noti_list, _preference_free_noti_node); -} - - -static gboolean _preference_kdb_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data) -{ - int fd, r, res; - struct inotify_event ie; - GList *l_notilist = NULL; - struct noti_node *t = NULL; - GList *noti_list = NULL; - keynode_t *keynode; - - fd = g_io_channel_unix_get_fd(src); - r = read(fd, &ie, sizeof(ie)); - - while (r > 0) { - if (ie.mask & INOTY_EVENT_MASK) { - - INFO("read event from GIOChannel. wd : %d", ie.wd); - - pthread_mutex_lock(&_kdb_g_ns_mutex); - l_notilist = _preference_copy_noti_list(g_notilist); - pthread_mutex_unlock(&_kdb_g_ns_mutex); - - if (l_notilist) { - noti_list = g_list_first(l_notilist); - while (noti_list) { - t = noti_list->data; - - keynode = _preference_keynode_new(); - if (keynode == NULL) { - ERR("key malloc fail"); - break; - } - - if ((t) && (t->wd == ie.wd) && (t->keyname)) { - res = _preference_keynode_set_keyname(keynode, t->keyname); - if (res != PREFERENCE_ERROR_NONE) { - ERR("_preference_keynode_set_keyname() failed(%d)", res); - goto out_func; - } - - if ((ie.mask & IN_DELETE_SELF)) { - res = _preference_kdb_del_notify(keynode); - if (res != PREFERENCE_ERROR_NONE) - ERR("_preference_kdb_del_notify() failed(%d)", res); - } else { - res = _preference_get_key(keynode); - if (res != PREFERENCE_ERROR_NONE) - ERR("_preference_get_key() failed(%d)", res); - - INFO("key(%s) is changed. cb(%p) called", t->keyname, t->cb); - t->cb(t->keyname, t->cb_data); - } - } else if ((t) && (t->keyname == NULL)) { /* for debugging */ - ERR("preference keyname is null."); - } -out_func: - _preference_keynode_free(keynode); - - noti_list = g_list_next(noti_list); - } - - _preference_free_noti_list(l_notilist); - } - } - - if (ie.len > 0) - (void) lseek(fd, ie.len, SEEK_CUR); - - r = read(fd, &ie, sizeof(ie)); - } - return TRUE; -} - -static int _preference_kdb_noti_init(void) -{ - GIOChannel *gio; - int ret = 0; - char err_buf[ERR_LEN] = { 0, }; - - pthread_mutex_lock(&_kdb_inoti_fd_mutex); - - if (0 < _kdb_inoti_fd) { - /* LCOV_EXCL_START */ - ERR("Error: invalid _kdb_inoti_fd"); - pthread_mutex_unlock(&_kdb_inoti_fd_mutex); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - _kdb_inoti_fd = inotify_init(); - if (_kdb_inoti_fd == -1) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("inotify init: %s", err_buf); - pthread_mutex_unlock(&_kdb_inoti_fd_mutex); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - - ret = fcntl(_kdb_inoti_fd, F_SETFD, FD_CLOEXEC); - if (ret < 0) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("inotify init: %s", err_buf); - pthread_mutex_unlock(&_kdb_inoti_fd_mutex); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - - ret = fcntl(_kdb_inoti_fd, F_SETFL, O_NONBLOCK); - if (ret < 0) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("inotify init: %s", err_buf); - pthread_mutex_unlock(&_kdb_inoti_fd_mutex); - return PREFERENCE_ERROR_IO_ERROR; - /* LCOV_EXCL_STOP */ - } - - pthread_mutex_unlock(&_kdb_inoti_fd_mutex); - - gio = g_io_channel_unix_new(_kdb_inoti_fd); - retvm_if(gio == NULL, -1, "Error: create a new GIOChannel"); - - g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL); - - _kdb_handler = g_io_create_watch(gio, G_IO_IN); - g_source_set_callback(_kdb_handler, (GSourceFunc) _preference_kdb_gio_cb, NULL, NULL); - g_source_attach(_kdb_handler, NULL); - g_io_channel_unref(gio); - g_source_unref(_kdb_handler); - - return PREFERENCE_ERROR_NONE; -} - -int _preference_kdb_add_notify(keynode_t *keynode, preference_changed_cb cb, void *data) -{ - char path[PATH_MAX]; - int wd; - struct noti_node t, *n, *node; - char err_buf[ERR_LEN] = { 0, }; - int ret = 0; - GList *list = NULL; - int func_ret = PREFERENCE_ERROR_NONE; - char *keyname = keynode->keyname; - - retvm_if((keyname == NULL || cb == NULL), PREFERENCE_ERROR_INVALID_PARAMETER, - "_preference_kdb_add_notify : Invalid argument - keyname(%s) cb(%p)", - keyname, cb); - - if (_kdb_inoti_fd <= 0) - if (_preference_kdb_noti_init()) - return PREFERENCE_ERROR_IO_ERROR; - - ret = _preference_get_key_path(keynode, path); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("Invalid argument: key is not valid"); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (access(path, F_OK) != 0) { - if (errno == ENOENT) { - ERR("_preference_kdb_add_notify : Key(%s) does not exist", keyname); - return PREFERENCE_ERROR_NO_KEY; - } - } - - wd = inotify_add_watch(_kdb_inoti_fd, path, INOTY_EVENT_MASK); - if (wd == -1) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("_preference_kdb_add_notify : add noti(%s)", err_buf); - return PREFERENCE_ERROR_IO_ERROR; - } - - t.wd = wd; - - pthread_mutex_lock(&_kdb_g_ns_mutex); - - list = g_list_find_custom(g_notilist, &t, (GCompareFunc)_preference_inoti_comp_with_wd); - if (list) { - /* LCOV_EXCL_START */ - WARN("_preference_kdb_add_notify : key(%s) change callback(%p)", keyname, cb); - - node = list->data; - node->wd = wd; - node->cb_data = data; - node->cb = cb; - - goto out_func; - /* LCOV_EXCL_STOP */ - } - - n = calloc(1, sizeof(noti_node_s)); - if (n == NULL) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("_preference_kdb_add_notify : add noti(%s)", err_buf); - func_ret = PREFERENCE_ERROR_IO_ERROR; - goto out_func; - /* LCOV_EXCL_STOP */ - } - - n->keyname = strndup(keyname, PREFERENCE_KEY_PATH_LEN); - if (n->keyname == NULL) { - /* LCOV_EXCL_START */ - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("The memory is insufficient, errno: %d (%s)", errno, err_buf); - free(n); - goto out_func; - /* LCOV_EXCL_STOP */ - } - n->wd = wd; - n->cb_data = data; - n->cb = cb; - - g_notilist = g_list_append(g_notilist, n); - if (!g_notilist) - ERR("g_list_append fail"); - - INFO("cb(%p) is added for %s. tot cb cnt : %d\n", cb, n->keyname, g_list_length(g_notilist)); - -out_func: - pthread_mutex_unlock(&_kdb_g_ns_mutex); - - return func_ret; -} - -int _preference_kdb_del_notify(keynode_t *keynode) -{ - int wd = 0; - int r = 0; - struct noti_node *n = NULL; - struct noti_node t; - char path[PATH_MAX] = { 0, }; - char err_buf[ERR_LEN] = { 0, }; - int del = 0; - int ret = 0; - char *keyname = keynode->keyname; - int func_ret = PREFERENCE_ERROR_NONE; - GList *noti_list; - - retvm_if(keyname == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: keyname is null"); - - ret = _preference_get_key_path(keynode, path); - if (ret != PREFERENCE_ERROR_NONE) { - ERR("Invalid argument: key is not valid"); - return PREFERENCE_ERROR_INVALID_PARAMETER; - } - - if (access(path, F_OK) != 0) { - if (errno == ENOENT) { - ERR("_preference_kdb_del_notify : Key(%s) does not exist", keyname); - return PREFERENCE_ERROR_NO_KEY; - } - } - - retvm_if(_kdb_inoti_fd == 0, PREFERENCE_ERROR_NONE, "Invalid operation: not exist anything for inotify"); - - /* get wd */ - wd = inotify_add_watch(_kdb_inoti_fd, path, INOTY_EVENT_MASK); - if (wd == -1) { - if (errno == ENOENT) - func_ret = PREFERENCE_ERROR_NO_KEY; - else - func_ret = PREFERENCE_ERROR_IO_ERROR; - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("Error: inotify_add_watch() [%s]: %s", path, err_buf); - return func_ret; - } - - pthread_mutex_lock(&_kdb_g_ns_mutex); - - t.wd = wd; - - noti_list = g_list_find_custom(g_notilist, &t, (GCompareFunc)_preference_inoti_comp_with_wd); - if (noti_list) { - del++; - - n = noti_list->data; - g_notilist = g_list_remove(g_notilist, n); - g_free(n->keyname); - g_free(n); - - r = inotify_rm_watch(_kdb_inoti_fd, wd); - if (r == -1) { - strerror_r(errno, err_buf, sizeof(err_buf)); - ERR("Error: inotify_rm_watch [%s]: %s", keyname, err_buf); - func_ret = PREFERENCE_ERROR_IO_ERROR; - } - - INFO("key(%s) cb is removed. remained noti list total length(%d)", - keyname, g_list_length(g_notilist)); - } - - if (g_list_length(g_notilist) == 0) { - close(_kdb_inoti_fd); - _kdb_inoti_fd = 0; - - g_source_destroy(_kdb_handler); - _kdb_handler = NULL; - - g_list_free(g_notilist); - g_notilist = NULL; - - INFO("all noti list is freed"); - } - - pthread_mutex_unlock(&_kdb_g_ns_mutex); - - if (del == 0) { - errno = ENOENT; - func_ret = PREFERENCE_ERROR_NO_KEY; - } - - return func_ret; -} - diff --git a/src/tool/CMakeLists.txt b/src/tool/CMakeLists.txt deleted file mode 100644 index 144de57..0000000 --- a/src/tool/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -SET(tool_name "preference_tool") - -SET(CMAKE_INSTALL_PREFIX /usr) -SET(PREFIX ${CMAKE_INSTALL_PREFIX}) - -SET(INC_DIR ${CMAKE_SOURCE_DIR}/include) -INCLUDE_DIRECTORIES(${INC_DIR}) - -SET(requires "sqlite3 glib-2.0 capi-appfw-app-common libtzplatform-config") - -INCLUDE(FindPkgConfig) -SET(EXTRA_CFLAGS "") -pkg_check_modules(${tool_name} REQUIRED ${requires}) -FOREACH(flag ${${tool_name}_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) - -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wall -Werror") -SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") - -SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") - -add_executable(${tool_name} - preference_tool.c - ) - -TARGET_LINK_LIBRARIES(${tool_name} ${fw_name} ${${tool_name}_LDFLAGS} -pie) -INSTALL(TARGETS ${tool_name} DESTINATION bin) -INSTALL(FILES pref_dump.sh DESTINATION /opt/etc/dump.d/module.d) - diff --git a/src/tool/preference_tool.c b/src/tool/preference_tool.c deleted file mode 100644 index 8dfed3b..0000000 --- a/src/tool/preference_tool.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved - * - * 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 -#include - -#define PREF_F_KEY_NAME "pref_key" -#define PREF_F_TYPE_NAME "pref_type" -#define PREF_F_DATA_NAME "pref_data" -#define PREF_TBL_NAME "pref" - -#define DELIMITER 29 -#define HISTORY "/opt/var/kdb/.restore/.history/preference" - -typedef enum { - PREFERENCE_OLD_TYPE_INT = 1, - PREFERENCE_OLD_TYPE_BOOLEAN, - PREFERENCE_OLD_TYPE_DOUBLE, - PREFERENCE_OLD_TYPE_STRING -} old_preference_type_e; - -typedef enum { - PREFERENCE_OP_RESTORE = 1, - PREFERENCE_OP_NEW_CREATE -} preference_op_type; - -static sqlite3 *pref_db; - -static void _finish(void *data) -{ - if (pref_db != NULL) { - sqlite3_close(pref_db); - pref_db = NULL; - } -} - -static int _busy_handler(void *pData, int count) -{ - if (count < 5) { - printf("Busy Handler Called!: PID(%d) / CNT(%d)\n", - getpid(), count + 1); - usleep((count + 1) * 100000); - return 1; - } - - return 0; -} - -static int _initialize(const char *db_path) -{ - int ret; - char *path = strdup(db_path); - - if (!path) { - printf("error, strdup(): Insufficient memory available\n"); - return -1; - } - - ret = sqlite3_open(path, &pref_db); - if (ret != SQLITE_OK) { - printf("error, fail to open db\n"); - pref_db = NULL; - free(path); - return -1; - } - - ret = sqlite3_busy_handler(pref_db, _busy_handler, NULL); - if (ret != SQLITE_OK) - printf("error, fail to resigter busy handler\n"); - app_finalizer_add(_finish, NULL); - free(path); - - return 0; -} - -static int __system(const char *cmd) -{ - int status; - pid_t cpid; - wordexp_t p; - char **w; - - cpid = fork(); - if (cpid < 0) { - perror("fork"); - return -1; - } - - if (cpid == 0) { - /* child */ - wordexp(cmd, &p, 0); - w = p.we_wordv; - - execv(w[0], (char * const *)w); - - wordfree(&p); - - _exit(-1); - } else { - /* parent */ - if (waitpid(cpid, &status, 0) == -1) { - perror("waitpid failed\n"); - return -1; - } - - if (WIFSIGNALED(status)) { - printf("signal(%d)\n", WTERMSIG(status)); - perror("exit by signal\n"); - return -1; - } - - if (!WIFEXITED(status)) { - perror("exit abnormally\n"); - return -1; - } - - if (WIFEXITED(status) && WEXITSTATUS(status)) { - perror("child return error\n"); - return -1; - } - } - - return 0; -} - -static const char *__get_package_path(const char *package_id) -{ - uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); - const char *path; - - tzplatform_set_user(uid); - path = tzplatform_mkpath(TZ_USER_APP, package_id); - tzplatform_reset_user(); - - return path; -} - -static int is_exist_package(const char *pkgid) -{ - const char *pkg_path; - - pkg_path = __get_package_path(pkgid); - if (pkg_path == NULL) { - printf("Failed to get package path(%s)\n", pkgid); - return -1; - } - - if (access(pkg_path, F_OK) == -1) { - printf("package(%s) is not exist.\n", pkgid); - return -1; - } - - return 0; -} - -static int is_exist_data_dir_in_package(const char *pkgid) -{ - char pkg_data_path[PATH_MAX]; - const char *pkg_path; - - pkg_path = __get_package_path(pkgid); - if (pkg_path == NULL) { - printf("Failed to get package path(%s)\n", pkgid); - return -1; - } - - snprintf(pkg_data_path, sizeof(pkg_data_path), "%s/data/", pkg_path); - if (access(pkg_data_path, F_OK) == -1) { - printf("Data directory is not exist in package(%s).\n", pkgid); - return -1; - } - - return 0; -} - -static gid_t __get_gid(const char *name) -{ - char buf[LINE_MAX]; - struct group entry; - struct group *ge; - int ret; - - ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge); - if (ret || ge == NULL) { - printf("Fail to get gid of %s\n", name); - return -1; - } - - return entry.gr_gid; -} - -static int _make_key_path(const char *pkgid, const char *keyname, char **path) -{ - const char *key; - gchar *convert_key; - char pref_dir[PATH_MAX]; - char *cmd; - int size; - mode_t dir_mode = 0664 | 0111; - const char *pkg_path; - uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); - gid_t gid = __get_gid("system_share"); - - pkg_path = __get_package_path(pkgid); - if (pkg_path == NULL) { - printf("Failed to get package path(%s)\n", pkgid); - return -1; - } - - snprintf(pref_dir, sizeof(pref_dir), "%s/data/.pref", pkg_path); - if (access(pref_dir, F_OK) == -1) { - if (mkdir(pref_dir, dir_mode) < 0) { - if (is_exist_package(pkgid) < 0) - return -1; - - if (is_exist_data_dir_in_package(pkgid) < 0) - return -1; - - printf("pref_dir making failed.(%d/%s)\n", - errno, strerror(errno)); - return -1; - } - if (chown(pref_dir, uid, gid) < 0) { - printf("chown() failed(%d/%s)\n", - errno, strerror(errno)); - return -1; - } - } - - size = 1 + snprintf(0, 0, "/usr/bin/chsmack -t -a User::Pkg::\"%s\" %s", - pkgid, pref_dir); - cmd = (char *)malloc(size); - if (cmd == NULL) { - printf("Out of memory\n"); - return -1; - } - - snprintf(cmd, size, - "/usr/bin/chsmack -t -a User::Pkg::\"%s\" %s", - pkgid, pref_dir); - if (__system(cmd)) { - printf("[pref] cmd error()\n"); - free(cmd); - return -1; - } - free(cmd); - - convert_key = g_compute_checksum_for_string(G_CHECKSUM_SHA1, - keyname, strlen(keyname)); - if (convert_key == NULL) { - LOGE("fail to convert"); - return PREFERENCE_ERROR_IO_ERROR; - } - - key = (const char *)convert_key; - - size = 1 + snprintf(0, 0, "%s/%s", pref_dir, key); - *path = (char *)malloc(size); - if (*path == NULL) { - printf("Out of memory\n"); - g_free(convert_key); - return -1; - } - - snprintf(*path, size, "%s/%s", pref_dir, key); - g_free(convert_key); - - return 0; -} - -static int _get_key_name(const char *keyfile, char **keyname) -{ - int read_size = 0; - size_t keyname_len = 0; - char *convert_key = NULL; - FILE *fp = NULL; - - fp = fopen(keyfile, "r"); - if (fp == NULL) - return PREFERENCE_ERROR_FILE_OPEN; - - read_size = fread((void *)&keyname_len, sizeof(int), 1, fp); - if (read_size <= 0 || keyname_len > PREFERENCE_KEY_PATH_LEN) { - fclose(fp); - return PREFERENCE_ERROR_FILE_FREAD; - } - - convert_key = (char *)calloc(1, keyname_len + 1); - if (convert_key == NULL) { - LOGE("memory alloc failed"); - fclose(fp); - return PREFERENCE_ERROR_OUT_OF_MEMORY; - } - - read_size = fread((void *)convert_key, keyname_len, 1, fp); - if (read_size <= 0) { - free(convert_key); - fclose(fp); - return PREFERENCE_ERROR_FILE_FREAD; - } - - *keyname = convert_key; - - fclose(fp); - - return PREFERENCE_ERROR_NONE; -} - -static int _create_key(const char *path, const char *pkgid) -{ - int fd; - char cmd[PATH_MAX]; - uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); - gid_t gid = __get_gid("system_share"); - - fd = open(path, O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (fd == -1) { - printf("[error] %d(%s)\n", errno, strerror(errno)); - return -1; - } - close(fd); - - if (chown(path, uid, gid) < 0) { - printf("chown() failed(%d/%s)\n", errno, strerror(errno)); - return -1; - } - - snprintf(cmd, sizeof(cmd), "/usr/bin/chsmack -a User::Pkg::\"%s\" %s", - pkgid, path); - if (__system(cmd)) { - printf("[pref] cmd error()\n"); - return -1; - } - - return 0; -} - -static int _create_new_preference_key(preference_op_type OP, const char *pkgid, - const char *key, const char *type, const char *value) -{ - FILE *fp; - int ret; - char *key_path; - size_t keyname_len; - int type_i; - int temp_i; - double temp_d; - locale_t loc; - - _make_key_path(pkgid, key, &key_path); -retry: - fp = fopen(key_path, "r+"); - if (fp == NULL) { - if (_create_key(key_path, pkgid) == -1) { - printf("preference key failed to create.(%d/%s)\n", - errno, strerror(errno)); - free(key_path); - return -1; - } - - goto retry; - } - - /* write keyname and size */ - keyname_len = strlen(key); - ret = fwrite((void *)&keyname_len, sizeof(int), 1, fp); - if (ret <= 0) { - printf("preference write key name length error(%d/%s)\n", - errno, strerror(errno)); - free(key_path); - fclose(fp); - return -1; - } - - ret = fwrite((void *)key, keyname_len, 1, fp); - if (ret <= 0) { - printf("preference write key name length error(%d/%s)\n", - errno, strerror(errno)); - free(key_path); - fclose(fp); - return -1; - } - - loc = newlocale(LC_NUMERIC_MASK, "C", NULL); - uselocale(loc); - - if (OP == PREFERENCE_OP_RESTORE) { - type_i = atoi(type); - switch (type_i) { - case PREFERENCE_OLD_TYPE_INT: - type_i = PREFERENCE_TYPE_INT; - break; - case PREFERENCE_OLD_TYPE_DOUBLE: - type_i = PREFERENCE_TYPE_DOUBLE; - break; - case PREFERENCE_OLD_TYPE_BOOLEAN: - type_i = PREFERENCE_TYPE_BOOLEAN; - break; - case PREFERENCE_OLD_TYPE_STRING: - type_i = PREFERENCE_TYPE_STRING; - break; - default: - break; - } - } else { /* OP is PREFERENCE_OP_NEW_CREATE.*/ - if (strcmp(type, "int") == 0) { - type_i = PREFERENCE_TYPE_INT; - } else if (strcmp(type, "double") == 0) { - type_i = PREFERENCE_TYPE_DOUBLE; - } else if (strcmp(type, "bool") == 0) { - type_i = PREFERENCE_TYPE_BOOLEAN; - } else if (strcmp(type, "string") == 0) { - type_i = PREFERENCE_TYPE_STRING; - } else { - printf("key type is invalid.int|double|bool|string\n"); - free(key_path); - fclose(fp); - return -1; - } - } - - ret = fwrite((void *)&type_i, sizeof(int), 1, fp); - if (ret <= 0) { - if (!errno) { - printf("number of written item is 0. try again\n"); - errno = EAGAIN; - } - } - - switch (type_i) { - case PREFERENCE_TYPE_INT: - temp_i = atoi(value); - ret = fwrite((void *)&temp_i, sizeof(int), 1, fp); - if (ret <= 0) { - printf("failed. fwrite() %d\n", ret); - } else { - printf("[SET][key]:%s [type]int[value]:%d\n", - key, temp_i); - } - break; - case PREFERENCE_TYPE_DOUBLE: - temp_d = atof(value); - ret = fwrite((void *)&temp_d, sizeof(double), 1, fp); - if (ret <= 0) { - printf("failed. fwrite() %d\n", ret); - } else { - printf("[SET][key]:%s[type]double[value]:%f\n", - key, temp_d); - } - break; - case PREFERENCE_TYPE_BOOLEAN: - temp_i = atoi(value); - ret = fwrite((void *)&temp_i, sizeof(int), 1, fp); - if (ret <= 0) { - printf("failed. fwrite() %d\n", ret); - } else { - printf("[SET][key]:%s [type]bool[value]:%d\n", - key, temp_i); - } - break; - case PREFERENCE_TYPE_STRING: - printf("[SET][key]:%s [type] string [value] %s\n", - key, value); - ret = fprintf(fp, "%s", value); - if (ftruncate(fileno(fp), ret) == -1) { - printf("[error] ftruncate failed %s(%s)\n", - key_path, value); - } - break; - default: - break; - } - - free(key_path); - - uselocale(LC_GLOBAL_LOCALE); - fflush(fp); - if (fp) { - ret = fdatasync(fileno(fp)); - fclose(fp); - } - - return 0; -} - -static int _print_pref_value_from_file_path(const char *path, - const char *keyname) -{ - FILE *fp; - int type = 0; - int read_size; - size_t keyname_len = 0; - int ret; - int value_int = 0; - double value_dbl = 0; - char file_buf[BUF_LEN] = {0,}; - char *value_str = NULL; - size_t value_size = 0; - size_t new_value_size = 0; - size_t diff; - size_t file_buf_size; - char *new_value_str; - - fp = fopen(path, "r"); - if (fp == NULL) { - printf("fopen() failed.(%d/%s).fp is null.\n", - errno, strerror(errno)); - return -1; - } - - read_size = fread((void *)&keyname_len, sizeof(int), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - printf("key(%s) name length read error(%d)\n", keyname, errno); - fclose(fp); - return -1; - } - - ret = fseek(fp, keyname_len, SEEK_CUR); - if (ret) { - printf("key(%s) name seek error(%d)\n", keyname, errno); - fclose(fp); - return -1; - } - - /* read data type */ - read_size = fread((void *)&type, sizeof(int), 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - printf("key(%s) type read error(%d)\n", keyname, errno); - fclose(fp); - return -1; - } - - /* read data value */ - switch (type) { - case PREFERENCE_TYPE_INT: - read_size = fread((void *)&value_int, sizeof(int), - 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - if (!ferror(fp)) { - printf("number of read items wrong.err: %d\n", - errno); - } - } else { - printf("[key] %s [type] int [value] %d\n", - keyname, value_int); - } - break; - case PREFERENCE_TYPE_DOUBLE: - read_size = fread((void *)&value_dbl, sizeof(double), - 1, fp); - if ((read_size <= 0) || (read_size > sizeof(double))) { - if (!ferror(fp)) { - printf("number of read items wrong.err:%d\n", - errno); - } - } else { - printf("[key] %s [type] double [value] %f\n", - keyname, value_dbl); - } - break; - case PREFERENCE_TYPE_BOOLEAN: - read_size = fread((void *)&value_int, sizeof(int), - 1, fp); - if ((read_size <= 0) || (read_size > sizeof(int))) { - if (!ferror(fp)) { - printf("number of read items wrong.err:%d\n", - errno); - } - } else { - printf("[key] %s [type] bool [value] %d\n", - keyname, value_int); - } - break; - case PREFERENCE_TYPE_STRING: - while (fgets(file_buf, sizeof(file_buf), fp)) { - if (value_str) { - file_buf_size = sizeof(file_buf); - diff = INT_MAX - file_buf_size; - if (value_size > diff) { - printf("Integer overflow\n"); - break; - } - - new_value_size = value_size + file_buf_size; - new_value_str = (char *)realloc(value_str, - new_value_size); - if (new_value_str == NULL) - break; - - memset(new_value_str + value_size, 0x00, sizeof(file_buf)); - strncat(new_value_str, file_buf, new_value_size - strlen(new_value_str)); - - value_str = new_value_str; - value_size = new_value_size; - memset(file_buf, 0x00, sizeof(file_buf)); - } else { - value_size = sizeof(file_buf) + 1; - value_str = (char *)malloc(value_size); - if (value_str == NULL) - break; - - memset(value_str, 0x00, value_size); - strncpy(value_str, file_buf, value_size - 1); - } - } - - if (ferror(fp)) { - printf("error, fgets() failed.\n"); - } else { - if (value_str) { - printf("[key] %s [type] string [value] %s\n", - keyname, value_str); - } else { - printf("[key] %s [value] NULL\n", keyname); - } - } - if (value_str) - free(value_str); - break; - default: - break; - } - fclose(fp); - - return 0; -} - -static int _restore(const char *pkgid) -{ - int ret; - char *query; - sqlite3_stmt *stmt = NULL; - const char *tmp_key; - const char *tmp_type; - const char *tmp_value; - - query = sqlite3_mprintf("SELECT * FROM %s;", PREF_TBL_NAME); - if (query == NULL) { - printf("error, query is null\n"); - return -1; - } - - /*prepare query*/ - ret = sqlite3_prepare_v2(pref_db, query, strlen(query), &stmt, NULL); - sqlite3_free(query); - if (ret != SQLITE_OK) { - printf("error, sqlite3_prepare_v2 failed(%d)\n", ret); - return -1; - } - - while (1) { - ret = sqlite3_step(stmt); - if (ret == SQLITE_ROW) { - tmp_key = (const char *)sqlite3_column_text(stmt, 0); - tmp_type = (const char *)sqlite3_column_text(stmt, 1); - tmp_value = (const char *)sqlite3_column_text(stmt, 2); - - printf("col[key]:%s\ncol[type]:%s\ncol[value]:%s\n", - tmp_key, tmp_type, tmp_value); - - /*key create*/ - ret = _create_new_preference_key(PREFERENCE_OP_RESTORE, - pkgid, tmp_key, tmp_type, tmp_value); - if (ret < 0) { - printf("create new prefer key failed (%d)\n", - ret); - sqlite3_finalize(stmt); - return -1; - } - } else { - break; - } - } - sqlite3_finalize(stmt); - - return 0; -} - - -static int _remove_old_db(const char *db_path) -{ - int ret; - char journal_path[PATH_MAX]; - char *path = strdup(db_path); - - if (!path) { - printf("error, strdup(): Insufficient memory available\n"); - return -1; - } - - ret = remove(path); - if (ret < 0) { - printf("error, remove(%d/%s)\n", errno, strerror(errno)); - free(path); - return -1; - } - - snprintf(journal_path, sizeof(journal_path), "%s-journal", path); - - if (access(journal_path, F_OK) == 0) { - ret = remove(journal_path); - if (ret < 0) { - printf("error, remove(%d/%s)\n", errno, - strerror(errno)); - free(path); - return -1; - } - } - free(path); - - return 0; -} - -static void _print_help(void) -{ - printf("\n[Set preference value]\n"); - printf("preference_tool set \n"); - printf("ex) preference_tool set "); - printf("org.tizen.preferencetest test_key string value\n\n"); - - printf("[Get preference value]\n"); - printf("preference_tool get \n"); - printf("ex) preference_tool get org.tizen.preferencetest\n\n"); - printf("preference_tool get \n"); - printf("ex) preference_tool get "); - printf("org.tizen.preferencetest test_key\n\n"); - - printf("[Convert preference file name from plain text]\n"); - printf("preference_tool convert_file_name \n"); - printf("ex) preference_tool convert_file_name /opt/usr/apps\n\n"); -} - -static void _preference_set_key(const char *pkgid, const char *key, - const char *type, const char *value) -{ - _create_new_preference_key(PREFERENCE_OP_NEW_CREATE, - pkgid, key, type, value); -} - -static void _print_preference_key(const char *pkgid, const char *key) -{ - char *key_path; - - _make_key_path(pkgid, key, &key_path); - _print_pref_value_from_file_path(key_path, key); - - free(key_path); -} - -static void _print_preference_in_package(const char *pkgid) -{ - char pref_dir[PATH_MAX]; - DIR *dir; - int dfd, res, size; - struct stat st; - struct dirent *ent = NULL; - const char *name; - char *keyname = NULL; - char *file_full_path; - const char *pkg_path; - - pkg_path = __get_package_path(pkgid); - if (pkg_path == NULL) - return; - - snprintf(pref_dir, sizeof(pref_dir), "%s/data/.pref", pkg_path); - - dir = opendir(pref_dir); - if (dir == NULL) { - printf("Is not exist preference key in %s.\n", pkgid); - return; - } - - dfd = dirfd(dir); - res = fstat(dfd, &st); - if (res < 0) { - printf("fstat() failed. path: %s, errno: %d(%s)\n", - pref_dir, errno, strerror(errno)); - closedir(dir); - return; - } - - while ((ent = readdir(dir))) { - name = ent->d_name; - if (name[0] == '.') { - if (name[1] == '\0') - continue; - if ((name[1] == '.') && (name[2] == '\0')) - continue; - } - - size = 1 + snprintf(0, 0, "%s/%s", pref_dir, name); - file_full_path = (char *)malloc(size); - if (file_full_path == NULL) { - printf("Out of memory\n"); - closedir(dir); - return; - } - - snprintf(file_full_path, size, "%s/%s", pref_dir, name); - _get_key_name(file_full_path, &keyname); - _print_pref_value_from_file_path(file_full_path, keyname); - free(file_full_path); - if (keyname) { - free(keyname); - keyname = NULL; - } - } - closedir(dir); -} - -static void write_history(const char *str) -{ - FILE *fp = NULL; - int ret = 0; - - fp = fopen(HISTORY, "a"); - if (fp == NULL) { - printf("fopen() failed. FOTA history log (%d/%s)", - errno, strerror(errno)); - return; - } - - ret = fwrite((void *)str, strlen(str) + 1, 1, fp); - if (ret <= 0) { - printf("fwrite() failed. FOTA history log (%d/%s)", - errno, strerror(errno)); - } - fclose(fp); -} - -static int _add_key_info_to_file(const char *key_path, const char *key) -{ - FILE *fp = NULL; - size_t keyname_len; - char *buf = NULL; - int read_size; - int ret; - long file_size; - - fp = fopen(key_path, "r+"); - if (fp == NULL) { - printf("fopen() failed.(%d/%s).fp is null.\n", - errno, strerror(errno)); - return -1; - } - - ret = fseek(fp, 0, SEEK_END); - if (ret == -1) { - printf("failed to fseek.(%d/%s)\n", errno, strerror(errno)); - ret = -1; - goto out; - } - - file_size = ftell(fp); - if (file_size == -1) { - printf("failed to ftell.(%d/%s)\n", errno, strerror(errno)); - ret = -1; - goto out; - } - - rewind(fp); - - buf = (char *)calloc(1, file_size); - if (buf == NULL) { - printf("Out of memory\n"); - ret = -1; - goto out; - } - - /* write keyname and size */ - read_size = fread(buf, 1, file_size, fp); - if ((read_size <= 0)) { - printf("preference read key-val data error(%d/%s)\n", - errno, strerror(errno)); - ret = -1; - goto out; - } - - rewind(fp); - - keyname_len = strlen(key); - ret = fwrite((void *)&keyname_len, sizeof(int), 1, fp); - if (ret <= 0) { - printf("preference write key name length error(%d/%s)\n", - errno, strerror(errno)); - ret = -1; - goto out; - } - - ret = fwrite((void *)key, keyname_len, 1, fp); - if (ret <= 0) { - printf("preference write key name error(%d/%s)\n", - errno, strerror(errno)); - ret = -1; - goto out; - } - ret = fwrite((void *)buf, read_size, 1, fp); - if (ret <= 0) { - printf("preference write key-val data error(%d/%s)\n", - errno, strerror(errno)); - ret = -1; - goto out; - } - - ret = 0; - -out: - if (fp) - fclose(fp); - if (buf) - free(buf); - - return ret; -} - -static int _convert_pref_file(const char *pref_dir) -{ - DIR *dir; - struct dirent *ent; - char *old_file; - char *new_file; - gchar *convert_key; - char _key[PREFERENCE_KEY_PATH_LEN] = {0,}; - char *chrptr = NULL; - int size; - - dir = opendir(pref_dir); - if (!dir) - return -1; - - while ((ent = readdir(dir))) { - if (ent->d_type != DT_REG) - continue; - - size = 1 + snprintf(0, 0, "%s/%s", pref_dir, ent->d_name); - old_file = (char *)malloc(size); - if (old_file == NULL) { - printf("Out of memory\n"); - closedir(dir); - return -1; - } - - snprintf(old_file, size, "%s/%s", pref_dir, ent->d_name); - - strncpy(_key, ent->d_name, PREFERENCE_KEY_PATH_LEN - 1); - - chrptr = strchr((const char*)_key, DELIMITER); - if (chrptr) { - chrptr = strchr((const char*)_key, DELIMITER); - while (chrptr) { - _key[chrptr-_key] = '/'; - chrptr = strchr((const char*)chrptr + 1, DELIMITER); - } - } - - convert_key = g_compute_checksum_for_string(G_CHECKSUM_SHA1, - _key, strlen(_key)); - if (convert_key == NULL) { - printf("fail to convert key\n"); - free(old_file); - closedir(dir); - return -1; - } - - - size = 1 + snprintf(0, 0, "%s/%s", pref_dir, convert_key); - new_file = (char *)malloc(size); - if (new_file == NULL) { - printf("Out of memory\n"); - free(old_file); - g_free(convert_key); - closedir(dir); - return -1; - } - - snprintf(new_file, size, "%s/%s", pref_dir, convert_key); - - g_free(convert_key); - - if (rename(old_file, new_file) < 0) { - printf("rename %s to %s failed.(%d/%s)\n", - old_file, new_file, - errno, strerror(errno)); - } - - if (_add_key_info_to_file(new_file, _key) < 0) - printf("convert %s file failed\n", new_file); - - free(old_file); - free(new_file); - } - - closedir(dir); - return 0; -} - -static int _convert_file_name(const char *app_dir) -{ - DIR *dir; - struct dirent *ent; - char buf[BUF_LEN]; - int res; - - dir = opendir(app_dir); - if (!dir) { - printf("failed to open app dir (%s)\n", app_dir); - return -1; - } - - while ((ent = readdir(dir))) { - if (ent->d_type != DT_DIR) - continue; - - if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) - continue; - - snprintf(buf, sizeof(buf), "%s/%s/data/.pref", - app_dir, ent->d_name); - if (access(buf, F_OK) == -1) - continue; - - res = _convert_pref_file(buf); - if (res < 0) { - printf("_convert_pref_file error (%s)\n", buf); - closedir(dir); - return -1; - } - } - - closedir(dir); - return 0; -} - -int main(int argc, char *argv[]) -{ - int res; - - if (getuid() != 0) { - printf("[pref] Only root user can use.\n"); - return -1; - } - - if (argc < 3) { - _print_help(); - return -1; - } - - if (strcmp(argv[1], "restore") == 0 && argc == 4) { - printf("[ start ] ----------------------------------------\n"); - printf("Db file path:%s\n\n", argv[2]); - - res = _initialize(argv[2]); - if (res < 0) { - printf("failed. _initialize(%d)\n", res); - return -1; - } - - res = _restore(argv[3]); - if (res < 0) { - printf("failed. _restore(%d)\n", res); - write_history("\t\t- restore failed.\n"); - printf("restore failed.\n"); - return -1; - } - - res = _remove_old_db(argv[2]); - if (res < 0) { - printf("failed. _remove_old_db(%d)\n", res); - return -1; - } - - printf("-------------------------------------------------\n"); - printf("done\n\n"); - write_history("\t\t+ restore success.\n"); - } else if (strcmp(argv[1], "get") == 0 || strcmp(argv[1], "GET") == 0) { - if (is_exist_package(argv[2]) < 0) - return -1; - - if (is_exist_data_dir_in_package(argv[2]) < 0) - return -1; - - if (argc > 3 && argv[3]) - _print_preference_key(argv[2], argv[3]); - else - _print_preference_in_package(argv[2]); - } else if (strcmp(argv[1], "set") == 0 || strcmp(argv[1], "SET") == 0) { - if (is_exist_package(argv[2]) < 0) - return -1; - - if (is_exist_data_dir_in_package(argv[2]) < 0) - return -1; - - if (argv[2] && argv[3] && argv[4] && argv[5]) - _preference_set_key(argv[2], argv[3], argv[4], argv[5]); - else - _print_help(); - } else if (strcmp(argv[1], "convert_file_name") == 0) { - res = _convert_file_name(argv[2]); - - if (res < 0) { - printf("converting preference file name failed (%s)\n", - argv[2]); - return -1; - } - } else { - _print_help(); - } - - return 0; -} diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt new file mode 100644 index 0000000..a12f918 --- /dev/null +++ b/tool/CMakeLists.txt @@ -0,0 +1,25 @@ +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TOOL_SRCS) + +ADD_EXECUTABLE(${TARGET_TOOL} ${TOOL_SRCS}) + +TARGET_INCLUDE_DIRECTORIES(${TARGET_TOOL} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../) + +APPLY_PKG_CONFIG(${TARGET_TOOL} PUBLIC + CAPI_BASE_COMMON_DEPS + DLOG_DEPS + LIBTZPLATFORM_CONFIG_DEPS + PKGMGR_INFO_DEPS + SQLITE3_DEPS +) + +TARGET_LINK_LIBRARIES(${TARGET_TOOL} PUBLIC ${TARGET_PREFERENCE}) +SET_TARGET_PROPERTIES(${TARGET_TOOL} PROPERTIES COMPILE_FLAGS + ${CFLAGS} "-fPIE") +SET_TARGET_PROPERTIES(${TARGET_TOOL} PROPERTIES LINK_FLAGS + "-Wl,--rpath=${LIBDIR} -pie") + +INSTALL(TARGETS ${TARGET_TOOL} + DESTINATION ${BINDIR}) +INSTALL(FILES pref_dump.sh + DESTINATION /opt/etc/dump.d/module.d) diff --git a/tool/log-private.hh b/tool/log-private.hh new file mode 100644 index 0000000..d309fdd --- /dev/null +++ b/tool/log-private.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 TOOL_LOG_PRIVATE_HH_ +#define TOOL_LOG_PRIVATE_HH_ + +#include + +#undef LOG_TAG +#define LOG_TAG "PREFERENCE_TOOL" + +#undef _E +#define _E LOGE + +#undef _W +#define _W LOGW + +#undef _I +#define _I LOGI + +#undef _D +#define _D LOGD + +#endif // TOOL_LOG_PRIVATE_HH_ diff --git a/src/tool/pref_dump.sh b/tool/pref_dump.sh similarity index 87% rename from src/tool/pref_dump.sh rename to tool/pref_dump.sh index 2b65cb8..ddf80ef 100644 --- a/src/tool/pref_dump.sh +++ b/tool/pref_dump.sh @@ -4,7 +4,7 @@ PATH="/usr/bin:/bin:/usr/sbin:/sbin" PREF_DUMP=$1/pref /bin/mkdir -p $PREF_DUMP -for file in `/usr/bin/find /opt/usr/apps/ -name *.pref` +for file in `/usr/bin/find /opt/usr/home/owner/apps_rw/ -name *.pref` do chsmack $file >> $PREF_DUMP/pref_value chsmack $file/* >> $PREF_DUMP/pref_value diff --git a/tool/preference_tool.cc b/tool/preference_tool.cc new file mode 100644 index 0000000..ceaa6da --- /dev/null +++ b/tool/preference_tool.cc @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2011 - 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "preference/file-internal.hh" +#include "tool/log-private.hh" + +namespace { +using namespace preference::internal; + +class PrefTool { + private: + PrefTool() = default; + ~PrefTool() = default; + + public: + static PrefTool& GetInst(); + void PrintHelp(); + void Set(const std::string& pkg_id, const std::string& key, + const std::string& type, const std::string& value); + void Get(const std::string& pkg_id); + void Get(const std::string& pkg_id, const std::string& key); + void GetAll(); + + private: + std::string GetPrefPath(const std::string& pkg_id); + int CreateDirectory(const std::string& path); + int ChangeOwner(const std::string& path); + int ChangeMode(const std::string& path, mode_t mode); + int ChangeSmack(const std::string& pkg_id, const std::string& path, + bool transmute = true); + gid_t GetGid(const std::string& name); + Data::Type ConvertType(const std::string& type); + std::string GetTypeName(Data::Type type); + void PrintData(const Data& data); +}; + +PrefTool& PrefTool::GetInst() { + static PrefTool inst; + return inst; +} + +void PrefTool::PrintHelp() { + std::cout << "[Set preference value]" + << std::endl; + std::cout << "$ preference_tool set " + << std::endl; + std::cout << "ex) preference_tool set org.tizen.helloworld key string value" + << std::endl; + std::cout << std::endl; + + std::cout << "[Get preference value]" + << std::endl; + std::cout << "$ preference_tool get " + << std::endl; + std::cout << "ex) preference_tool get org.tizen.helloworld" + << std::endl; + std::cout << std::endl; + + std::cout << "$ preference_tool get " + << std::endl; + std::cout << "ex) preference_tool get org.tizen.helloworld key" + << std::endl; + std::cout << std::endl; + + std::cout << "[Get all preference values]" + << std::endl; + std::cout << "$ preference_tool get_all" + << std::endl; + std::cout << "ex) preference_tool get_all" + << std::endl; + std::cout << std::endl; +} + +void PrefTool::Set(const std::string& pkg_id, const std::string& key, + const std::string& type, const std::string& value) { + std::string pref_path = GetPrefPath(pkg_id); + if (access(pref_path.c_str(), F_OK) < 0) { + if (CreateDirectory(pref_path) < 0) + return; + + if (ChangeOwner(pref_path) < 0) + return; + + if (ChangeSmack(pkg_id, pref_path) < 0) + return; + } + + Data::Type data_type = ConvertType(type); + if (data_type == Data::Type::NONE) { + fprintf(stderr, "Invalid type. type(%d)\n", static_cast(data_type)); + return; + } + + Data data(key); + if (data_type == Data::Type::STRING) { + data.SetString(value.c_str()); + } else if (data_type == Data::Type::INT) { + data.SetInt(std::stoi(value)); + } else if (data_type == Data::Type::DOUBLE) { + data.SetDouble(std::stod(value)); + } else { + if (value == "ture" || value == "1") + data.SetBoolean(true); + else + data.SetBoolean(false); + } + + File file(key, pref_path); + file.SetData(data); + int ret = file.Write(); + if (ret != 0) { + fprintf(stderr, "Write() is failed. key(%s), type(%s), value(%s), " + "error(%d)\n", key.c_str(), type.c_str(), value.c_str(), ret); + return; + } + file.Close(); + + ChangeOwner(file.GetPath()); + ChangeMode(file.GetPath(), 0660); + ChangeSmack(pkg_id, file.GetPath(), false); + Get(pkg_id, key); +} + +void PrefTool::Get(const std::string& pkg_id, const std::string& key) { + std::string pref_path = GetPrefPath(pkg_id); + File file(key, pref_path); + int ret = file.Read(); + if (ret != 0) { + fprintf(stderr, "Read() is failed. pkg_id(%s), key(%s), error(%d)\n", + pkg_id.c_str(), key.c_str(), ret); + return; + } + + Data data = file.GetData(); + PrintData(data); +} + +void PrefTool::Get(const std::string& pkg_id) { + std::string pref_path = GetPrefPath(pkg_id); + if (access(pref_path.c_str(), F_OK) != 0) { + return; + } + + DIR* dp = opendir(pref_path.c_str()); + if (dp == nullptr) { + fprintf(stderr, "opendir(%s) is failed. errno(%d)\n", + pref_path.c_str(), errno); + return; + } + + printf("[%s]\n", pkg_id.c_str()); + struct dirent* dentry; + while ((dentry = readdir(dp)) != nullptr) { + const char* name = dentry->d_name; + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + + File file(name, pref_path, true); + int ret = file.Read(); + if (ret != 0) { + fprintf(stderr, "Read() is failed. pkg_id(%s), key(%s), error(%d)\n", + pkg_id.c_str(), name, ret); + break; + } + + Data data = file.GetData(); + PrintData(data); + } + printf("=================================================================\n"); + closedir(dp); +} + +void PrefTool::GetAll() { + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + tzplatform_set_user(uid); + const char* path = tzplatform_getenv(TZ_USER_APP); + tzplatform_reset_user(); + DIR* dp = opendir(path); + if (dp == nullptr) { + fprintf(stderr, "opendir(%s) is failed. errno(%d)\n", path, errno); + return; + } + + struct dirent* dentry; + while ((dentry = readdir(dp)) != nullptr) { + const char* name = dentry->d_name; + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + + Get(name); + } + closedir(dp); +} + +std::string PrefTool::GetPrefPath(const std::string& pkg_id) { + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + tzplatform_set_user(uid); + const char* path = tzplatform_mkpath(TZ_USER_APP, pkg_id.c_str()); + tzplatform_reset_user(); + if (path == nullptr) { + std::cerr << "tzplatform_mkpath() is failed" << std::endl; + return {}; + } + + return std::string(path) + "/data/.pref"; +} + +int PrefTool::CreateDirectory(const std::string& path) { + mode_t mode = 0664 | 0111; + int ret = mkdir(path.c_str(), mode); + if (ret != 0) { + fprintf(stderr, "mkdir(%s, %d) is failed. errno(%d)\n", + path.c_str(), mode, errno); + return -1; + } + + return 0; +} + +int PrefTool::ChangeOwner(const std::string& path) { + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + gid_t gid = GetGid("system_share"); + int ret = chown(path.c_str(), uid, gid); + if (ret != 0) { + fprintf(stderr, "chown(%s, %u, %u) is failed. errno(%d)\n", + path.c_str(), uid, gid, errno); + return -1; + } + + return 0; +} + +int PrefTool::ChangeMode(const std::string& path, mode_t mode) { + int ret = chmod(path.c_str(), mode); + if (ret != 0) { + fprintf(stderr, "chmod(%s, %d) is failed. errno(%d)\n", + path.c_str(), mode, errno); + return -1; + } + + return 0; +} + +int PrefTool::ChangeSmack(const std::string& pkg_id, const std::string& path, + bool transmute) { + std::string option = transmute ? "-t" : " "; + std::string command = "/usr/bin/chsmack " + option + " -a User::Pkg::" + + pkg_id + " " + path; + pid_t pid = fork(); + if (pid == -1) { + perror("fork() is failed\n"); + return -1; + } + + if (pid == 0) { + wordexp_t p; + wordexp(command.c_str(), &p, 0); + char** w = p.we_wordv; + int ret = execv(w[0], const_cast(w)); + wordfree(&p); + exit(ret); + } else { + int status; + if (waitpid(pid, &status, 0) == -1) { + perror("waitpid() is failed\n"); + return -1; + } + + if (WIFSIGNALED(status)) { + fprintf(stderr, "signal(%d)\n", WTERMSIG(status)); + perror("exit by signal\n"); + return -1; + } + + if (!WIFEXITED(status)) { + perror("exit abnormally\n"); + return -1; + } + + if (WIFEXITED(status) && WEXITSTATUS(status)) { + perror("child process returns an error\n"); + return -1; + } + } + + return 0; +} + +gid_t PrefTool::GetGid(const std::string& name) { + struct group entry; + struct group* ge = nullptr; + char buf[LINE_MAX]; + int ret = getgrnam_r(name.c_str(), &entry, buf, sizeof(buf), &ge); + if (ret != 0) { + fprintf(stderr, "getgrnam_r() is failed. errno(%d)\n", errno); + return -1; + } + + return entry.gr_gid; +} + +Data::Type PrefTool::ConvertType(const std::string& type) { + if (type == "string") + return Data::Type::STRING; + + if (type == "int") + return Data::Type::INT; + + if (type == "double") + return Data::Type::DOUBLE; + + if (type == "boolean" || type == "bool") + return Data::Type::BOOLEAN; + + return Data::Type::NONE; +} + +std::string PrefTool::GetTypeName(Data::Type type) { + if (type == Data::Type::STRING) + return "string"; + if (type == Data::Type::INT) + return "integer"; + if (type == Data::Type::DOUBLE) + return "double"; + if (type == Data::Type::BOOLEAN) + return "boolean"; + + return "none"; +} + +void PrefTool::PrintData(const Data& data) { + auto type = data.GetType(); + printf("[key] %s [type] %s [value] ", + data.GetKey().c_str(), GetTypeName(type).c_str()); + if (type == Data::Type::STRING) + printf("%s\n", data.GetString()); + else if (type == Data::Type::INT) + printf("%d\n", data.GetInt()); + else if (type == Data::Type::DOUBLE) + printf("%f\n", data.GetDouble()); + else + printf("%s\n", data.GetBoolean() ? "true" : "false"); +} + +} // namespace + +int main(int argc, char** argv) { + if (getuid() != 0) { + std::cerr << "[pref] Only root user can use." << std::endl; + return -1; + } + + if (argc < 2) { + ::PrefTool::GetInst().PrintHelp(); + return -1; + } + + int ret = 0; + if (!strcasecmp(argv[1], "set")) { + if (argc > 5) + ::PrefTool::GetInst().Set(argv[2], argv[3], argv[4], argv[5]); + else + ret = -1; + } else if (!strcasecmp(argv[1], "get")) { + if (argc > 3) + ::PrefTool::GetInst().Get(argv[2], argv[3]); + else if (argc > 2) + ::PrefTool::GetInst().Get(argv[2]); + else + ret = -1; + } else if (!strcasecmp(argv[1], "get_all")) { + ::PrefTool::GetInst().GetAll(); + } else { + ret = -1; + } + + if (ret == -1) + ::PrefTool::GetInst().PrintHelp(); + + return 0; +} diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 93444f8..2682162 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,20 +1,28 @@ AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TEST_SRCS) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/mock MOCK_SRCS) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include/) -ENABLE_TESTING() +INCLUDE_DIRECTORIES(${TARGET_UNIT_TESTS} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../include/ + ${CMAKE_CURRENT_SOURCE_DIR}/../preference/ +) -SET(TARGET_TEST "preference-test") -ADD_EXECUTABLE(${TARGET_TEST} ${TEST_SRCS} ${MOCK_SRCS}) -ADD_TEST(${TARGET_TEST} ${TARGET_TEST}) +ADD_EXECUTABLE(${TARGET_UNIT_TESTS} + ${MOCK_SRCS} + ${TEST_SRCS} +) -INCLUDE(FindPkgConfig) -pkg_check_modules(test REQUIRED dlog glib-2.0 capi-appfw-app-common) -FOREACH(flag ${test_CFLAGS}) - SET(EXTRA_CXXFLAGS_test "${EXTRA_CXXFLAGS_test} ${flag}") -ENDFOREACH(flag) +ADD_TEST(${TARGET_UNIT_TESTS} ${TARGET_UNIT_TESTS}) -SET(${EXTRA_CXXFLAGS_test} "${EXTRA_CXXFLAGS_test} --std=c++14") -SET_TARGET_PROPERTIES(${TARGET_TEST} PROPERTIES COMPILE_FLAGS ${EXTRA_CXXFLAGS_test}) +APPLY_PKG_CONFIG(${TARGET_UNIT_TESTS} PUBLIC + CAPI_APPFW_APP_COMMON_DEPS + DLOG_DEPS + GLIB_DEPS + GMOCK_DEPS +) -TARGET_LINK_LIBRARIES(${TARGET_TEST} gmock capi-appfw-preference pthread) \ No newline at end of file +TARGET_LINK_LIBRARIES(${TARGET_UNIT_TESTS} PUBLIC ${TARGET_PREFERENCE} pthread) +SET_TARGET_PROPERTIES(${TARGET_UNIT_TESTS} PROPERTIES COMPILE_FLAGS "-fPIE") +SET_TARGET_PROPERTIES(${TARGET_UNIT_TESTS} PROPERTIES LINK_FLAGS "-pie") + +INSTALL(TARGETS ${TARGET_UNIT_TESTS} DESTINATION bin) diff --git a/unittests/main.cc b/unittests/main.cc new file mode 100644 index 0000000..bcb21a6 --- /dev/null +++ b/unittests/main.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * 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 + +int main(int argc, char* argv[]) { + int ret = 0; + try { + ::testing::InitGoogleTest(&argc, argv); + } catch(...) { + std::cout << "Exception occured" << std::endl; + return 1; + } + + try { + return RUN_ALL_TESTS(); + } catch(const ::testing::internal::GoogleTestFailureException& e) { + std::cout << "GoogleTestFailureException occured:" << e.what() << std::endl; + ret = 1; + } + + return ret; +} diff --git a/unittests/mock/common_mock.cc b/unittests/mock/common_mock.cc index 7f4a2c5..df44be4 100644 --- a/unittests/mock/common_mock.cc +++ b/unittests/mock/common_mock.cc @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "common_mock.h" -#include "mock_hook.h" -#include "test_fixture.h" +#include "unittests/mock/common_mock.h" +#include "unittests/mock/mock_hook.h" +#include "unittests/mock/test_fixture.h" extern "C" char* app_get_data_path() { return MOCK_HOOK_P0(CommonMock, app_get_data_path); diff --git a/unittests/mock/common_mock.h b/unittests/mock/common_mock.h index 408a7da..2fe155f 100644 --- a/unittests/mock/common_mock.h +++ b/unittests/mock/common_mock.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef MOCK_COMMON_MOCK_H_ -#define MOCK_COMMON_MOCK_H_ +#ifndef UNITTESTS_MOCK_COMMON_MOCK_H_ +#define UNITTESTS_MOCK_COMMON_MOCK_H_ + #include -#include "module_mock.h" +#include "unittests/mock/module_mock.h" class CommonMock : public virtual ModuleMock { public: @@ -27,4 +28,4 @@ class CommonMock : public virtual ModuleMock { MOCK_METHOD0(app_get_data_path, char*()); }; -#endif // MOCK_COMMON_HOOK_H_ +#endif // UNITTESTS_MOCK_COMMON_MOCK_H_ diff --git a/unittests/mock/mock_hook.h b/unittests/mock/mock_hook.h index 79831d7..035a29a 100644 --- a/unittests/mock/mock_hook.h +++ b/unittests/mock/mock_hook.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef MOCK_MOCK_HOOK_H_ -#define MOCK_MOCK_HOOK_H_ +#ifndef UNITTESTS_MOCK_MOCK_HOOK_H_ +#define UNITTESTS_MOCK_MOCK_HOOK_H_ #define MOCK_HOOK_P0(MOCK_CLASS, f) \ TestFixture::GetMock().f() @@ -39,4 +39,4 @@ TestFixture::GetMock().f( \ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) -#endif // MOCK_MOCK_HOOK_H_ +#endif // UNITTESTS_MOCK_MOCK_HOOK_H_ diff --git a/unittests/mock/module_mock.h b/unittests/mock/module_mock.h index 0934014..fce1cac 100644 --- a/unittests/mock/module_mock.h +++ b/unittests/mock/module_mock.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef MOCK_MODULE_MOCK_H_ -#define MOCK_MODULE_MOCK_H_ +#ifndef UNITTESTS_MOCK_MODULE_MOCK_H_ +#define UNITTESTS_MOCK_MODULE_MOCK_H_ class ModuleMock { public: virtual ~ModuleMock() {} }; -#endif // MOCK_MODULE_MOCK_H_ +#endif // UNITTESTS_MOCK_MODULE_MOCK_H_ diff --git a/unittests/mock/test_fixture.cc b/unittests/mock/test_fixture.cc index 4a77054..d156759 100644 --- a/unittests/mock/test_fixture.cc +++ b/unittests/mock/test_fixture.cc @@ -16,6 +16,6 @@ #include -#include "test_fixture.h" +#include "unittests/mock/test_fixture.h" std::unique_ptr TestFixture::mock_; diff --git a/unittests/mock/test_fixture.h b/unittests/mock/test_fixture.h index db223f1..2fe4f5f 100644 --- a/unittests/mock/test_fixture.h +++ b/unittests/mock/test_fixture.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef MOCK_TEST_FIXTURE_H_ -#define MOCK_TEST_FIXTURE_H_ +#ifndef UNITTESTS_MOCK_TEST_FIXTURE_H_ +#define UNITTESTS_MOCK_TEST_FIXTURE_H_ #include @@ -24,7 +24,7 @@ #include #include -#include "module_mock.h" +#include "unittests/mock/module_mock.h" class TestFixture : public ::testing::Test { public: @@ -50,4 +50,4 @@ class TestFixture : public ::testing::Test { static std::unique_ptr mock_; }; -#endif // MOCK_TEST_FIXTURE_H_ +#endif // UNITTESTS_MOCK_TEST_FIXTURE_H_ diff --git a/unittests/preference_test.cc b/unittests/preference_test.cc index e4993f0..0b9b7a1 100644 --- a/unittests/preference_test.cc +++ b/unittests/preference_test.cc @@ -14,26 +14,25 @@ * limitations under the License. */ -#include - -#include - #include #include #include #include +#include + +#include -#include "mock/common_mock.h" -#include "mock/test_fixture.h" +#include "unittests/mock/common_mock.h" +#include "unittests/mock/test_fixture.h" -extern "C" int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...) { +extern "C" int __dlog_print(log_id_t log_id, int prio, const char* tag, + const char* fmt, ...) { printf("%s:", tag); va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); - return 0; } @@ -80,21 +79,21 @@ TEST_F(PreferenceTest, Basic) { })); ret = preference_set_int("testint", 0); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_get_int("testint", &intval); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_set_double("testdouble", 0.0f); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_get_double("testdouble", &doubleval); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_set_string("teststring", "test"); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_get_string("teststring", &strval); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_set_boolean("testboolean", false); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_get_boolean("testboolean", &boolval); - EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR)); + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); EXPECT_CALL(GetMock(), app_get_data_path()) .WillRepeatedly(testing::Invoke([&]() { @@ -242,15 +241,17 @@ TEST_F(PreferenceTest, Callback) { ret = preference_set_int("test1", 0); EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); bool called = false; - ret = preference_set_changed_cb("test1", [](const char* key, void* user_data) { - bool* called = reinterpret_cast(user_data); - *called = true; - }, reinterpret_cast(&called)); + ret = preference_set_changed_cb("test1", + [](const char* key, void* user_data) { + bool* called = reinterpret_cast(user_data); + *called = true; + }, reinterpret_cast(&called)); EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); EXPECT_THAT(called, testing::Eq(false)); ret = preference_set_int("test1", 1); - while (g_main_context_iteration(g_main_context_default(), true)); + while (g_main_context_iteration(g_main_context_default(), true)) { + } EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); EXPECT_THAT(called, testing::Eq(true)); @@ -260,7 +261,9 @@ TEST_F(PreferenceTest, Callback) { EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); ret = preference_set_int("test1", 1); - while (g_main_context_iteration(g_main_context_default(), true)); + while (g_main_context_iteration(g_main_context_default(), true)) { + } + EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); EXPECT_THAT(called, testing::Eq(false)); @@ -274,23 +277,4 @@ TEST_F(PreferenceTest, Callback) { EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE)); } -} // namespace - -int main(int argc, char* argv[]) { - int ret = 0; - try { - ::testing::InitGoogleTest(&argc, argv); - } catch(...) { - std::cout << "Exception occured" << std::endl; - return 1; - } - - try { - return RUN_ALL_TESTS(); - } catch(const ::testing::internal::GoogleTestFailureException& e) { - std::cout << "GoogleTestFailureException occured:" << e.what() << std::endl; - ret = 1; - } - - return ret; -} +} // namespace preference diff --git a/unittests/preference_unittest.cc b/unittests/preference_unittest.cc new file mode 100644 index 0000000..5026c25 --- /dev/null +++ b/unittests/preference_unittest.cc @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * 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 + +class PreferenceUnitTest : public testing::Test { + public: + virtual void SetUp() { + mainloop_ = g_main_loop_new(nullptr, FALSE); + + preference_remove_all(); + } + virtual void TearDown() { + preference_remove_all(); + + g_main_loop_unref(mainloop_); + mainloop_ = nullptr; + } + + void RunMainLoop() { + g_main_loop_run(mainloop_); + } + + void Finish() { + g_main_loop_quit(mainloop_); + } + + bool touch_preference_changed_cb_ = false; + int item_count_ = 0; + + private: + GMainLoop* mainloop_; +}; + +TEST_F(PreferenceUnitTest, preference_set_int_P) { + int ret = preference_set_int("key:int", 10); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); +} + +TEST_F(PreferenceUnitTest, preference_set_int_N) { + int ret = preference_set_int(nullptr, 10); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_get_int_P) { + int ret = preference_set_int("key:int", 20); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + int value = 0; + ret = preference_get_int("key:int", &value); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(value, 20); +} + +TEST_F(PreferenceUnitTest, preference_get_int_N) { + int ret = preference_get_int(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_set_double_P) { + int ret = preference_set_double("key:double", 22.22f); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); +} + +TEST_F(PreferenceUnitTest, preference_set_double_N) { + int ret = preference_set_double(nullptr, 22.22f); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_get_double_P) { + int ret = preference_set_double("key:double", 12.34f); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + double value = 0; + ret = preference_get_double("key:double", &value); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(value, 12.34f); +} + +TEST_F(PreferenceUnitTest, preference_get_double_N) { + int ret = preference_get_double(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_set_string_P) { + int ret = preference_set_string("key:string", "PreferenceUnitTest"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); +} + +TEST_F(PreferenceUnitTest, preference_set_string_N) { + int ret = preference_set_string(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_get_string_P) { + int ret = preference_set_string("key:string", "PreferenceUnitTest2"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + char* value = nullptr; + ret = preference_get_string("key:string", &value); + ASSERT_NE(value, nullptr); + auto vp = std::unique_ptr(value, free); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_STREQ(vp.get(), "PreferenceUnitTest2"); +} + +TEST_F(PreferenceUnitTest, preference_get_string_N) { + int ret = preference_get_string(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_set_boolean_P) { + int ret = preference_set_boolean("key:boolean", true); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); +} + +TEST_F(PreferenceUnitTest, preference_set_boolean_N) { + int ret = preference_set_boolean(nullptr, true); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_get_boolean_P) { + int ret = preference_set_boolean("key:boolean", false); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + bool value = true; + ret = preference_get_boolean("key:boolean", &value); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(value, false); +} + +TEST_F(PreferenceUnitTest, preference_get_boolean_N) { + int ret = preference_get_boolean(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_remove_P) { + int ret = preference_set_int("key:remove", 100); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_remove("key:remove"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + int value; + ret = preference_get_int("key:remove", &value); + ASSERT_EQ(ret, PREFERENCE_ERROR_NO_KEY); +} + +TEST_F(PreferenceUnitTest, preference_remove_N) { + int ret = preference_remove(nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_remove_all_P) { + int ret = preference_set_int("key:removeall_int", 100); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_string("key:removeall_string", "RemoveTest"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_remove_all(); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + int intval; + ret = preference_get_int("key:removeall_int", &intval); + ASSERT_EQ(ret, PREFERENCE_ERROR_NO_KEY); + + char* strval; + ret = preference_get_string("key:removeall_string", &strval); + ASSERT_EQ(ret, PREFERENCE_ERROR_NO_KEY); +} + +TEST_F(PreferenceUnitTest, preference_set_changed_cb_P) { + int ret = preference_set_int("key:changed", 1); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_changed_cb("key:changed", + [](const char* key, void* user_data) { + PreferenceUnitTest* p = static_cast(user_data); + p->touch_preference_changed_cb_ = true; + p->Finish(); + }, this); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_int("key:changed", 2); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + RunMainLoop(); + + int value = 0; + ret = preference_get_int("key:changed", &value); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(value, 2); + + preference_unset_changed_cb("key:changed"); +} + +TEST_F(PreferenceUnitTest, preference_set_changed_cb_N) { + int ret = preference_set_changed_cb(nullptr, nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_unset_changed_cb_P) { + int ret = preference_set_string("key:changed", "Changed"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_changed_cb("key:changed", + [](const char* key, void* user_data) { + }, this); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_unset_changed_cb("key:changed"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); +} + +TEST_F(PreferenceUnitTest, preference_unset_changed_cb_N) { + int ret = preference_unset_changed_cb(nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} + +TEST_F(PreferenceUnitTest, preference_foreach_item_P) { + int ret = preference_set_string("key:item1", "item1"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_int("key:item2", 1); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_double("key:item3", 1); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_set_boolean("key:item4", true); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + ret = preference_foreach_item( + [](const char* key, void* user_data) { + PreferenceUnitTest* p = static_cast(user_data); + p->item_count_++; + return true; + }, this); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(this->item_count_, 4); +} + +TEST_F(PreferenceUnitTest, preference_get_type_P) { + int ret = preference_set_string("key:str", "val:str"); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + + preference_type_e type = PREFERENCE_TYPE_NONE; + ret = preference_get_type("key:str", &type); + ASSERT_EQ(ret, PREFERENCE_ERROR_NONE); + ASSERT_EQ(type, PREFERENCE_TYPE_STRING); +} + +TEST_F(PreferenceUnitTest, preference_get_type_N) { + int ret = preference_get_type(nullptr, nullptr); + ASSERT_EQ(ret, PREFERENCE_ERROR_INVALID_PARAMETER); +} -- 2.34.1