storage_processing.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. #include "storage_processing.h"
  2. #include <m-list.h>
  3. #include <m-dict.h>
  4. #include <m-string.h>
  5. #define FS_CALL(_storage, _fn) \
  6. storage_data_lock(_storage); \
  7. ret = _storage->fs_api->_fn; \
  8. storage_data_unlock(_storage);
  9. #define ST_CALL(_storage, _fn) \
  10. storage_data_lock(_storage); \
  11. ret = _storage->api._fn; \
  12. storage_data_unlock(_storage);
  13. static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) {
  14. furi_check(type == ST_EXT || type == ST_INT);
  15. StorageData* storage = &app->storage[type];
  16. return storage;
  17. }
  18. static bool storage_type_is_not_valid(StorageType type) {
  19. return type >= ST_ERROR;
  20. }
  21. static StorageData* get_storage_by_file(File* file, StorageData* storages) {
  22. StorageData* storage_data = NULL;
  23. for(uint8_t i = 0; i < STORAGE_COUNT; i++) {
  24. if(storage_has_file(file, &storages[i])) {
  25. storage_data = &storages[i];
  26. }
  27. }
  28. return storage_data;
  29. }
  30. static const char* remove_vfs(const char* path) {
  31. return path + MIN(4, strlen(path));
  32. }
  33. static const char* ext_path = "/ext";
  34. static const char* int_path = "/int";
  35. static const char* any_path = "/any";
  36. static StorageType storage_get_type_by_path(Storage* app, const char* path) {
  37. StorageType type = ST_ERROR;
  38. if(strlen(path) >= strlen(ext_path) && memcmp(path, ext_path, strlen(ext_path)) == 0) {
  39. type = ST_EXT;
  40. } else if(strlen(path) >= strlen(int_path) && memcmp(path, int_path, strlen(int_path)) == 0) {
  41. type = ST_INT;
  42. } else if(strlen(path) >= strlen(any_path) && memcmp(path, any_path, strlen(any_path)) == 0) {
  43. type = ST_ANY;
  44. }
  45. if(type == ST_ANY) {
  46. type = ST_INT;
  47. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusOK) {
  48. type = ST_EXT;
  49. }
  50. }
  51. return type;
  52. }
  53. static void storage_path_change_to_real_storage(string_t path, StorageType real_storage) {
  54. if(memcmp(string_get_cstr(path), any_path, strlen(any_path)) == 0) {
  55. switch(real_storage) {
  56. case ST_EXT:
  57. string_set_char(path, 0, ext_path[0]);
  58. string_set_char(path, 1, ext_path[1]);
  59. string_set_char(path, 2, ext_path[2]);
  60. string_set_char(path, 3, ext_path[3]);
  61. break;
  62. case ST_INT:
  63. string_set_char(path, 0, int_path[0]);
  64. string_set_char(path, 1, int_path[1]);
  65. string_set_char(path, 2, int_path[2]);
  66. string_set_char(path, 3, int_path[3]);
  67. break;
  68. default:
  69. break;
  70. }
  71. }
  72. }
  73. /******************* File Functions *******************/
  74. bool storage_process_file_open(
  75. Storage* app,
  76. File* file,
  77. const char* path,
  78. FS_AccessMode access_mode,
  79. FS_OpenMode open_mode) {
  80. bool ret = false;
  81. StorageType type = storage_get_type_by_path(app, path);
  82. StorageData* storage;
  83. file->error_id = FSE_OK;
  84. if(storage_type_is_not_valid(type)) {
  85. file->error_id = FSE_INVALID_NAME;
  86. } else {
  87. storage = storage_get_storage_by_type(app, type);
  88. string_t real_path;
  89. string_init_set(real_path, path);
  90. storage_path_change_to_real_storage(real_path, type);
  91. if(storage_path_already_open(real_path, storage->files)) {
  92. file->error_id = FSE_ALREADY_OPEN;
  93. } else {
  94. storage_push_storage_file(file, real_path, type, storage);
  95. FS_CALL(storage, file.open(storage, file, remove_vfs(path), access_mode, open_mode));
  96. }
  97. string_clear(real_path);
  98. }
  99. return ret;
  100. }
  101. bool storage_process_file_close(Storage* app, File* file) {
  102. bool ret = false;
  103. StorageData* storage = get_storage_by_file(file, app->storage);
  104. if(storage == NULL) {
  105. file->error_id = FSE_INVALID_PARAMETER;
  106. } else {
  107. FS_CALL(storage, file.close(storage, file));
  108. storage_pop_storage_file(file, storage);
  109. StorageEvent event = {.type = StorageEventTypeFileClose};
  110. furi_pubsub_publish(app->pubsub, &event);
  111. }
  112. return ret;
  113. }
  114. static uint16_t
  115. storage_process_file_read(Storage* app, File* file, void* buff, uint16_t const bytes_to_read) {
  116. uint16_t ret = 0;
  117. StorageData* storage = get_storage_by_file(file, app->storage);
  118. if(storage == NULL) {
  119. file->error_id = FSE_INVALID_PARAMETER;
  120. } else {
  121. FS_CALL(storage, file.read(storage, file, buff, bytes_to_read));
  122. }
  123. return ret;
  124. }
  125. static uint16_t storage_process_file_write(
  126. Storage* app,
  127. File* file,
  128. const void* buff,
  129. uint16_t const bytes_to_write) {
  130. uint16_t ret = 0;
  131. StorageData* storage = get_storage_by_file(file, app->storage);
  132. if(storage == NULL) {
  133. file->error_id = FSE_INVALID_PARAMETER;
  134. } else {
  135. FS_CALL(storage, file.write(storage, file, buff, bytes_to_write));
  136. }
  137. return ret;
  138. }
  139. static bool storage_process_file_seek(
  140. Storage* app,
  141. File* file,
  142. const uint32_t offset,
  143. const bool from_start) {
  144. bool ret = false;
  145. StorageData* storage = get_storage_by_file(file, app->storage);
  146. if(storage == NULL) {
  147. file->error_id = FSE_INVALID_PARAMETER;
  148. } else {
  149. FS_CALL(storage, file.seek(storage, file, offset, from_start));
  150. }
  151. return ret;
  152. }
  153. static uint64_t storage_process_file_tell(Storage* app, File* file) {
  154. uint64_t ret = 0;
  155. StorageData* storage = get_storage_by_file(file, app->storage);
  156. if(storage == NULL) {
  157. file->error_id = FSE_INVALID_PARAMETER;
  158. } else {
  159. FS_CALL(storage, file.tell(storage, file));
  160. }
  161. return ret;
  162. }
  163. static bool storage_process_file_truncate(Storage* app, File* file) {
  164. bool ret = false;
  165. StorageData* storage = get_storage_by_file(file, app->storage);
  166. if(storage == NULL) {
  167. file->error_id = FSE_INVALID_PARAMETER;
  168. } else {
  169. FS_CALL(storage, file.truncate(storage, file));
  170. }
  171. return ret;
  172. }
  173. static bool storage_process_file_sync(Storage* app, File* file) {
  174. bool ret = false;
  175. StorageData* storage = get_storage_by_file(file, app->storage);
  176. if(storage == NULL) {
  177. file->error_id = FSE_INVALID_PARAMETER;
  178. } else {
  179. FS_CALL(storage, file.sync(storage, file));
  180. }
  181. return ret;
  182. }
  183. static uint64_t storage_process_file_size(Storage* app, File* file) {
  184. uint64_t ret = 0;
  185. StorageData* storage = get_storage_by_file(file, app->storage);
  186. if(storage == NULL) {
  187. file->error_id = FSE_INVALID_PARAMETER;
  188. } else {
  189. FS_CALL(storage, file.size(storage, file));
  190. }
  191. return ret;
  192. }
  193. static bool storage_process_file_eof(Storage* app, File* file) {
  194. bool ret = false;
  195. StorageData* storage = get_storage_by_file(file, app->storage);
  196. if(storage == NULL) {
  197. file->error_id = FSE_INVALID_PARAMETER;
  198. } else {
  199. FS_CALL(storage, file.eof(storage, file));
  200. }
  201. return ret;
  202. }
  203. /******************* Dir Functions *******************/
  204. bool storage_process_dir_open(Storage* app, File* file, const char* path) {
  205. bool ret = false;
  206. StorageType type = storage_get_type_by_path(app, path);
  207. StorageData* storage;
  208. file->error_id = FSE_OK;
  209. if(storage_type_is_not_valid(type)) {
  210. file->error_id = FSE_INVALID_NAME;
  211. } else {
  212. storage = storage_get_storage_by_type(app, type);
  213. string_t real_path;
  214. string_init_set(real_path, path);
  215. storage_path_change_to_real_storage(real_path, type);
  216. if(storage_path_already_open(real_path, storage->files)) {
  217. file->error_id = FSE_ALREADY_OPEN;
  218. } else {
  219. storage_push_storage_file(file, real_path, type, storage);
  220. FS_CALL(storage, dir.open(storage, file, remove_vfs(path)));
  221. }
  222. string_clear(real_path);
  223. }
  224. return ret;
  225. }
  226. bool storage_process_dir_close(Storage* app, File* file) {
  227. bool ret = false;
  228. StorageData* storage = get_storage_by_file(file, app->storage);
  229. if(storage == NULL) {
  230. file->error_id = FSE_INVALID_PARAMETER;
  231. } else {
  232. FS_CALL(storage, dir.close(storage, file));
  233. storage_pop_storage_file(file, storage);
  234. }
  235. return ret;
  236. }
  237. bool storage_process_dir_read(
  238. Storage* app,
  239. File* file,
  240. FileInfo* fileinfo,
  241. char* name,
  242. const uint16_t name_length) {
  243. bool ret = false;
  244. StorageData* storage = get_storage_by_file(file, app->storage);
  245. if(storage == NULL) {
  246. file->error_id = FSE_INVALID_PARAMETER;
  247. } else {
  248. FS_CALL(storage, dir.read(storage, file, fileinfo, name, name_length));
  249. }
  250. return ret;
  251. }
  252. bool storage_process_dir_rewind(Storage* app, File* file) {
  253. bool ret = false;
  254. StorageData* storage = get_storage_by_file(file, app->storage);
  255. if(storage == NULL) {
  256. file->error_id = FSE_INVALID_PARAMETER;
  257. } else {
  258. FS_CALL(storage, dir.rewind(storage, file));
  259. }
  260. return ret;
  261. }
  262. /******************* Common FS Functions *******************/
  263. static FS_Error storage_process_common_stat(Storage* app, const char* path, FileInfo* fileinfo) {
  264. FS_Error ret = FSE_OK;
  265. StorageType type = storage_get_type_by_path(app, path);
  266. if(storage_type_is_not_valid(type)) {
  267. ret = FSE_INVALID_NAME;
  268. } else {
  269. StorageData* storage = storage_get_storage_by_type(app, type);
  270. FS_CALL(storage, common.stat(storage, remove_vfs(path), fileinfo));
  271. }
  272. return ret;
  273. }
  274. static FS_Error storage_process_common_remove(Storage* app, const char* path) {
  275. FS_Error ret = FSE_OK;
  276. StorageType type = storage_get_type_by_path(app, path);
  277. string_t real_path;
  278. string_init_set(real_path, path);
  279. storage_path_change_to_real_storage(real_path, type);
  280. do {
  281. if(storage_type_is_not_valid(type)) {
  282. ret = FSE_INVALID_NAME;
  283. break;
  284. }
  285. StorageData* storage = storage_get_storage_by_type(app, type);
  286. if(storage_path_already_open(real_path, storage->files)) {
  287. ret = FSE_ALREADY_OPEN;
  288. break;
  289. }
  290. FS_CALL(storage, common.remove(storage, remove_vfs(path)));
  291. } while(false);
  292. string_clear(real_path);
  293. return ret;
  294. }
  295. static FS_Error storage_process_common_mkdir(Storage* app, const char* path) {
  296. FS_Error ret = FSE_OK;
  297. StorageType type = storage_get_type_by_path(app, path);
  298. if(storage_type_is_not_valid(type)) {
  299. ret = FSE_INVALID_NAME;
  300. } else {
  301. StorageData* storage = storage_get_storage_by_type(app, type);
  302. FS_CALL(storage, common.mkdir(storage, remove_vfs(path)));
  303. }
  304. return ret;
  305. }
  306. static FS_Error storage_process_common_fs_info(
  307. Storage* app,
  308. const char* fs_path,
  309. uint64_t* total_space,
  310. uint64_t* free_space) {
  311. FS_Error ret = FSE_OK;
  312. StorageType type = storage_get_type_by_path(app, fs_path);
  313. if(storage_type_is_not_valid(type)) {
  314. ret = FSE_INVALID_NAME;
  315. } else {
  316. StorageData* storage = storage_get_storage_by_type(app, type);
  317. FS_CALL(storage, common.fs_info(storage, remove_vfs(fs_path), total_space, free_space));
  318. }
  319. return ret;
  320. }
  321. /****************** Raw SD API ******************/
  322. // TODO think about implementing a custom storage API to split that kind of api linkage
  323. #include "storages/storage_ext.h"
  324. static FS_Error storage_process_sd_format(Storage* app) {
  325. FS_Error ret = FSE_OK;
  326. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  327. ret = FSE_NOT_READY;
  328. } else {
  329. ret = sd_format_card(&app->storage[ST_EXT]);
  330. }
  331. return ret;
  332. }
  333. static FS_Error storage_process_sd_unmount(Storage* app) {
  334. FS_Error ret = FSE_OK;
  335. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  336. ret = FSE_NOT_READY;
  337. } else {
  338. sd_unmount_card(&app->storage[ST_EXT]);
  339. }
  340. return ret;
  341. }
  342. static FS_Error storage_process_sd_info(Storage* app, SDInfo* info) {
  343. FS_Error ret = FSE_OK;
  344. if(storage_data_status(&app->storage[ST_EXT]) == StorageStatusNotReady) {
  345. ret = FSE_NOT_READY;
  346. } else {
  347. ret = sd_card_info(&app->storage[ST_EXT], info);
  348. }
  349. return ret;
  350. }
  351. static FS_Error storage_process_sd_status(Storage* app) {
  352. FS_Error ret;
  353. StorageStatus status = storage_data_status(&app->storage[ST_EXT]);
  354. switch(status) {
  355. case StorageStatusOK:
  356. ret = FSE_OK;
  357. break;
  358. case StorageStatusNotReady:
  359. ret = FSE_NOT_READY;
  360. break;
  361. default:
  362. ret = FSE_INTERNAL;
  363. break;
  364. }
  365. return ret;
  366. }
  367. /****************** API calls processing ******************/
  368. void storage_process_message_internal(Storage* app, StorageMessage* message) {
  369. switch(message->command) {
  370. case StorageCommandFileOpen:
  371. message->return_data->bool_value = storage_process_file_open(
  372. app,
  373. message->data->fopen.file,
  374. message->data->fopen.path,
  375. message->data->fopen.access_mode,
  376. message->data->fopen.open_mode);
  377. break;
  378. case StorageCommandFileClose:
  379. message->return_data->bool_value =
  380. storage_process_file_close(app, message->data->fopen.file);
  381. break;
  382. case StorageCommandFileRead:
  383. message->return_data->uint16_value = storage_process_file_read(
  384. app,
  385. message->data->fread.file,
  386. message->data->fread.buff,
  387. message->data->fread.bytes_to_read);
  388. break;
  389. case StorageCommandFileWrite:
  390. message->return_data->uint16_value = storage_process_file_write(
  391. app,
  392. message->data->fwrite.file,
  393. message->data->fwrite.buff,
  394. message->data->fwrite.bytes_to_write);
  395. break;
  396. case StorageCommandFileSeek:
  397. message->return_data->bool_value = storage_process_file_seek(
  398. app,
  399. message->data->fseek.file,
  400. message->data->fseek.offset,
  401. message->data->fseek.from_start);
  402. break;
  403. case StorageCommandFileTell:
  404. message->return_data->uint64_value =
  405. storage_process_file_tell(app, message->data->file.file);
  406. break;
  407. case StorageCommandFileTruncate:
  408. message->return_data->bool_value =
  409. storage_process_file_truncate(app, message->data->file.file);
  410. break;
  411. case StorageCommandFileSync:
  412. message->return_data->bool_value =
  413. storage_process_file_sync(app, message->data->file.file);
  414. break;
  415. case StorageCommandFileSize:
  416. message->return_data->uint64_value =
  417. storage_process_file_size(app, message->data->file.file);
  418. break;
  419. case StorageCommandFileEof:
  420. message->return_data->bool_value = storage_process_file_eof(app, message->data->file.file);
  421. break;
  422. case StorageCommandDirOpen:
  423. message->return_data->bool_value =
  424. storage_process_dir_open(app, message->data->dopen.file, message->data->dopen.path);
  425. break;
  426. case StorageCommandDirClose:
  427. message->return_data->bool_value =
  428. storage_process_dir_close(app, message->data->file.file);
  429. break;
  430. case StorageCommandDirRead:
  431. message->return_data->bool_value = storage_process_dir_read(
  432. app,
  433. message->data->dread.file,
  434. message->data->dread.fileinfo,
  435. message->data->dread.name,
  436. message->data->dread.name_length);
  437. break;
  438. case StorageCommandDirRewind:
  439. message->return_data->bool_value =
  440. storage_process_dir_rewind(app, message->data->file.file);
  441. break;
  442. case StorageCommandCommonStat:
  443. message->return_data->error_value = storage_process_common_stat(
  444. app, message->data->cstat.path, message->data->cstat.fileinfo);
  445. break;
  446. case StorageCommandCommonRemove:
  447. message->return_data->error_value =
  448. storage_process_common_remove(app, message->data->path.path);
  449. break;
  450. case StorageCommandCommonMkDir:
  451. message->return_data->error_value =
  452. storage_process_common_mkdir(app, message->data->path.path);
  453. break;
  454. case StorageCommandCommonFSInfo:
  455. message->return_data->error_value = storage_process_common_fs_info(
  456. app,
  457. message->data->cfsinfo.fs_path,
  458. message->data->cfsinfo.total_space,
  459. message->data->cfsinfo.free_space);
  460. break;
  461. case StorageCommandSDFormat:
  462. message->return_data->error_value = storage_process_sd_format(app);
  463. break;
  464. case StorageCommandSDUnmount:
  465. message->return_data->error_value = storage_process_sd_unmount(app);
  466. break;
  467. case StorageCommandSDInfo:
  468. message->return_data->error_value =
  469. storage_process_sd_info(app, message->data->sdinfo.info);
  470. break;
  471. case StorageCommandSDStatus:
  472. message->return_data->error_value = storage_process_sd_status(app);
  473. break;
  474. }
  475. osSemaphoreRelease(message->semaphore);
  476. }
  477. void storage_process_message(Storage* app, StorageMessage* message) {
  478. storage_process_message_internal(app, message);
  479. }