본문으로 바로 가기

SFTP는 SSH의 일부인 FTP 하위 시스템으로, 암호화된 파일 전송을 가능하게 합니다. 지난주 동안 SFTP를 통해 파일이 제대로 전송되지 않는 문제가 두 건 발생했습니다. 한 건은 OpenVOS가 파일의 송신원이었고, 다른 한 건은 OpenVOS가 파일을 수신하는 상황이었습니다. 두 경우 모두 파일에는 ASCII 데이터가 포함되어 있었으며, 문제는 Microsoft Windows와 OpenVOS가 텍스트 파일의 줄을 종료하는 방식의 차이에서 비롯되었습니다.

먼저 OpenVOS를 예로 들어보겠습니다. 선호하는 편집기를 사용하여 텍스트 파일을 만들면 순차 파일이 생성됩니다. 예를 들어

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

ready 08:13:49

그림 1 – 텍스트 파일 표시
display_file_status 명령어를 실행해 보면, 해당 파일이 순차 파일이며 데이터 바이트 수는 10개이지만 실제로는 파일에 20바이트가 포함되어 있음을 확인할 수 있습니다.
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

그림 2 – display_file 상태
dump_file 명령어는 파일의 실제 구조를 보여줍니다. 각 “줄”의 앞뒤에는 해당 줄의 길이를 나타내는 2바이트가 붙습니다. 이 길이 바이트는 짝수 바이트 경계에서 시작해야 하므로, 이를 위한 채움 바이트도 포함됩니다. 주목할 점은 일반적인 줄 끝 문자, 즉 줄 바꿈(0x0A)이나 캐리지 리턴-줄 바꿈(0x0D0A) 시퀀스가 전혀 없다는 것입니다.
dump_file test%phx_vos#m16_mas>시스템 관리자>Noah_Davids>테스트 2010년 9월 5일 08:14:07 (MST)
블록 번호 1000  00053132 333435FF 00050005 36373839 |..12345…..6789|010 30FF0005 FFFFFFFF FFFFFFFF FFFFFFFF |0……………|020 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |…………….|

=

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

준비됨 08:14:07

그림 3 – 파일의 실제 구조를 보여주는 dump_file

 

SFTP를 사용하여 파일을 전송할 때, OpenVOS는 해당 행에서 길이 바이트를 제거하고 줄 바꿈 문자를 추가합니다. 그 결과, 원본 파일에는 10개의 데이터 유형이 포함되어 있었지만 전송된 파일에는 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
그림 4 – 전송된 파일의 길이가 원본 파일의 길이와 일치하지 않음
또한, 메모장 같은 프로그램에서 파일을 열어보면, 줄바꿈이 있어야 할 위치에 이상한 기호들이 들어간 채 한 줄로 표시됩니다.
그림 5 – 메모장에서 파일 표시
유틸리티를 사용하여 파일의 16진수 덤프를 확인해 보면, 각 줄의 끝에 줄 바꿈 문자(0x0A)가 있는 것을 확인할 수 있습니다. 표준 Microsoft Windows 줄 끝 처리 시퀀스는 캐리지 리턴과 줄 바꿈(0x0D0A)입니다. 메모장은 줄 바꿈 문자만으로는 이를 해석할 수 없지만, 파일을 올바르게 표시해 주는 다른 편집기들도 있습니다.

 

그림 6 – 전송된 파일의 16진수 덤프
그 결과, 전송된 파일이 손상된 것처럼 보이고, 파일 크기가 다르며, 적어도 메모장에서는 파일을 열 수 없게 됩니다. 파일을 전송하기 전에 스트림 파일로 변환하면 파일 크기 문제는 해결됩니다. 두 파일의 크기가 동일하게 표시되지만, 줄 끝 처리 문제는 여전히 남아 있을 것입니다.

 

그렇다면 OpenVOS가 Microsoft Windows 시스템으로부터 파일을 수신할 때는 어떻게 될까요? 앞서 말씀드렸듯이, Microsoft Windows는 줄 끝을 표시하기 위해 캐리지 리턴과 라인 피드 시퀀스를 사용합니다.
그림 7 – Microsoft Windows 시스템에서 생성된 파일의 16진수 덤프
OpenVOS SFTP 하위 시스템은 스트림 파일을 생성합니다. 줄 바꿈 문자는 줄 끝 문자로 간주되며, 캐리지 리턴 문자는 해당 줄의 데이터 일부로 처리됩니다.

dump_file pc1.txt

%phx_vos#m16_mas>SysAdmin>Noah_Davids>pc1.txt 2010-09-05 08:52:21 (MST)
블록 번호 1

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

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

=

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

준비됨 08:52:21

그림 8 – 전송된 파일의 덤프 파일
display 명령어를 사용하면 파일이 올바르게 표시됩니다.

d pc1.txt

%phx_vos#m16_mas>시스템 관리자>Noah_Davids>pc1.txt 2010년 9월 5일 08:54:25 (MST)

abcde

fghij

준비됨 08:54:25

그림 9 – 전송된 파일 표시
하지만 실제로 파일을 읽어보면 모든 줄의 끝에 캐리지 리턴 문자가 표시됩니다.
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:

그림 10 – 파일을 읽을 때 캐리지 리턴 문자가 나타납니다
결국, 파일은 손상된 것처럼 보입니다.
다음 Perl 스크립트를 사용하여 캐리지 리턴 문자를 추가하거나 제거할 수 있습니다. 파일을 Microsoft Windows 시스템으로 전송하기 전에 이 문자를 추가하고, 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

그림 11 – 캐리지 리턴 문자를 제거하거나 추가하는 Perl 스크립트
FTP는 왜 작동하는 것처럼 보일까요? FTP에는 ASCII 모드와 바이너리 모드, 두 가지 모드가 있습니다. Microsoft Windows 시스템에서 OpenVOS로 전송할 때 ASCII 모드를 사용하면 레코드에서 캐리지 리턴(CR)과 라인 피드(LF) 문자가 모두 제거된 순차 파일이 생성됩니다. 마이크로소프트 윈도우 시스템에서 OpenVOS로 바이너리 모드로 전송하면, SFTP의 바이너리 모드 전송과 정확히 마찬가지로 캐리지 리턴 및 라인 피드 문자가 포함된 스트림 파일이 생성됩니다. OpenVOS에서 마이크로소프트 윈도우 시스템으로 ASCII 모드로 전송하면 각 줄 끝에 캐리지 리턴 및 라인 피드 문자가 포함된 파일이 생성되는 반면, 바이너리 모드로 전송하면 각 줄 끝에 라인 피드 문자만 포함된 파일이 생성됩니다. 이 또한 SFTP의 바이너리 모드 전송과 정확히 같습니다. FTP RFC는 줄 끝 처리 방법에 대해 상세히 설명하고 있지만, 요점은 ASCII 모드에서는 클라이언트와 서버 모두 로컬 운영 체제에 맞게 필요에 따라 줄을 끝낼 수 있는 반면, 바이너리 모드에서는 클라이언트와 서버 모두 그러한 재량권이 없다는 것입니다.

© 2024 Stratus Technologies.