update preference source from tizen 2.4 05/40105/3 accepted/tizen_3.0.2015.q2_common tizen_3.0.2015.q2_common accepted/tizen/3.0.2015.q2/common/20150609.181955 accepted/tizen/3.0.2015.q2/common/20150615.091844 accepted/tizen/common/20150609.084317 accepted/tizen/mobile/20150609.085836 accepted/tizen/tv/20150612.003517 accepted/tizen/wearable/20150609.085858 submit/tizen/20150604.025832 submit/tizen/20150605.114228 submit/tizen_3.0.2015.q2_common/20150609.170642 submit/tizen_3.0.2015.q2_common/20150615.075539 submit/tizen_tv/20150611.000000
authorJiwoong Im <jiwoong.im@samsung.com>
Fri, 29 May 2015 07:54:32 +0000 (16:54 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Wed, 3 Jun 2015 05:08:32 +0000 (14:08 +0900)
change logic and apply inotify.

Change-Id: If361b058c81cf1cb235c661e967417fc9cca9e19
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
include/app_preference.h
include/app_preference_internal.h [new file with mode: 0755]
include/app_preference_log.h [new file with mode: 0755]
preference/CMakeLists.txt
preference/preference.c
preference/preference_db.c [new file with mode: 0755]
preference/preference_inoti.c [new file with mode: 0755]

index 9aeb3af..8b2ff86 100644 (file)
@@ -11,7 +11,7 @@
  * 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. 
+ * limitations under the License.
  */
 
 
@@ -25,32 +25,38 @@ extern "C" {
 #endif
 
 /**
- * @addtogroup CAPI_PREFERENCE_MODULE 
+ * @file app_preference.h
+ */
+
+/**
+ * @addtogroup CAPI_PREFERENCE_MODULE
  * @{
  */
 
 
 /**
- * @brief Enumerations of error code for Preference.
+ * @brief Enumeration for Preference Error.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
  */
 typedef enum
 {
        PREFERENCE_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
        PREFERENCE_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
        PREFERENCE_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
-       PREFERENCE_ERROR_NO_KEY = TIZEN_ERROR_KEY_NOT_AVAILABLE, /**< Required key not available */
+       PREFERENCE_ERROR_NO_KEY = TIZEN_ERROR_APPLICATION | 0x30, /**< Required key not available */
        PREFERENCE_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR , /**< Internal I/O Error */
 } preference_error_e;
 
 
 /**
- * @brief      Called when the given key's value in the preference changes.
+ * @brief Called when the given key's value in the preference changes.
  *
- * @details When the @a key is added or removed, this callback function is skipped. (only update can be handled)
+ * @details When the @a key is added or removed, this callback function is skipped(only update can be handled).
  *
- * @param   [in] key   The name of the key in the preference
- * @param   [in] user_data The user data passed from the callback registration function
- * @pre                This function is invoked when the value of the key is overwritten after you register this callback using preference_set_changed_cb()
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key in the preference
+ * @param[in] user_data The user data passed from the callback registration function
+ * @pre This function is invoked when the value of the key is overwritten after you register this callback using preference_set_changed_cb().
  * @see preference_set_changed_cb()
  * @see preference_unset_changed_cb()
  * @see        preference_set_boolean()
@@ -62,42 +68,47 @@ typedef void (*preference_changed_cb) (const char *key, void *user_data);
 
 
 /**
-* @brief   Called to get key string once for each key-value pair in the preference.
-*
-* @remarks You should not free @a key returned by this function.
-*
-* @param       [in] key The key of the value added to the preference
-* @param       [in] value The value associated with the key
-* @param       [in] user_data The user data passed from the foreach function
-* @return @c true to continue with the next iteration of the loop, \n @c false to break out of the loop.
-* @pre         preference_foreach_item() will invoke this callback function.
-* @see         preference_foreach_item()
-*/
+ * @brief Called to get key string, once for each key-value pair in the preference.
+ *
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @remarks You should not free the @a key returned by this function.
+ *
+ * @param[in] key The key of the value added to the preference
+ * @param[in] value The value associated with the key
+ * @param[in] user_data The user data passed from the foreach function
+ * @return @c true to continue with the next iteration of the loop,
+ *         otherwise @c false to break out of the loop
+ * @pre                preference_foreach_item() will invoke this callback function.
+ * @see                preference_foreach_item()
+ */
 typedef bool (*preference_item_cb)(const char *key, void *user_data);
 
 
 /**
  * @brief Sets an integer value in the preference.
  *
- * @param [in] key     The name of the key to modify
- * @param [in] value  The new @c int value for the given key
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to modify
+ * @param[in] value  The new @c int value for the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_get_int()
- *
  */
 int preference_set_int(const char *key, int value);
 
 
 /**
- * @brief Gets a integer value from the preference.
+ * @brief Gets an integer value from the preference.
  *
- * @param [in] key The name of the key to retrieve
- * @param [out] value  The @c int value for the given key
- * @return 0 on success, otherwise a negative error value.
- * @retval #PREFERENCE_ERROR_NONE      Successful
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to retrieve
+ * @param[out] value The @c int value for the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_NO_KEY    Required key not available
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
@@ -109,14 +120,15 @@ int preference_get_int(const char *key, int *value);
 /**
  * @brief Sets a double value in the preference.
  *
- * @param [in] key The name of the key to modify
- * @param [in] value  The new @c double value associated with given key
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to modify
+ * @param[in] value  The new @c double value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE      Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_get_double()
- *
  */
 int preference_set_double(const char *key, double value);
 
@@ -124,15 +136,16 @@ int preference_set_double(const char *key, double value);
 /**
  * @brief Gets a double value from the preference.
  *
- * @param [in] key The name of the key to retrieve
- * @param [out] value  The @c double value associated with given key
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to retrieve
+ * @param[out] value  The @c double value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE      Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_NO_KEY    Required key not available
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_set_double()
- *
  */
 int preference_get_double(const char *key, double *value);
 
@@ -141,15 +154,16 @@ int preference_get_double(const char *key, double *value);
  * @brief Sets a string value in the preference.
  *
  * @details It makes a deep copy of the added string value.
- * 
- * @param [in] key The name of the key to modify
- * @param [in] value  The new @c string value associated with given key
- * @return 0 on success, otherwise a negative error value.
+ *
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to modify
+ * @param[in] value  The new @c string value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE      Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_get_string()
- *
  */
 int preference_set_string(const char *key, const char *value);
 
@@ -157,11 +171,13 @@ int preference_set_string(const char *key, const char *value);
 /**
  * @brief Gets a string value from the preference.
  *
- * @remarks @a value must be released with free() by you.
- * @param [in] key     The name of the key to retrieve
- * @param [out] value  The @c string value associated with given key
- * @return 0 on success, otherwise a negative error value.
- * @retval #PREFERENCE_ERROR_NONE      Successful
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @remarks @a value must be released using free().
+ * @param[in] key The name of the key to retrieve
+ * @param[out] value The @c string value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_OUT_OF_MEMORY     Out of memory
  * @retval #PREFERENCE_ERROR_NO_KEY    Required key not available
@@ -174,12 +190,14 @@ int preference_get_string(const char *key, char **value);
 /**
  * @brief Sets a boolean value in the preference.
  *
- * @param [in] key The name of the key to modify
- * @param [in] value  The new boolean @c value associated with given key
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to modify
+ * @param[in] value The new @c boolean value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE      Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error   
+ * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_get_boolean()
  */
 int preference_set_boolean(const char *key, bool value);
@@ -188,9 +206,11 @@ int preference_set_boolean(const char *key, bool value);
 /**
  * @brief Gets a boolean value from the preference.
  *
- * @param [in] key The name of the key to retrieve
- * @param [out] value  The boolean @c value associated with given key
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to retrieve
+ * @param[out] value  The @c boolean value associated with the given key
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE      Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_NO_KEY    Required key not available
@@ -203,22 +223,26 @@ int preference_get_boolean(const char *key, bool *value);
 /**
  * @brief Removes any value with the given @a key from the preference.
  *
- * @param [in] key The name of the key to remove
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to remove
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
- * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter 
+ * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
- *
  */
 int preference_remove(const char *key);
 
 
 /**
- * @brief Checks whether if the given @a key exists in the preference.
+ * @brief Checks whether the given @a key exists in the preference.
  *
- * @param [in] key The name of the key to check
- * @param [out] existing  @c true if the @a key exists in the preference, otherwise @c false
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to check
+ * @param[out] existing  If @c true the @a key exists in the preference,
+ *                       otherwise @c false
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
@@ -229,7 +253,9 @@ int preference_is_existing(const char *key, bool *existing);
 /**
  * @brief Removes all key-value pairs from the preference.
  *
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
  * @see        preference_remove()
@@ -240,10 +266,12 @@ int preference_remove_all(void);
 /**
  * @brief Registers a callback function to be invoked when value of the given key in the preference changes.
  *
- * @param [in] key The name of the key to monitor
- * @param [in] callback The callback function to register
- * @param [in] user_data The user data to be passed to the callback function
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to monitor
+ * @param[in] callback The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_OUT_OF_MEMORY Out of memory
@@ -259,8 +287,10 @@ int preference_set_changed_cb(const char *key, preference_changed_cb callback, v
 /**
  * @brief Unregisters the callback function.
  *
- * @param [in] key The name of the key to monitor
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] key The name of the key to monitor
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
@@ -272,9 +302,11 @@ int preference_unset_changed_cb(const char *key);
 /**
  * @brief Retrieves all key-value pairs in the preference by invoking the callback function.
  *
- * @param [in] callback The callback function to get key value once for each key-value pair in the preference
- * @param [in] user_data The user data to be passed to the callback function
- * @return 0 on success, otherwise a negative error value.
+ * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
+ * @param[in] callback The callback function to get key value once for each key-value pair in the preference
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
  * @retval #PREFERENCE_ERROR_NONE Successful
  * @retval #PREFERENCE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #PREFERENCE_ERROR_IO_ERROR Internal I/O Error
diff --git a/include/app_preference_internal.h b/include/app_preference_internal.h
new file mode 100755 (executable)
index 0000000..8108903
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 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"
+
+#define BUF_LEN                        (4096)
+#define PREF_DIR       ".pref/"
+
+#define PREFERENCE_KEY_PATH_LEN        1024
+#define ERR_LEN                128
+
+#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"
+
+/**
+ * @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 enum
+{
+       PREFERENCE_TYPE_NONE = 0,
+       PREFERENCE_TYPE_STRING,
+       PREFERENCE_TYPE_INT,
+       PREFERENCE_TYPE_DOUBLE,
+       PREFERENCE_TYPE_BOOLEAN,
+} preference_type_e;
+
+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
+       (const char *keyname, preference_changed_cb cb, void *data);
+int _preference_kdb_del_notify
+       (const char *keyname);
+
+int _preference_get_key_path(const char *keyname, char *path);
+int _preference_get_key(keynode_t *keynode);
+
+int _preference_keynode_set_keyname(keynode_t *keynode, const char *keyname);
+inline void _preference_keynode_set_null(keynode_t *keynode);
+inline keynode_t *_preference_keynode_new(void);
+inline void _preference_keynode_free(keynode_t *keynode);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_APPFW_PREFERENCE_INTERNAL_H__ */
diff --git a/include/app_preference_log.h b/include/app_preference_log.h
new file mode 100755 (executable)
index 0000000..8bd87a7
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015 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__ */
index 73b2d4e..21da809 100644 (file)
@@ -32,6 +32,7 @@ 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})
index 98faf5d..c19b641 100644 (file)
  * 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,
+ * 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 <limits.h>
 #include <string.h>
-#include <sqlite3.h>
-
-#include <app_private.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 <app_preference.h>
-#include <app_preference_private.h>
+#include <app_preference_internal.h>
+#include <app_common.h>
 
-#include <dlog.h>
-
-#ifdef LOG_TAG
-#undef LOG_TAG
+#ifndef API
+#define API __attribute__ ((visibility("default")))
 #endif
 
-#define LOG_TAG "CAPI_APPFW_APPLICATION_PREFERENCE"
-#define DBG_MODE (1)
+#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;
 
-static sqlite3 *pref_db;
-static bool is_update_hook_registered;
-static pref_changed_cb_node_t *head;
 
-static void _finish(void *data)
+enum preference_op_t {
+    PREFERENCE_OP_GET = 0,
+    PREFERENCE_OP_SET = 1
+};
+
+#ifdef PREFERENCE_TIMECHECK
+double correction, startT;
+
+double set_start_time(void)
 {
-       if (pref_db != NULL) {
-               sqlite3_close(pref_db);
-               pref_db = NULL;
-       }
+       struct timeval tv;
+       double curtime;
+
+       gettimeofday(&tv, NULL);
+       curtime = tv.tv_sec * 1000 + (double)tv.tv_usec / 1000;
+       return curtime;
 }
 
-static int _busy_handler(void *pData, int count)
+double exec_time(double start)
 {
-       if (count < 5) {
-               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;
-       }
+       double end = set_start_time();
+       return (end - start - correction);
 }
 
-static int _initialize(void)
+int init_time(void)
 {
-       char *data_path;
-       char db_path[TIZEN_PATH_MAX];
-       int ret;
-       char *errmsg;
+       double temp_t;
+       temp_t = set_start_time();
+       correction = exec_time(temp_t);
 
-       data_path = app_get_data_path();
-       if (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);
+       return 0;
+}
+#endif
 
-       ret = sqlite3_open_v2(db_path, &pref_db, SQLITE_OPEN_CREATE, NULL);
-       if (ret != SQLITE_OK) {
-               LOGE("IO_ERROR(0x%08x) : fail to open db(%s)",
-                               PREFERENCE_ERROR_IO_ERROR, sqlite3_errmsg(pref_db));
-               _finish(NULL);
-               return PREFERENCE_ERROR_IO_ERROR;
+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 ((app_data_path = app_get_data_path()) == NULL)
+               {
+                       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;
+               }
+               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;
+}
 
-       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));
-       }
+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;
+}
 
-       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);
-               _finish(NULL);
-               return PREFERENCE_ERROR_IO_ERROR;
-       }
+static inline void _preference_keynode_set_value_int(keynode_t *keynode, const int value)
+{
+       keynode->type = PREFERENCE_TYPE_INT;
+       keynode->value.i = value;
+}
 
-       app_finalizer_add(_finish, NULL);
+static inline void _preference_keynode_set_value_boolean(keynode_t *keynode, const int value)
+{
+       keynode->type = PREFERENCE_TYPE_BOOLEAN;
+       keynode->value.b = !!value;
+}
 
-       return PREFERENCE_ERROR_NONE;
+static inline void _preference_keynode_set_value_double(keynode_t *keynode, const double value)
+{
+       keynode->type = PREFERENCE_TYPE_DOUBLE;
+       keynode->value.d = value;
 }
 
-static int _prepare_and_bind_stmt(char *buf, const char *type,
-               const char *data, const char *key, sqlite3_stmt **stmt)
+static inline void _preference_keynode_set_value_string(keynode_t *keynode, const char *value)
 {
-       int ret;
+       keynode->type = PREFERENCE_TYPE_STRING;
+       keynode->value.s = strdup(value);
+}
 
-       ret = sqlite3_prepare(pref_db, buf, -1, 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;
-       }
+inline keynode_t *_preference_keynode_new(void)
+{
+       keynode_t *keynode;
+       keynode = calloc(1, sizeof(keynode_t));
 
-       ret = sqlite3_bind_text(*stmt, 1, type, -1, 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, -1, 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;
+       return keynode;
+}
+
+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);
        }
-       ret = sqlite3_bind_text(*stmt, 3, key, -1, 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;
+}
+
+int _preference_get_key_name(const char *keyfile, char *keyname)
+{
+       char convert_key[PREFERENCE_KEY_PATH_LEN] = {0,};
+       char *chrptr = NULL;
+
+       strncpy(convert_key, keyfile, strlen(keyfile));
+
+       chrptr = strchr((const char*)convert_key, DELIMITER);
+       if(chrptr) {
+               chrptr = strchr((const char*)convert_key, DELIMITER);
+               while(chrptr) {
+                       convert_key[chrptr-convert_key] = '/';
+                       chrptr = strchr((const char*)chrptr+1, DELIMITER);
+               }
        }
+       snprintf(keyname, PREFERENCE_KEY_PATH_LEN, "%s", (const char*)convert_key);
 
        return PREFERENCE_ERROR_NONE;
 }
 
-static int _write_data(const char *key, const char *type, const char *data)
+
+int _preference_get_key_path(const char *keyname, char *path)
 {
-       int ret;
-       bool exist = false;
-       sqlite3_stmt *stmt;
-       char buf[BUF_LEN];
+       const char *key = NULL;
 
-       if (key == NULL || key[0] == '\0' || data == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+       if(!keyname) {
+               ERR("keyname is null");
+               return PREFERENCE_ERROR_WRONG_PREFIX;
        }
-       /* insert data or update data if data already exist */
-       ret = preference_is_existing(key, &exist);
-       if (ret != PREFERENCE_ERROR_NONE)
-               return ret;
-
-       if (exist)
-               snprintf(buf, sizeof(buf), "UPDATE %s SET %s=?1, %s=?2 WHERE %s=?3;",
-                               PREF_TBL_NAME, PREF_F_TYPE_NAME,
-                               PREF_F_DATA_NAME, PREF_F_KEY_NAME);
-       else
-               snprintf(buf, sizeof(buf),
-                               "INSERT INTO %s (%s, %s, %s) values (?3, ?1, ?2);",
-                               PREF_TBL_NAME, PREF_F_KEY_NAME,
-                               PREF_F_TYPE_NAME, PREF_F_DATA_NAME);
 
-       ret = _prepare_and_bind_stmt(buf, type, data, key, &stmt);
+       char convert_key[PREFERENCE_KEY_PATH_LEN] = {0,};
+       char *chrptr = NULL;
+       char *pref_dir_path = NULL;
 
-       if (ret != PREFERENCE_ERROR_NONE)
-               return ret;
+       strncpy(convert_key, keyname, strlen(keyname));
 
-       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);
+       pref_dir_path = _preference_get_pref_dir_path();
+       if (!pref_dir_path)
+       {
+               LOGE("_preference_get_pref_dir_path() failed.");
                return PREFERENCE_ERROR_IO_ERROR;
        }
 
-       sqlite3_finalize(stmt);
+       chrptr = strchr((const char*)convert_key, (int)'/');
+       if(!chrptr)     {
+               key = (const char*)convert_key;
+       }
+       else {
+               chrptr = strchr((const char*)convert_key, (int)'/');
+               while(chrptr) {
+                       convert_key[chrptr-convert_key] = DELIMITER;
+                       chrptr = strchr((const char*)chrptr+1, (int)'/');
+               }
+               key = (const char*)convert_key;
+       }
+
+       snprintf(path, PREFERENCE_KEY_PATH_LEN, "%s%s", pref_dir_path, key);
 
        return PREFERENCE_ERROR_NONE;
 }
 
-static int _read_data(const char *key, char *type, char *data)
+static int _preference_set_key_check_pref_dir()
 {
-       int ret;
-       char *buf;
-       char **result;
-       int rows;
-       int columns;
-       char *errmsg;
+       char *pref_dir_path = NULL;
+       mode_t dir_mode = 0664 | 0111;
 
-       if (key == NULL || key[0] == '\0'  || data == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+       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 (pref_db == NULL) {
-               if (_initialize() != PREFERENCE_ERROR_NONE) {
-                       LOGE("IO_ERROR(0x%08x) : fail to initialize db",
-                                       PREFERENCE_ERROR_IO_ERROR);
+       if (access(pref_dir_path, F_OK) < 0)
+       {
+               if (mkdir(pref_dir_path, dir_mode) < 0)
+               {
+                       ERR("mkdir() failed(%d/%s)", errno, strerror(errno));
                        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);
+       return PREFERENCE_ERROR_NONE;
+}
 
-       if (buf == NULL) {
-               LOGE("IO_ERROR(0x%08x) : fail to create query string",
-                               PREFERENCE_ERROR_IO_ERROR);
+static int _preference_set_key_creation(const char* path)
+{
+       int fd;
+       mode_t temp;
+       temp = umask(0000);
+       fd = open(path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+       umask(temp);
+       if(fd == -1) {
+               ERR("open(rdwr,create) error: %d(%s)", errno, strerror(errno));
                return PREFERENCE_ERROR_IO_ERROR;
        }
+       close(fd);
 
-       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;
-       }
+       return PREFERENCE_ERROR_NONE;
+}
 
-       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;
-       }
+static int _preference_set_file_lock(int fd, short type)
+{
+       struct flock l;
 
-       snprintf(type, 2, "%s", result[4]);
-       snprintf(data, BUF_LEN, "%s", result[5]);
+       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*/
 
-       sqlite3_free_table(result);
+       return fcntl(fd, F_SETLK, &l);
+}
 
-       return PREFERENCE_ERROR_NONE;
+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;
 }
 
 
-int preference_set_int(const char *key, int value)
+static int _preference_set_read_lock(int fd)
 {
-       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);
+       return _preference_set_file_lock(fd, F_RDLCK);
 }
 
-int preference_get_int(const char *key, int *value)
+static int _preference_set_write_lock(int fd)
 {
-       char type[2];
-       char data[BUF_LEN];
-       int ret;
+       return _preference_set_file_lock(fd, F_WRLCK);
+}
 
-       if (value == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
-       }
+static int _preference_set_unlock(int fd)
+{
+       return _preference_set_file_lock(fd, F_UNLCK);
+}
 
-       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;
+static int _preference_check_retry_err(keynode_t *keynode, int preference_errno, int io_errno, int op_type)
+{
+       int is_busy_err = 0;
+
+       if (preference_errno == PREFERENCE_ERROR_FILE_OPEN)
+       {
+               switch (io_errno)
+               {
+                       case ENOENT :
+                       {
+                               if(op_type == PREFERENCE_OP_SET)
+                               {
+                                       int rc = 0;
+                                       char path[PREFERENCE_KEY_PATH_LEN] = {0,};
+                                       rc = _preference_get_key_path(keynode->keyname, path);
+                                       if (rc != PREFERENCE_ERROR_NONE) {
+                                               ERR("_preference_get_key_path error");
+                                               break;
+                                       }
+
+                                       rc = _preference_set_key_check_pref_dir();
+                                       if (rc != PREFERENCE_ERROR_NONE) {
+                                               ERR("_preference_set_key_check_pref_dir() failed.");
+                                               break;
+                                       }
+
+                                       preference_errno = _preference_set_key_creation(path);
+                                       if (rc != PREFERENCE_ERROR_NONE) {
+                                               ERR("_preference_set_key_creation error : %s", path);
+                                               break;
+                                       }
+                                       INFO("%s key is created", keynode->keyname);
+
+                                       is_busy_err = 1;
+                               }
+                               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;
+       }
 
-       return ret;
+       if (is_busy_err == 1) {
+               return 1;
+       }
+       else
+       {
+               ERR("key(%s), check retry err: %d/(%d/%s).",keynode->keyname, preference_errno, io_errno, strerror(io_errno));
+               return 0;
+       }
 }
 
-int preference_set_double(const char *key, double value)
+static int _preference_set_key_filesys(keynode_t *keynode, int *io_errno)
 {
-       char type[2];
-       char data[BUF_LEN];
-       snprintf(type, 2, "%d", PREFERENCE_TYPE_DOUBLE);
-       snprintf(data, BUF_LEN, "%f", value);
-       return _write_data(key, type, data);
-}
+       char path[PREFERENCE_KEY_PATH_LEN] = {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;
+
+retry_open :
+       errno = 0;
+       err_no = 0;
+       func_ret = PREFERENCE_ERROR_NONE;
+
+       ret = _preference_get_key_path(keynode->keyname, 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;
+       }
 
-int preference_get_double(const char *key, double *value)
-{
-       char type[2];
-       char data[BUF_LEN];
+retry :
+       errno = 0;
+       err_no = 0;
+       func_ret = PREFERENCE_ERROR_NONE;
+
+       ret = _preference_set_write_lock(fileno(fp));
+       if(ret == -1) {
+               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;
+       }
 
-       int ret;
+       /* write key type */
+       ret = fwrite((void *)&(keynode->type), sizeof(int), 1, fp);
+       if(ret <= 0)
+       {
+               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;
+       }
 
-       if (value == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+       /* 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;
+                       if (ftruncate(fileno(fp), ret) == -1) {
+                               is_write_error = 1;
+                       }
+                       break;
+               default :
+                       func_ret = PREFERENCE_ERROR_WRONG_TYPE;
+                       goto out_unlock;
+       }
+       if(is_write_error)
+       {
+               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;
        }
 
-       ret = _read_data(key, type, data);
-       if (ret == PREFERENCE_ERROR_NONE) {
-               if (atoi(type) == PREFERENCE_TYPE_DOUBLE)
-                       *value = atof(data);
-               else {
-                       LOGE("INVALID_PARAMETER(0x%08x) : param type(%d)",
-                                       PREFERENCE_ERROR_INVALID_PARAMETER, atoi(type));
-                       return PREFERENCE_ERROR_INVALID_PARAMETER;
+       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
+       {
+               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;
+       }
+
        return ret;
 }
 
-int preference_set_string(const char *key, const char *value)
+
+/*
+ * 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)
 {
-       char type[2];
+       START_TIME_CHECK
+
+       retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL");
+
+       int func_ret = PREFERENCE_ERROR_NONE;
 
-       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;
+       keynode_t* 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) {
+               _preference_keynode_free(pKeyNode);
+               ERR("set key name error");
+               return PREFERENCE_ERROR_IO_ERROR;
        }
-       return _write_data(key, type, value);
+       _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;
 }
 
-int preference_get_string(const char *key, char **value)
+/*
+* 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)
 {
-       char type[2];
-       char data[BUF_LEN];
+       START_TIME_CHECK
 
-       int ret;
+       retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL");
 
-       if (value == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+       int func_ret = PREFERENCE_ERROR_NONE;
+       keynode_t* 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) {
+               _preference_keynode_free(pKeyNode);
+               ERR("set key name error");
+               return PREFERENCE_ERROR_IO_ERROR;
        }
+       _preference_keynode_set_value_boolean(pKeyNode, boolval);
 
-       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;
-               }
+       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);
        }
 
-       return ret;
+       _preference_keynode_free(pKeyNode);
+
+       END_TIME_CHECK
+
+       return func_ret;
 }
 
-int preference_set_boolean(const char *key, bool value)
+/*
+ * 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)
 {
-       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);
+       START_TIME_CHECK
+
+       retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is NULL");
+
+       int func_ret = PREFERENCE_ERROR_NONE;
+       keynode_t* 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) {
+               _preference_keynode_free(pKeyNode);
+               ERR("set key name error");
+               return PREFERENCE_ERROR_IO_ERROR;
+       }
+       _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;
 }
 
-int preference_get_boolean(const char *key, bool *value)
+/*
+ * 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)
 {
-       char type[2];
-       char data[BUF_LEN];
+       START_TIME_CHECK
 
-       int ret;
+       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");
 
-       if (value == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+       int func_ret = PREFERENCE_ERROR_NONE;
+       keynode_t* 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) {
+               _preference_keynode_free(pKeyNode);
+               ERR("set key name error");
+               return PREFERENCE_ERROR_IO_ERROR;
        }
+       _preference_keynode_set_value_string(pKeyNode, strval);
 
-       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;
-               }
+       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);
        }
 
-       return ret;
-}
+       _preference_keynode_free(pKeyNode);
 
+       END_TIME_CHECK
 
-/* TODO: below operation is too heavy, let's find the light way to check. */
-int preference_is_existing(const char *key, bool *exist)
+       return func_ret;
+}
+
+static int _preference_get_key_filesys(keynode_t *keynode, int* io_errno)
 {
-       int ret;
-       char *buf;
-       char **result;
-       int rows;
-       int columns;
-       char *errmsg;
+       char path[PREFERENCE_KEY_PATH_LEN] = {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;
+
+retry_open :
+       errno = 0;
+       func_ret = PREFERENCE_ERROR_NONE;
+
+       ret = _preference_get_key_path(keynode->keyname, 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;
+       }
 
-       if (key == NULL  || key[0] == '\0'  || exist == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
+retry :
+       err_no = 0;
+       func_ret = PREFERENCE_ERROR_NONE;
+
+       ret = _preference_set_read_lock(fileno(fp));
+       if(ret == -1) {
+               func_ret = PREFERENCE_ERROR_FILE_LOCK;
+               err_no = errno;
+               goto out_return;
        }
 
-       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;
+
+       /* read data type */
+       read_size = fread((void*)&type, sizeof(int), 1, fp);
+       if((read_size <= 0) || (read_size > sizeof(int))) {
+               if(!ferror(fp)) {
+                       LOGW("number of read items for type is 0 with false ferror. err : %d", errno);
+                       errno = ENODATA;
                }
+               err_no = errno;
+               func_ret = PREFERENCE_ERROR_FILE_FREAD;
+               goto out_unlock;
        }
 
-       /* 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);
+       /* read data value */
+       switch(type)
+       {
+               case PREFERENCE_TYPE_INT:
+               {
+                       int value_int = 0;
+                       int read_size = 0;
+                       read_size = fread((void*)&value_int, sizeof(int), 1, fp);
+                       if((read_size <= 0) || (read_size > sizeof(int))) {
+                               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;
+                       } else {
+                               _preference_keynode_set_value_int(keynode, value_int);
+                       }
 
-       if (buf == NULL) {
-               LOGE("IO_ERROR(0x%08x) : fail to create query string",
-                               PREFERENCE_ERROR_IO_ERROR);
-               return PREFERENCE_ERROR_IO_ERROR;
+                       break;
+               }
+               case PREFERENCE_TYPE_DOUBLE:
+               {
+                       double value_dbl = 0;
+                       int read_size = 0;
+                       read_size = fread((void*)&value_dbl, sizeof(double), 1, fp);
+                       if((read_size <= 0) || (read_size > sizeof(double))) {
+                               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;
+                       } else {
+                               _preference_keynode_set_value_double(keynode, value_dbl);
+                       }
+
+                       break;
+               }
+               case PREFERENCE_TYPE_BOOLEAN:
+               {
+                       int value_int = 0;
+                       int read_size = 0;
+                       read_size = fread((void*)&value_int, sizeof(int), 1, fp);
+                       if((read_size <= 0) || (read_size > sizeof(int))) {
+                               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;
+                       } else {
+                               _preference_keynode_set_value_boolean(keynode, value_int);
+                       }
+
+                       break;
+               }
+               case PREFERENCE_TYPE_STRING:
+               {
+                       char file_buf[BUF_LEN] = {0,};
+                       char *value = NULL;
+                       int value_size = 0;
+
+                       while(fgets(file_buf, sizeof(file_buf), fp))
+                       {
+                               if(value) {
+                                       value_size = value_size + strlen(file_buf);
+                                       value = (char *) realloc(value, value_size);
+                                       if(value == NULL) {
+                                               func_ret = PREFERENCE_ERROR_OUT_OF_MEMORY;
+                                               break;
+                                       }
+                                       strncat(value, file_buf, strlen(file_buf));
+                               } else {
+                                       value_size = strlen(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, strlen(file_buf));
+                               }
+                       }
+
+                       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;
        }
 
-       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;
+out_unlock :
+       ret = _preference_set_unlock(fileno(fp));
+       if(ret == -1) {
+               func_ret = PREFERENCE_ERROR_FILE_LOCK;
+               err_no = errno;
+               goto out_return;
        }
 
-       if (rows > 0)
-               *exist = true;
-       else
-               *exist = false;
 
-       sqlite3_free_table(result);
-       return PREFERENCE_ERROR_NONE;
-}
+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))
+               {
+                       if (retry_cnt < PREFERENCE_ERROR_RETRY_CNT)
+                       {
+                               WARN("_preference_get_key_filesys(%s) step(%d) failed(%d / %s) retry(%d)",
+                                       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_get_key_filesys(%s) step(%d) faild(%d / %s) over the retry count.",
+                                       keynode->keyname, func_ret, err_no, err_buf);
+                       }
+               }
+               else
+               {
+                       ERR("_preference_get_key_filesys(%s) step(%d) failed(%d / %s) retry(%d) ",
+                               keynode->keyname, func_ret, err_no, err_buf, retry_cnt);
+               }
+       } else {
+               if(retry_cnt > 0) {
+                       DBG("preference get filesys ok with retry cnt(%d)", retry_cnt);
+               }
+       }
 
-static pref_changed_cb_node_t *_find_node(const char *key)
-{
-       pref_changed_cb_node_t *tmp_node;
+       if (fp)
+               fclose(fp);
 
-       if (key == NULL || key[0] == '\0')
-               return NULL;
+       *io_errno = err_no;
 
-       tmp_node = head;
+       return func_ret;
+}
 
-       while (tmp_node) {
-               if (strcmp(tmp_node->key, key) == 0)
-                       break;
-               tmp_node = tmp_node->next;
+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 tmp_node;
+       return ret;
 }
 
 
-static int _add_node(const char *key, preference_changed_cb cb, void *user_data)
+/*
+ * 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)
 {
-       pref_changed_cb_node_t *tmp_node;
+       START_TIME_CHECK
 
-       if (key == NULL || key[0] == '\0' || cb == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
-       }
+       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");
+
+       int func_ret = PREFERENCE_ERROR_IO_ERROR;
+       keynode_t* pKeyNode = _preference_keynode_new();
+       retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail");
 
-       tmp_node = _find_node(key);
+       _preference_keynode_set_keyname(pKeyNode, key);
 
-       if (tmp_node != NULL) {
-               tmp_node->cb = cb;
-               tmp_node->user_data = user_data;
+       func_ret = _preference_get_key(pKeyNode);
+
+       if (func_ret != PREFERENCE_ERROR_NONE) {
+               ERR("preference_get_int(%d) : key(%s) error", getpid(), key);
        } 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;
+               *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;
                }
+       }
 
-               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;
-               }
+       _preference_keynode_free(pKeyNode);
 
-               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;
-       }
+       END_TIME_CHECK
 
-       return PREFERENCE_ERROR_NONE;
+       return func_ret;
 }
 
-static int _remove_node(const char *key)
+/*
+ * 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)
 {
-       pref_changed_cb_node_t *tmp_node;
+       START_TIME_CHECK
 
-       if (key == NULL || key[0] == '\0') {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
-       }
+       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");
 
-       tmp_node = _find_node(key);
+       int func_ret = PREFERENCE_ERROR_IO_ERROR;
+       keynode_t* pKeyNode = _preference_keynode_new();
+       retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail");
 
-       if (tmp_node == NULL)
-               return PREFERENCE_ERROR_NONE;
+       _preference_keynode_set_keyname(pKeyNode, key);
 
-       if (tmp_node->prev != NULL)
-               tmp_node->prev->next = tmp_node->next;
-       else
-               head = tmp_node->next;
+       func_ret = _preference_get_key(pKeyNode);
 
-       if (tmp_node->next != NULL)
-               tmp_node->next->prev = tmp_node->prev;
+       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;
+               }
+       }
 
-       if (tmp_node->key)
-               free(tmp_node->key);
+       _preference_keynode_free(pKeyNode);
 
-       free(tmp_node);
+       END_TIME_CHECK
 
-       return PREFERENCE_ERROR_NONE;
+       return func_ret;
 }
 
-
-static void _remove_all_node(void)
+/*
+ * 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)
 {
-       pref_changed_cb_node_t *tmp_node;
+       START_TIME_CHECK
 
-       while (head) {
-               tmp_node = head;
-               head = tmp_node->next;
+       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");
 
-               if (tmp_node->key)
-                       free(tmp_node->key);
+       int func_ret = PREFERENCE_ERROR_IO_ERROR;
+       keynode_t* pKeyNode = _preference_keynode_new();
+       retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail");
 
-               free(tmp_node);
+       _preference_keynode_set_keyname(pKeyNode, key);
+
+       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
 
-static void _update_cb(void *data, int action, char const *db_name,
-               char const *table_name, sqlite_int64 rowid)
+       return func_ret;
+}
+
+/*
+ * This function get the string value of given key
+ * @param[in]  key     key
+ * @return pointer of key value on success, NULL on error
+ */
+API int preference_get_string(const char *key, char **value)
 {
-       int ret;
-       char *buf;
-       char **result;
-       int rows;
-       int columns;
-       char *errmsg;
-       pref_changed_cb_node_t *tmp_node;
+       START_TIME_CHECK
 
-       if (action != SQLITE_UPDATE)
-               return;
+       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");
 
-       if (strcmp(table_name, PREF_TBL_NAME) != 0) {
-               SECURE_LOGE("given table name (%s) is not same", table_name);
-               return;
-       }
+       int func_ret = PREFERENCE_ERROR_IO_ERROR;
+       keynode_t* pKeyNode = _preference_keynode_new();
+       retvm_if(pKeyNode == NULL, PREFERENCE_ERROR_OUT_OF_MEMORY, "key malloc fail");
 
-       buf = sqlite3_mprintf("SELECT %s FROM %s WHERE rowid='%lld';",
-                       PREF_F_KEY_NAME, PREF_TBL_NAME, rowid);
-       if (buf == NULL)
-               return;
+       _preference_keynode_set_keyname(pKeyNode, key);
 
-       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;
-       }
+       char *tempstr = NULL;
+
+       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 (rows == 0) {
-               sqlite3_free_table(result);
-               return;
+               if(tempstr) {
+                       *value = strdup(tempstr);
+                       INFO("%s(%s) success", key, value);
+               }
        }
 
-       tmp_node = _find_node(result[1]);
+       _preference_keynode_free(pKeyNode);
 
-       if (tmp_node != NULL && tmp_node->cb != NULL)
-               tmp_node->cb(result[1], tmp_node->user_data);
+       END_TIME_CHECK
 
-       sqlite3_free_table(result);
+       return func_ret;
 }
 
-
-int preference_remove(const char *key)
+/*
+ * This function unset given key
+ * @param[in]  key     key
+ * @return 0 on success, -1 on error
+ */
+API int preference_remove(const char *key)
 {
-       int ret;
-       char buf[BUF_LEN];
-       bool exist;
-       sqlite3_stmt *stmt;
+       START_TIME_CHECK
 
-       ret = preference_is_existing(key, &exist);
-       if (ret != PREFERENCE_ERROR_NONE)
-               return ret;
+       char path[PREFERENCE_KEY_PATH_LEN] = {0,};
+       int ret = -1;
+       int err_retry = PREFERENCE_ERROR_RETRY_CNT;
+       int func_ret = PREFERENCE_ERROR_NONE;
 
-       if (!exist)
-               return PREFERENCE_ERROR_NO_KEY;
+       retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null");
+
+       ret = _preference_get_key_path(key, path);
+       retvm_if(ret != PREFERENCE_ERROR_NONE, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is not valid");
 
-       snprintf(buf, sizeof(buf), "DELETE FROM %s WHERE %s = ?",
-                       PREF_TBL_NAME, PREF_F_KEY_NAME);
+       retvm_if(access(path, F_OK) == -1, PREFERENCE_ERROR_NO_KEY, "Error : key(%s) is not exist", key);
 
-       ret = sqlite3_prepare(pref_db, buf, -1, &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));
+       do {
+               ret = remove(path);
+               if(ret == -1) {
+                       ERR("preference_remove() failed. ret=%d(%s), key(%s)", errno, strerror(errno), key);
+                       func_ret = PREFERENCE_ERROR_IO_ERROR;
+               } else {
+                       func_ret = PREFERENCE_ERROR_NONE;
+                       break;
+               }
+       } while(err_retry--);
+
+       END_TIME_CHECK
+
+       return func_ret;
+}
+
+API int preference_remove_all(void)
+{
+       START_TIME_CHECK
+
+       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;
+
+       pref_dir_path = _preference_get_pref_dir_path();
+       if (!pref_dir_path)
+       {
+               LOGE("_preference_get_pref_dir_path() failed.");
                return PREFERENCE_ERROR_IO_ERROR;
        }
 
-       ret = sqlite3_bind_text(stmt, 1, key, -1, 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);
+       dir = opendir(pref_dir_path);
+       if (dir == NULL)
+       {
+               LOGE("opendir() failed. pref_path: %s, error: %d(%s)", pref_dir_path, errno, strerror(errno));
                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;
+       while ((dent = readdir(dir)))
+       {
+               const char *entry = dent->d_name;
+               char keyname[PREFERENCE_KEY_PATH_LEN] = {0,};
+               char path[PREFERENCE_KEY_PATH_LEN] = {0,};
+
+               if (entry[0] == '.')
+               {
+                       continue;
+               }
+
+               ret = _preference_get_key_name(entry, keyname);
+               if (ret != PREFERENCE_ERROR_NONE)
+               {
+                       ERR("_preference_get_key_name() failed(%d)", ret);
+                       closedir(dir);
+                       return ret;
+               }
+
+               ret = preference_unset_changed_cb(keyname);
+               if (ret != PREFERENCE_ERROR_NONE)
+               {
+                       ERR("preference_unset_changed_cb() failed(%d)", ret);
+                       closedir(dir);
+                       return PREFERENCE_ERROR_IO_ERROR;
+               }
+
+               ret = _preference_get_key_path(keyname, path);
+               if (ret != PREFERENCE_ERROR_NONE)
+               {
+                       ERR("_preference_get_key_path() failed(%d)", ret);
+                       closedir(dir);
+                       return ret;
+               }
+
+       // delete
+               do {
+                       ret = remove(path);
+                       if(ret == -1) {
+                               ERR("preference_remove_all error: %d(%s)", errno, strerror(errno));
+                               func_ret = PREFERENCE_ERROR_IO_ERROR;
+                       } else {
+                               func_ret = PREFERENCE_ERROR_NONE;
+                               break;
+                       }
+               } while(err_retry--);
        }
 
-       sqlite3_finalize(stmt);
+       closedir(dir);
 
-        _remove_node(key);
+       END_TIME_CHECK
 
-       return PREFERENCE_ERROR_NONE;
+       return func_ret;
 }
 
-
-int preference_remove_all(void)
+int preference_is_existing(const char *key, bool *exist)
 {
-       int ret;
-       char *buf;
-       char *errmsg;
+       START_TIME_CHECK
 
-       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;
-               }
-       }
+       char path[PREFERENCE_KEY_PATH_LEN] = {0,};
+       int ret = -1;
+       int func_ret = PREFERENCE_ERROR_NONE;
 
-       /* 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;
-       }
+       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");
 
-       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;
+       ret = _preference_get_key_path(key, path);
+       retv_if(ret != PREFERENCE_ERROR_NONE, ret);
+
+       ret = access(path, F_OK);
+       if (ret == -1)
+       {
+               ERR("Error : key(%s) is not exist", key);
+               *exist = 0;
+       }
+       else
+       {
+               *exist = 1;
        }
 
-       _remove_all_node();
+       END_TIME_CHECK
 
-       return PREFERENCE_ERROR_NONE;
+       return func_ret;
 }
 
 
-int preference_set_changed_cb(const char *key,
-               preference_changed_cb callback, void *user_data)
+API int preference_set_changed_cb(const char *key, preference_changed_cb callback, void *user_data)
 {
-       int ret;
+       START_TIME_CHECK
+
+       int ret = -1;
        bool exist;
 
+       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);
+
        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);
+       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;
+       if (_preference_kdb_add_notify(key, callback, user_data)) {
+               if(errno != 0 && errno != ENOENT) {
+                       ERR("preference_notify_key_changed : key(%s) add notify fail", key);
+                       return PREFERENCE_ERROR_IO_ERROR;
+               }
        }
+       INFO("%s noti is added", key);
+
+       END_TIME_CHECK
 
-       return _add_node(key, callback, user_data);
+       return PREFERENCE_ERROR_NONE;
 }
 
-int preference_unset_changed_cb(const char *key)
+API int preference_unset_changed_cb(const char *key)
 {
-       int ret;
+       START_TIME_CHECK
+
+       int ret = -1;
        bool exist;
 
+       retvm_if(key == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is null");
+
        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);
+       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);
+       if (_preference_kdb_del_notify(key)) {
+               if (errno != 0 && errno != ENOENT) {
+                       ERR("preference_unset_changed_cb() failed: key(%s) error(%d/%s)", key, errno, strerror(errno));
+                       return PREFERENCE_ERROR_IO_ERROR;
+               }
+       }
+       INFO("%s noti removed", key);
+
+       END_TIME_CHECK
+
+       return PREFERENCE_ERROR_NONE;
 }
 
-int preference_foreach_item(preference_item_cb callback, void *user_data)
+
+API 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;
+       START_TIME_CHECK
 
-       if (callback == NULL) {
-               LOGE("INVALID_PARAMETER(0x%08x)",
-                               PREFERENCE_ERROR_INVALID_PARAMETER);
-               return PREFERENCE_ERROR_INVALID_PARAMETER;
-       }
+       retvm_if(callback == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: cb(%p)", callback);
 
-       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;
-               }
-       }
+       int ret = 0;
+       DIR *dir;
+       struct dirent *dent = NULL;
+       char *pref_dir_path = NULL;
 
-       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);
+       pref_dir_path = _preference_get_pref_dir_path();
+       if (!pref_dir_path)
+       {
+               LOGE("_preference_get_pref_dir_path() failed.");
                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);
+       dir = opendir(pref_dir_path);
+       if (dir == NULL)
+       {
+               LOGE("opendir() failed. path: %s, error: %d(%s)", pref_dir_path, errno, strerror(errno));
                return PREFERENCE_ERROR_IO_ERROR;
        }
 
-       for (i = 1; i <= rows; i++) {
-               if (callback(result[i], user_data) != true)
-                       break;
+       while((dent = readdir(dir)))
+       {
+               const char *entry = dent->d_name;
+               char keyname[PREFERENCE_KEY_PATH_LEN] = {0,};
+
+               if (entry[0] == '.')
+               {
+                       continue;
+               }
+
+               ret = _preference_get_key_name(entry, keyname);
+               retv_if(ret != PREFERENCE_ERROR_NONE, ret);
+
+               callback(keyname, user_data);
        }
 
-       sqlite3_free_table(result);
+       closedir(dir);
+       END_TIME_CHECK
 
        return PREFERENCE_ERROR_NONE;
 }
diff --git a/preference/preference_db.c b/preference/preference_db.c
new file mode 100755 (executable)
index 0000000..31e9e9f
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 2015 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;
+}
+
diff --git a/preference/preference_inoti.c b/preference/preference_inoti.c
new file mode 100755 (executable)
index 0000000..dbdea63
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2015 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;
+
+       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)
+                       {
+                               ERR("The memory is insufficient, errno: %d (%s)", errno, strerror(errno));
+                               free(n);
+                               break;
+                       }
+                       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;
+
+       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) {
+
+                               struct noti_node *t = NULL;
+                               GList *noti_list = NULL;
+
+                               noti_list = g_list_first(l_notilist);
+
+                               while (noti_list) {
+                                       t = noti_list->data;
+
+                                       keynode_t* keynode = _preference_keynode_new();
+                                       if (keynode == NULL) {
+                                               ERR("key malloc fail");
+                                               break;
+                                       }
+
+                                       if ( (t) && (t->wd == ie.wd) && (t->keyname) ) {
+                                               if ((ie.mask & IN_DELETE_SELF))
+                                               {
+                                                       res = _preference_kdb_del_notify(t->keyname);
+                                                       if (res != PREFERENCE_ERROR_NONE)
+                                                               ERR("_preference_kdb_del_notify() failed(%d)", res);
+                                               }
+                                               else
+                                               {
+                                                       res = _preference_keynode_set_keyname(keynode, t->keyname);
+                                                       if (res != PREFERENCE_ERROR_NONE) {
+                                                               ERR("_preference_keynode_set_keyname() failed(%d)", res);
+                                                               goto out_func;
+                                                       }
+
+                                                       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;
+
+       pthread_mutex_lock(&_kdb_inoti_fd_mutex);
+
+       if (0 < _kdb_inoti_fd) {
+               ERR("Error: invalid _kdb_inoti_fd");
+               pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
+               return PREFERENCE_ERROR_IO_ERROR;
+       }
+       _kdb_inoti_fd = inotify_init();
+       if (_kdb_inoti_fd == -1) {
+               char err_buf[100] = { 0, };
+               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;
+       }
+
+       ret = fcntl(_kdb_inoti_fd, F_SETFD, FD_CLOEXEC);
+       if (ret < 0) {
+               char err_buf[100] = { 0, };
+               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;
+       }
+
+       ret = fcntl(_kdb_inoti_fd, F_SETFL, O_NONBLOCK);
+       if (ret < 0) {
+               char err_buf[100] = { 0, };
+               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;
+       }
+
+       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(const char *keyname, preference_changed_cb cb, void *data)
+{
+       char path[PREFERENCE_KEY_PATH_LEN];
+       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;
+
+       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((char*)keyname, path);
+       retvm_if(ret != PREFERENCE_ERROR_NONE, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is not valid");
+
+       if (0 != access(path, F_OK)) {
+               if (errno == ENOENT) {
+                       ERR("_preference_kdb_add_notify : Key(%s) does not exist", keyname);
+                       return PREFERENCE_ERROR_IO_ERROR;
+               }
+       }
+
+       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) {
+               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;
+       }
+
+       n = calloc(1, sizeof(noti_node_s));
+       if (n == NULL) {
+               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;
+       }
+
+       n->keyname = strndup(keyname, PREFERENCE_KEY_PATH_LEN);
+       if (n->keyname == NULL)
+       {
+               ERR("The memory is insufficient, errno: %d (%s)", errno, strerror(errno));
+               free(n);
+               goto out_func;
+       }
+       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(const char *keyname)
+{
+       int wd = 0;
+       int r = 0;
+       struct noti_node *n = NULL;
+       struct noti_node t;
+       char path[PREFERENCE_KEY_PATH_LEN] = { 0, };
+       char err_buf[ERR_LEN] = { 0, };
+       int del = 0;
+       int ret = 0;
+       int func_ret = PREFERENCE_ERROR_NONE;
+       GList *noti_list;
+
+       retvm_if(keyname == NULL, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: keyname(%s)", keyname);
+       retvm_if(_kdb_inoti_fd == 0, PREFERENCE_ERROR_NONE, "Invalid operation: not exist anything for inotify");
+
+       ret = _preference_get_key_path((char*)keyname, path);
+       retvm_if(ret != PREFERENCE_ERROR_NONE, PREFERENCE_ERROR_INVALID_PARAMETER, "Invalid argument: key is not valid");
+
+       /* get wd */
+       wd = inotify_add_watch(_kdb_inoti_fd, path, INOTY_EVENT_MASK);
+       if (wd == -1) {
+               strerror_r(errno, err_buf, sizeof(err_buf));
+               ERR("Error: inotify_add_watch() [%s]: %s", path, err_buf);
+               return PREFERENCE_ERROR_IO_ERROR;
+       }
+
+       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_IO_ERROR;
+       }
+
+       return func_ret;
+}