archive_files.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include "archive_files.h"
  2. #include "archive_apps.h"
  3. #include "archive_browser.h"
  4. #define TAG "Archive"
  5. #define ASSETS_DIR "assets"
  6. bool archive_filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) {
  7. furi_assert(file_info);
  8. furi_assert(tab_ext);
  9. furi_assert(name);
  10. bool result = false;
  11. if(strcmp(tab_ext, "*") == 0) {
  12. result = true;
  13. } else if(strstr(name, tab_ext) != NULL) {
  14. result = true;
  15. } else if(file_info->flags & FSF_DIRECTORY) {
  16. if(strstr(name, ASSETS_DIR) != NULL) {
  17. result = false; // Skip assets folder in all tabs except browser
  18. } else {
  19. result = true;
  20. }
  21. }
  22. return result;
  23. }
  24. void archive_trim_file_path(char* name, bool ext) {
  25. char* slash = strrchr(name, '/') + 1;
  26. if(strlen(slash)) strlcpy(name, slash, strlen(slash) + 1);
  27. if(ext) {
  28. char* dot = strrchr(name, '.');
  29. if(strlen(dot)) *dot = '\0';
  30. }
  31. }
  32. void archive_get_file_extension(char* name, char* ext) {
  33. char* dot = strrchr(name, '.');
  34. if(dot == NULL)
  35. *ext = '\0';
  36. else
  37. strncpy(ext, dot, MAX_EXT_LEN);
  38. }
  39. void archive_set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app) {
  40. furi_assert(file);
  41. file->is_app = is_app;
  42. if(is_app) {
  43. file->type = archive_get_app_filetype(archive_get_app_type(path));
  44. } else {
  45. furi_assert(file_info);
  46. for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) {
  47. if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue;
  48. if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) {
  49. if(i == ArchiveFileTypeBadUsb) {
  50. if(string_search_str(file->name, archive_get_default_path(ArchiveTabBadUsb)) ==
  51. 0) {
  52. file->type = i;
  53. return; // *.txt file is a BadUSB script only if it is in BadUSB folder
  54. }
  55. } else {
  56. file->type = i;
  57. return;
  58. }
  59. }
  60. }
  61. if(file_info->flags & FSF_DIRECTORY) {
  62. file->type = ArchiveFileTypeFolder;
  63. } else {
  64. file->type = ArchiveFileTypeUnknown;
  65. }
  66. }
  67. }
  68. bool archive_get_filenames(void* context, const char* path) {
  69. furi_assert(context);
  70. bool res;
  71. ArchiveBrowserView* browser = context;
  72. if(archive_get_tab(browser) == ArchiveTabFavorites) {
  73. res = archive_favorites_read(browser);
  74. } else if(strncmp(path, "/app:", 5) == 0) {
  75. res = archive_app_read_dir(browser, path);
  76. } else {
  77. res = archive_file_array_load(browser, 0);
  78. }
  79. return res;
  80. }
  81. uint32_t archive_dir_count_items(void* context, const char* path) {
  82. furi_assert(context);
  83. ArchiveBrowserView* browser = context;
  84. FileInfo file_info;
  85. Storage* fs_api = furi_record_open("storage");
  86. File* directory = storage_file_alloc(fs_api);
  87. char name[MAX_NAME_LEN];
  88. if(!storage_dir_open(directory, path)) {
  89. storage_dir_close(directory);
  90. storage_file_free(directory);
  91. return 0;
  92. }
  93. uint32_t files_found = 0;
  94. while(1) {
  95. if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) {
  96. break;
  97. }
  98. if((storage_file_get_error(directory) == FSE_OK) && (name[0])) {
  99. if(archive_filter_by_extension(
  100. &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) {
  101. files_found++;
  102. }
  103. }
  104. }
  105. storage_dir_close(directory);
  106. storage_file_free(directory);
  107. furi_record_close("storage");
  108. archive_set_item_count(browser, files_found);
  109. return files_found;
  110. }
  111. uint32_t archive_dir_read_items(void* context, const char* path, uint32_t offset, uint32_t count) {
  112. furi_assert(context);
  113. ArchiveBrowserView* browser = context;
  114. FileInfo file_info;
  115. Storage* fs_api = furi_record_open("storage");
  116. File* directory = storage_file_alloc(fs_api);
  117. char name[MAX_NAME_LEN];
  118. snprintf(name, MAX_NAME_LEN, "%s/", path);
  119. size_t path_len = strlen(name);
  120. if(!storage_dir_open(directory, path)) {
  121. storage_dir_close(directory);
  122. storage_file_free(directory);
  123. return false;
  124. }
  125. // Skip items before offset
  126. uint32_t items_cnt = 0;
  127. while(items_cnt < offset) {
  128. if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN)) {
  129. break;
  130. }
  131. if(storage_file_get_error(directory) == FSE_OK) {
  132. if(archive_filter_by_extension(
  133. &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) {
  134. items_cnt++;
  135. }
  136. } else {
  137. break;
  138. }
  139. }
  140. if(items_cnt != offset) {
  141. storage_dir_close(directory);
  142. storage_file_free(directory);
  143. furi_record_close("storage");
  144. return false;
  145. }
  146. items_cnt = 0;
  147. archive_file_array_rm_all(browser);
  148. while(items_cnt < count) {
  149. if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN - path_len)) {
  150. break;
  151. }
  152. if(storage_file_get_error(directory) == FSE_OK) {
  153. archive_add_file_item(browser, &file_info, name);
  154. items_cnt++;
  155. } else {
  156. break;
  157. }
  158. }
  159. storage_dir_close(directory);
  160. storage_file_free(directory);
  161. furi_record_close("storage");
  162. return (items_cnt == count);
  163. }
  164. void archive_file_append(const char* path, const char* format, ...) {
  165. furi_assert(path);
  166. string_t string;
  167. va_list args;
  168. va_start(args, format);
  169. string_init_vprintf(string, format, args);
  170. va_end(args);
  171. Storage* fs_api = furi_record_open("storage");
  172. File* file = storage_file_alloc(fs_api);
  173. bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
  174. if(res) {
  175. storage_file_write(file, string_get_cstr(string), string_size(string));
  176. }
  177. storage_file_close(file);
  178. storage_file_free(file);
  179. furi_record_close("storage");
  180. }
  181. void archive_delete_file(void* context, const char* format, ...) {
  182. furi_assert(context);
  183. string_t filename;
  184. va_list args;
  185. va_start(args, format);
  186. string_init_vprintf(filename, format, args);
  187. va_end(args);
  188. ArchiveBrowserView* browser = context;
  189. Storage* fs_api = furi_record_open("storage");
  190. FileInfo fileinfo;
  191. storage_common_stat(fs_api, string_get_cstr(filename), &fileinfo);
  192. bool res = false;
  193. if(fileinfo.flags & FSF_DIRECTORY) {
  194. res = storage_simply_remove_recursive(fs_api, string_get_cstr(filename));
  195. } else {
  196. res = (storage_common_remove(fs_api, string_get_cstr(filename)) == FSE_OK);
  197. }
  198. furi_record_close("storage");
  199. if(archive_is_favorite("%s", string_get_cstr(filename))) {
  200. archive_favorites_delete("%s", string_get_cstr(filename));
  201. }
  202. if(res) {
  203. archive_file_array_rm_selected(browser);
  204. }
  205. string_clear(filename);
  206. }