archive_files.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 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 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. archive_file_array_rm_all(browser);
  73. if(archive_get_tab(browser) == ArchiveTabFavorites) {
  74. res = archive_favorites_read(browser);
  75. } else if(strncmp(path, "/app:", 5) == 0) {
  76. res = archive_app_read_dir(browser, path);
  77. } else {
  78. res = archive_read_dir(browser, path);
  79. }
  80. return res;
  81. }
  82. bool archive_dir_not_empty(void* context, const char* path) { // can be simpler?
  83. furi_assert(context);
  84. ArchiveBrowserView* browser = context;
  85. FileInfo file_info;
  86. Storage* fs_api = furi_record_open("storage");
  87. File* directory = storage_file_alloc(fs_api);
  88. char name[MAX_NAME_LEN];
  89. if(!storage_dir_open(directory, path)) {
  90. storage_dir_close(directory);
  91. storage_file_free(directory);
  92. return false;
  93. }
  94. bool files_found = false;
  95. while(1) {
  96. if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) {
  97. break;
  98. }
  99. if(files_found) {
  100. break;
  101. } else if((storage_file_get_error(directory) == FSE_OK) && (name[0])) {
  102. if(filter_by_extension(
  103. &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) {
  104. files_found = true;
  105. }
  106. } else {
  107. return false;
  108. }
  109. }
  110. storage_dir_close(directory);
  111. storage_file_free(directory);
  112. furi_record_close("storage");
  113. return files_found;
  114. }
  115. bool archive_read_dir(void* context, const char* path) {
  116. furi_assert(context);
  117. ArchiveBrowserView* browser = context;
  118. FileInfo file_info;
  119. Storage* fs_api = furi_record_open("storage");
  120. File* directory = storage_file_alloc(fs_api);
  121. char name[MAX_NAME_LEN];
  122. snprintf(name, MAX_NAME_LEN, "%s/", path);
  123. size_t path_len = strlen(name);
  124. size_t files_cnt = 0;
  125. if(!storage_dir_open(directory, path)) {
  126. storage_dir_close(directory);
  127. storage_file_free(directory);
  128. return false;
  129. }
  130. while(1) {
  131. if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN - path_len)) {
  132. break;
  133. }
  134. if(files_cnt > MAX_FILES) {
  135. break;
  136. } else if(storage_file_get_error(directory) == FSE_OK) {
  137. archive_add_file_item(browser, &file_info, name);
  138. ++files_cnt;
  139. } else {
  140. storage_dir_close(directory);
  141. storage_file_free(directory);
  142. return false;
  143. }
  144. }
  145. storage_dir_close(directory);
  146. storage_file_free(directory);
  147. furi_record_close("storage");
  148. return true;
  149. }
  150. void archive_file_append(const char* path, const char* format, ...) {
  151. furi_assert(path);
  152. string_t string;
  153. va_list args;
  154. va_start(args, format);
  155. string_init_vprintf(string, format, args);
  156. va_end(args);
  157. FileWorker* file_worker = file_worker_alloc(false);
  158. if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) {
  159. FURI_LOG_E(TAG, "Append open error");
  160. }
  161. if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) {
  162. FURI_LOG_E(TAG, "Append write error");
  163. }
  164. file_worker_close(file_worker);
  165. file_worker_free(file_worker);
  166. }
  167. void archive_delete_file(void* context, const char* format, ...) {
  168. furi_assert(context);
  169. string_t filename;
  170. va_list args;
  171. va_start(args, format);
  172. string_init_vprintf(filename, format, args);
  173. va_end(args);
  174. ArchiveBrowserView* browser = context;
  175. FileWorker* file_worker = file_worker_alloc(true);
  176. bool res = file_worker_remove(file_worker, string_get_cstr(filename));
  177. file_worker_free(file_worker);
  178. if(archive_is_favorite("%s", string_get_cstr(filename))) {
  179. archive_favorites_delete("%s", string_get_cstr(filename));
  180. }
  181. if(res) {
  182. archive_file_array_rm_selected(browser);
  183. }
  184. string_clear(filename);
  185. }