Je lis un flux, qui est testé avec une expression régulière:

var deviceReadStream = fs.createReadStream("/path/to/stream");

deviceReadStream.on('data',function(data){
  if( data.match(aRegex) )
    //do something
});

Mais comme le flux est divisé en plusieurs morceaux, il est possible que la coupure me fasse rater un match. Il existe donc un meilleur modèle pour tester en continu un flux avec une expression régulière?

plus de détails

Le flux est le contenu d'un système de fichiers en panne. Je recherche une signature ext2 (0xef53). Comme je ne sais pas comment les morceaux sont divisés, la signature pourrait être divisée et ne pas être détectée.

J'ai donc utilisé une boucle pour pouvoir me délimiter la façon dont les morceaux sont divisés, c'est-à-dire par bloc du système de fichiers.

Mais l'utilisation de flux semble être un meilleur modèle, alors comment puis-je utiliser des flux tout en me définissant la taille des morceaux?

14
Gaël Barbin 22 juil. 2015 à 12:46

3 réponses

Meilleure réponse

Tout d'abord, si vous êtes déterminé à utiliser une expression régulière avec nodejs, essayez pcre. Un wrapper de noeud pour pcre est disponible. Pcre peut être configuré pour effectuer des correspondances partielles qui peuvent reprendre à travers les limites du tampon.

Vous pouvez, cependant, simplement grep (ou fgrep pour plusieurs chaînes statiques) pour un décalage d'octet par rapport au terminal. Vous pouvez ensuite le suivre avec xxd et less pour l'afficher ou dd pour extraire une partie.

Par exemple, pour obtenir des décalages avec grep:

grep --text --byte-offset --only-matching --perl-regex "\xef\x53" recovery.img

Notez que les options de la ligne de commande grep peuvent varier en fonction de votre distribution.

Vous pouvez également consulter bgrep même si je ne l'ai pas utilisé.

J'ai eu de la chance de faire de la récupération en utilisant divers outils et scripts shell.

Quelques autres commentaires tangentiels:

  1. Gardez à l'esprit l'endianité de tout ce que vous recherchez.
  2. Prenez une image puisque vous effectuez une récupération, si vous ne l'avez pas déjà fait. Entre autres dangers, si un appareil commence à tomber en panne, un accès supplémentaire peut l'aggraver.
  3. Outils de sculpture de données de référence. ref
  4. Comme vous l'avez mentionné, les fichiers peuvent être fragmentés. Je m'attends quand même à ce que les partitions et les fichiers commencent aux limites du secteur. Autant que je sache, la magie ne serait généralement pas divisée.
  5. Veillez à ne pas écrire par inadvertance sur le périphérique que vous récupérez.
  6. Comme vous le savez peut-être, si vous reconstruisez l'image, vous pourrez peut-être monter l'image à l'aide d'un pilote de bouclage.
2
user650881 25 août 2015 à 21:10

J'irais avec regarder le flux de données comme une fenêtre mobile de taille 6 octets.

Par exemple, si vous avez le fichier suivant (en octets): 23, 34, 45, 67, 76

Une fenêtre mobile de 2 passant sur les données sera:

[23, 34]
[34, 45]
[45, 67]
[67, 76]

Je vous propose de parcourir ces fenêtres à la recherche de votre chaîne.

var Stream = require('stream');
var fs = require('fs');

var exampleStream = fs.createReadStream("./dump.dmp");
var matchCounter = 0;
windowStream(exampleStream, 6).on('window', function(buffer){
    if (buffer.toString() === '0xEF53') {
        ++matchCounter;
    }
}).on('end', function(){
    console.log('done scanning the file, found', matchCounter);
});
function windowStream(inputStream, windowSize) {
    var outStream = new Stream();
    var soFar = [];
    inputStream.on('data', function(data){
        Array.prototype.slice.call(data).forEach(function(byte){
            soFar.push(byte);
            if (soFar.length === windowSize) {
                outStream.emit('window', new Buffer(soFar));
                soFar.shift();
            }
        });
    });
    inputStream.on('end', function(){
        outStream.emit('end');
    });
    return outStream;
}

Habituellement, je ne suis pas fan des octets lorsque vous avez réellement besoin de la chaîne sous-jacente. Dans UTF-8, il y a des cas où cela pourrait causer des problèmes, mais en supposant que tout est en anglais, ça devrait aller. L'exemple peut être amélioré pour prendre en charge ces cas en utilisant un décodeur de chaîne

MODIFIER

Voici une version UTF8

var Stream = require('stream');
var fs = require('fs');

var exampleStream = fs.createReadStream("./dump.dmp", {encoding: 'utf8'});
var matchCounter = 0;

windowStream(exampleStream, 6).on('window', function(windowStr){
    if (windowStr === '0xEF53') {
        ++matchCounter;
    }
}).on('end', function(){
    console.log('done scanning the file, found', matchCounter);
});
function windowStream(inputStream, windowSize) {
    var outStream = new Stream();
    var soFar = "";
    inputStream.on('data', function(data){
        Array.prototype.slice.call(data).forEach(function(char){
            soFar += char;
            if (soFar.length === windowSize) {
                outStream.emit('window', soFar);
                soFar = soFar.slice(1);
            }
        });
    });
    inputStream.on('end', function(){
        outStream.emit('end');
    });
    return outStream;
}
0
surui 27 août 2015 à 22:49

En supposant que votre code a juste besoin de rechercher la signature 0xef53 (comme spécifié dans la partie "plus de détails" de votre question ...

Une façon de le faire et de continuer à utiliser l'expression régulière consiste à conserver une référence au tampon de données précédent, à le concaténer avec le tampon de données actuel et à exécuter l'expression régulière à ce sujet. C'est un peu lourd sur l'utilisation du processeur car il analyse efficacement chaque tampon de données deux fois (et il y a beaucoup d'allocation de mémoire en raison de la concaténation). Il est relativement facile à lire et devrait donc être maintenable à l'avenir.

Voici un exemple de ce à quoi ressemblerait le code

var deviceReadStream = fs.createReadStream("/path/to/stream");
var prevData = '';

deviceReadStream.on('data',function(data){
  var buffer = prevData + data;
  if( buffer.match(aRegex) )
    //do something

  prevData = data;
});

Une autre option serait de faire plus manuellement les comparaisons de caractères afin que le code puisse intercepter lorsque la signature est divisée entre les tampons de données. Vous pouvez voir une solution à cela dans cette question connexe Un moyen efficace de rechercher une chaîne dans un flux. Selon l'article de blog de la première réponse, le code Haxe qu'il a écrit peut être construit pour produire du JavaScript que vous pouvez ensuite utiliser. Ou vous pouvez écrire votre propre code personnalisé pour effectuer la recherche, car la signature que vous recherchez ne comporte que 4 caractères.

6
Community 23 mai 2017 à 12:31