luat_fs_lfs2.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include "luat_base.h"
  2. #include "luat_fs.h"
  3. #include "luat_spi.h"
  4. #include "luat_mem.h"
  5. #define LUAT_LOG_TAG "vfs.lfs2"
  6. #include "luat_log.h"
  7. #ifdef LUAT_USE_FS_VFS
  8. // #ifdef LUAT_VFS_USE_LFS2
  9. #include "lfs.h"
  10. FILE* luat_vfs_lfs2_fopen(void* userdata, const char *filename, const char *mode) {
  11. lfs_t* fs = (lfs_t*)userdata;
  12. lfs_file_t *file = (lfs_file_t*)luat_heap_malloc(sizeof(lfs_file_t));
  13. if (file == NULL) {
  14. LLOGD("out of memory when open file %s", filename);
  15. return NULL;
  16. }
  17. memset(file, 0, sizeof(lfs_file_t));
  18. int flag = 0;
  19. /*
  20. "r": 读模式(默认);
  21. "w": 写模式;
  22. "a": 追加模式;
  23. "r+": 更新模式,所有之前的数据都保留;
  24. "w+": 更新模式,所有之前的数据都删除;
  25. "a+": 追加更新模式,所有之前的数据都保留,只允许在文件尾部做写入。
  26. */
  27. if (!strcmp("r+", mode) || !strcmp("r+b", mode) || !strcmp("rb+", mode)) {
  28. flag = LFS_O_RDWR | LFS_O_CREAT;
  29. }
  30. else if(!strcmp("w+", mode) || !strcmp("w+b", mode) || !strcmp("wb+", mode)) {
  31. flag = LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC;
  32. }
  33. else if(!strcmp("a+", mode) || !strcmp("a+b", mode) || !strcmp("ab+", mode)) {
  34. flag = LFS_O_APPEND | LFS_O_CREAT | LFS_O_WRONLY;
  35. }
  36. else if(!strcmp("w", mode) || !strcmp("wb", mode)) {
  37. flag = LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC;
  38. }
  39. else if(!strcmp("r", mode) || !strcmp("rb", mode)) {
  40. flag = LFS_O_RDONLY;
  41. }
  42. else if(!strcmp("a", mode) || !strcmp("ab", mode)) {
  43. flag = LFS_O_APPEND | LFS_O_CREAT | LFS_O_WRONLY;
  44. }
  45. else {
  46. LLOGW("bad file open mode %s, fallback to 'r'", mode);
  47. flag = LFS_O_RDONLY;
  48. }
  49. int ret = lfs_file_open(fs, file, filename, flag);
  50. if (ret < 0) {
  51. luat_heap_free(file);
  52. return 0;
  53. }
  54. return (FILE*)file;
  55. }
  56. int luat_vfs_lfs2_getc(void* userdata, FILE* stream) {
  57. //LLOGD("posix_getc %p", stream);
  58. lfs_t* fs = (lfs_t*)userdata;
  59. lfs_file_t* file = (lfs_file_t*)stream;
  60. char buff = 0;
  61. int ret = lfs_file_read(fs, file, &buff, 1);
  62. if (ret != 1)
  63. return -1;
  64. return (int)buff;
  65. }
  66. int luat_vfs_lfs2_fseek(void* userdata, FILE* stream, long int offset, int origin) {
  67. lfs_t* fs = (lfs_t*)userdata;
  68. lfs_file_t* file = (lfs_file_t*)stream;
  69. int ret = lfs_file_seek(fs, file, offset, origin);
  70. return ret < 0 ? -1 : 0;
  71. }
  72. int luat_vfs_lfs2_ftell(void* userdata, FILE* stream) {
  73. lfs_t* fs = (lfs_t*)userdata;
  74. lfs_file_t* file = (lfs_file_t*)stream;
  75. int ret = lfs_file_tell(fs, file);
  76. return ret < 0 ? -1 : ret;
  77. }
  78. int luat_vfs_lfs2_fclose(void* userdata, FILE* stream) {
  79. lfs_t* fs = (lfs_t*)userdata;
  80. lfs_file_t* file = (lfs_file_t*)stream;
  81. lfs_file_close(fs, file);
  82. if (file != NULL)
  83. luat_heap_free(file);
  84. return 0;
  85. }
  86. int luat_vfs_lfs2_feof(void* userdata, FILE* stream) {
  87. lfs_t* fs = (lfs_t*)userdata;
  88. lfs_file_t* file = (lfs_file_t*)stream;
  89. if (lfs_file_size(fs, file) <= lfs_file_tell(fs, file))
  90. return 1;
  91. return 0;
  92. }
  93. int luat_vfs_lfs2_ferror(void* userdata, FILE *stream) {
  94. return 0;
  95. }
  96. size_t luat_vfs_lfs2_fread(void* userdata, void *ptr, size_t size, size_t nmemb, FILE *stream) {
  97. lfs_t* fs = (lfs_t*)userdata;
  98. lfs_file_t* file = (lfs_file_t*)stream;
  99. int ret = lfs_file_read(fs, file, ptr, size*nmemb);
  100. return ret < 0 ? 0 : ret;
  101. }
  102. size_t luat_vfs_lfs2_fwrite(void* userdata, const void *ptr, size_t size, size_t nmemb, FILE *stream) {
  103. lfs_t* fs = (lfs_t*)userdata;
  104. lfs_file_t* file = (lfs_file_t*)stream;
  105. if ((file->flags & LFS_O_WRONLY) != LFS_O_WRONLY && (file->flags & LFS_O_APPEND) != LFS_O_APPEND) {
  106. LLOGE("open file at readonly mode, reject for write flags=%08X", file->flags);
  107. return 0;
  108. }
  109. int ret = lfs_file_write(fs, file, ptr, size*nmemb);
  110. return ret < 0 ? 0 : ret;
  111. }
  112. int luat_vfs_lfs2_fflush(void* userdata, FILE *stream) {
  113. lfs_t* fs = (lfs_t*)userdata;
  114. lfs_file_t* file = (lfs_file_t*)stream;
  115. int ret = lfs_file_sync(fs, file);
  116. return ret < 0 ? 0 : ret;
  117. }
  118. int luat_vfs_lfs2_remove(void* userdata, const char *filename) {
  119. lfs_t* fs = (lfs_t*)userdata;
  120. return lfs_remove(fs, filename);
  121. }
  122. int luat_vfs_lfs2_rename(void* userdata, const char *old_filename, const char *new_filename) {
  123. lfs_t* fs = (lfs_t*)userdata;
  124. return lfs_rename(fs, old_filename, new_filename);
  125. }
  126. int luat_vfs_lfs2_fexist(void* userdata, const char *filename) {
  127. FILE* fd = luat_vfs_lfs2_fopen(userdata, filename, "rb");
  128. if (fd) {
  129. luat_vfs_lfs2_fclose(userdata, fd);
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. size_t luat_vfs_lfs2_fsize(void* userdata, const char *filename) {
  135. FILE *fd;
  136. size_t size = 0;
  137. fd = luat_vfs_lfs2_fopen(userdata, filename, "rb");
  138. if (fd) {
  139. size = lfs_file_size((lfs_t*)userdata, (lfs_file_t*)fd);
  140. luat_vfs_lfs2_fclose(userdata, fd);
  141. }
  142. return size;
  143. }
  144. int luat_vfs_lfs2_mkfs(void* userdata, luat_fs_conf_t *conf) {
  145. int ret = 0;
  146. lfs_t* fs = (lfs_t*)userdata;
  147. if (fs != NULL && fs->cfg != NULL) {
  148. ret = lfs_format(fs, fs->cfg);
  149. // LLOGD("lfs2 format ret %d", ret);
  150. if (ret < 0)
  151. return ret;
  152. ret = lfs_mount(fs, fs->cfg);
  153. // LLOGD("lfs2 mount ret %d", ret);
  154. return ret;
  155. }
  156. return -1;
  157. }
  158. int luat_vfs_lfs2_mount(void** userdata, luat_fs_conf_t *conf) {
  159. *userdata = (void*)conf->busname;
  160. return 0;
  161. }
  162. int luat_vfs_lfs2_umount(void* userdata, luat_fs_conf_t *conf) {
  163. LLOGE("not support yet : umount");
  164. return 0;
  165. }
  166. static int dir2name(char* buff, char const* _DirName) {
  167. size_t dirlen = strlen(_DirName);
  168. if (dirlen > 63) {
  169. LLOGE("dir too long!! %s", _DirName);
  170. return -1;
  171. }
  172. else if (dirlen < 1) {
  173. LLOGE("dir too short!! %s", _DirName);
  174. return -1;
  175. }
  176. memcpy(buff, _DirName, dirlen);
  177. if (buff[dirlen -1] == '/') {
  178. buff[dirlen -1] = 0;
  179. }
  180. return 0;
  181. }
  182. int luat_vfs_lfs2_mkdir(void* userdata, char const* _DirName) {
  183. lfs_t* fs = (lfs_t*)userdata;
  184. char buff[64] = {0};
  185. if (dir2name(buff, _DirName)) {
  186. return -1;
  187. }
  188. int ret = lfs_mkdir(fs, buff);
  189. return ret == LFS_ERR_OK ? 0 : -1;
  190. }
  191. int luat_vfs_lfs2_rmdir(void* userdata, char const* _DirName) {
  192. lfs_t* fs = (lfs_t*)userdata;
  193. char buff[64] = {0};
  194. if (dir2name(buff, _DirName)) {
  195. return -1;
  196. }
  197. int ret = lfs_remove(fs, buff);
  198. return ret == LFS_ERR_OK ? 0 : -1;
  199. }
  200. int luat_vfs_lfs2_lsdir(void* userdata, char const* _DirName, luat_fs_dirent_t* ents, size_t offset, size_t len) {
  201. lfs_t* fs = (lfs_t*)userdata;
  202. int ret , num = 0;
  203. lfs_dir_t *dir;
  204. struct lfs_info info;
  205. char buff[64] = {0};
  206. if (strlen(_DirName) == 0) {
  207. // OK的, 根目录嘛
  208. }
  209. else if (dir2name(buff, _DirName)) {
  210. return -1;
  211. }
  212. // if (fs->filecount > offset) {
  213. // if (offset + len > fs->filecount)
  214. // len = fs->filecount - offset;
  215. dir = luat_heap_malloc(sizeof(lfs_dir_t));
  216. if (dir == NULL) {
  217. // LLOGE("out of memory when lsdir");
  218. return 0;
  219. }
  220. ret = lfs_dir_open(fs, dir, buff);
  221. if (ret < 0) {
  222. luat_heap_free(dir);
  223. // LLOGE("no such dir %s _DirName");
  224. return 0;
  225. }
  226. // TODO 使用seek/tell组合更快更省
  227. for (size_t i = 0; i < offset; i++)
  228. {
  229. ret = lfs_dir_read(fs, dir, &info);
  230. if (ret <= 0) {
  231. lfs_dir_close(fs, dir);
  232. luat_heap_free(dir);
  233. return 0;
  234. }
  235. }
  236. while (num < len)
  237. {
  238. ret = lfs_dir_read(fs, dir, &info);
  239. if (ret < 0) {
  240. lfs_dir_close(fs, dir);
  241. luat_heap_free(dir);
  242. return 0;
  243. }
  244. if (ret == 0) {
  245. break;
  246. }
  247. if (info.type == 2 && (memcmp(info.name, ".", 2) ==0 ||memcmp(info.name, "..", 3)==0))
  248. continue;
  249. ents[num].d_type = info.type - 1; // lfs file =1, dir=2
  250. strcpy(ents[num].d_name, info.name);
  251. num++;
  252. }
  253. lfs_dir_close(fs, dir);
  254. luat_heap_free(dir);
  255. return num;
  256. // }
  257. return 0;
  258. }
  259. int luat_vfs_lfs2_info(void* userdata, const char* path, luat_fs_info_t *conf) {
  260. //LLOGD("why ? luat_vfs_lfs2_info %p", userdata);
  261. lfs_t* fs = (lfs_t*)userdata;
  262. memcpy(conf->filesystem, "lfs", strlen("lfs")+1);
  263. conf->type = 0;
  264. conf->total_block = fs->cfg->block_count;
  265. conf->block_used = lfs_fs_size(fs);
  266. conf->block_size = fs->cfg->block_size;
  267. //LLOGD("total %d used %d size %d", conf->total_block, conf->block_used, conf->block_size);
  268. return 0;
  269. }
  270. int luat_vfs_lfs2_truncate(void* userdata, const char *filename, size_t len) {
  271. FILE *fd;
  272. int ret = -1;
  273. fd = luat_vfs_lfs2_fopen(userdata, filename, "wb");
  274. if (fd) {
  275. ret = lfs_file_truncate((lfs_t*)userdata, (lfs_file_t*)fd ,(lfs_off_t)len);
  276. luat_vfs_lfs2_fclose(userdata, fd);
  277. }
  278. return ret;
  279. }
  280. void* luat_vfs_lfs2_opendir(void* userdata, const char *_DirName) {
  281. lfs_dir_t *dir = (lfs_dir_t*)luat_heap_malloc(sizeof(lfs_dir_t));
  282. if (dir == NULL) {
  283. LLOGD("out of memory when open file %s", dir);
  284. return NULL;
  285. }
  286. memset(dir, 0, sizeof(lfs_dir_t));
  287. int ret = lfs_dir_open((lfs_t*)userdata, dir, _DirName);
  288. if (ret < 0) {
  289. luat_heap_free(dir);
  290. return NULL;
  291. }
  292. return (void*)dir;
  293. }
  294. int luat_vfs_lfs2_closedir(void* userdata, void* dir) {
  295. lfs_dir_close((lfs_t*)userdata, (lfs_dir_t *)dir);
  296. if (dir)luat_heap_free(dir);
  297. return 0;
  298. }
  299. #define T(name) .name = luat_vfs_lfs2_##name
  300. const struct luat_vfs_filesystem vfs_fs_lfs2 = {
  301. .name = "lfs2",
  302. .opts = {
  303. T(mkfs),
  304. T(mount),
  305. T(umount),
  306. T(mkdir),
  307. T(rmdir),
  308. T(lsdir),
  309. T(remove),
  310. T(rename),
  311. T(fsize),
  312. T(fexist),
  313. T(info),
  314. T(truncate),
  315. T(opendir),
  316. T(closedir)
  317. },
  318. .fopts = {
  319. T(fopen),
  320. T(getc),
  321. T(fseek),
  322. T(ftell),
  323. T(fclose),
  324. T(feof),
  325. T(ferror),
  326. T(fread),
  327. T(fwrite),
  328. T(fflush)
  329. }
  330. };
  331. // #endif
  332. #endif