From 5a7a88ccbdfcfc43f80a5f3ee7162203fa1cb8fb Mon Sep 17 00:00:00 2001 From: remittor Date: Fri, 16 Jan 2026 11:34:09 +0300 Subject: [PATCH] luci: Fix save very long textareas to file --- .../resources/view/zapret/tools.js | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js index 5751128..61d11c6 100644 --- a/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js +++ b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js @@ -370,40 +370,56 @@ return baseclass.extend({ ]); }, - handleSaveAdv: async function(ev) { - let txt = document.getElementById('widget.modal_content'); - let value = txt.value.trim().replace(/\r\n/g, '\n'); - if (value.length > 0) { - value += '\n'; - } - let data = value.replace(/'/g, `'\"'\"'`); - let chunkSize = 8000; + writeAdv: async function(fileName, data, chunkSize = 8000) + { + let tmpFile = fileName + '.tmp'; try { - for (let wsize = -1; wsize < data.length; wsize += chunkSize) { - let chunk = ''; - if (wsize < 0) { - wsize = 0; + for (let wsize = 0; wsize <= data.length; wsize += chunkSize) { + let chunk = data.slice(wsize, wsize + chunkSize); + if (wsize > 0 && chunk.length == 0) { + break; // EOF } - if (data.length > 0) { - chunk = data.slice(wsize, wsize + chunkSize); - } - let teeArg = (wsize === 0) ? '' : '-a '; - let cmd = `printf %s '${chunk}' | tee ${teeArg} '${this.file}'`; + chunk = chunk.replace(/'/g, `'\"'\"'`); + let teeArg = (wsize === 0) ? '' : '-a'; + let cmd = `printf %s '${chunk}' | tee ${teeArg} '${tmpFile}'`; let res = await fs.exec('/bin/busybox', [ 'sh', '-c', cmd ]); if (res.code !== 0) { throw new Error('tee failed, rc = ' + res.code); } } + let res = await fs.exec('/bin/busybox', [ 'mv', '-f', tmpFile, fileName ]); + if (res.code != 0) { + throw new Error('mv failed, rc = ' + res.code); + } + } catch(e) { + try { + await fs.exec('/bin/busybox', [ 'rm', '-f', tmpFile ]); + } catch(e2) { + // nothing + } + throw e; + } + return fs.stat(fileName); + }, + + handleSaveAdv: async function(ev) + { + let txt = document.getElementById('widget.modal_content'); + let value = txt.value.trim().replace(/\r\n/g, '\n'); + if (value.length > 0) { + value += '\n'; + } + return this.writeAdv(this.file, value).then(async rc => { txt.value = value; ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); if (this.callback) { return this.callback(rc); } - } catch(e) { + }).catch(e => { ui.addNotification(null, E('p', _('Unable to save the contents') + ': %s'.format(e.message))); - } finally { + }).finally(() => { ui.hideModal(); - } + }); }, error: function(e) {