file.c 7.5 KB

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