-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)
+++ /dev/null
-# Package Information for pkg-config
-
-prefix=@PREFIX@
-exec_prefix=/usr
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCLUDE_INSTALL_DIR@/appfw
-
-Name: @PC_NAME@
-Description: @PACKAGE_DESCRIPTION@
-Version: @VERSION@
-Requires: @PC_REQUIRED@
-Libs: -L${libdir} @PC_LDFLAGS@
-Cflags: -I${includedir}
--- /dev/null
+# 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)
+++ /dev/null
-/*
- * 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__ */
-
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <dlog.h>
-
-
-#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__ */
-
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
%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
%{_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
--- /dev/null
+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)
--- /dev/null
+/*
+ * 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 <vector>
+#include <memory>
+#include <string>
+
+#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<Data> 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<std::string> GetKeys() = 0;
+ virtual bool IsExisting(const std::string& key) = 0;
+};
+
+} // namespace internal
+} // namespace preference
+
+#endif // PREFERENCE_BACKEND_INTERFACE_HH_
--- /dev/null
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@/appfw
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
--- /dev/null
+/*
+ * 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 <string>
+
+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_
--- /dev/null
+/*
+ * 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 <cstring>
+
+#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<const char*>(str);
+}
+
+void Data::SetInt(int i) {
+ Set<int>(i);
+ SetType<int>(i);
+}
+
+void Data::SetDouble(double d) {
+ Set<double>(d);
+ SetType<double>(d);
+}
+
+void Data::SetBoolean(bool b) {
+ Set<bool>(b);
+ SetType<bool>(b);
+}
+
+const char* Data::GetString() const {
+ const char* str = reinterpret_cast<const char*>(&value_[0]);
+ return str;
+}
+
+int Data::GetInt() const {
+ return Get<int>();
+}
+
+double Data::GetDouble() const {
+ return Get<double>();
+}
+
+bool Data::GetBoolean() const {
+ return Get<bool>();
+}
+
+const Data::Type Data::GetType() const {
+ return type_;
+}
+
+} // namespace internal
+} // namespace preference
--- /dev/null
+/*
+ * 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 <string>
+#include <typeinfo>
+#include <vector>
+
+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<uint8_t>& GetRaw() const {
+ return value_;
+ }
+
+ private:
+ template<typename T>
+ 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<typename T>
+ void Set(T d) {
+ value_.clear();
+ uint8_t* p = reinterpret_cast<uint8_t*>(&d);
+ std::copy(p, p + sizeof(T), std::back_inserter(value_));
+ }
+
+ template<typename T>
+ T Get() const {
+ T d;
+ uint8_t* p = reinterpret_cast<uint8_t*>(&d);
+ std::copy(value_.begin(), value_.begin() + sizeof(T), p);
+ return d;
+ }
+
+ private:
+ std::string key_;
+ std::vector<uint8_t> value_;
+ Type type_ = Type::NONE;
+};
+
+} // namespace internal
+} // namespace preference
+
+#endif // PREFERENCE_DATA_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <sys/inotify.h>
+
+#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<Data> FileBackend::Get(const std::string& key) {
+ File file(key, false);
+ if (file.Read() < 0)
+ return nullptr;
+
+ return std::make_shared<Data>(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<std::string> FileBackend::GetKeys() {
+ std::vector<std::string> 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<FileBackend*>(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<struct inotify_event*>(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
--- /dev/null
+/*
+ * 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 <glib.h>
+#include <gio/gio.h>
+
+#include <map>
+
+#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<Data> 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<std::string> 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<std::string, std::string> key_map_;
+ std::map<std::string, IDataEvent*> watch_map_;
+};
+
+} // namespace internal
+} // namespace preference
+
+#endif // PREFERENCE_FILE_BACKEND_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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<uint8_t*>(&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<int>(data.GetType());
+ p = reinterpret_cast<uint8_t*>(&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<uint8_t*>(&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<uint8_t*>(&type);
+ std::copy(&raw_data_[index], &raw_data_[index] + sizeof(int), p);
+ index += sizeof(int);
+
+ Data data(key);
+
+ Data::Type data_type = static_cast<Data::Type>(type);
+ if (data_type == Data::Type::STRING) {
+ const char* str = reinterpret_cast<const char*>(&raw_data_[index]);
+ data.SetString(str);
+ } else if (data_type == Data::Type::INT) {
+ int i = 0;
+ p = reinterpret_cast<uint8_t*>(&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<uint8_t*>(&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<uint8_t*>(&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<int>(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<int>(Error::ERROR_FILE_OPEN);
+
+ if (!Lock(false)) {
+ Close();
+ return static_cast<int>(Error::ERROR_FILE_LOCK);
+ }
+
+ ssize_t bytes_written;
+ ssize_t size = raw_data_.size();
+ uint8_t* buffer = static_cast<uint8_t*>(&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<int>(Error::ERROR_FILE_WRITE);
+ } else {
+ ret = Sync();
+ }
+
+ Unlock();
+ Close();
+ return ret;
+}
+
+int File::TryRead() {
+ int ret = Open();
+ if (ret < 0)
+ return static_cast<int>(Error::ERROR_FILE_OPEN);
+
+ if (!Lock()) {
+ Close();
+ return static_cast<int>(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<int>(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
--- /dev/null
+/*
+ * 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 <list>
+#include <memory>
+#include <string>
+
+#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<uint8_t> raw_data_;
+ int fd_ = 0;
+};
+
+} // namespace internal
+} // namespace preference
+
+#endif // PREFERENCE_FILE_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <dlog.h>
+
+#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_
--- /dev/null
+/*
+ * 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 <app_common.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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
--- /dev/null
+/*
+ * 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 <string>
+
+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_
--- /dev/null
+/*
+ * 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<int>(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<std::string> 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
--- /dev/null
+/*
+ * 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 <map>
+#include <memory>
+#include <string>
+
+#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<std::string> 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<IBackend> backend_;
+ IEventListener* listener_ = nullptr;
+};
+
+} // namespace internal
+} // namespace preference
+
+#endif // PREFERENCE_PREFERENCE_INTERNAL_HH_
--- /dev/null
+/*
+ * 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 <app_common.h>
+#include <app_preference.h>
+
+#include <map>
+#include <mutex>
+#include <thread>
+
+#include "include/app_preference.h"
+#include "preference/log-internal.hh"
+#include "preference/preference-internal.hh"
+
+#undef API
+#define API __attribute__ ((visibility("default")))
+
+namespace {
+
+template<typename T>
+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<std::recursive_mutex> lock(GetMutex());
+ if (Preference::AddWatch(key) < 0)
+ return -1;
+
+ map_[std::string(key)] = std::unique_ptr<Event<preference_changed_cb>>(
+ new Event<preference_changed_cb>(cb, user_data));
+
+ return 0;
+ }
+
+ int RemoveWatch(const char* key) {
+ std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(GetMutex());
+ auto i = map_.find(key);
+ if (i == map_.end())
+ return;
+
+ map_.erase(key);
+ Preference::RemoveWatch(key);
+ }
+
+ private:
+ std::map<std::string, std::unique_ptr<Event<preference_changed_cb>>> 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<preference_type_e>(pref.GetType(key));
+ SECURE_LOGD("key(%s), type(%d)", key, *type);
+ return PREFERENCE_ERROR_NONE;
+}
+++ /dev/null
-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)
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/xattr.h>
-#include <ctype.h>
-#include <string.h>
-#include <execinfo.h>
-#include <glib.h>
-
-#include <app_preference.h>
-#include <app_preference_internal.h>
-#include <app_common.h>
-
-#include <sys/syscall.h>
-
-#ifdef PREFERENCE_TIMECHECK
-#include <sys/time.h>
-#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;
-}
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sqlite3.h>
-
-#include <app_internal.h>
-
-#include <app_preference.h>
-#include <app_preference_internal.h>
-
-#include <dlog.h>
-
-#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;
-}
-
+++ /dev/null
-/*
- * 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 <sys/types.h>
-#include <sys/inotify.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <linux/version.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <glib.h>
-
-#include <app_preference.h>
-#include <app_preference_internal.h>
-
-#include <glib.h>
-
-#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;
-}
-
+++ /dev/null
-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)
-
+++ /dev/null
-#!/bin/sh
-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`
-do
- chsmack $file >> $PREF_DUMP/pref_value
- chsmack $file/* >> $PREF_DUMP/pref_value
- ls -alZ $file >> $PREF_DUMP/pref_value
- PKG_ID=`echo "$file" | awk -F'/' '{print $5}'`
- /usr/bin/preference_tool get $PKG_ID >> $PREF_DUMP/pref_value
- mkdir -p $PREF_DUMP/$PKG_ID
- cp -rf --preserve=all $file/* $PREF_DUMP/$PKG_ID
- echo "===============================================" >> $PREF_DUMP/pref_value
-done
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <grp.h>
-#include <linux/limits.h>
-#include <wordexp.h>
-#include <sqlite3.h>
-#include <glib.h>
-#include <locale.h>
-
-#include <app_common_internal.h>
-#include <app_preference.h>
-#include <app_preference_internal.h>
-#include <tzplatform_config.h>
-
-#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 <pkgid> <key_name> <type> <value>\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 <pkgid>\n");
- printf("ex) preference_tool get org.tizen.preferencetest\n\n");
- printf("preference_tool get <pkgid> <key>\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 <app_dir>\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;
-}
--- /dev/null
+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)
--- /dev/null
+/*
+ * 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 <dlog.h>
+
+#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_
--- /dev/null
+#!/bin/sh
+PATH="/usr/bin:/bin:/usr/sbin:/sbin"
+
+PREF_DUMP=$1/pref
+/bin/mkdir -p $PREF_DUMP
+
+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
+ ls -alZ $file >> $PREF_DUMP/pref_value
+ PKG_ID=`echo "$file" | awk -F'/' '{print $5}'`
+ /usr/bin/preference_tool get $PKG_ID >> $PREF_DUMP/pref_value
+ mkdir -p $PREF_DUMP/$PKG_ID
+ cp -rf --preserve=all $file/* $PREF_DUMP/$PKG_ID
+ echo "===============================================" >> $PREF_DUMP/pref_value
+done
--- /dev/null
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <tzplatform_config.h>
+#include <unistd.h>
+#include <wordexp.h>
+
+#include <iostream>
+#include <string>
+
+#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 <pkgid> <key_name> <type> <value>"
+ << 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 <pkgid>"
+ << std::endl;
+ std::cout << "ex) preference_tool get org.tizen.helloworld"
+ << std::endl;
+ std::cout << std::endl;
+
+ std::cout << "$ preference_tool get <pkgid> <key>"
+ << 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<int>(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<char* const*>(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;
+}
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)
--- /dev/null
+/*
+ * 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 <gmock/gmock.h>
+
+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;
+}
* 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);
* 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 <gmock/gmock.h>
-#include "module_mock.h"
+#include "unittests/mock/module_mock.h"
class CommonMock : public virtual ModuleMock {
public:
MOCK_METHOD0(app_get_data_path, char*());
};
-#endif // MOCK_COMMON_HOOK_H_
+#endif // UNITTESTS_MOCK_COMMON_MOCK_H_
* 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<MOCK_CLASS>().f()
TestFixture::GetMock<MOCK_CLASS>().f( \
p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
-#endif // MOCK_MOCK_HOOK_H_
+#endif // UNITTESTS_MOCK_MOCK_HOOK_H_
* 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_
#include <memory>
-#include "test_fixture.h"
+#include "unittests/mock/test_fixture.h"
std::unique_ptr<ModuleMock> TestFixture::mock_;
* 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 <gtest/gtest.h>
#include <string>
#include <utility>
-#include "module_mock.h"
+#include "unittests/mock/module_mock.h"
class TestFixture : public ::testing::Test {
public:
static std::unique_ptr<ModuleMock> mock_;
};
-#endif // MOCK_TEST_FIXTURE_H_
+#endif // UNITTESTS_MOCK_TEST_FIXTURE_H_
* limitations under the License.
*/
-#include <string.h>
-
-#include <functional>
-
#include <app_preference.h>
#include <dlog.h>
#include <glib.h>
#include <gmock/gmock.h>
+#include <string.h>
+
+#include <functional>
-#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;
}
}));
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<CommonMock>(), app_get_data_path())
.WillRepeatedly(testing::Invoke([&]() {
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<bool*>(user_data);
- *called = true;
- }, reinterpret_cast<bool*>(&called));
+ ret = preference_set_changed_cb("test1",
+ [](const char* key, void* user_data) {
+ bool* called = reinterpret_cast<bool*>(user_data);
+ *called = true;
+ }, reinterpret_cast<bool*>(&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));
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));
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
--- /dev/null
+/*
+ * 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 <app_preference.h>
+#include <gtest/gtest.h>
+#include <glib.h>
+
+#include <iostream>
+#include <memory>
+
+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<char, decltype(free)*>(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<PreferenceUnitTest*>(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<PreferenceUnitTest*>(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);
+}