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).
| Velikost údaje | Posunutí od zacátku | Popis |
| 100 | 0 | jméno souboru |
| 8 | 100 | mód souboru (prístupová práva, ulozeno jako oktalová císla v ASCII) |
| 8 | 108 | uid (ID vlastníka - uzivatele), (oktalove) |
| 8 | 116 | gid (ID vlastníka - skupiny) (oktalove) |
| 12 | 124 | délka souboru v bytech (oktalove) |
| 12 | 136 | cas poslední zmeny souboru (oktalove jako pocet sekund od pocátku "unixové éry" 1. 1. 1970) |
| 8 | 148 | kontrolní soucet hlavicky (pro nás nepodstatný) |
| 1 | 156 | typ souboru (0 - bezný soubor, 1 - odkaz (symbolický link), ...) |
| 100 | 157 | jméno odkazovaného souboru |
| 257 | vyuzito 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
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).
basictar.C.l pro výpis obsahu archivu, nebo e
pro extrakci souboru (rozsírené zadání). Druhým parametrem je jméno
vstupního TAR souboru. Tretím parametrem muze být cást jména souboru,
který chceme extrahovat (souboru vyhovujících zadanému podretezci muze
být samozrejme víc, extrahovány by mely být vsechny). Pri zadání
neznámých parametru program vrací nenulové císlo. Príklad pouzití: basictar l soubor.tar basictar e soubor.tar cast_jmena (funguje jen v rozsíreném zadání)tellg a seekg vstupních a výstupních souborových proudu.long int (unsigned long int)find).
Pokud je podretezec ve jménu nalezen, pokusí se program soubor
extrahovat. Pokud pri extrakci dojde k problému (nelze vytvorit cílový
soubor – napr. problém s právy), program zahlásí chybu, ze soubor
nemohl extrahovat a pokracuje v procházení archivu. Na konci vrátí
pocet souboru, se kterými mel pri extrakci problém.basictar e soubor.tar "" by melo zpusobit pokus o extrakci kompletního obsah archivu (tedy vsechny soubory typu '0').strtoul, s jejíz obdobou jste se jiz setkali.ctime z hlavickového souboru ctime, nevadí, ze cas bude vypisován ve formátu neodpovídajícím nasemu národnímu prostredí. gcc, u tohoto príkladu doporucujeme
mít modul aktivován.
#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;
}