Waňov web

PB161 Jazyk C++ - 9. cvicení

Práce se soubory TAR

Úvod:

Souborový formát TAR (Tape ARchive) vznikl na unixových operacních systémech v 70tých letech minulého století. Slouzí k archivaci vetsího mnozství souboru uvnitr jednoho a svou funkci úspesne plní do dnes.
Formát se za léta pouzívání vyvíjel tak, aby splnoval i nové nároky na archivaci. Byl nekolikrát standardizován standardy POSIX. My se budeme zabývat jeho základní variantou, tedy necím, na cem se shodnou snad vsechny dnes vyuzívané implementace. Zároven vyuzijeme jen ty moznosti formátu, které nám dovolí implementovat jazyk C++ jako takový, aniz bychom museli pouzívat dalsí funkce, které by zabranovaly prenositelnosti programu. Pokud se tedy na webu setkáte s jinými popisy, nez je tento, povazujte prosím níze uvedený za závazný.
Soubor TAR se skládá z bloku dlouhých 512 bytu. Jednotlivé archivované soubory jsou v nem ulozeny za sebou. Kazdému z nich predchází hlavicka, (celá ve formátu ASCII, i císla v oktalové - osmickové soustave jsou zapsána jako retezce ASCII znaku podle potreby s levostrannými nulami), dlouhá 512 bytu, obsahující napr. jméno archivovaného souboru, jeho velikost atd. Její popis uvedu dále. Nevyuzité místo v hlavicce je zaplneno binárními nulami. Obdobne konec archivu je reprezentován alespon dvema bloky („hlavicka a blok po ní“) vyplnenými binárními nulami. Uvnitr souboru bezprostredne po hlavicce následují data, opet zarovnaná do bloku po 512ti bytech (poslední blok je doplnen binárními nulami).

Tabulka s popisem hlavicky jednoho souboru v TAR archivu:
Velikost
údaje
Posunutí od
zacátku
Popis
1000jméno souboru
8100mód souboru (prístupová práva, ulozeno jako oktalová císla v ASCII)
8108uid (ID vlastníka - uzivatele), (oktalove)
8116gid (ID vlastníka - skupiny) (oktalove)
12124délka souboru v bytech (oktalove)
12136cas poslední zmeny souboru (oktalove jako pocet sekund od pocátku "unixové éry" 1. 1. 1970)
8148kontrolní soucet hlavicky (pro nás nepodstatný)
1156typ souboru (0 - bezný soubor, 1 - odkaz (symbolický link), ...)
100157jméno odkazovaného souboru
257vyuzito v novejsích verzích TARu, pro nás nepodstatné

Formát tar-souboru vcetne hlavicky je podrobneji popsán v http://en.wikipedia.org/wiki/Tar_%28file_format%29

Zadání:

Vytvorte program basictar, který bude umoznovat výpis obsahu TAR souboru, poprípade provádení extrakce souboru podle zadané cásti jména (rozsírené zadání – získáte navíc 3 body).

Pozadavky:

Pozadavky na rozsírení:

Poznámky:


Riešenie:


basictar.C
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <ctime>
using namespace std;

char buffer[512];

int i;
long int pozicia=0;
struct hlavicka
{ string meno;
  long int prava;
  long int uid;
  long int gid;
  long int velkost;
  long int cas_zmeny;
  char typ;
} subor;

struct hlavicka_char
{ char meno[100];
  char prava[8];
  char uid[8];
  char gid[8];
  char velkost[12];
  char cas_zmeny[16];
  char kontrolny_sucet[8];
  char typ;
} subor_char;

//----------------------Napoveda------------------------------------------------
void napoveda(void)
{
 cout<<"Program basictar bol spusteny bez patricnych parametrov"<<endl
  <<"-prosim zadajte \"basictar l meno_suboru\" pre vypis obsahu archivu"
  <<endl<<endl;
}
//------------------------------------------------------------------------------

//===================== MAIN ===================================================
int main(int argc,char *argv[] )
{
//----------------------Kontrola argumentov-------------------------------------
 if(argc==3)
   {if(argv[1][0]=='l'&& argv[1][1]=='\0')
      {if(strstr(argv[2],".tar"))
         {ifstream vstup(argv[2]);
           if(!vstup) 
           {cout<<"Archiv sa nepodarilo otvorit"<<endl;return 2;}
           else vstup.close();
         }
       else{cout<<"Subor nema priponu .tar"<<endl;return 2;}
      }        
    else {napoveda();return 1;}
   }      
  else {napoveda(); return 1;}
//------------------------------------------------------------------------------

ifstream vstup(argv[2],ios::in|ios::binary);;
cout << "\nVypis obsahu archivu: " <<argv[2]<<endl;

//----------- Hlavny cyklus ----------------------------------------------------
for(i=0;i<30;i++)
 {
  stringstream pamat;  
  if(!vstup.read(buffer,512))
   {cout<<"Neocakavany koniec suboru"<<endl; return 5;}
  pamat.write(buffer,512);
  
  pamat.read(subor_char.meno,100);
  pamat.read(subor_char.prava,8);
  pamat.read(subor_char.uid,8);
  pamat.read(subor_char.gid,8);
  pamat.read(subor_char.velkost,12);
  pamat.read(subor_char.cas_zmeny,12);
  pamat.read(subor_char.kontrolny_sucet,8);
  pamat.seekg(156);
  pamat.get(subor_char.typ);
  
  if (subor_char.meno[0]=='\0')  break;                   // hlavicka je prazdna

  subor.velkost=strtol(subor_char.velkost,NULL,8);
  subor.cas_zmeny=strtol(subor_char.cas_zmeny,NULL,8);
 
  cout<<setfill('-')<<setw(80)<<""<<'\n';                        //MANIPULATORY
  cout<<"Nazov suboru: "<< subor_char.meno <<'\n'
      <<"Typ: "<<subor_char.typ<<'\n'
      <<"Velkost suboru: "<<subor.velkost<<" Bytov \n"
      <<"Cas zmeny suboru: "<< ctime(&subor.cas_zmeny);
  
  pozicia+=512;
  if(subor.velkost!=0)     // preskocit bloky
   { 
    pozicia+=(static_cast<int>(subor.velkost/512))*512;
    if (subor.velkost%512) pozicia+=512;
   }; 
  vstup.seekg(pozicia);
 }
//------------- Koniec hlavneho cyklu ------------------------------------------
 
 vstup.close();

 return 0;
}


Nahor