Allow writing to hidden files on Windows (#1653)
* feat(system): add system.ftruncate * fix: EPERM writing to hidden files on Windows * chore(doc): fix capitalization * refactor(system): make ftruncate length optional * refactor(doc): don't specify length
This commit is contained in:
parent
08fd994423
commit
d925da47fa
|
@ -103,7 +103,23 @@ function Doc:save(filename, abs_filename)
|
|||
else
|
||||
assert(self.filename or abs_filename, "calling save on unnamed doc without absolute path")
|
||||
end
|
||||
local fp = assert(io.open(filename, "wb"))
|
||||
|
||||
local fp
|
||||
if PLATFORM == "Windows" then
|
||||
-- On Windows, opening a hidden file with wb fails with a permission error.
|
||||
-- To get around this, we must open the file as r+b and truncate.
|
||||
-- Since r+b fails if file doesn't exist, fall back to wb.
|
||||
fp = io.open(filename, "r+b")
|
||||
if fp then
|
||||
system.ftruncate(fp)
|
||||
else
|
||||
-- file probably doesn't exist, create one
|
||||
fp = assert ( io.open(filename, "wb") )
|
||||
end
|
||||
else
|
||||
fp = assert ( io.open(filename, "wb") )
|
||||
end
|
||||
|
||||
for _, line in ipairs(self.lines) do
|
||||
if self.crlf then line = line:gsub("\n", "\r\n") end
|
||||
fp:write(line)
|
||||
|
|
|
@ -190,6 +190,15 @@ function system.rmdir(path) end
|
|||
---@param path string
|
||||
function system.chdir(path) end
|
||||
|
||||
---
|
||||
---Truncates a file to a set length.
|
||||
---
|
||||
---@param file file* A file handle returned by io.open().
|
||||
---@param length integer? Number of bytes to truncate to. Defaults to 0.
|
||||
---@return boolean success True if the operation suceeded, false otherwise
|
||||
---@return string? message An error message if the operation failed.
|
||||
function system.ftruncate(file, length) end
|
||||
|
||||
---
|
||||
---Create a new directory, note that this function doesn't recursively
|
||||
---creates the directories on the given path.
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#define fileno _fileno
|
||||
#define ftruncate _chsize
|
||||
#else
|
||||
|
||||
#include <dirent.h>
|
||||
|
@ -847,6 +850,26 @@ static int f_get_fs_type(lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
static int f_ftruncate(lua_State *L) {
|
||||
#if LUA_VERSION_NUM < 503
|
||||
// note: it is possible to support pre 5.3 and JIT
|
||||
// since file handles are just FILE* wrapped in a userdata;
|
||||
// but it is not standardized. YMMV.
|
||||
#error luaL_Stream is not supported in this version of Lua.
|
||||
#endif
|
||||
luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
|
||||
lua_Integer len = luaL_optinteger(L, 2, 0);
|
||||
if (ftruncate(fileno(stream->f), len) != 0) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushfstring(L, "ftruncate(): %s", strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int f_mkdir(lua_State *L) {
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
|
||||
|
@ -1285,6 +1308,7 @@ static const luaL_Reg lib[] = {
|
|||
{ "get_fs_type", f_get_fs_type },
|
||||
{ "text_input", f_text_input },
|
||||
{ "setenv", f_setenv },
|
||||
{ "ftruncate", f_ftruncate },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue