Každý zřejmě ví, že pomocí příkazu ln
můžeme v Linuxu tvořit symbolické odkazy (symlinks, příkaz ln -s
) a pevné odkazy (hard links, příkaz ln
bez parametru -s
). Přestože se vytvářejí stejným příkazem, nemají symbolické a pevné odkazy mnoho společného a jejich využití a chování se značně liší.
V zásadě můžeme říci, že pevné odkazy jsou odkazy na soubor, kdežto symbolické odkazy jsou odkazy na jméno souboru. Pro vysvětlení předchozí věty si uděláme malou exkurzi do nitra souborového systému. Soubory v souborovém systému Linuxu jsou uloženy v lineární struktuře. Každý soubor je označen identifikačním číslem (inode number), které je pro daný soubor v souborovém systému jedinečné. Kromě tohoto „skladiště souborů“ obsahuje souborový systém ještě hierarchickou strukturu adresářů obsahující jména souborů. Každému jménu souboru je pak přiřazeno číslo inode souboru, na který dané jméno „ukazuje“.
Vše si ukážeme na příkladu. Příkaz ls
má volbu -i
, která ke každému jménu souboru vypíše číslo inode, na nějž jméno souboru ukazuje:
# ls -i1 84970 fff 84985 x.x 84983 xxx 84983 yyy
Jak vidíme, vazba mezi soubory a jmény souborů umožňuje, aby jeden fyzický soubor na disku měl několik odpovídajících jmen souboru, případně žádné (návod, jak vytvořit v Linuxu soubor beze jména, zde raději nebudu uvádět, protože si nedokážu přestavit žádné legální využití této „featury“ :-)) Pojmem pevný odkaz (hard link) se rozumí právě vazba mezi inode souboru a jménem souboru.
Oproti pevnému odkazu je symbolický odkaz (symlink) speciální soubor, který obsahuje cestu k jinému jménu souboru. Vlastní soubory a jejich inode v symbolickém odkazu nefigurují. Nyní se budeme věnovat tomu, co rozdíly mezi symbolickými a pevnými odkazy znamenají v praxi.
Náročnost na diskový prostor
Pevný odkaz je vlastně pouze jedna položka v adresářové struktuře (jméno odkazu). Symbolický odkaz naproti tomu vyžaduje položku v adresářové struktuře (jméno odkazu) a speciální soubor, ve kterém je zapsána cesta k cílovému jménu souboru. Pevné odkazy tedy zabírají méně místa.
Univerzálnost
Pevné odkazy jsou, díky své vazbě na inode, omezeny na použití v rámci jednoho souborového systému. Navíc není možné tvořit pevné odkazy na adresáře. Symbolické odkazy, díky použití jmen souborů, mohou ukazovat i na adresáře a nejsou omezeny na jeden souborový systém, lze je použít i na svazky připojené pomocí NFS apod. Díky této vlastnosti byly do UNIXu také zavedeny.
Síla vazby mezi odkazem a cílovým souborem
Pokud smažeme nebo přesuneme soubor, na který ukazuje symbolický odkaz, přestane odkaz fungovat (broken link). U pevných odkazů je tomu jinak. Nově vytvořený pevný odkaz nemá žádnou vazbu na původní jméno souboru, takže s původním souborem můžeme manipulovat (přesouvat, mazat), aniž by se to jakkoli dotklo našeho odkazu. Zvídavý čtenář si teď jistě klade otázku, jak systém pozná, zda má při mazání souboru vymazat pouze položku v adresářové struktuře, nebo i vlastní soubor (inode). K tomuto účelu se pro každý soubor (inode) udržuje čítač, obsahující počet pevných odkazů na daný soubor. Při mazání souboru pak systém vymaže položku v adresářové struktuře a zmenší čítač odkazů o jedničku. Jakmile čítač dosáhne nuly, vymaže se i vlastní soubor. Také proto se v jazyce C funkce pro smazání souboru jmenuje unlink()
, a ne třeba delete() nebo remove(). Pro zjištění, kolik jmen souborů ukazuje na daný soubor, můžeme v shellu použít příkaz stat
(položka Links):
# stat xxx File: `xxx' Size: 5 Blocks: 8 IO Block: 4096 Regular File Device: 342h/834d Inode: 84983 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2002-10-14 18:08:29.000000000 +0200 Modify: 2002-10-15 11:43:46.000000000 +0200 Change: 2002-10-15 11:43:46.000000000 +0200
Správa odkazů
Běžný souborový systém v Linuxu obsahuje hned po instalaci několik tisíc jak symbolických, tak pevných odkazů. Symbolické odkazy, které jsou speciálním typem souboru, lze je snadno vyhledat například pomocí příkazu find
:
find / -type l -print
U pevných odkazů je situace složitější. Mezi jednotlivými jmény souborů ukazujících na jeden inode neexistuje žádná vazba. Je tedy potřeba projít celý souborový systém, najít soubory, které mají více než jedno jméno, a jména pak spárovat podle čísla inode. Viz tento krátký skript find_hard_links
:
#!/bin/sh res=""; for i in `find $1 -type f -xdev -print`; do if [[ `stat -c "%h" $i` > 1 ]]; then res="`stat -c %i $i` $i\n"$res; fi done echo -e $res | sort
Vyhledávání může v závislosti na množství souborů trvat značně dlouho.
Zálohování s využitím pevných odkazů
Při dnešních cenách hardware mnoho uživatelů zálohuje data na pevné disky. Jedna ze základních zkušeností při zálohování říká, že není problém data zálohovat, problém představuje je v případě potřeby obnovit, zvláště používáme-li inkrementální zálohy.
Protože při zálohování na pevný disk máme k dispozici souborový systém včetně pevných odkazů, ukážeme si, jak tvořit komfortní řady záloh, které se tváří jako kompletní „kopie“ zálohovaných dat v daném čase a přitom zabírají velmi málo místa. Trik je v tom, že v zálohovaných datech je od poslední zálohy vždy jen určité množství změn a zbytek souborů zůstává stejný. Místo udržování několika kopií takových nezměněných souborů použijeme pevné odkazy.
Teď už jen potřebujeme mechanismus, který nezměněné soubory ponechá a u změněných souborů vytvoří novou kopii, na kterou se neodkazují ostatní zálohy. Přesně takto se chová synchronizační utilita rsync
. Postup při zálohování pak bude následující:
- Vytvoříme kopii aktuální zálohy pomocí pevných odkazů (příkaz
cp -l
) - Spustíme
rsync
, který aktualizuje změněné soubory v aktuální záloze
Zde je hotový skript do_backup
, který můžeme spouštět v určitých intervalech pomocí cron
:
!/bin/sh #Number of backup copies to keep NUM_DIRS=5 #Source and destination dirs for backup SOURCE=/home DEST=/nekam/backup #See how many dirs already exist, purge if neccessary if [[ `ls $DEST | wc -l | awk '{print $1;}'` == $NUM_DIRS ]]; then rm -rf $DEST/`ls $DEST | head -1`; fi #If exists 'current' copy it to its time's dir if [ -d $DEST/current ]; then NAME=`ls -ld --time-style="+%F-%T" $DEST/current | awk '{print $6;}'`; #mkdir $DEST/$NAME cp -al $DEST/current $DEST/$NAME fi #Do rsync rsync -a --delete $SOURCE/ $DEST/current/ touch $DEST/current
v adresáři /nekam/backup
pak bude adresář current
, obsahující aktuální zálohu a adresáře označené datumem a časem, obsahující předchozí zálohy:
ls -1 backup 2002-10-14-10:29:56/ 2002-10-15-10:29:57/ 2002-10-16-10:29:58/ 2002-10-17-10:42:28/ current/
Jednotlivé adresáře se tváří jako naprosto nezávislé, obsahující kompletní kopii zálohovaných dat, všechny nezměněné soubory jsou však ve skutečnosti na disku uloženy pouze jednou a výrazně se šetří diskový prostor.
Pro úplnost ještě připomeňme, že pokud se u souboru změní pouze přístupová práva, rsync
nevytvoří kopii souboru a změna se tak projeví i ve všech předchozích zálohách.