elua: load regular file if bytecode cache fails
authorDaniel Kolesa <d.kolesa@osg.samsung.com>
Wed, 30 Aug 2017 18:19:24 +0000 (20:19 +0200)
committerDaniel Kolesa <d.kolesa@osg.samsung.com>
Wed, 30 Aug 2017 18:21:23 +0000 (20:21 +0200)
If bytecode is requested and fails to load, load original file
instead. Force re-write of bytecode if that succeeds.

This is useful if there is bytecode newer than the source file that
the current Lua version can't load, for example when migrating from
LuaJIT 2.0 to 2.1, which changed bytecode format.

Fixes confusing cases such as in T2728.

src/lib/elua/cache.c

index fe6825f..91fcdac 100644 (file)
@@ -35,11 +35,11 @@ generate:
 }
 
 static Eina_File *
-open_src(const char *fname, Eina_Bool *bc)
+open_src(const char *fname, Eina_Bool *bc, Eina_Bool allow_bc)
 {
    Eina_File  *f   = NULL;
    const char *ext = strstr(fname, ".lua");
-   if (ext && !ext[4])
+   if (ext && !ext[4] && allow_bc)
      {
         char buf[PATH_MAX];
         snprintf(buf, sizeof(buf), "%sc", fname);
@@ -151,7 +151,7 @@ elua_io_loadfile(const Elua_State *es, const char *fname)
      {
         return elua_loadstdin(L);
      }
-   if (!(f = open_src(fname, &bcache)))
+   if (!(f = open_src(fname, &bcache, EINA_TRUE)))
      {
         lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno));
         return LUA_ERRFILE;
@@ -167,7 +167,37 @@ elua_io_loadfile(const Elua_State *es, const char *fname)
    status = lua_load(L, getf_map, &s, chname);
    eina_file_map_free(f, s.fmap);
    eina_file_close(f);
-   if (!status && bcache) write_bc(L, fname);
+   if (status)
+     {
+        /* we loaded bytecode and that failed; try loading source instead */
+        if (!bcache)
+          {
+             /* can't open real file, so return original error */
+             if (!(f = open_src(fname, &bcache, EINA_FALSE)))
+               {
+                  lua_remove(L, -2);
+                  return status;
+               }
+             s.flen = eina_file_size_get(f);
+             /* can't read real file, so return original error */
+             if (!(s.fmap = eina_file_map_all(f, EINA_FILE_RANDOM)))
+               {
+                  lua_remove(L, -2);
+                  return status;
+               }
+             /* loaded original file, pop old error and load again */
+             lua_pop(L, 1);
+             status = lua_load(L, getf_map, &s, chname);
+             eina_file_map_free(f, s.fmap);
+             eina_file_close(f);
+             /* force write new bytecode */
+             if (!status)
+               write_bc(L, fname);
+          }
+        /* whatever happened here, proceed to the end... */
+     }
+   else if (bcache)
+     write_bc(L, fname); /* success and bytecode write */
    lua_remove(L, -2);
    return status;
 }