UNIX作業系統tar命令之隱患及解決方案

來源:互聯網
上載者:User
unix|解決    目前,UNIX作業系統在我國金融界被廣泛地採用,UNIX以其強大的功能(分時、多任務、多使用者、網路互連、圖形介面等),倍受金融企業青睞。中國農業銀行現應用的SCO UNIX OPENSERVER50更是功能強勁。
   各家銀行的儲蓄、會計、信用卡等電腦業務處理系統均運行在UNIX作業系統平台上。電子化的發展拓展了銀行的業務領域,提高了工作效率,加強了業務的準確性、保密性、安全性,樹立了銀行的社會形象,產生間接的經濟效益。電子化銀行的發展對電腦資料的可靠性提出了更高的要求。
   據筆者調查,在UNIX作業系統上備份和恢複資料的控製程序決大多數是用tar命令實現的。tar命令具有使用簡單好學易用的特點。但筆者在使用tar命令的過程中,發現tar命令對於中國使用者具有一個嚴重的隱患:對檔案名稱為漢字且較長的檔案能夠歸檔打包,但不能解開該檔案包。
   例如:
   1先創立一個長漢字檔案名稱檔案:
   # cd /tmp
   # cat /etc/passwd>長長長長長長長長長長長長長長長長長長
   2將該檔案歸檔至abc檔案包:
   # mtar cvf abc *
   3解開或查看abc檔案包:
   # tar xvf abc 或atr tvf abc
   abc檔案包將不能解開或查看。

二、 剖析
   UNIX的tar命令產生的歸檔檔案稱tar格式檔案檔案,具有以下格式:
   1每個檔案被加上了一個512位元組的檔案屬性頭,然後以512位元組為單位塊在包中連續存放,佔有整數個塊。最後一個塊不能寫滿,其後用0x00填寫。
   2如檔案長度為零位元組或是連結檔案,則只有512位元組的檔案屬性頭。
   3用1024位元組的0x00作為檔案檔案尾。
   4檔案屬性頭結構:
union hblock {
   char dummy [512];    512位元組檔案屬性頭
   struct header {
     char name[100];   100位元組以內檔案名稱
     char mode [8];    八進位檔案許可權
     char uid[8];     八進位檔案主人號
     char gid[8];     八進位檔案組號
     char size[12];    八進位檔案長度
     char mtime[12];   八進位檔案修改時間
     char chksum[8];   八進位屬性頭校正和
     char 1inkf1ag;    檔案串連狀態
     char 1inkname[100]; 串連檔案名稱
     char extno[4];    連續卷分卷號
     char extota1[4];   分卷個數
     char efsize[12];   八進位續分卷檔案長度
     char compid;    檔案壓縮狀態
    }dbuf;
   }dblock;
   檔案屬性頭結構中位元組校正和chksum是(頭結構除chksum部分的位元組和)加(八位元400)加(檔案壓縮狀態值)後轉換為八進位得到的。檔案壓縮狀態為‘1'時表示檔案內容處於壓縮狀態,在解包時,tar命令將自動調用compress把檔案內容解壓縮,而不改變檔案名稱。
   筆者在分析一個含有長漢字檔案名稱的tar檔案檔案時發現:長漢字檔案名稱的屬性頭中chksum值是錯誤的。經分析發現造成這種錯誤的原因是:一個漢字的位元組和是負整數,長漢字檔案名稱的屬性頭的位元組和有可能為負整數,tar命令來源程式由於為西文而設計未能判斷屬性頭位元組和為負的情況。在創立檔案檔案時,tar命令用sprintf()函數轉換屬性頭位元組和為八進位輸出到chksum,這時破壞了chksum正常格式。在開啟檔案檔案時,tar命令用sscanf()函數從屬性頭按八進位格式化讀取chksum時,不能得到正確資料,tar命令將中止展開檔案檔案。

三、 解決方案
   從上面分析我們得出以下結論:(1)要解決問題必須修改tar來源程式,充分考慮漢化UNIX產生的tar檔案包檔案屬性頭中位元組校正和為負的情況。(2)編寫Hotfix,將出錯的tar檔案檔案屬性頭中位元組校正和chksum修複。
   第一種方法需得到UNIX公司來源程式級的支援人員或由UNIX公司技術人員解決,這也是筆者對UNIX公司的建議,我們只能期待。
   第二種方法筆者進行了有效嘗試,並用c編寫了一個Hotfixmtar.c,經編譯成mtar運行程式,本程式具有以下功能:
   Amtar -v tarfi1e 修補任何原因造成的tar檔案包中檔案的chksum錯誤(包括本程式的-c功能)。
   Bmtar -t tarfi1e 查考tar檔案包中檔案資訊。
   C mtar -c tarfi1e 加密tar檔案包,使tar命令不能開啟該包。
   D mtar -p tarfi1e 將包中的所有檔案置壓縮狀態標誌。
   E mtar -u tarfi1e 將包中所有檔案置非壓縮狀態標誌。

四、 實際應用
   本程式使用5個選項 -t -c -v -p -u,每次只能用一個參數,每個參數對應一個功能。
   例如:mtar -v abc 既可修複上面提到的abc包打不開問題。
   mtar -v /dev/fd0135ds18可修複tar格式3″磁碟片。
   mtar -c /dev/fd0135ds18可加密tar格式3″磁碟片。
   mtar -v /dev/fd0135ds18可解密tar格式3″磁碟片。
   mtar -t abc可詳細列出abc包中檔案資訊,sum_v=0表示檔案屬性頭校正正常,compress=[1]表示檔案抽取時自動解壓縮。
   本程式從編寫至今筆者進行了十四次改版,使該程式適合含任何檔案類型的tar檔案包。並在SCO UNIX 3242和SCO OPENSERVER 50下多次進行編譯和全面功能測試。現將該程式整理出來,敬請同行多加指教。來源程式附後。
   Mtar.c內容如下:
   #include″stdio.h″
   #include″string.h″
   #include″unistd.h″
   #include″sys/types.h″
   #include″sys/stat.h″
   #include″fcntl.h″

   #define TBLOCK 512
   #define NBLOCK 20
   #define NAMSIZ 100
    union hblock {
       char dummy[TBLOCK];
       struct header {
        char name[NAMSIZ];
        char mode[8];
        char uid[8];
        char gid[8];
        char size[12];
        char mtime[12];
        char chksum[8];
        char linkflag;
        char linkname[NAMSIZ];
        char extno[4];
        char extotal[4];
        char efsize[12];
        char compid;
      } dbuf,
    } dblock;
   main(argc,argv)
   int argc;
   char *argv[];
   {
     char compress;
     int i,seekip=0,ip,compc;
     long sum,sum_v,filesize=0,mvblock=0,total;
     FILE*fp;
   ip=0;
   if(strncmp(argv[1],″-c″,2)==0) ip=1;
   if(strncmp(argv[1],″-v″,2)==0) ip=1;
   if(strncmp(argv[1],″-t″,2)==0) ip=1;
   if(strncmp(argv[1],″-p″,2)==0) ip=1;
   if(strncmp(argv[1],″-u″,2)==0) ip=1;

   if(argc !=3||ip !=1)
     {
     printf(″Usage:mtar-[c,v,t,p,u]tarfile\n″);
     exit(1);
     }
   if((fp=fopen(argv[2],″r+″))==NULL)
     {
     printf(″Can not open the %s\n″,argv[2]);
     exit(1);
     }
   while(seekip==0)
   {
     if(fread((dblock.dummy),TBLOCK,1,fp)!=1)
      {
      printf(″Can not read the%s !\n″,argv[2]);
      break;
      }
   sum=0;
   compc=0;
   for(i=0;i< TBLOCK;i++) sum=sum+dblock.dumm
y[i];
   for(i=0;i< 8,i++)sum=sum-dblock.dbuf.chksum[i];
   if(sum==0)break;

   ip=0;
   if(strncmp(argv[1],″-c″,2)==0)
      compress=dblock.dbuf.compid;
      sum_v=270*0xff+0400; ip=1;
      }
   if(strncmp(argv[1],″-v″,2)==0)
      compress=dblock.dbuf.compid;
      sum_v=sum+0400; ip=1
      }
   if(strncmp(argv[1],″-p″,2)==0)
      compc=dblock.dbuf.compid;
      compc=0x31-compc;
      sum_v=sum+0400+compc;
      compress=0x31; ip=1;
      }
   if(strncmp(argv[1],″-u″,2)==0)
      compc=dblock.dbuf.compid;
      compc=0x00-compc;
      sum_v=sum+0400+compc;
      compress=0x00; ip=1;
   }
if(ip==1)
   {
   if(sum-v >=0)sprintf (dblock.dbuf.
chksum,″%60″,sum_v);
   else
   {
   dblock.dbuf.chksum[0]=′-′;
   dblock.dbuf.chksum[6]=0x00;
   dblock.dbuf.chksum[7]=0x00;
   sum_v=sum_v-dblock.dbuf.linkflag;
   sum=sum-dblock.dbuf.linkflag;
   dblock.dbuf.linkflag=0x00;
   for(i=0;i<NAMSIZ;i++){
      sum_v=sum_v-dblock.dbuf.linkname[i];
      sum=sum-dblock.dbuf.linkname[i];
      dblock.dbuf.linkname[i]=0x00;
      }
   sprintf(dblock.dbuf.chksum+1,″%-50″,-sum_v);
   }
   sprintf(&dblock.dbuf.compid,″%c″,compress);
   seekip=fseek(fp,-TBLOCK,SEEK_CUR);
   if(seekip==0)
     {
     if(fwrite((dblock.dummy),TBLOCK,1,fp)!=1)
       {
     printf(″Can not read the %s!\n″,argv[2]);
       break;
       }
     fflush(fp);
     }
   }
   sscanf(dblock.dbuf.size,″%12o″,&filesize);
   sscanf(dblock,dbuf.chksum,″%6o″,&sum_v);
   sum_v=sum_v-sum-0400-compc;
   if(filesize>0&&(dblock.dbuf.linkflag==0x00|| dbloc
k.dbuf.chksum[0]==0x33))
     {
     mvblock=(filesize-1)/TBLOCK+1;
    seekip=fseek(fp,(long)mvblock*TBLOCK,SEEK
_CUR);
     }
     seekip=fseek(fp,0L,SEEK_CUR);
   if(dblock.dbuf.linkflag==″1″)
    printf(″%s\n\t\tnormal linked to %s\t\tcompress=[%c]\tsum_v=%o\n″,
   dblock.dbuf.name,dblock.dbuf.linkname,dblock.dbuf.
compid,sum-v);
   else if (dblock.dbuf.linkflag==″2″)
   printf(″%s\n\t\tsymbolic linked to %s\tcompress=[%c]\tsum_v=%o\n,
   ″dblock.dbuf.name,dblock.dbuf.linkname,dblock.dbuf.
compid,sum_v);
   else
   printf(″%s\n\t %8d byte-->%6d tape_blocks\tcompress=[%c]\tsum_v=%o\n″,dblock.dbuf.name,filesize,mvblock,dblock.dbuf.cmpid,sum_v);

   }
   printf(″Total=%dK\n″,ftell(fp)/1024);
   fclose(fp);
   }



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。