#include <sys/statvfs.h>
#include <vconf.h>
#include <tzplatform_config.h>
+#include <libsyscommon/list.h>
#include "common.h"
-#include "list.h"
#include "log.h"
#include "storage-external-dbus.h"
+#define EXTERNAL_STORAGE_PATH "/run/storaged/external-storage"
+#define EXTENDED_INTERNAL_PATH "/run/storaged/extended-internal-sd"
+#define PATH_LEN 55
+
+#define LUKS_NAME "crypto_LUKS"
+
+static GList *cb_list[STORAGE_CALLBACK_MAX];
+
static int storage_ext_get_dev_state(storage_ext_device *dev,
enum storage_ext_state blk_state,
storage_state_e *state)
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;
default:
return -EINVAL;
}
+ case STORAGE_EXT_BLOCKED:
+ *state = STORAGE_STATE_UNMOUNTABLE;
+ return 0;
default:
return -EINVAL;
}
}
-int storage_ext_foreach_device_list(storage_device_supported_cb callback, void *user_data)
+int storage_ext_get_space(int storage_id,
+ unsigned long long *total, unsigned long long *available)
{
+ storage_state_e state;
+ struct statvfs s;
int ret;
+ unsigned long long t = 0, a = 0;
+ storage_ext_device *dev;
+
+ if (storage_id < 0)
+ return -ENODEV;
+
+ dev = calloc(1, sizeof(storage_ext_device));
+ if (!dev) {
+//LCOV_EXCL_START System Error
+ _E("calloc failed");
+ return -ENOMEM;
+//LCOV_EXCL_STOP
+ }
+
+ ret = storage_ext_get_device_info(storage_id, dev);
+ if (ret < 0) {
+ _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
+ goto out; //LCOV_EXCL_LINE
+ }
+
+ ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
+ if (ret < 0) {
+ _E("Failed to get state of storage (id:%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
+ goto out; //LCOV_EXCL_LINE
+ }
+
+ if (state >= STORAGE_STATE_MOUNTED) {
+#ifdef __USE_FILE_OFFSET64
+ ret = storage_get_external_memory_size64_with_path(dev->mount_point, &s);
+#else
+ ret = storage_get_external_memory_size_with_path(dev->mount_point, &s);
+#endif
+ if (ret < 0) {
+ _E("Failed to get external memory size of (%s)(ret:%d)", dev->mount_point, ret); //LCOV_EXCL_LINE
+ goto out; //LCOV_EXCL_LINE
+ }
+
+ t = (unsigned long long)s.f_frsize*s.f_blocks;
+ a = (unsigned long long)s.f_bsize*s.f_bavail;
+ }
+
+ if (total)
+ *total = t;
+ if (available)
+ *available = a;
+
+ ret = 0;
+out:
+ storage_ext_release_device(&dev);
+ return ret;
+}
+
+int storage_ext_foreach_device_list(storage_device_supported_cb callback, void *user_data)
+{
+ int ret_val;
bool ret_cb;
- dd_list *list = NULL, *elem;
+ GList *list = NULL, *elem;
storage_ext_device *dev;
storage_state_e state;
if (!callback)
return -EINVAL;
- ret = storage_ext_get_list(&list);
- if (ret < 0) {
- _E("Failed to get external storage list from deviced (%d)", errno);
- return ret;
+ ret_val = storage_ext_get_list(&list);
+ if (ret_val < 0) {
+ _E("Failed to get external storage list from deviced (%d)", errno); //LCOV_EXCL_LINE
+ return ret_val; //LCOV_EXCL_LINE
}
- DD_LIST_FOREACH(list, elem, dev) {
- ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
- if (ret < 0) {
- _E("Failed to get storage state (devnode:%s, ret:%d)", dev->devnode, ret);
- continue;
+ SYS_G_LIST_FOREACH(list, elem, dev) {
+ ret_val = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
+ if (ret_val < 0) {
+ _E("Failed to get storage state (devnode:%s, ret_val:%d)", dev->devnode, ret_val); //LCOV_EXCL_LINE
+ continue; //LCOV_EXCL_LINE
}
- ret_cb = callback(dev->storage_id, STORAGE_TYPE_EXTERNAL,
- state, dev->mount_point, user_data);
+ if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL)
+ ret_cb = callback(dev->storage_id,
+ STORAGE_TYPE_EXTENDED_INTERNAL,
+ state, dev->mount_point, user_data);
+ else
+ ret_cb = callback(dev->storage_id, STORAGE_TYPE_EXTERNAL,
+ state, dev->mount_point, user_data);
if (!ret_cb)
break;
}
if (list)
storage_ext_release_list(&list);
return 0;
-}
\ No newline at end of file
+}
+
+//LCOV_EXCL_START Not called Callback
+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;
+ GList *elem;
+ storage_state_e state;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (type != STORAGE_CALLBACK_ID)
+ return 0;
+
+ 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;
+ }
+
+ SYS_G_LIST_FOREACH(cb_list[STORAGE_CALLBACK_ID], elem, cb_info)
+ cb_info->state_cb(cb_info->id, state, cb_info->user_data);
+
+ return 0;
+}
+
+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;
+ GList *elem;
+ storage_state_e state;
+ int ret_val;
+ storage_dev_e strdev;
+ storage_type_e storage_type;
+ const char *fstype, *fsuuid, *mountpath;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (type != STORAGE_CALLBACK_TYPE)
+ return -EINVAL;
+
+ ret_val = storage_ext_get_dev_state(dev, blk_state, &state);
+ if (ret_val < 0) {
+ _E("Failed to get storage state (devnode:%s, ret_val:%d)", dev->devnode, ret_val);
+ return ret_val;
+ }
+
+ if (dev->type == STORAGE_EXT_SCSI) {
+ strdev = STORAGE_DEV_EXT_USB_MASS_STORAGE;
+ storage_type = STORAGE_TYPE_EXTERNAL;
+ } else if (dev->type == STORAGE_EXT_MMC) {
+ strdev = STORAGE_DEV_EXT_SDCARD;
+ storage_type = STORAGE_TYPE_EXTERNAL;
+ } else if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL) {
+ strdev = STORAGE_DEV_EXTENDED_INTERNAL;
+ storage_type = STORAGE_TYPE_EXTENDED_INTERNAL;
+ } 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 : "");
+
+ if (!strncmp(fstype, LUKS_NAME, strlen(LUKS_NAME)))
+ storage_type = STORAGE_TYPE_EXTENDED_INTERNAL;
+
+ SYS_G_LIST_FOREACH(cb_list[STORAGE_CALLBACK_TYPE], elem, cb_info) {
+ if (cb_info->type != storage_type)
+ continue;
+ 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;
+ GList *elem;
+
+ if (!info)
+ return false;
+
+ if (type == STORAGE_CALLBACK_ID) {
+ SYS_G_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) {
+ SYS_G_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_val;
+ 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;
+ }
+
+ n = SYS_G_LIST_LENGTH(cb_list[type]);
+ if (n == 0) {
+ ret_val = storage_ext_register_device_change(callback, (void *)type);
+ if (ret_val < 0)
+ return -EPERM;
+ }
+
+ if (check_if_callback_exist(type, info, NULL)) {
+ _E("The callback is already registered");
+ return 0;
+ }
+
+ /* add device changed callback to list (local) */
+ cb_info = malloc(sizeof(struct storage_cb_info));
+ if (!cb_info)
+ return -errno; //LCOV_EXCL_LINE
+
+ memcpy(cb_info, info, sizeof(struct storage_cb_info));
+ SYS_G_LIST_APPEND(cb_list[type], cb_info);
+
+ return 0;
+}
+
+int storage_ext_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
+{
+ struct storage_cb_info *cb_info;
+ int n;
+ 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;
+ }
+
+ if (!check_if_callback_exist(type, info, &cb_info)) {
+ //LCOV_EXCL_START Callbacked is not registered case
+ _E("The callback is not registered");
+ return 0;
+ //LCOV_EXCL_STOP
+ }
+
+ /* remove device callback from list (local) */
+ if (cb_info) {
+ SYS_G_LIST_REMOVE(cb_list[type], cb_info);
+ free(cb_info);
+ }
+
+ /* check if this callback is last element */
+ n = SYS_G_LIST_LENGTH(cb_list[type]);
+ if (n == 0)
+ storage_ext_unregister_device_change(callback);
+
+ return 0;
+}
+
+int storage_ext_get_root(int storage_id, char *path, size_t len, bool *extendedinternal)
+{
+ FILE *fp;
+ storage_ext_device *dev;
+ char file_name[PATH_LEN];
+ char file_name2[PATH_LEN];
+ char *tmp;
+ int ret = 0;
+
+ if (storage_id < 0)
+ return -ENODEV;
+
+ if (!path)
+ return -EINVAL;
+ if (!extendedinternal)
+ return -EINVAL;
+
+ snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", storage_id);
+ snprintf(file_name2, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", storage_id);
+
+ *extendedinternal = false;
+
+ if (access(file_name, R_OK) == 0) {
+ fp = fopen(file_name, "r");
+ if (!fp) {
+ //LCOV_EXCL_START File operation error
+ _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret);
+ ret = -ENODEV;
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+
+ tmp = fgets(path, len, fp);
+ fclose(fp);
+ if (!tmp) {
+ //LCOV_EXCL_START File operation error
+ ret = -ENODEV;
+ _D("Failed to get path");
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+ *extendedinternal = false;
+ } else if (access(file_name2, R_OK) == 0) {
+ fp = fopen(file_name2, "r");
+ if (!fp) {
+ //LCOV_EXCL_START File operation error
+ _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret);
+ ret = -ENODEV;
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+
+ tmp = fgets(path, len, fp);
+ fclose(fp);
+ if (!tmp) {
+ //LCOV_EXCL_START File operation error
+ ret = -ENODEV;
+ _D("Failed to get path");
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+ *extendedinternal = true;
+ } else {
+ dev = calloc(1, sizeof(storage_ext_device));
+ if (!dev) {
+//LCOV_EXCL_START System Error
+ _E("calloc failed");
+ return -ENOMEM;
+//LCOV_EXCL_STOP
+ }
+
+ ret = storage_ext_get_device_info(storage_id, dev);
+ if (ret < 0) {
+ //LCOV_EXCL_START
+ _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret);
+ storage_ext_release_device(&dev);
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+
+ snprintf(path, len, "%s", dev->mount_point);
+ if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL)
+ *extendedinternal = true;
+ else
+ *extendedinternal = false;
+ storage_ext_release_device(&dev);
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+int storage_ext_get_state(int storage_id, storage_state_e *state)
+{
+ storage_ext_device *dev;
+ int ret;
+
+ if (storage_id < 0)
+ return -ENODEV;
+
+ if (!state)
+ return -EINVAL;
+
+ dev = calloc(1, sizeof(storage_ext_device));
+ if (!dev) {
+//LCOV_EXCL_START System Error
+ _E("calloc failed");
+ return -ENOMEM;
+//LCOV_EXCL_STOP
+ }
+
+ ret = storage_ext_get_device_info(storage_id, dev);
+ if (ret < 0) {
+ //LCOV_EXCL_START
+ _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret);
+ goto out;
+ //LCOV_EXCL_STOP
+ }
+
+ ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, state);
+ if (ret < 0)
+ _E("Failed to get state of storage id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
+
+out:
+ storage_ext_release_device(&dev);
+ return ret;
+}
+
+int storage_ext_get_primary_mmc_path(char *path, size_t len)
+{
+ GList *list = NULL, *elem;
+ storage_ext_device *dev;
+ int ret;
+
+ ret = storage_ext_get_list(&list);
+ if (ret < 0) {
+ //LCOV_EXCL_START
+ _E("Failed to get external storage list from deviced (%d)", errno);
+ return ret;
+ //LCOV_EXCL_STOP
+ }
+
+ SYS_G_LIST_FOREACH(list, elem, dev) {
+ if (dev->primary) {
+ snprintf(path, len, "%s", dev->mount_point);
+ ret = 0;
+ goto out;
+ }
+ }
+
+ ret = -ENODEV;
+
+out:
+ if (list)
+ storage_ext_release_list(&list);
+ return ret;
+}