File Manager / src / model /

fs-manager.c

  1. /*
  2. * Copyright 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17.  
  18. #include "model/fs-manager.h"
  19. #include "model/fs-operation.h"
  20. #include "utils/config.h"
  21. #include "utils/model-utils.h"
  22. #include "utils/logger.h"
  23.  
  24. #include <storage.h>
  25. #include <stdbool.h>
  26.  
  27. enum {
  28. FM_CHECK_ARG_VALID = 0x0001,
  29. FM_CHECK_EXIST = 0x0002,
  30. FM_CHECK_PATH_VALID = 0x0004,
  31. FM_CHECK_PARENT_DIR_EXIST = 0x0008,
  32. FM_CHECK_DUPLICATED = 0x0010
  33. };
  34.  
  35. #define FM_COMP_RES_D1_LESS_D2 -1
  36. #define FM_COMP_RES_D1_GREATER_D2 1
  37. #define FM_COMP_RES_D1_EQUAL_D2 0
  38.  
  39. struct _fs_manager {
  40. Eina_Bool is_locked;
  41. fs_operation *operation;
  42. fs_manager_complete_cb_func user_cb_func;
  43. void *user_cb_data;
  44. };
  45.  
  46. static void _fs_manager_clear_data(fs_manager *manager);
  47. static Eina_Bool _fs_manager_check_path_valid(const char *path, int *ret);
  48. static Eina_Bool _fs_manager_check_parent_exists(const char *path, int *ret);
  49. static int _fs_manager_check_error(const char *fullpath, int check_option);
  50. static int _fs_manager_sort_by_name_cb(const void *d1, const void *d2);
  51. static int _fs_manager_is_mmc_supported(bool *supported);
  52. static int _fs_manager_generate_operation(fs_manager *manager,
  53. Eina_List *source_list,
  54. const char *dest_path,
  55. operation_type oper_type,
  56. fs_manager_complete_cb_func func,
  57. void *data);
  58.  
  59. static void _on_operation_completed(void *data);
  60.  
  61. fs_manager *fs_manager_create()
  62. {
  63. fs_manager *manager = calloc(1, sizeof(fs_manager));
  64. if (manager) {
  65. manager->is_locked = EINA_FALSE;
  66. }
  67.  
  68. return manager;
  69. }
  70.  
  71. void fs_manager_destroy(fs_manager *manager)
  72. {
  73. if (manager) {
  74. _fs_manager_clear_data(manager);
  75. free(manager);
  76. }
  77. }
  78.  
  79. int fs_manager_get_storage_list(fs_manager *manager, Eina_List **storage_list)
  80. {
  81. RETVM_IF(!manager, RESULT_TYPE_INVALID_ARG, "File manager is NULL");
  82.  
  83. char *buf = model_utils_get_phone_path();
  84. if (!buf) {
  85. dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] buf == NULL", __FILE__, __LINE__);
  86. return RESULT_TYPE_INVALID_PATH;
  87. }
  88.  
  89. if (manager->is_locked) {
  90. ERR("File manager is busy");
  91. free(buf);
  92. return RESULT_TYPE_BUSY;
  93. }
  94.  
  95. bool is_supported = false;
  96.  
  97. int res = _fs_manager_is_mmc_supported(&is_supported);
  98. if (res != RESULT_TYPE_OK) {
  99. free(buf);
  100. return res;
  101. }
  102.  
  103. if (is_supported) {
  104. storage_info *const pNode_internal = calloc(1, sizeof(node_info));
  105. pNode_internal->root_name = strdup(FM_MEMORY_LABEL);
  106. pNode_internal->root_path = strdup(FM_MEMORY_FOLDER);
  107. pNode_internal->type = STORAGE_TYPE_MMC;
  108.  
  109. *storage_list = eina_list_append(*storage_list, pNode_internal);
  110. }
  111.  
  112. storage_info *const pNode_device = calloc(1, sizeof(node_info));
  113. pNode_device->root_name = strdup(FM_PHONE_LABEL);
  114. pNode_device->root_path = strdup(buf);
  115. pNode_device->type = STORAGE_TYPE_PHONE;
  116.  
  117. *storage_list = eina_list_append(*storage_list, pNode_device);
  118.  
  119. *storage_list = eina_list_sort(*storage_list, eina_list_count(*storage_list), _fs_manager_sort_by_name_cb);
  120.  
  121. free(buf);
  122.  
  123. return RESULT_TYPE_OK;
  124. }
  125.  
  126. int fs_manager_get_file_list(fs_manager *manager, const char *dir_path, Eina_List **file_list)
  127. {
  128. RETVM_IF(!manager, RESULT_TYPE_INVALID_ARG, "File manager is NULL");
  129. RETVM_IF(!dir_path, RESULT_TYPE_INVALID_ARG, "Path is NULL");
  130. RETVM_IF(!file_list, RESULT_TYPE_INVALID_ARG, "File list is NULL");
  131.  
  132. if (manager->is_locked) {
  133. ERR("File manager is busy");
  134. return RESULT_TYPE_BUSY;
  135. }
  136.  
  137. int option = FM_CHECK_EXIST;
  138. int ret = _fs_manager_check_error(dir_path, option);
  139. if (ret != RESULT_TYPE_OK) {
  140. return ret;
  141. }
  142.  
  143. Eina_List *dirs = NULL;
  144. Eina_List *files = NULL;
  145. ret = model_utils_read_dir(dir_path, &dirs, &files);
  146. if (ret != RESULT_TYPE_OK) {
  147. ERR("Failed to read dir '%s'", dir_path);
  148. return ret;
  149. }
  150.  
  151. dirs = eina_list_sort(dirs, eina_list_count(dirs), _fs_manager_sort_by_name_cb);
  152.  
  153. files = eina_list_sort(files, eina_list_count(files), _fs_manager_sort_by_name_cb);
  154.  
  155. *file_list = eina_list_merge(dirs, files);
  156.  
  157. return RESULT_TYPE_OK;
  158. }
  159.  
  160. int fs_manager_copy_files(fs_manager *manager,
  161. Eina_List *source_list,
  162. const char *dest_path,
  163. fs_manager_complete_cb_func cb_func,
  164. void *cb_data)
  165. {
  166. return _fs_manager_generate_operation(manager,
  167. source_list,
  168. dest_path,
  169. OPERATION_TYPE_COPY,
  170. cb_func,
  171. cb_data);
  172. }
  173.  
  174. int fs_manager_move_files(fs_manager *manager,
  175. Eina_List *source_list,
  176. const char *dest_path,
  177. fs_manager_complete_cb_func cb_func,
  178. void *cb_data)
  179. {
  180. return _fs_manager_generate_operation(manager,
  181. source_list,
  182. dest_path,
  183. OPERATION_TYPE_MOVE,
  184. cb_func,
  185. cb_data);
  186. }
  187.  
  188. int fs_manager_delete_files(fs_manager *manager,
  189. Eina_List *source_list,
  190. fs_manager_complete_cb_func cb_func,
  191. void *cb_data)
  192. {
  193. return _fs_manager_generate_operation(manager,
  194. source_list,
  195. NULL,
  196. OPERATION_TYPE_DELETE,
  197. cb_func,
  198. cb_data);
  199. }
  200.  
  201. int fs_manager_create_folder(fs_manager *manager, const char *dir)
  202. {
  203. RETVM_IF(!manager, RESULT_TYPE_INVALID_ARG, "File manager is NULL");
  204. RETVM_IF(!dir, RESULT_TYPE_INVALID_ARG, "Directory path is NULL");
  205.  
  206. if (manager->is_locked) {
  207. ERR("File manager is busy");
  208. return RESULT_TYPE_BUSY;
  209. }
  210.  
  211. int option = FM_CHECK_DUPLICATED | FM_CHECK_PATH_VALID;
  212. int ret = _fs_manager_check_error(dir, option);
  213. if (ret != RESULT_TYPE_OK) {
  214. return ret;
  215. }
  216.  
  217. if (mkdir(dir, DIR_MODE) < 0) {
  218. ERR("Failed to create folder '%s'", dir);
  219. return RESULT_TYPE_FAIL;
  220. }
  221. return RESULT_TYPE_OK;
  222. }
  223.  
  224. static Eina_Bool _fs_manager_check_path_valid(const char *path, int *ret)
  225. {
  226. *ret = model_utils_is_path_valid(path, model_utils_is_file_exists(path));
  227. return (*ret == RESULT_TYPE_OK);
  228. }
  229.  
  230. static Eina_Bool _fs_manager_check_parent_exists(const char *path, int *ret)
  231. {
  232. *ret = RESULT_TYPE_FAIL;
  233. char *const parent_path = model_utils_get_dir_name(path);
  234. if (parent_path) {
  235. *ret = model_utils_is_file_exists(parent_path) ?
  236. RESULT_TYPE_OK :
  237. RESULT_TYPE_DIR_NOT_FOUND;
  238. free(parent_path);
  239. } else {
  240. *ret = RESULT_TYPE_FAIL_ALLOCATE_MEMORY;
  241. }
  242. return (*ret == RESULT_TYPE_OK);
  243. }
  244.  
  245. static int _fs_manager_sort_by_name_cb(const void *d1, const void *d2)
  246. {
  247. node_info *txt1 = (node_info *)d1;
  248. node_info *txt2 = (node_info *)d2;
  249. char *name1 = NULL;
  250. char *name2 = NULL;
  251. int comp_res = FM_COMP_RES_D1_EQUAL_D2;
  252.  
  253. if (!txt1 || !txt1->name) {
  254. return FM_COMP_RES_D1_GREATER_D2;
  255. }
  256. if (!txt2 || !txt2->name) {
  257. return FM_COMP_RES_D1_LESS_D2;
  258. }
  259. name1 = strdup(txt1->name);
  260. if (!name1) {
  261. return FM_COMP_RES_D1_LESS_D2;
  262. }
  263. eina_str_tolower(&name1);
  264.  
  265. name2 = strdup(txt2->name);
  266. if (!name2) {
  267. free(name1);
  268. name1 = NULL;
  269. return FM_COMP_RES_D1_LESS_D2;
  270. }
  271. eina_str_tolower(&name2);
  272.  
  273. comp_res = strcmp(name1, name2);
  274.  
  275. free(name1);
  276. free(name2);
  277. return comp_res;
  278. }
  279.  
  280. static int _fs_manager_check_error(const char *fullpath, int check_option)
  281. {
  282. int ret = RESULT_TYPE_OK;
  283. int ret2 = RESULT_TYPE_OK;
  284.  
  285. if ((check_option & FM_CHECK_ARG_VALID) && !fullpath) {
  286. ERR("Input argument is NULL");
  287. ret = RESULT_TYPE_INVALID_ARG;
  288. } else if ((check_option & FM_CHECK_EXIST) && (!model_utils_is_file_exists(fullpath))) {
  289. ERR("'%s' doesn't exist", fullpath);
  290. ret = RESULT_TYPE_NOT_EXIST;
  291. } else if ((check_option & FM_CHECK_PATH_VALID) && (!_fs_manager_check_path_valid(fullpath, &ret2))) {
  292. ERR("Path '%s' is invalid", fullpath);
  293. ret = ret2;
  294. } else if ((check_option & FM_CHECK_PARENT_DIR_EXIST) && (!_fs_manager_check_parent_exists(fullpath, &ret2))) {
  295. ERR("Parent directory for '%s' doesn't exist", fullpath);
  296. ret = ret2;
  297. } else if ((check_option & FM_CHECK_DUPLICATED) && (model_utils_is_file_exists(fullpath))) {
  298. ERR("Duplicated name. '%s' already exists", fullpath);
  299. ret = RESULT_TYPE_DUPLICATED_NAME;
  300. }
  301. return ret;
  302. }
  303.  
  304. static int _fs_manager_is_mmc_supported(bool *supported)
  305. {
  306. RETVM_IF(!supported, RESULT_TYPE_INVALID_ARG, "Input argument is NULL");
  307.  
  308. *supported = false;
  309. struct statvfs st;
  310.  
  311. RETVM_IF(storage_get_external_memory_size(&st) < 0,
  312. RESULT_TYPE_FAIL,
  313. "Failed to get external memory size");
  314.  
  315. double total_size = (double)st.f_frsize * st.f_blocks;
  316. if (total_size > 0) {
  317. *supported = true;
  318. }
  319.  
  320. return RESULT_TYPE_OK;
  321. }
  322.  
  323. static int _fs_manager_generate_operation(fs_manager *manager,
  324. Eina_List *source_list,
  325. const char *dest_path,
  326. operation_type oper_type,
  327. fs_manager_complete_cb_func func,
  328. void *data)
  329. {
  330. RETVM_IF(!manager, RESULT_TYPE_INVALID_ARG, "File manager is NULL");
  331. RETVM_IF(!source_list, RESULT_TYPE_INVALID_ARG, "Source list is NULL");
  332. RETVM_IF(oper_type == OPERATION_TYPE_NONE, RESULT_TYPE_INVALID_ARG, "No appropriate operation type");
  333. RETVM_IF(!dest_path && (oper_type != OPERATION_TYPE_DELETE), RESULT_TYPE_INVALID_ARG, "Destination path is NULL");
  334.  
  335. if (manager->is_locked) {
  336. ERR("File manager is busy");
  337. return RESULT_TYPE_BUSY;
  338. }
  339.  
  340. manager->user_cb_func = func;
  341. manager->user_cb_data = data;
  342.  
  343. manager->operation = fs_operation_create();
  344. if (!manager->operation) {
  345. _fs_manager_clear_data(manager);
  346. ERR("Failed to allocate memory for file operation");
  347. return RESULT_TYPE_FAIL_ALLOCATE_MEMORY;
  348. }
  349.  
  350. int result = fs_operation_set_data(manager->operation, source_list, dest_path, oper_type);
  351. if (result != RESULT_TYPE_OK) {
  352. _fs_manager_clear_data(manager);
  353. ERR("Failed to set operation data");
  354. return result;
  355. }
  356.  
  357. fs_operation_cb_data *cb_data = calloc(1, sizeof(fs_operation_cb_data));
  358. if (!cb_data) {
  359. _fs_manager_clear_data(manager);
  360. ERR("Failed to allocate memory for callback operation data");
  361. return RESULT_TYPE_FAIL_ALLOCATE_MEMORY;
  362. }
  363.  
  364. cb_data->manager = manager;
  365. cb_data->result = RESULT_TYPE_FAIL;
  366.  
  367. /* Lock file system manager */
  368. manager->is_locked = EINA_TRUE;
  369.  
  370. result = fs_operation_execute(manager->operation, _on_operation_completed, cb_data);
  371. if (result != RESULT_TYPE_OK) {
  372. free(cb_data);
  373. _fs_manager_clear_data(manager);
  374. manager->is_locked = EINA_FALSE;
  375. ERR("Failed to execute operation");
  376. }
  377.  
  378. return result;
  379. }
  380.  
  381. static void _on_operation_completed(void *data)
  382. {
  383. RETM_IF(!data, "Callback data is NULL");
  384.  
  385. fs_operation_cb_data *operation_data = data;
  386. fs_manager *manager = operation_data->manager;
  387.  
  388. RETM_IF(!manager, "File manager in callback data is NULL");
  389.  
  390. fs_operation_destroy(manager->operation);
  391. manager->operation = NULL;
  392.  
  393. /* Unlock file system manager */
  394. manager->is_locked = EINA_FALSE;
  395.  
  396. /* User callback calling */
  397. if (manager->user_cb_func) {
  398. manager->user_cb_func(manager->user_cb_data, operation_data->result);
  399. manager->user_cb_func = NULL;
  400. manager->user_cb_data = NULL;
  401. }
  402.  
  403. free(operation_data);
  404. }
  405.  
  406. static void _fs_manager_clear_data(fs_manager *manager)
  407. {
  408. manager->user_cb_func = NULL;
  409. manager->user_cb_data = NULL;
  410. fs_operation_destroy(manager->operation);
  411. manager->operation = NULL;
  412. }