Skip to content

Commit e70c305

Browse files
committed
fix: escrita via SaveResourceFile (sem truncar) + respeita sandbox
Diagnostico confirmou: o sandbox do FiveM bloqueia escrita cross-resource (io cru e SaveResourceFile barrados). Pior: io.open('wb') no caminho cru ABRE e TRUNCA o arquivo antes do write falhar -> risco de zerar o arquivo de outro resource. Passa a usar so a native SaveResourceFile, que respeita o sandbox de forma limpa (nao toca o arquivo quando barra) e funciona quando ha add_filesystem_permission. Remove o writePhysicalFile (io cru) morto.
1 parent 4245007 commit e70c305

1 file changed

Lines changed: 17 additions & 47 deletions

File tree

server/resources.lua

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -109,27 +109,8 @@ local function targetKey(target)
109109
return tostring(target.resource or '') .. ':' .. tostring(target.relative or '')
110110
end
111111

112-
local function writePhysicalFile(absolutePath, content)
113-
local handle, err = io.open(absolutePath, 'wb')
114-
if not handle then
115-
return false, ('Falha ao abrir arquivo para escrita: %s'):format(tostring(err or 'sem detalhe'))
116-
end
117-
118-
local ok, writeErr = handle:write(tostring(content or ''))
119-
handle:close()
120-
-- No Lua do FiveM, write/close podem retornar valores nao-padrao mesmo no
121-
-- sucesso; so tratamos como falha quando o write retorna erro explicito. A
122-
-- verdade final fica com a verificacao por leitura (writeDiskFile).
123-
if ok == nil and writeErr ~= nil then
124-
return false, ('Falha ao gravar arquivo: %s'):format(tostring(writeErr))
125-
end
126-
127-
return true
128-
end
129-
130-
-- A escrita/criacao/exclusao em disco e feita por io/os crus do Lua (que nao
131-
-- passam pelo sandbox do FiveM); o FS bridge em Node so e usado para LISTAR
132-
-- (leitura), entao mantemos apenas o list aqui.
112+
-- A escrita usa a native SaveResourceFile (writeDiskFile). O FS bridge em Node
113+
-- so e usado para LISTAR (leitura), entao mantemos apenas o list aqui.
133114
local function listWithFsBridge(target)
134115
local ok, result = pcall(function()
135116
return exports[GetCurrentResourceName()]:QadminListPhysicalResourceDirectory(target.root, target.relative)
@@ -686,41 +667,30 @@ end
686667

687668
local function writeDiskFile(target, content)
688669
local text = tostring(content or '')
670+
-- best-effort: garante a pasta pai (no-op se ja existir).
689671
ensureDirectoryExists(target.absolute:match('^(.*)[\\/][^\\/]+$') or normalizeSlashes(target.root))
690672

691-
-- 1) io cru do Lua (nao passa pelo sandbox). Ignora o retorno de write/close
692-
-- (o Lua do FiveM pode retornar nil mesmo no sucesso) — a verdade e a
693-
-- verificacao por leitura.
694-
local ioOk, ioErr = writePhysicalFile(target.absolute, text)
695-
if writtenMatches(target, text) then
696-
recentWrites[targetKey(target)] = text
697-
return true
698-
end
699-
700-
-- 2) fallback: native SaveResourceFile (grava relativo ao resource). Sempre
701-
-- funciona para os arquivos do proprio mri_Qadmin; para outros resources
702-
-- depende do sandbox do FiveM (add_filesystem_permission).
703-
local nativeOk = SaveResourceFile(target.resource, target.relative, text, #text)
673+
-- Usa a native SaveResourceFile (grava relativo ao resource). Importante: NAO
674+
-- usar io.open('wb') no caminho cru — em artifacts com sandbox o write e
675+
-- bloqueado, mas o 'wb' ja TRUNCOU o arquivo na abertura (perda de dados). A
676+
-- native respeita o sandbox de forma limpa, sem tocar o arquivo quando barra.
677+
-- Para o proprio mri_Qadmin sempre funciona; para outros resources depende de
678+
-- add_filesystem_permission no server.cfg.
679+
SaveResourceFile(target.resource, target.relative, text, #text)
704680
if writtenMatches(target, text) then
705681
recentWrites[targetKey(target)] = text
706682
return true
707683
end
708684

709-
-- Diagnostico no console pra distinguir sandbox cross-resource de io bloqueado.
710-
print(('[mri_Qadmin] write falhou | resource=%s self=%s rel=%s | abs=%s | io.open(wb)=%s ioErr=%s | SaveResourceFile=%s')
711-
:format(
712-
tostring(target.resource),
713-
tostring(target.resource == GetCurrentResourceName()),
714-
tostring(target.relative),
715-
tostring(target.absolute),
716-
tostring(ioOk),
717-
tostring(ioErr),
718-
tostring(nativeOk)
719-
))
685+
print(('[mri_Qadmin] write falhou | resource=%s self=%s rel=%s'):format(
686+
tostring(target.resource),
687+
tostring(target.resource == GetCurrentResourceName()),
688+
tostring(target.relative)
689+
))
720690

721691
local hint = (target.resource == GetCurrentResourceName())
722-
and 'Falha ao gravar mesmo no proprio mri_Qadmin — io/SaveResourceFile bloqueados no servidor.'
723-
or ('Sandbox do FiveM bloqueia escrita em "%s". Adicione no server.cfg: add_filesystem_permission mri_Qadmin write %s'):format(target.resource, target.resource)
692+
and 'Falha ao gravar mesmo no proprio mri_Qadmin.'
693+
or ('O sandbox do FiveM bloqueia escrita em "%s". Adicione no server.cfg: add_filesystem_permission mri_Qadmin write %s'):format(target.resource, target.resource)
724694

725695
return false, ('Nao foi possivel gravar o arquivo. %s'):format(hint)
726696
end

0 commit comments

Comments
 (0)