Increase line coverage using LCOV_EXCL
[platform/core/system/libstorage.git] / src / storage-external.c
index 63d564a..65719d4 100755 (executable)
 #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"
 
-static dd_list *cb_list[STORAGE_CALLBACK_MAX];
+#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,
@@ -38,6 +44,9 @@ static int storage_ext_get_dev_state(storage_ext_device *dev,
                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;
@@ -55,37 +64,103 @@ static int storage_ext_get_dev_state(storage_ext_device *dev,
                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;
        }
@@ -95,18 +170,19 @@ int storage_ext_foreach_device_list(storage_device_supported_cb callback, void *
        return 0;
 }
 
-static int storage_ext_state_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
+//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;
-       dd_list *elem;
+       GList *elem;
        storage_state_e state;
        int ret;
 
        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);
@@ -115,46 +191,145 @@ static int storage_ext_state_changed(storage_ext_device *dev, enum storage_ext_s
                return ret;
        }
 
-       DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
+       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;
 }
 
-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;
+       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 < 0 || type >= STORAGE_CALLBACK_MAX)
+       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;
 
-       /* check if it is the first request */
-       n = DD_LIST_LENGTH(cb_list[type]);
+       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 = storage_ext_register_device_change(storage_ext_state_changed, (void *)type);
-               if (ret < 0)
+               ret_val = storage_ext_register_device_change(callback, (void *)type);
+               if (ret_val < 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) */
        cb_info = malloc(sizeof(struct storage_cb_info));
        if (!cb_info)
-               return -errno;
+               return -errno; //LCOV_EXCL_LINE
 
        memcpy(cb_info, info, sizeof(struct storage_cb_info));
-       DD_LIST_APPEND(cb_list[type], cb_info);
+       SYS_G_LIST_APPEND(cb_list[type], cb_info);
 
        return 0;
 }
@@ -162,61 +337,201 @@ int storage_ext_register_cb(enum storage_cb_type type, struct storage_cb_info *i
 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)) {
+               //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) */
-       DD_LIST_REMOVE(cb_list[type], cb_info);
-       free(cb_info);
+       if (cb_info) {
+               SYS_G_LIST_REMOVE(cb_list[type], cb_info);
+               free(cb_info);
+       }
 
        /* check if this callback is last element */
-       n = DD_LIST_LENGTH(cb_list[type]);
+       n = SYS_G_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;
 }
 
-int storage_ext_get_root(int storage_id, char *path, size_t len)
+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 || !path)
+       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
        }
 
-       snprintf(path, len, "%s", dev->mount_point);
-       ret = 0;
+       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;
+}