file.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Module for interfacing with file system
  2. #include "module.h"
  3. #include "lauxlib.h"
  4. #include "platform.h"
  5. #include "c_types.h"
  6. #include "flash_fs.h"
  7. #include "c_string.h"
  8. static volatile int file_fd = FS_OPEN_OK - 1;
  9. // Lua: open(filename, mode)
  10. static int file_open( lua_State* L )
  11. {
  12. size_t len;
  13. if((FS_OPEN_OK - 1)!=file_fd){
  14. fs_close(file_fd);
  15. file_fd = FS_OPEN_OK - 1;
  16. }
  17. const char *fname = luaL_checklstring( L, 1, &len );
  18. if( len > FS_NAME_MAX_LENGTH )
  19. return luaL_error(L, "filename too long");
  20. const char *mode = luaL_optstring(L, 2, "r");
  21. file_fd = fs_open(fname, fs_mode2flag(mode));
  22. if(file_fd < FS_OPEN_OK){
  23. file_fd = FS_OPEN_OK - 1;
  24. lua_pushnil(L);
  25. } else {
  26. lua_pushboolean(L, 1);
  27. }
  28. return 1;
  29. }
  30. // Lua: close()
  31. static int file_close( lua_State* L )
  32. {
  33. if((FS_OPEN_OK - 1)!=file_fd){
  34. fs_close(file_fd);
  35. file_fd = FS_OPEN_OK - 1;
  36. }
  37. return 0;
  38. }
  39. // Lua: format()
  40. static int file_format( lua_State* L )
  41. {
  42. size_t len;
  43. file_close(L);
  44. if( !fs_format() )
  45. {
  46. NODE_ERR( "\ni*** ERROR ***: unable to format. FS might be compromised.\n" );
  47. NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
  48. }
  49. else{
  50. NODE_ERR( "format done.\n" );
  51. }
  52. return 0;
  53. }
  54. #if defined(BUILD_WOFS)
  55. // Lua: list()
  56. static int file_list( lua_State* L )
  57. {
  58. uint32_t start = 0;
  59. size_t act_len = 0;
  60. char fsname[ FS_NAME_MAX_LENGTH + 1 ];
  61. lua_newtable( L );
  62. while( FS_FILE_OK == wofs_next(&start, fsname, FS_NAME_MAX_LENGTH, &act_len) ){
  63. lua_pushinteger(L, act_len);
  64. lua_setfield( L, -2, fsname );
  65. }
  66. return 1;
  67. }
  68. #elif defined(BUILD_SPIFFS)
  69. extern spiffs fs;
  70. // Lua: list()
  71. static int file_list( lua_State* L )
  72. {
  73. spiffs_DIR d;
  74. struct spiffs_dirent e;
  75. struct spiffs_dirent *pe = &e;
  76. lua_newtable( L );
  77. SPIFFS_opendir(&fs, "/", &d);
  78. while ((pe = SPIFFS_readdir(&d, pe))) {
  79. // NODE_ERR(" %s size:%i\n", pe->name, pe->size);
  80. lua_pushinteger(L, pe->size);
  81. lua_setfield( L, -2, pe->name );
  82. }
  83. SPIFFS_closedir(&d);
  84. return 1;
  85. }
  86. static int file_seek (lua_State *L)
  87. {
  88. static const int mode[] = {FS_SEEK_SET, FS_SEEK_CUR, FS_SEEK_END};
  89. static const char *const modenames[] = {"set", "cur", "end", NULL};
  90. if((FS_OPEN_OK - 1)==file_fd)
  91. return luaL_error(L, "open a file first");
  92. int op = luaL_checkoption(L, 1, "cur", modenames);
  93. long offset = luaL_optlong(L, 2, 0);
  94. op = fs_seek(file_fd, offset, mode[op]);
  95. if (op < 0)
  96. lua_pushnil(L); /* error */
  97. else
  98. lua_pushinteger(L, fs_tell(file_fd));
  99. return 1;
  100. }
  101. // Lua: remove(filename)
  102. static int file_remove( lua_State* L )
  103. {
  104. size_t len;
  105. const char *fname = luaL_checklstring( L, 1, &len );
  106. if( len > FS_NAME_MAX_LENGTH )
  107. return luaL_error(L, "filename too long");
  108. file_close(L);
  109. SPIFFS_remove(&fs, (char *)fname);
  110. return 0;
  111. }
  112. // Lua: flush()
  113. static int file_flush( lua_State* L )
  114. {
  115. if((FS_OPEN_OK - 1)==file_fd)
  116. return luaL_error(L, "open a file first");
  117. if(fs_flush(file_fd) == 0)
  118. lua_pushboolean(L, 1);
  119. else
  120. lua_pushnil(L);
  121. return 1;
  122. }
  123. #if 0
  124. // Lua: check()
  125. static int file_check( lua_State* L )
  126. {
  127. file_close(L);
  128. lua_pushinteger(L, fs_check());
  129. return 1;
  130. }
  131. #endif
  132. // Lua: rename("oldname", "newname")
  133. static int file_rename( lua_State* L )
  134. {
  135. size_t len;
  136. if((FS_OPEN_OK - 1)!=file_fd){
  137. fs_close(file_fd);
  138. file_fd = FS_OPEN_OK - 1;
  139. }
  140. const char *oldname = luaL_checklstring( L, 1, &len );
  141. if( len > FS_NAME_MAX_LENGTH )
  142. return luaL_error(L, "filename too long");
  143. const char *newname = luaL_checklstring( L, 2, &len );
  144. if( len > FS_NAME_MAX_LENGTH )
  145. return luaL_error(L, "filename too long");
  146. if(SPIFFS_OK==myspiffs_rename( oldname, newname )){
  147. lua_pushboolean(L, 1);
  148. } else {
  149. lua_pushboolean(L, 0);
  150. }
  151. return 1;
  152. }
  153. // Lua: fsinfo()
  154. static int file_fsinfo( lua_State* L )
  155. {
  156. u32_t total, used;
  157. SPIFFS_info(&fs, &total, &used);
  158. NODE_DBG("total: %d, used:%d\n", total, used);
  159. if(total>0x7FFFFFFF || used>0x7FFFFFFF || used > total)
  160. {
  161. return luaL_error(L, "file system error");;
  162. }
  163. lua_pushinteger(L, total-used);
  164. lua_pushinteger(L, used);
  165. lua_pushinteger(L, total);
  166. return 3;
  167. }
  168. #endif
  169. // g_read()
  170. static int file_g_read( lua_State* L, int n, int16_t end_char )
  171. {
  172. if(n <= 0 || n > LUAL_BUFFERSIZE)
  173. n = LUAL_BUFFERSIZE;
  174. if(end_char < 0 || end_char >255)
  175. end_char = EOF;
  176. luaL_Buffer b;
  177. if((FS_OPEN_OK - 1)==file_fd)
  178. return luaL_error(L, "open a file first");
  179. luaL_buffinit(L, &b);
  180. char *p = luaL_prepbuffer(&b);
  181. int i;
  182. n = fs_read(file_fd, p, n);
  183. for (i = 0; i < n; ++i)
  184. if (p[i] == end_char)
  185. {
  186. ++i;
  187. break;
  188. }
  189. if(i==0){
  190. luaL_pushresult(&b); /* close buffer */
  191. return (lua_objlen(L, -1) > 0); /* check whether read something */
  192. }
  193. fs_seek(file_fd, -(n - i), SEEK_CUR);
  194. luaL_addsize(&b, i);
  195. luaL_pushresult(&b); /* close buffer */
  196. return 1; /* read at least an `eol' */
  197. }
  198. // Lua: read()
  199. // file.read() will read all byte in file
  200. // file.read(10) will read 10 byte from file, or EOF is reached.
  201. // file.read('q') will read until 'q' or EOF is reached.
  202. static int file_read( lua_State* L )
  203. {
  204. unsigned need_len = LUAL_BUFFERSIZE;
  205. int16_t end_char = EOF;
  206. size_t el;
  207. if( lua_type( L, 1 ) == LUA_TNUMBER )
  208. {
  209. need_len = ( unsigned )luaL_checkinteger( L, 1 );
  210. if( need_len > LUAL_BUFFERSIZE ){
  211. need_len = LUAL_BUFFERSIZE;
  212. }
  213. }
  214. else if(lua_isstring(L, 1))
  215. {
  216. const char *end = luaL_checklstring( L, 1, &el );
  217. if(el!=1){
  218. return luaL_error( L, "wrong arg range" );
  219. }
  220. end_char = (int16_t)end[0];
  221. }
  222. return file_g_read(L, need_len, end_char);
  223. }
  224. // Lua: readline()
  225. static int file_readline( lua_State* L )
  226. {
  227. return file_g_read(L, LUAL_BUFFERSIZE, '\n');
  228. }
  229. // Lua: write("string")
  230. static int file_write( lua_State* L )
  231. {
  232. if((FS_OPEN_OK - 1)==file_fd)
  233. return luaL_error(L, "open a file first");
  234. size_t l, rl;
  235. const char *s = luaL_checklstring(L, 1, &l);
  236. rl = fs_write(file_fd, s, l);
  237. if(rl==l)
  238. lua_pushboolean(L, 1);
  239. else
  240. lua_pushnil(L);
  241. return 1;
  242. }
  243. // Lua: writeline("string")
  244. static int file_writeline( lua_State* L )
  245. {
  246. if((FS_OPEN_OK - 1)==file_fd)
  247. return luaL_error(L, "open a file first");
  248. size_t l, rl;
  249. const char *s = luaL_checklstring(L, 1, &l);
  250. rl = fs_write(file_fd, s, l);
  251. if(rl==l){
  252. rl = fs_write(file_fd, "\n", 1);
  253. if(rl==1)
  254. lua_pushboolean(L, 1);
  255. else
  256. lua_pushnil(L);
  257. }
  258. else{
  259. lua_pushnil(L);
  260. }
  261. return 1;
  262. }
  263. // Module function map
  264. static const LUA_REG_TYPE file_map[] = {
  265. { LSTRKEY( "list" ), LFUNCVAL( file_list ) },
  266. { LSTRKEY( "open" ), LFUNCVAL( file_open ) },
  267. { LSTRKEY( "close" ), LFUNCVAL( file_close ) },
  268. { LSTRKEY( "write" ), LFUNCVAL( file_write ) },
  269. { LSTRKEY( "writeline" ), LFUNCVAL( file_writeline ) },
  270. { LSTRKEY( "read" ), LFUNCVAL( file_read ) },
  271. { LSTRKEY( "readline" ), LFUNCVAL( file_readline ) },
  272. { LSTRKEY( "format" ), LFUNCVAL( file_format ) },
  273. #if defined(BUILD_SPIFFS) && !defined(BUILD_WOFS)
  274. { LSTRKEY( "remove" ), LFUNCVAL( file_remove ) },
  275. { LSTRKEY( "seek" ), LFUNCVAL( file_seek ) },
  276. { LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
  277. //{ LSTRKEY( "check" ), LFUNCVAL( file_check ) },
  278. { LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
  279. { LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
  280. #endif
  281. { LNILKEY, LNILVAL }
  282. };
  283. NODEMCU_MODULE(FILE, "file", file_map, NULL);