rsync: escape U+2028/U+2029

JSON strings can contain unescaped U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR
characters while ECMAScript strings cannot. ES2019 now allows those unescaped.

The integrity code assumes that each JSON is a single line but that assumption does
not hold true when these characters are there in the string. Fix is to escape them.
This commit is contained in:
Girish Ramakrishnan
2026-03-15 09:20:38 +05:30
parent cee1180aa7
commit 6e0dc24eca
+7 -2
View File
@@ -10,6 +10,11 @@ import util from 'node:util';
const { log } = logger('syncer');
// JSON.stringify does not escape U+2028/U+2029 and readline treats them as line terminators
// https://github.com/tc39/proposal-json-superset
function jsonLineStringify(obj) {
return JSON.stringify(obj).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
}
function readCache(cacheFile) {
assert.strictEqual(typeof cacheFile, 'string');
@@ -111,7 +116,7 @@ async function sync(dataLayout, cacheFile) {
if (!entryStat.isDirectory() && !entryStat.isFile()) continue; // ignore non-files and dirs
if (entryStat.isSymbolicLink()) continue;
safe.fs.appendFileSync(newCacheFd, JSON.stringify({ path: entryPath, stat: { mtime: entryStat.mtime.getTime(), size: entryStat.size, inode: entryStat.inode, mode: entryStat.mode } }) + '\n');
safe.fs.appendFileSync(newCacheFd, jsonLineStringify({ path: entryPath, stat: { mtime: entryStat.mtime.getTime(), size: entryStat.size, inode: entryStat.inode, mode: entryStat.mode } }) + '\n');
if (curCacheIndex !== cache.length && cache[curCacheIndex].path < entryPath) { // files disappeared. first advance cache as needed
advanceCache(entryPath);
@@ -185,7 +190,7 @@ async function finalize(integrityMap, cacheFile) {
cacheEntry.integrity = integrityMap.get(cacheEntry.path); // { size, sha256 }
if (typeof cacheEntry.integrity === 'undefined') throw new BoxError(BoxError.INTERNAL_ERROR, `No integrity information for ${cacheEntry.path}`);
}
safe.fs.appendFileSync(tempCacheFd, JSON.stringify(cacheEntry) + '\n');
safe.fs.appendFileSync(tempCacheFd, jsonLineStringify(cacheEntry) + '\n');
}
safe.fs.closeSync(tempCacheFd);