Passa al contenuto principale

SFTP è il sottosistema FTP che fa parte di SSH e consente di eseguire trasferimenti di file crittografati. La scorsa settimana ho riscontrato due problemi relativi al trasferimento non corretto dei file tramite SFTP. In un caso OpenVOS era la fonte del file, mentre nell'altro era il destinatario. In entrambi i casi i file contenevano dati ASCII e i problemi erano legati alle differenze tra Microsoft Windows e OpenVOS nella terminazione delle righe in un file di testo.

Cominciamo con OpenVOS come fonte. Se crei un file di testo utilizzando il tuo editor preferito, crei un file sequenziale. Ad esempio

d test
%phx_vos#m16_mas>SysAdmin>Noah_Davids>test  10-09-05 08:13:49 mst
12345
67890

ready 08:13:49

Figura 1 – visualizzazione di un file di testo
Il comando display_file_status mostra che si tratta di un file sequenziale e che, sebbene il conteggio dei byte di dati sia 10, nel file sono effettivamente presenti 20 byte.
display_file_status test
name: %phx_vos#m16_mas>SysAdmin>Noah_Davids>test
file organization: sequential file
. . .
next byte:                 20
blocks used: 1
. . .
record count: 2
data byte count:           10

ready 08:14:01

Figura 2 – Stato del file display_file
Il comando dump_file mostra la struttura effettiva del file. Ogni "riga" è preceduta e terminata da 2 byte che ne indicano la lunghezza. Questi byte di lunghezza devono iniziare su un confine di byte pari, quindi è presente anche un byte di riempimento. La cosa importante da notare è che non ci sono caratteri di terminazione di riga tipici, né una sequenza di avanzamento riga (0x0A) né una sequenza di ritorno a capo e avanzamento riga (0x0D0A).
dump_file test%phx_vos#m16_mas>SysAdmin>Noah_Davids>test 10-09-05 08:14:07 mst
Numero di blocco 1000  00053132 333435FF 00050005 36373839 |..12345…..6789|010 30FF0005 FFFFFFFF FFFFFFFF FFFFFFFF |0……………|020 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |…………….|

=

FF0 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |…………….|

pronto 08:14:07

Figura 3 – dump_file che mostra la struttura effettiva del file

 

Quando si trasferisce il file utilizzando SFTP, OpenVOS rimuove i byte di lunghezza dalla riga e aggiunge un carattere di avanzamento riga. Il risultato è che mentre il file originale conteneva 10 tipi di dati, il file trasferito ne contiene 12.
C:Documents and SettingsnoahMy Documentstemp>"C:Program FilesPuTTYpsftp" [email protected]
Using username "nd".
[email protected]'s password:
Remote working directory is /SysAdmin/Noah_Davids
psftp> get test test.txt
remote:/SysAdmin/Noah_Davids/test => local:test.txt
psftp> quit
C:Documents and SettingsnoahMy Documentstemp>dir
Volume in drive C has no label.
Volume Serial Number is 38B1-9C13
Directory of C:Documents and SettingsnoahMy Documentstempblog - sftp
08/27/2010 01:50 PM <DIR> .
08/27/2010 01:50 PM <DIR> ..
08/27/2010 01:50 PM 12 test.txt
1 File(s) 12 bytes
2 Dir(s) 39,471,644,672 bytes free
Figura 4 – La lunghezza del file trasferito non corrisponde alla lunghezza del file di origine
Inoltre, se visualizzi il file in un programma come Blocco note, viene visualizzato come una riga con simboli strani dove dovrebbero terminare le righe.
Figura 5 – Visualizzazione del file in Blocco note
Se si utilizza un'utilità per ottenere un dump esadecimale del file, si noterà che alla fine di ogni riga è presente un carattere di avanzamento riga (0x0A). La sequenza di terminazione riga standard di Microsoft Windows è ritorno carrello avanzamento riga (0x0D0A). Notepad non è in grado di interpretare il solo carattere di avanzamento riga, mentre altri editor sono in grado di visualizzare correttamente il file.

 

Figura 6 – Dump esadecimale del file trasferito
Il risultato è che il file trasferito appare danneggiato, la lunghezza è diversa e non è possibile visualizzarlo, almeno in Blocco note. La conversione del file in un file di flusso prima del trasferimento risolverà il problema della lunghezza; entrambi i file mostreranno ora la stessa lunghezza, ma il problema della terminazione di riga rimarrà.

 

Cosa succede se OpenVOS riceve un file da un sistema Microsoft Windows? Come ho già detto, Microsoft Windows utilizza una sequenza di ritorno a capo e avanzamento riga per terminare una riga.
Figura 7 – Dump esadecimale di un file creato su un sistema Microsoft Windows
Il sottosistema SFTP di OpenVOS creerà un file di flusso. I caratteri di avanzamento riga saranno considerati come caratteri di terminazione riga, mentre i caratteri di ritorno a capo saranno trattati come parte dei dati della riga.

dump_file pc1.txt

%phx_vos#m16_mas>SysAdmin>Noah_Davids>pc1.txt 10-09-05 08:52:21 mst
Numero blocco 1

000 61626364650D0A666768696A 0D0AFFFF |abcde..fghij….|

010 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |…………….|

=

FF0 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |…………….|

pronto 08:52:21

Figura 8 – File di dump del file trasferito
Il comando display visualizzerà correttamente il file.

d pc1.txt

%phx_vos#m16_mas>SysAdmin>Noah_Davids>pc1.txt 10-09-05 08:54:25 mst

abcde

fghij

pronto 08:54:25

Figura 9 – visualizzazione del file trasferito
Ma quando vai effettivamente a leggere il file, il carattere di ritorno a capo apparirà alla fine di ogni riga.
test_system_calls
tsc: s$attach_port p pc1.txt
tsc: s$open
tsc: s$seq_read p
Buffer length = 6
00000000 61626364 650D |abcde. |
tsc: s$seq_read p
Buffer length = 6
00000000 66676869 6A0D |fghij. |

tsc:

Figura 10 – I caratteri di ritorno a capo vengono visualizzati quando si legge il file.
Ancora una volta, il risultato è che il file sembra essere danneggiato.
Il seguente script Perl può essere utilizzato per aggiungere o rimuovere i caratteri di ritorno a capo. È consigliabile aggiungerli prima di trasferire il file su un sistema Microsoft Windows e rimuoverli dopo aver trasferito il file dal sistema Microsoft Windows.
# cr.pl begins here
#
# cr
# version 1.0 10-08-27
#
use strict;
use warnings;
use Getopt::Long;
my ($inFile, $outFile, @files, $add, $remove);
my ($INFILE);
my ($result, $count, $verbose, $addremove);
$result = GetOptions ('in=s' => $inFile,
'out=s' => $outFile,
'add' => $add,
'remove' => $remove,
'verbose=s' => $verbose);
if (($result != 1) || !defined ($inFile) || !defined ($outFile))
{
print "nnUsage:n";
print "perl cr.pl -in PATH -out PATH [[-add] | [-remove]] [-verbose]}n";
exit;
}
if (defined ($add) && defined ($remove))
{
print "You can only specify -add or -remove not bothnn";
print "nnUsage:n";
print "perl cr.pl -in PATH -out PATH [[-add] | [-remove]] [-verbose]}n";
exit;
}
@files = glob ($inFile);
if (@files < 1) {print "nNo files found for " . $inFile . "nn";}
if (@files > 1) {print "nMore than 1 file found for " . $inFile . "nn";}
open (OUT, ">".$outFile) || die "Can't open output file " . $outFile . "nn";
open ($INFILE, $files[0]) || die "Can't open input file " . $files[0] . "nn";
if (!defined ($verbose)) { $verbose = -1; }
$count = 0;
while ($_ = <$INFILE>)
{
if (defined ($remove))
{
s/r//;
print OUT $_ ;
}
else
{
s/n//;
print OUT $_ . "rn";
}
$count++;
if (($verbose > 0) && ($count % $verbose) == 0)
{ print "Line " . $count . " of " . $files[0] . " processedn"; }
}
close $INFILE;
#

# cr ends here

Figura 11 – Script Perl per rimuovere o aggiungere caratteri di ritorno a capo
Perché l'FTP sembra funzionare? L'FTP ha due modalità, ASCII e binaria. Nella modalità ASCII, i trasferimenti da un sistema Microsoft Windows a OpenVOS generano un file sequenziale in cui i caratteri di ritorno a capo e avanzamento riga vengono rimossi dai record. I trasferimenti in modalità binaria dal sistema Microsoft Windows a Open VOS danno come risultato un file stream con i caratteri di ritorno a capo e avanzamento riga presenti, esattamente come il trasferimento in modalità binaria di SFTP. I trasferimenti in modalità ASCII da OpenVOS a un sistema Microsoft Windows danno come risultato un file con i caratteri di ritorno a capo e avanzamento riga alla fine di ogni riga, mentre i trasferimenti in modalità binaria danno come risultato un file con solo il carattere di avanzamento riga alla fine di ogni riga. Anche in questo caso, esattamente come il trasferimento in modalità binaria di SFTP. L'RFC FTP descrive in dettaglio come terminare le righe, ma in sostanza in modalità ASCII sia il client che il server sono liberi di terminare le righe secondo le necessità del sistema operativo locale, mentre in modalità binaria il client e il server non hanno tale discrezionalità.