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
|
else
|
||||||
assert(self.filename or abs_filename, "calling save on unnamed doc without absolute path")
|
assert(self.filename or abs_filename, "calling save on unnamed doc without absolute path")
|
||||||
end
|
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
|
for _, line in ipairs(self.lines) do
|
||||||
if self.crlf then line = line:gsub("\n", "\r\n") end
|
if self.crlf then line = line:gsub("\n", "\r\n") end
|
||||||
fp:write(line)
|
fp:write(line)
|
||||||
|
|
|
@ -190,6 +190,15 @@ function system.rmdir(path) end
|
||||||
---@param path string
|
---@param path string
|
||||||
function system.chdir(path) end
|
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
|
---Create a new directory, note that this function doesn't recursively
|
||||||
---creates the directories on the given path.
|
---creates the directories on the given path.
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
||||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define fileno _fileno
|
||||||
|
#define ftruncate _chsize
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <dirent.h>
|
#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) {
|
static int f_mkdir(lua_State *L) {
|
||||||
const char *path = luaL_checkstring(L, 1);
|
const char *path = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
@ -1285,6 +1308,7 @@ static const luaL_Reg lib[] = {
|
||||||
{ "get_fs_type", f_get_fs_type },
|
{ "get_fs_type", f_get_fs_type },
|
||||||
{ "text_input", f_text_input },
|
{ "text_input", f_text_input },
|
||||||
{ "setenv", f_setenv },
|
{ "setenv", f_setenv },
|
||||||
|
{ "ftruncate", f_ftruncate },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue