13 aprile 2016

Copia verificata dei file con Windows

Oggi un testo leggero leggero, più una pillola che un vero e proprio articolo.

L'interesse verso questa esigenza è nato dalla necessità di essere davvero sicuro che durante la copia di una grande quantità di file di grandi dimensioni, effettuata tramite uno script in Powershell "unattended" e pianificato, non occorressero errori di copiatura.


"Make things as simple as possible, but not simpler"
Albert Einstein


La natura dello script era tale per cui non potevo interrompere l'operazione in caso di errore, ma dovevo portare tutto a compimento oppure non eseguire affatto i comandi... ho dunque implementato tutti i controlli necessari per prevenire errori grossolani come la dimensione dei file, lo spazio disponibile, la presenza del server di posta per l'invio del rapporto di completamento.
Un ulteriore requirement mi chiedeva di verificare i file dopo averli copiati. Dal momento che era la prima volta che mi trovavo di fronte a questa esigenza, ho "improvvisato" implementando il calcolo del checksum SHA1 e il confronto di questo per ciascun file, tra originale e copia (la velocità di esecuzione non era un requisito!). Di certo la soluzione era robusta, ma trascurava un problema...
In fase di test mi sono trovato di fronte una condizione inattesa: alcuni percorsi di copia risultavano più lunghi di 260 caratteri, un limite che da Powershell (e in generale ciò che utilizza le Windows API, incluse le classi .NET) non può sempre essere superato agevolmente. Questo intoppo non solo rompeva la nuda copia dei file, cosa che avrei potuto bypassare senza problemi utilizzando robocopy (che supporta i percorsi "lunghi"), ma non avevo più possibilità di utilizzare la classe System.IO.File per leggere il contenuto dei file ed elaborarne lo SHA1.
Per una serie di motivi non potevo andare a utilizzare classi e librerie di terzi (soprattutto per limitazioni di policy interna), quindi dovevo trovare una alternativa. È stato in questo momento che sono stato fulminato da una scoperta così ridicola che mi ha fatto sentire un niubbo di dimensioni galattiche.
Quando si effettua la copia di file con Windows Explorer, ciascun file copiato viene verificato trasparentemente dal sistema operativo, mentre questo non avviene quando lo si fa dalla cmd (o da Powershell). Ma ecco la sorpresa: si può abilitare la verifica utilizzando il comando "verify on" (e rileggere semplicemente con il commando "verify").
Per ricapitolare:
  1. il controllo che avevo implementato usando il checksum dei file era inutile;
  2. per una cosa così banale ho impiegato diverse ore a causa della mia ignoranza;
  3. le ore perse per riempire l'ignoranza che ci divora non lo sono mai.
E in regalo, per i lettori pazienti che hanno seguito fino a qui, un "filettino" .bat che potrebbe semplificarvi la vita, in casi simili:

@echo off
REM ***************************************************************************
REM SYNOPSIS:
REM This script activates Windows file copy verification then
REM copies recursively all content of the path %1 inside the path %2
REM and sets each file as "read-only", while logging everything inside
REM RobocopyLog.txt on the actual prompt folder
REM ***************************************************************************
REM File Name : rbcpy.bat
REM Version : 1.2
REM Date : 25 MAR 2016
REM Author : Michele Brami
REM ***************************************************************************
REM Usage: rbcpy.bat $sourcepath $destinationpath
REM
REM Example:
REM
REM C:\SomeFolder>rbcpy.bat C:\Source \\server\share\folder
REM
REM (RobocopyLog.txt will be saved to C:\SomeFolder)
REM
REM ***************************************************************************
verify on
robocopy %1 %2 /E /NP /V /TEE /MT:8 /A+:R /LOG:RobocopyLog.txt