Получение нечетных результатов из криптографической библиотеки Node.js

56
6

Я пытаюсь написать функцию, чтобы рекурсивно получить md5sum всех файлов в каталоге, но каждый раз, когда он запускается без каких-либо файлов, я получаю разные результаты.

Код Я получаю эти результаты от:

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');

function _deepMD5(dir, md5){
var files = fs.readdirSync(dir);
for(var i = 0; i < files.length; i++){
var fp = dir+path.sep+files[i];
if(fs.lstatSync(fp).isDirectory()){
_deepMD5(fp, md5);
}
else{
var fh = fs.openSync(fp, 'r');
var chunkSize=1024;
var buffer=new Buffer(chunkSize, 'binary');
while(fs.readSync(fh, buffer, 0, chunkSize, null) != 0){
md5.update(buffer);
}
}
}
}

function deepMD5(dir){
var md5sum = crypto.createHash('md5');
_deepMD5(dir, md5sum);
return md5sum.digest('hex');
}

console.log(deepMD5("."));

спросил(а) 2014-02-06T09:16:00+04:00 5 лет, 10 месяцев назад
2
Решение
55

Когда вы создаете новый буфер, он не очищается. Итак, вы начинаете с случайно заполненного буфера - здесь происходят изменения между прогонами.

Затем вы читаете 1024 байта и обновляете хэш с этим. Тем не менее, это чтение на самом деле читает до 1024 байт. Он возвращает количество фактически прочитанных байтов. Вы хотите знать об этом. В противном случае каждый раз, когда вы просматриваете файл, не делящийся на 1024 байта, вы обновляете хэш с дополнительными материалами в конце (что-то случайное, если его первое чтение или что-то оставленное от предыдущего чтения.

Поэтому всякий раз, когда вы читаете меньше байтов chunkSize, вы хотите chunkSize байты, которые на самом деле происходят из самого последнего чтения и передать этот буфер для update:

var length;
while((length = fs.readSync(fh, buffer, 0, chunkSize, null)) != 0){
if(length == chunkSize)
md5.update(buffer);
else
md5.update(buffer.slice(0, length));
}

Для эффективности я избегал нарезки, когда нам этого не нужно. Конечно, вы можете просто нарезать каждый раз, если вы предпочитаете более короткий код и не беспокоитесь о производительности.

ответил(а) 2014-02-06T09:53:00+04:00 5 лет, 10 месяцев назад
Еще 1 ответ
47

В вашем коде требуется очень небольшое изменение, чтобы он работал buffer.fill(0): вам нужно сбросить новый буфер после создания, используя buffer.fill(0).

new Buffer() выражение new Buffer() выделяет память, но не очищает ее, поэтому вам нужно сделать это вручную. Если все ваши файлы имели размер 1024 байта, вы, вероятно, не заметили бы эту проблему. Но если есть хотя бы один файл размером менее 1024 байт, проблема, скорее всего, произойдет.

Исправлена функция _deepMD5:

function _deepMD5(dir, md5){
var files = fs.readdirSync(dir);
console.info("running with files: ", files)
for(var i = 0; i < files.length; i++){
var fp = dir+path.sep+files[i];
if(fs.lstatSync(fp).isDirectory()){
_deepMD5(fp, md5);
}
else{
var fh = fs.openSync(fp, 'r');
var chunkSize=1024;
var buffer=new Buffer(chunkSize, 'binary');
buffer.fill(0) // that will fix the issue.
while(fs.readSync(fh, buffer, 0, chunkSize, null) != 0){
md5.update(buffer);
}
}
}
}

Надеюсь, это поможет.

ответил(а) 2014-02-06T09:39:00+04:00 5 лет, 10 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема