file.c 7.7 KB

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