Ir al contenido principal

SFTP es el subsistema FTP que forma parte de SSH, permite hacer transferencias de archivos encriptados. En la última semana he tenido 2 problemas con SFTP que no transfería archivos correctamente. En un caso OpenVOS era la fuente del archivo y en el otro caso OpenVOS estaba recibiendo el archivo. En ambos casos los archivos contenían datos ASCII y los problemas tenían que ver con las diferencias entre cómo Microsoft Windows y OpenVOS terminan las líneas en un archivo de texto.

Empecemos con OpenVOS como fuente. Si creas un archivo de texto usando tu editor favorito, crearás un archivo secuencial. Por ejemplo

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 - visualización de un archivo de texto
El comando display_file_status muestra que se trata de un archivo secuencial y que, aunque el recuento de bytes de datos es de 10, en realidad hay 20 bytes en el archivo.
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 - estado de display_file
El comando dump_file muestra la estructura real del archivo. Cada "línea" está precedida y terminada por 2 bytes que indican su longitud. Estos bytes de longitud tienen que empezar en un límite de bytes par, por lo que también hay un byte de relleno. Lo más significativo es que no hay los típicos caracteres de terminación de línea, ya sea un salto de línea (0x0A) o un salto de línea de retorno de carro (0x0D0A).
dump_file test%phx_vos#m16_mas>SysAdmin>Noah_Davids>test 10-09-05 08:14:07 mst
Bloque número 1000  00053132 333435FF 00050005 36373839 |..12345…..6789|010 30FF0005 FFFFFFFF FFFFFFFF FFFFFFFF |0...............|020 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|

=

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

listo 08:14:07

Figura 3 - dump_file mostrando la estructura real del archivo

 

Cuando se transfiere el archivo mediante SFTP, OpenVOS elimina los bytes de longitud de la línea y añade un carácter de avance de línea. El resultado es que mientras el archivo original contenía 10 tipos de datos, el archivo transferido 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 longitud del archivo transferido no coincide con la del archivo de origen
Además, si muestra el archivo en algo como el Bloc de notas, se muestra como una línea con símbolos divertidos donde las líneas deberían terminar.
Figura 5 - visualización del archivo en el Bloc de notas
Si utilizas una utilidad para obtener un volcado hexadecimal del archivo verás que al final de cada línea hay un carácter de salto de línea (0x0A). La secuencia estándar de terminación de línea de Microsoft Windows es el salto de línea de retorno de carro (0x0D0A), el Bloc de notas no sabe interpretar sólo el carácter de salto de línea, aunque hay otros editores que mostrarán el archivo correctamente.

 

Figura 6 - Volcado hexadecimal del archivo transferido
El resultado es que el archivo transferido parece estar corrupto, la longitud es diferente y no se puede visualizar, al menos en el Bloc de notas. Convertir el archivo en un archivo de flujo antes de transferirlo corregirá el problema de la longitud; ambos archivos mostrarán ahora la misma longitud, pero el problema de la terminación de la línea permanecerá.

 

Ahora, ¿qué pasa si OpenVOS está recibiendo un archivo de un sistema Microsoft Windows? Como ya he dicho, Microsoft Windows utiliza una secuencia de avance de línea de retorno de carro para terminar una línea.
Figura 7 - Volcado hexadecimal de un archivo creado en un sistema Microsoft Windows
El subsistema SFTP de OpenVOS creará un archivo de flujo. Los caracteres de avance de línea se tomarán como caracteres de terminación de línea y los caracteres de retorno de carro se tratarán como parte de los datos de la línea.

dump_file pc1.txt

%phx_vos#m16_mas>SysAdmin>Noah_Davids>pc1.txt 10-09-05 08:52:21 mst
Bloque número 1

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

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

=

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

listo 08:52:21

Figura 8 - archivo de volcado del fichero transferido
El comando de visualización mostrará el archivo correctamente.

d pc1.txt

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

abcde

fghij

listo 08:54:25

Figura 9 - visualización del archivo transferido
Pero cuando vayas a leer el archivo, el carácter de retorno de carro aparecerá al final de cada línea.
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 - Los caracteres de retorno de carro aparecen al leer el archivo
De nuevo, el resultado es que el archivo parece estar corrupto.
El siguiente script de Perl puede utilizarse para añadir o eliminar los caracteres de retorno de carro. Se desea añadirlos antes de transferir el archivo a un sistema Microsoft Windows y eliminarlos después de transferir el archivo desde el 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 para eliminar o añadir caracteres de retorno de carro
¿Por qué parece que el FTP funciona? FTP tiene dos modos, ASCII y binario. En el modo ASCII, las transferencias desde un sistema Microsoft Windows a OpenVOS dan como resultado un archivo secuencial con los caracteres de retorno de carro y avance de línea eliminados de los registros. Las transferencias en modo binario desde el sistema Microsoft Windows a Open VOS dan como resultado un archivo de flujo con los caracteres de retorno de carro y de avance de línea presentes - exactamente como la transferencia en modo binario de SFTP. Las transferencias en modo ASCII desde OpenVOS a un sistema Microsoft Windows resultan en un archivo con caracteres de retorno de carro y avance de línea al final de cada línea, mientras que las transferencias en modo binario resultan en un archivo con sólo el carácter de avance de línea al final de cada línea. De nuevo, al igual que la transferencia en modo binario de SFTP. El RFC de FTP entra en detalles sobre cómo terminar las líneas, pero la conclusión es que en el modo ASCII tanto el cliente como el servidor son libres de terminar las líneas como sea necesario para el sistema operativo local, mientras que en el modo binario el cliente y el servidor no tienen tal discreción.