Копируем некопируемое (на примере Node.js)

Сейчас бóльшую часть времени я переписываю наш сервис GeekJOB.ru. Сервис переписывается на новую архитектуру с новыми фичами. Для переезда нужно мигрировать все текущие данные с текущего сервиса в новый. И это не только база, но и файлы. И вот написал я скрипт для миграции логотипов компаний (попутно их конвертируя, оптимизируя и адаптируя, ресайз и прочие манипуляции…). И натолкнулся на ситуацию: на каких-то файлах скрипт падает, потому, что просто не может их скопировать. Ошибка банальная — not found, но файлы есть физически. Это файлы содержащие различные символы, которые не дают найти файл используя программные методы. Никакие приёмы, такие как экранирование и прочие способы (например представить имя файла в hex формате) не помогли.

Текущая версия GeekJOB написана на C#, ASP.NET и работает на Windows Server. При этом файлы загружаются с теми же именами, с какими их загружали пользователи. Поэтому некоторые файлы содержат символы, которые делают файлы “недоступными”.

Скопировать их руками через консоль так же затруднительно. Приходится применять специальные техники. Конечно можно было бы ручками перенести, но хочется все же чтобы это делал скрипт (мыжпрогрпамисты). Скрипт миграции написан на Node.js (моя любимая платформа, если что 😉 ).

Я искал как можно копировать такие файлы стандартными методами, но я не нашел. В итоге наколбасил вот такой вариант решения проблемы:

const fs = require('fs');
const path = require('path');
const exec = require('child_process').execSync;
...
try {
...
fs.copyFileSync(srcFile, dstFile);
} catch {
  let inode = exec(`echo $(ls -i ${dirName}/)|awk '{print $1}'`).toString().trim();
  let shellLog = exec(`find ${dirName} -inum ${inode} -exec cp -v {} ${newFile} \;`).toString();
  console.log(shellLog);
}

Что мы делаем: мы пытаемся скопировать файл. Если вылетает ошибка, то используя системные вызовы вычисляем inode файла и копируем файл используя inode.

Таким образом я смог мигрировать все файлы, даже те, которые нельзя было скопировать. В моем случае мне повезло с тем, что в каждой директории был ровно 1 целевой файл, поэтому я смело получал первый попавшийся inode из директории. Если же в директории больше одного файла — надо думать как вычислить inode конкретного файла (при условии что больше 1го битого файла).

Возможно кто-то из вас сталкивался с такой ситуацией и если да, поделитесь своим опытом. Если нет — вот вам решение.

Если у вас есть решение лучше или просто другое, то напишите, пожалуйста в комментариях. Может быть есть способ скопировать такие файлы проще?