#endif
enum storage_cb_type {
- STORAGE_CALLBACK_STATE,
+ STORAGE_CALLBACK_ID,
+ STORAGE_CALLBACK_TYPE,
STORAGE_CALLBACK_MAX,
};
struct storage_cb_info {
int id;
+ storage_type_e type;
storage_state_changed_cb state_cb;
+ storage_changed_cb type_cb;
void *user_data;
};
/**
* @brief Gets the absolute path to the root directory of the given storage.
- * @details Files saved on the internal/external storage are readable or writeable by all applications.
- * When an application is uninstalled, the files written by that application are not removed from the internal/external storage.
- *
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
*
- * @remarks If you want to access files or directories in internal storage, you must declare http://tizen.org/privilege/mediastorage.\n
+ * @remarks Files saved on the internal/external storage are readable or writable by all applications.\n
+ * When an application is uninstalled, the files written by that application are not removed from the internal/external storage.\n
+ * If you want to access files or directories in internal storage, you must declare http://tizen.org/privilege/mediastorage.\n
* If you want to access files or directories in external storage, you must declare http://tizen.org/privilege/externalstorage.\n
* You must release @a path using free().
*
/**
* @brief Gets the absolute path to the each directory of the given storage.
- * @details Files saved on the internal/external storage are readable or writeable by all applications.
- * When an application is uninstalled, the files written by that application are not removed from the internal/external storage.
- *
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
*
- * @remarks The directory path may not exist, so you must make sure that it exists before using it.\n
+ * @remarks Files saved on the internal/external storage are readable or writable by all applications.\n
+ * When an application is uninstalled, the files written by that application are not removed from the internal/external storage.\n
+ * The directory path may not exist, so you must make sure that it exists before using it.\n
* If you want to access files or directories in internal storage except #STORAGE_DIRECTORY_SYSTEM_RINGTONES, you must declare http://tizen.org/privilege/mediastorage.\n
* If you want to access files or directories in #STORAGE_DIRECTORY_SYSTEM_RINGTONES, you must declare %http://tizen.org/privilege/systemsettings.\n
* If you want to access files or directories in external storage, you must declare http://tizen.org/privilege/externalstorage.\n
int storage_unset_state_changed_cb(int storage_id, storage_state_changed_cb callback);
/**
+ * @brief Enumeration of storage device types
+ * @since_tizen 3.0
+ */
+typedef enum {
+ STORAGE_DEV_EXT_SDCARD = 1001, /**< sdcard device (external storage) */
+ STORAGE_DEV_EXT_USB_MASS_STORAGE, /**< USB storage device (external storage) */
+} storage_dev_e;
+
+/**
+ * @brief Called when the state of a storage type changes.
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] storage_id The unique storage ID
+ * @param[in] type The type of the storage device
+ * @param[in] state The state of the storage
+ * @param[in] fstype The type of the file system
+ * @param[in] fsuuid The uuid of the file system
+ * @param[in] mountpath The mount path of the file system
+ * @param[in] primary The primary partition
+ * @param[in] flags The flags for the storage status
+ * @param[in] user_data The user data
+ *
+ * @pre storage_set_changed_cb() will invoke this callback function.
+ * @see storage_set_changed_cb()
+ * @see storage_unset_changed_cb()
+ */
+typedef void (*storage_changed_cb)(int storage_id,
+ storage_dev_e dev, storage_state_e state,
+ const char *fstype, const char *fsuuid, const char *mountpath,
+ bool primary, int flags, void *user_data);
+
+/**
+ * @brief Registers a callback function to be invoked when the state of the specified storage device type changes.
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] type The type of the storage device
+ * @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 #STORAGE_ERROR_NONE Successful
+ * @retval #STORAGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #STORAGE_ERROR_NOT_SUPPORTED Storage not supported
+ * @retval #STORAGE_ERROR_OPERATION_FAILED Operation failed
+ *
+ * @post storage_changed_cb() will be invoked if the state of the registered storage type changes.
+ * @see storage_changed_cb()
+ * @see storage_unset_changed_cb()
+ */
+int storage_set_changed_cb(storage_type_e type, storage_changed_cb callback, void *user_data);
+
+/**
+ * @brief Unregisters the callback function for storage type state changes.
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] type The type of the the storage device
+ * @param[in] callback The callback function to unregister
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ *
+ * @retval #STORAGE_ERROR_NONE Successful
+ * @retval #STORAGE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #STORAGE_ERROR_NOT_SUPPORTED Storage not supported
+ * @retval #STORAGE_ERROR_OPERATION_FAILED Operation failed
+ *
+ * @see storage_changed_cb()
+ * @see storage_set_changed_cb()
+ */
+int storage_unset_changed_cb(storage_type_e type, storage_changed_cb callback);
+
+/**
* @brief Gets the total space of the given storage in bytes.
*
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
#define STORAGE_EXT_GET_LIST "GetDeviceList"
-#define STORAGE_EXT_OBJECT_ADDED "ObjectAdded"
-#define STORAGE_EXT_OBJECT_REMOVED "ObjectRemoved"
#define STORAGE_EXT_DEVICE_CHANGED "DeviceChanged"
+#define STORAGE_EXT_DEVICE_ADDED "DeviceAdded"
+#define STORAGE_EXT_DEVICE_REMOVED "DeviceRemoved"
#define DBUS_REPLY_TIMEOUT (-1)
-#define DEV_PREFIX "/dev/"
-
struct storage_ext_callback {
storage_ext_changed_cb func;
void *data;
guint block_id;
- guint blockmanager_id;
};
static dd_list *changed_list;
}
//LCOV_EXCL_START Not called Callback
-static char *get_devnode_from_path(char *path)
-{
- if (!path)
- return NULL;
- /* 1 means '/' */
- return path + strlen(STORAGE_EXT_PATH_DEVICES) + 1;
-}
-//LCOV_EXCL_STOP
-
-//LCOV_EXCL_START Not called Callback
-static void storage_ext_object_path_changed(enum storage_ext_state state,
- GVariant *params, gpointer user_data)
-{
- storage_ext_device *dev = NULL;
- dd_list *elem;
- struct storage_ext_callback *callback;
- char *path = NULL;
- char *devnode;
- int ret;
-
- if (!params)
- return;
-
- g_variant_get(params, "(s)", &path);
-
- devnode = get_devnode_from_path(path);
- if (!devnode)
- goto out;
-
- dev = calloc(1, sizeof(storage_ext_device));
- if (!dev)
- goto out;
-
- dev->devnode = strdup(devnode);
- if (dev->devnode == NULL) {
- _E("strdup() failed");
- goto out;
- }
-
- DD_LIST_FOREACH(changed_list, elem, callback) {
- if (!callback->func)
- continue;
- ret = callback->func(dev, state, callback->data);
- if (ret < 0)
- _E("Failed to call callback for devnode(%s, %d)", devnode, ret);
- }
-
-out:
- if (dev) {
- free(dev->devnode);
- free(dev);
- }
- free(path);
-}
-//LCOV_EXCL_STOP
-
-//LCOV_EXCL_START Not called Callback
-static void storage_ext_device_added(GVariant *params, gpointer user_data)
-{
- storage_ext_object_path_changed(STORAGE_EXT_ADDED, params, user_data);
-}
-//LCOV_EXCL_STOP
-
-//LCOV_EXCL_START Not called Callback
-static void storage_ext_device_removed(GVariant *params, gpointer user_data)
-{
- storage_ext_object_path_changed(STORAGE_EXT_REMOVED, params, user_data);
-}
-//LCOV_EXCL_STOP
-
-//LCOV_EXCL_START Not called Callback
-static void storage_ext_device_changed(GVariant *params, gpointer user_data)
+static void storage_ext_device_changed(GVariant *params, enum storage_ext_state state, gpointer user_data)
{
storage_ext_device *dev;
dd_list *elem;
DD_LIST_FOREACH(changed_list, elem, callback) {
if (!callback->func)
continue;
- ret = callback->func(dev, STORAGE_EXT_CHANGED, callback->data);
+ ret = callback->func(dev, state, callback->data);
if (ret < 0)
_E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret);
}
gpointer user_data)
{
size_t iface_len, signal_len;
+ enum storage_ext_state state;
if (!params || !sender || !path || !iface || !signal)
return;
iface_len = strlen(iface) + 1;
signal_len = strlen(signal) + 1;
- if (!strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len)) {
- if (!strncmp(signal, STORAGE_EXT_OBJECT_ADDED, signal_len))
- storage_ext_device_added(params, user_data);
- else if (!strncmp(signal, STORAGE_EXT_OBJECT_REMOVED, signal_len))
- storage_ext_device_removed(params, user_data);
+ if (strncmp(iface, STORAGE_EXT_IFACE, iface_len))
return;
- }
- if (!strncmp(iface, STORAGE_EXT_IFACE, iface_len) &&
- !strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len)) {
- storage_ext_device_changed(params, user_data);
+ if (!strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len))
+ state = STORAGE_EXT_CHANGED;
+
+ else if (!strncmp(signal, STORAGE_EXT_DEVICE_ADDED, signal_len))
+ state = STORAGE_EXT_ADDED;
+
+ else if (!strncmp(signal, STORAGE_EXT_DEVICE_REMOVED, signal_len))
+ state = STORAGE_EXT_REMOVED;
+
+ else
return;
- }
+
+ storage_ext_device_changed(params, state, user_data);
}
//LCOV_EXCL_STOP
int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
{
GDBusConnection *conn;
- guint block_id = NULL, blockmanager_id = NULL;
+ guint block_id = 0;
struct storage_ext_callback *callback;
dd_list *elem;
DD_LIST_FOREACH(changed_list, elem, callback) {
if (callback->func != func)
continue;
- if (callback->block_id == 0 || callback->blockmanager_id == 0)
+ if (callback->block_id == 0)
continue;
return -EEXIST;
block_id = g_dbus_connection_signal_subscribe(conn,
STORAGE_EXT_BUS_NAME,
STORAGE_EXT_IFACE,
- STORAGE_EXT_DEVICE_CHANGED,
NULL,
NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- storage_ext_changed,
- NULL,
- NULL);
- if (block_id == 0) {
- free(callback);
- _E("Failed to subscrive bus signal");
- return -EPERM;
- }
-
- blockmanager_id = g_dbus_connection_signal_subscribe(conn,
- STORAGE_EXT_BUS_NAME,
- STORAGE_EXT_IFACE_MANAGER,
- NULL,
- STORAGE_EXT_PATH_MANAGER,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
storage_ext_changed,
NULL,
NULL);
- if (blockmanager_id == 0) {
-//LCOV_EXCL_START System Error
+ if (block_id == 0) {
free(callback);
_E("Failed to subscrive bus signal");
return -EPERM;
-//LCOV_EXCL_STOP
}
callback->func = func;
callback->data = data;
callback->block_id = block_id;
- callback->blockmanager_id = blockmanager_id;
DD_LIST_APPEND(changed_list, callback);
continue;
if (callback->block_id > 0)
g_dbus_connection_signal_unsubscribe(conn, callback->block_id);
- if (callback->blockmanager_id > 0)
- g_dbus_connection_signal_unsubscribe(conn, callback->blockmanager_id);
DD_LIST_REMOVE(changed_list, callback);
free(callback);
return -EINVAL;
switch (blk_state) {
+ case STORAGE_EXT_ADDED:
+ *state = STORAGE_STATE_UNMOUNTABLE;
+ return 0;
case STORAGE_EXT_REMOVED:
*state = STORAGE_STATE_REMOVED;
return 0;
}
//LCOV_EXCL_START Not called Callback
-static int storage_ext_state_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
+static int storage_ext_id_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
{
enum storage_cb_type type = (enum storage_cb_type)data;
struct storage_cb_info *cb_info;
if (!dev)
return -EINVAL;
- if (type != STORAGE_CALLBACK_STATE)
+ if (type != STORAGE_CALLBACK_ID)
return 0;
ret = storage_ext_get_dev_state(dev, blk_state, &state);
return ret;
}
- DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
+ DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_ID], elem, cb_info)
cb_info->state_cb(cb_info->id, state, cb_info->user_data);
return 0;
}
-//LCOV_EXCL_STOP
-int storage_ext_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
+static int storage_ext_type_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
{
+ enum storage_cb_type type = (enum storage_cb_type)data;
struct storage_cb_info *cb_info;
dd_list *elem;
- int ret, n;
+ storage_state_e state;
+ int ret;
+ storage_dev_e strdev;
+ const char *fstype, *fsuuid, *mountpath;
+
+ if (!dev)
+ return -EINVAL;
- if (type < 0 || type >= STORAGE_CALLBACK_MAX)
+ if (type != STORAGE_CALLBACK_TYPE)
return -EINVAL;
+ ret = storage_ext_get_dev_state(dev, blk_state, &state);
+ if (ret < 0) {
+ _E("Failed to get storage state (devnode:%s, ret:%d)", dev->devnode, ret);
+ return ret;
+ }
+
+ if (dev->type == STORAGE_EXT_SCSI)
+ strdev = STORAGE_DEV_EXT_USB_MASS_STORAGE;
+ else if (dev->type == STORAGE_EXT_MMC)
+ strdev = STORAGE_DEV_EXT_SDCARD;
+ else {
+ _E("Invalid dev type (%d)", dev->type);
+ return -EINVAL;
+ }
+
+ fstype = (dev->fs_type ? (const char *)dev->fs_type : "");
+ fsuuid = (dev->fs_uuid ? (const char *)dev->fs_uuid : "");
+ mountpath = (dev->mount_point ? (const char *)dev->mount_point : "");
+
+ DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_TYPE], elem, cb_info)
+ if (cb_info->type_cb)
+ cb_info->type_cb(dev->storage_id, strdev, state,
+ fstype, fsuuid, mountpath, dev->primary,
+ dev->flags, cb_info->user_data);
+
+ return 0;
+}
+
+//LCOV_EXCL_STOP
+
+static bool check_if_callback_exist(enum storage_cb_type type,
+ struct storage_cb_info *info, struct storage_cb_info **cb_data)
+{
+ struct storage_cb_info *cb_info;
+ dd_list *elem;
+
if (!info)
+ return false;
+
+ if (type == STORAGE_CALLBACK_ID) {
+ DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
+ if (cb_info->id == info->id &&
+ cb_info->state_cb == info->state_cb) {
+ goto out;
+ }
+ }
+ }
+
+ if (type == STORAGE_CALLBACK_TYPE) {
+ DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
+ if (cb_info->type == info->type &&
+ cb_info->type_cb == info->type_cb)
+ goto out;
+ }
+ }
+
+ return false;
+
+out:
+ if (cb_data)
+ *cb_data = cb_info;
+
+ return true;
+}
+
+int storage_ext_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
+{
+ struct storage_cb_info *cb_info;
+ int n, ret;
+ storage_ext_changed_cb callback;
+
+ if (!info)
+ return -EINVAL;
+
+ switch (type) {
+ case STORAGE_CALLBACK_ID:
+ callback = storage_ext_id_changed;
+ break;
+ case STORAGE_CALLBACK_TYPE:
+ callback = storage_ext_type_changed;
+ break;
+ default:
+ _E("Invalid callback type (%d)", type);
return -EINVAL;
+ }
- /* check if it is the first request */
n = DD_LIST_LENGTH(cb_list[type]);
if (n == 0) {
- ret = storage_ext_register_device_change(storage_ext_state_changed, (void *)type);
+ ret = storage_ext_register_device_change(callback, (void *)type);
if (ret < 0)
return -EPERM;
}
- /* check for the same request */
- DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
- if (cb_info->id == info->id &&
- cb_info->state_cb == info->state_cb)
- return -EEXIST;
+ if (check_if_callback_exist(type, info, NULL)) {
+ _E("The callback is already registered");
+ return 0;
}
/* add device changed callback to list (local) */
int storage_ext_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
{
struct storage_cb_info *cb_info;
- dd_list *elem;
int n;
-
- if (type < 0 || type >= STORAGE_CALLBACK_MAX)
- return -EINVAL;
+ storage_ext_changed_cb callback;
if (!info)
return -EINVAL;
- /* search for the same element with callback */
- DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
- if (cb_info->id == info->id &&
- cb_info->state_cb == info->state_cb)
- break;
+ switch (type) {
+ case STORAGE_CALLBACK_ID:
+ callback = storage_ext_id_changed;
+ break;
+ case STORAGE_CALLBACK_TYPE:
+ callback = storage_ext_type_changed;
+ break;
+ default:
+ _E("Invalid callback type (%d)", type);
+ return -EINVAL;
}
- if (!cb_info)
- return -EINVAL;
+ if (!check_if_callback_exist(type, info, &cb_info)) {
+ _E("The callback is not registered");
+ return 0;
+ }
/* remove device callback from list (local) */
- DD_LIST_REMOVE(cb_list[type], cb_info);
- free(cb_info);
+ if (cb_info) {
+ DD_LIST_REMOVE(cb_list[type], cb_info);
+ free(cb_info);
+ }
/* check if this callback is last element */
n = DD_LIST_LENGTH(cb_list[type]);
if (n == 0)
- storage_ext_unregister_device_change(storage_ext_state_changed);
+ storage_ext_unregister_device_change(callback);
return 0;
}
info.state_cb = callback;
info.user_data = user_data;
- ret = storage_ext_register_cb(STORAGE_CALLBACK_STATE, &info);
+ ret = storage_ext_register_cb(STORAGE_CALLBACK_ID, &info);
if (ret < 0) {
_E("Failed to register callback : id(%d)", storage_id); //LCOV_EXCL_LINE
return STORAGE_ERROR_OPERATION_FAILED;
info.id = storage_id;
info.state_cb = callback;
- ret = storage_ext_unregister_cb(STORAGE_CALLBACK_STATE, &info);
+ ret = storage_ext_unregister_cb(STORAGE_CALLBACK_ID, &info);
if (ret < 0) {
_E("Failed to unregister callback : id(%d)", storage_id); //LCOV_EXCL_LINE
return STORAGE_ERROR_OPERATION_FAILED;
*bytes = avail;
return STORAGE_ERROR_NONE;
}
+
+API int storage_set_changed_cb(storage_type_e type, storage_changed_cb callback, void *user_data)
+{
+ int ret;
+ struct storage_cb_info info;
+
+ if (type == STORAGE_TYPE_INTERNAL) {
+ _E("Internal storage is not supported");
+ return STORAGE_ERROR_NOT_SUPPORTED;
+ }
+
+ if (type != STORAGE_TYPE_EXTERNAL) {
+ _E("Invalid type (%d)", type);
+ return STORAGE_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!callback) {
+ _E("Callback is NULL");
+ return STORAGE_ERROR_INVALID_PARAMETER;
+ }
+
+ /* external storage */
+ info.type = type;
+ info.type_cb = callback;
+ info.user_data = user_data;
+
+ ret = storage_ext_register_cb(STORAGE_CALLBACK_TYPE, &info);
+ if (ret < 0) {
+ _E("Failed to register storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
+ return STORAGE_ERROR_OPERATION_FAILED;
+ }
+
+ return STORAGE_ERROR_NONE;
+}
+
+API int storage_unset_changed_cb(storage_type_e type, storage_changed_cb callback)
+{
+ struct storage_cb_info info;
+ int ret;
+
+ if (type == STORAGE_TYPE_INTERNAL) {
+ _E("Internal storage is not supported");
+ return STORAGE_ERROR_NOT_SUPPORTED;
+ }
+
+ if (type != STORAGE_TYPE_EXTERNAL) {
+ _E("Invalid type (%d)", type);
+ return STORAGE_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!callback) {
+ _E("Callback is NULL");
+ return STORAGE_ERROR_INVALID_PARAMETER;
+ }
+
+ /* external storage */
+ info.type = type;
+ info.type_cb = callback;
+
+ ret = storage_ext_unregister_cb(STORAGE_CALLBACK_TYPE, &info);
+ if (ret < 0) {
+ _E("Failed to unregister storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
+ return STORAGE_ERROR_OPERATION_FAILED;
+ }
+
+ return STORAGE_ERROR_NONE;
+}