UNIX Türevi Sistemlerde Dosya Bağları

Transkript

UNIX Türevi Sistemlerde Dosya Bağları
UNIX Türevi Sistemlerde Dosya Bağları
Kaan Aslan
11 Kasım 2007
i-node tabanlı dosya sistemlerinde dizin girişleri, dosya ismi ve o dosyaya ilişkin
düğüm numarasından oluşan kayıtlar biçimindedir[1]. Dosyaların gerçek bilgileri ise
düğüm elemanlarında saklanmaktadır. Dizin girişleri düğüm elemanlarını gösteren
birer gösterici gibidir. Örneğin aşağıdaki şekilde “/a/b” dizininin bir bölümünü
görüyorsunuz:
Burada "x.dat" dosyasının düğüm numarası 50315, "y.dat" dosyasının 45670, "z.dat"
dosyasının ise 37418'dir. Pekiyi farklı dizinlerdeki farklı girişler aynı düğüm
numaralarını gösterirse ne olur? Aşağıdaki şekli inceleyiniz:
1
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Burada “/a/b” dizini içerisindeki "y.dat" ile “/a/c” dizini içerisindeki "k.dat" girişleri aynı
düğüm elemanını göstermektedir. Dosyanın tüm bilgileri düğüm elemanı içerisinde
tutulduğuna göre nasıl bir durumla karşı karşıyayız? "y.dat" girişi ile "k.dat" girişi
arasında yalnızca isim farklılığı vardır. Bu iki iki giriş farklı yol ifadelerine sahip olsa
da aslında aynı fiziksel dosyaya ilişkindir. Biz bu dosya üzerinde işlemler yaparken
“/a/b/y.dat” yol ifadesini ya da “/a/c/k.dat” yol ifadesini kullanabiliriz.
Gördüğünüz gibi eğer farklı dizin girişleri aynı düğüm numarasına sahipse aslında
bu dizin girişleri aynı dosyayı belirtiyor durumdadır. Böylesi bir durumda bu dizin
girişlerinden her birine birer katı bağ (hard link) denir. Aynı dosyayı belirten çok
sayıda katı bağ söz konusu olabilir. Ayrıca dikkat ediniz, yukarıdaki örnekte "y.dat" ile
"k.dat" dosyaları farklı dizinde bulunuyorlar.Tabi bunlar aynı dizinlerde de olabilirlerdi.
Bir dosya için yeni bir katı bağ oluşturma işlemi ln ya da link kabuk komutuyla
yapılabilir. ln komutu tamamen cp komutu gibi kullanılır:
ln <kaynak yol ifadesi> <hedef yol ifadesi>
link <kaynak yol ifadesi> <hedef yol ifadesi>
ln ya da link komutu yeni bir düğüm elemanı oluşturmaz. Dolayısıyla dosyanın yeni
bir kopyasını yaratmaz. Yalnızca kaynak yol ifadesi ile belirtilen düğüm numarası ile
aynı olacak biçimde yeni bir dizin elemanı oluşturur. Örneğin:
ln a.dat b.dat
ya da:
link a.dat b.dat
2
Kaan Aslan Makale Arşivi – www.kaanaslan.net
komutuyla var olan "a.dat" dosyası için "b.dat" isminde yeni bir giriş oluşturulur. Bu iki
dizin girişinin de düğüm numaraları aynıdır. Bu örneği kendi makinamda yaparak şu
sonuçları elde ettim:
Gördüğünüz gibi iki dizin girişinin de isimleri dışında herşeyi aynı. Bu dosyayı "a.dat"
ismiyle kullanmak ile "b.dat" ismiyle kullanmak tamamen aynı etkiye sahip olacaktır.
ls -l komutunda dosyanın katı bağ sayısı da rapor edilmektedir. Eğer düğüm
elemanını gösteren tek bir dizin girişi varsa dosyanın katı bağ sayısı 1'dir. Aynı
düğüm elemanını gösteren iki dizin girişi varsa bu dizin girişlerine ilişkin bağ sayısını
2 olarak göreceksiniz. Yukarıdaki örnekte erişim haklarından sonra gördüğünüz 2
sayısı katı bağ sayısını belirtiyor. Dosyaların katı bağ sayısı istenildiği kadar çok
olabilir. Örneğin biz "a.dat" dosyasının "b.dat" isimli bir katı bağını oluşturduktan
sonra "c.dat" ya da "d.dat" isimleriyle yeni katı bağlarını da oluşturabiliriz:
Katı bağ oluşturma işlemi ile kopya oluşturma işleminin farklılığına dikkat ediniz.
Dosya kopyalama sırasında hem yeni bir düğüm elemanı hem de dosyayı oluşturan
blokların yeni bir kopyası oluşturulmaktadır.
Dosyanın katı bağları arasında hiçbir önem ilişkisi yoktur. Tüm bağların dosya sistemi
için durumu aynıdır. Örneğin bizim işleme "a.dat" girişi ile başlamış olmamız "a.dat"
girişini diğer katı bağ girişlerinden farklı kılmaz. Katı bağ oluşturma işlemi sonrasında
asıl giriş ile onun katı bağı arasında hiçbir fark kalmamıştır.
Pekiyi, katı bağ sayısı 1'den fazla olan bir dizin girişi silindiğinde ne olur? Dizin
girişi ile birlikte hemen düğüm elemanının silinmesi düşünülemez. Çünkü bu durumda
dosyanın diğer katı bağları geçersiz kalacaktır. Böyle bir durumda sistem düğüm
elemanının katı bağ sayısını 1 eksiltir. Eğer katı bağ sayısı sıfıra düşerse düğüm
elemanını siler, sıfıra düşmezse silmez. Örneğin yukarıda yaptığımız denemenin son
durumunda tek tek dosyaları silelim:
3
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Dosyaların katı bağ sayısı stat yapısı içerisindeki st_nlink elemanı ile elde edilebilir.
Zaten ls programı da bağ sayısını bu biçimde elde etmektedir. Bu aşamada stat
fonksiyonunu ve stat yapısını yeniden gözden geçirmenizi salık veririm.
Dizinlerin de normal dosyalar gibi katı bağ sayıları vardır. Bir dizine ilişkin düğüm
elemanını kaç dizin girişi gösteriyorsa dizinin de katı bağ sayısı o kadar olur. Örneğin,
yeni bir dizin yaratıp katı bağ sayısına bakarsanız 2 olduğunu görürsünüz. Deneme
amacıyla "x" adında yeni bir dizin yaratalım ve bu dizine ls -ld komutunu uygulayalım
(ls komutusndaki -d seçeneği dizin içeriğinin değil kendisinin gösterilmesini sağlar):
Bildiğiniz gibi i-node tabanlı ve Microsoft tabanlı dosya sistemlerinde yeni bir dizin
yaratıldığında, o dizinin içerisinde “.” ve “..” isimli iki giriş oluşturulmaktadır. “.” girişi,
dizinin kendisine ilişkin katı bağı, “..” girişi ise dizinin üst dizinine ilişkin katı bağı
belirtir. İşte yeni yaratılan bir dizinin katı bağ sayacının 2 olmasının nedeni “.” isimli
dizin girişidir. Yani yeni yaratılan bir dizinin düğüm elemanını iki dizin girişi
göstermektedir. Birincisi dizinin yaratıldığı dizindeki asıl dizin girişidir, ikincisi de
yaratılan dizinin içerisindeki “.” isimli dizin girişidir. Bu durumu şekilsel olarak şöyle
açıklayabiliriz:
4
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Bir dizinin içerisinde her yeni yaratılan dizin “..” girişi nedeniyle onun üst dizininin bağ
sayısını da 1 artırır. Yukarıda verdiğimiz örnekte “x” dizininin içerisinde bir dizin daha
yaratsak “x” dizininin bağ sayacı 3 olacaktır.
POSIX standartlarında dizinler için katı bağ oluşturulup oluşturulamayacağı işletim
sistemini yazanların isteğine bırakmıştır (implementation dependent). Örneğin Linux
sistemleri buna izin vermiyorlar. Dizinler için katı bağ oluşturmaya izin veren
sistemlerde bu işlem ancak ayrıcalıklı (privileged) kullanıcı tarafından (yani root
tarafından) yapılabilir. Çünkü dizinler için katı bağların oluşturulması sorunlu bir
konudur. Dizin ağacını dolaşan programlar katı dizin bağları yüzünden sonsuz
döngüye girebilirler. Örneğin, bir dizin ağacında ilerlerken bir dizine ilişkin katı bir bağ
ile karşılaştığınızı düşünün. Bu katı bağ daha önce geçmiş olduğunuz bir dizine
ilişkinse ne olur? Sonsuz döngüye girersiniz, değil mi?.. İşte bu nedenden dolayı
dizinler için katı bağların oluşturulması güvenli olarak değerlendirilmemektedir.
Katı bağ oluşturma işlemi programlama yoluyla link isimli POSIX fonksiyonu
kullanılarak gerçekleştirilebilir. Fonksiyonun prototipini inceleyiniz:
#include <unistd.h>
int link(const char *source, const char *dest);
Fonksiyonun birinci parametresi kaynak dosyaya ilişkin yol ifadesini, ikinci
parametresi yaratılacak dizin girişine ilişkin yol ifadesini alır. Fonksiyon başarı
durumunda sıfır değerine başarısızlık durumunda -1 değerine geri döner. errno
değişkeninin alabileceği önemli değerleri şunlardır:
EACCESS
:
Parametrelerde belirtilen yol bileşenlerine ilişkin dizinlerden en az birine
‘x’ hakkı yoktur ya da hedef dosyanın ilişkin olduğu dizine ‘w’ hakkı
yoktur.
ENOENT
:
Kaynak ya da hedef yol ifadelerinde belirtilen bir dizin yoktur ya da
kaynak yol bileşeni bir dizin girişi belirtmemektedir ya da kaynak ya da
hedef yol ifadeleri boş string’ten oluşmaktadır.
ENOTDIR
:
Yol bileşenlerinden biri dizin olması gerekirken dizin değildir.
EEXIST
:
Hedef yol ifadesine ilişkin dizin girişi zaten vardır.
...
:
...
link fonksiyonu başarı durumunda dosyaya ilişkin bağ sayacını 1 artırır ve söz konusu
dosyanın st_ctime elemanını, hedef dizin girişinin içerisinde bulunduğu dizinin
st_ctime ve st_mtime elemanlarını günceller. link fonksiyonunu bağ oluşturma
işlemini yapan basit bir programı şöyle yazabiliriz:
5
Kaan Aslan Makale Arşivi – www.kaanaslan.net
/* myln.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc != 3) {
fprintf(stderr, "Wrong number of arguments!..\n");
exit(EXIT_FAILURE);
}
if (link(argv[1], argv[2]) < 0) {
perror("link");
exit(EXIT_FAILURE);
}
return 0;
}
Derleme işlemini şöyle yapabilirsiniz:
gcc –o myln myln.c
Sembolik bağlar başka dosyalara referans eden özel dosyalardır. Bir sembolik bağ
normal bir dosyadır fakat içerisinde dosya bilgileri yerine referans edilen dosyanın yol
ifadesi bulunur. İşletim sisteminin sistem fonksiyonları sembolik bağlarla
karşılaştığında sembolik bağ dosyası üzerinde işlem yapmak yerine o sembolik bağın
referans ettiği dosya üzerinde işlem yaparlar.
Sembolik bağlar ln –s komutuyla yaratılabilir. Örneğin:
Sembolik bağlar listelenirken o bağların referans ettiği dosyalar da görüntülenir.
Örneğin:
Sembolik bağlar için rapor edilen uzunluğun sembolik bağın tuttuğu dosyanın yol
uzunluğu kadar olduğuna dikkat ediniz. Bir sembolik bağ dosyası referans ettiği
dosyanın yol ifadesinden başka bir bilgi tutmaz.
Pekiyi sembolik bağlarda referans edilen dosyaların yol ifadeleri nasıl saklanıyor?
Modern POSIX sistemlerinde eğer referans edilen dosyanın yol ifadesi kısa ise (yani
az karakterden oluşuyorsa) bu yol ifadesi doğrudan sembolik bağlara ilişkin i-node
elemanında saklanır:
6
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Eğer referans edilen dosyanın yol ifadesi uzunsa sembolik bağ için 1 tane veri bloğu
tahsis edilip, referans edilen dosyanın yol ifadesi o veri bloğunda tutulur:
Örneğin ext2 dosya sisteminde referans edilen dosyanın yol ifadesi 60
karakterden kısaysa yol ifadesi doğrudan i-node içerisindeki veri bloklarına ilişkin
göstericilerde saklanmaktadır. (12 tane doğrudan gösterici + 1 tane tekli blok
gösterici + 1 tane ikili blok göstericisi + 1 tane üçlü blok göstericisi = 15 gösterici * 4 =
60 byte.)
Sembolik bağ dosyalarının referans ettiği dosyalar üzerinde değil de sembolik bağ
dosyalarının kendileri üzerinde işlem yapabilir miyiz? Bu sorunun yanıtı "bazı işlemler
için evet bazıları için ise hayır"dır. Bazı POSIX fonksiyonlarının sembolik bağ
üzerinde işlem yapan biçimiyle sembolik bağın referans ettiği dosya üzerinde işlem
yapan farklı biçimleri vardır. Bunları özetleyelim:
- open fonksiyonu her zaman sembolik bağın referans ettiği dosyayı açar. Sembolik
bağ dosyasının kendisi open fonksiyonu ile açılamaz.
- stat fonksiyonu sembolik bağın referans ettiği dosyanın bilgilerini elde eder.
Sembolik bağ dosyasının kendisine ilişkin bilgiler lstat fonksiyonuyla elde
edilmektedir.
- remove ve unlink fonksiyonları her zaman sembolik bağ dosyasının kendisi
üzerinde işlem yapar
7
Kaan Aslan Makale Arşivi – www.kaanaslan.net
- chmod fonksiyonu sembolik bağın referans ettiği dosyanın erişim haklarını değiştirir.
Sembolik bağ dosyasının kendisine ilişkin erişim hakları lchmod fonksiyonuyla
değiştirilmektedir.
- chown fonksiyonu sembolik bağın referans ettiği dosyanın sahiplik bilgilerini
değiştirir. Sembolik bağ dosyasının kendisine ilişkin sahiplik bilgileri lchmod
fonksiyonuyla değiştirilmektedir.
Sembolik bağın referans ettiği dosyanın silinmesi ya da başka bir yere taşınması
durumunda sembolik bağ durmaya devam eder (dangling symbolic link). Bu durumda
sembolik bağ kullanıldığında sanki olmayan bir dosya üzerinde işlem yapılıyormuş
gibi bir etki oluşur. Örneğin sembolik bağın referans ettiği dosyayı sildikten sonra
open fonksiyonuyla sembolik bağı açmaya çalışsak open fonksiyonu -1 ile geri döner
ve errno değişkeni ENOENT değeriyle doldurulur.
Sembolik bağ dosyaları symlink isimli POSIX fonksiyonuyla yaratılmaktadır:
#include <unistd.h>
int symlink(const char *path1, const char *path2);
Fonksiyonun birinci parametresi sembolik bağın referans edeceği dosyanın yol
ifadesini, ikinci parametresi ise yaratılacak sembolik bağ dosyasının yol ifadesini
belirtir. Birinci parametresiyle belirtilen yol ifadesine ilişkin dosyanın var olması
gerekmemektedir. (Aslında bu parametrenin bir dosyaya ilişkin geçerli bir yol ifadesi
bile olması gerekmez.) Örneğin:
if (symlink("/home/kaan/a", "b") < 0) {
perror("symlink");
exit(EXIT_FAILURE);
}
Burada prosesin çalışma dizininde “/home/kaan/a” dosyasına referans eden “b”
isminde bir sembolik bağ dosyası yaratılmak istenmiştir. Birinci argümanda belirtilen
“/home/kaan/a” dosyası bulunmuyor olsa bile fonksiyon başarısız olmaz. symlink
fonksiyonu başarısızlık durumunda -1 değerine geri döner. Bu durumda errno
değişkeninin alabileceği önemli değerler şunlardır:
8
Kaan Aslan Makale Arşivi – www.kaanaslan.net
EACCESS
:
Prosesin ikinci parametreyle belirtilen yol bileşenine ilişkin dizinlerden
en az birine ‘x’ hakkı yoktur ya da sembolik bağlantı dosyasının
yaratılacağı dizine ‘w’ hakkı yoktur.
ENOTDIR
:
İkinci parametreye ilişkin yol bileşenlerinden biri dizin olması gerekirken
dizin değildir.
EEXIST
:
Hedef yol ifadesine ilişkin dizin girişi zaten vardır.
...
:
...
Bazen elimizde bir sembolik bağ dosyası vardır ve biz bu sembolik bağ dosyasının
referans ettiği dosyayı bilmek isteriz. İşte bu işlem readlink isimli POSIX fonksiyonu
tarafından yapılmaktadır:
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsize);
Fonksiyonun birinci parametresi sembolik bağ dosyasının yol ifadesini, ikinci
parametresi ise sembolik bağ dosyasının içeriğinin (yani sembolik bağ dosyasının
referans ettiği dosyanın yol ifadesinin) yerleştirileceği char türden dizi’nin adresini
belirtir. Üçüncü parametreye ise ikinci parametreyle belirtilen dizi’nin uzunluğu
girilmelidir. Fonksiyon başarı durumunda diziye yerleştirdiği byte sayısı ile
başarısızlık durumunda -1 değeriyle geri döner. Eğer fonksiyonun üçüncü
parametresine yerleştirilecek bilginin uzunluğundan küçük bir değer girilirse bu
durumda fonksiyon üçüncü parametresinde belirtilmiş olan sayıda byte kadar bilgiyi
diziye yerleştirir. Fonksiyon yerleştirme işleminden sonra null karakteri diziye
eklemez. null karakter programcı tarafından eklenmelidir. Örneğin:
char buf[1024];
ssize_t len;
...
if ((len = readlink("b", buf, 1023)) < 0) {
perror("readlink");
exit(EXIT_FAILURE);
}
buf[len] = '\0';
Başarısızlık durumunda errno değişkeninin alabileceği önemli değerler şunlardır:
9
Kaan Aslan Makale Arşivi – www.kaanaslan.net
EACCESS
:
Parametrelerde belirtilen yol bileşenlerine ilişkin dizinlerden en az birine
‘x’ hakkı yoktur ya da hedef dosyanın ilişkin olduğu dizine yazma hakkı
yoktur.
ENOENT
:
Fonksiyonun birinci parametresine ilişkin yol ifadesinde belirtilen bir
dizin yoktur ya da bu yol ifadesine ilişkin bir yol bileşeni bir dizin girişi
belirtmemektedir ya da bu yol ifadesi boş bir string’ten oluşmaktadır.
ENOTDIR
:
Yol bileşenlerinden biri dizin olması gerekirken dizin değildir.
EINVAL
:
Fonksiyonun birinci parametresine ilişkin dizin girişi bir sembolik
bağlantı dosyası değildir.
...
:
...
[1]
Dizin girişlerinde başka ek bilgiler de tutuluyor olabilir. Örneğin ext2 sistemerinde
dosyaların özellikleri ve sonraki dizin girişinin yeri de dizin girişlerinde tutulmaktadır.
Kaynaklar
Aslan, K. (2002). UNIX/Linux Sistem Programlama Kurs Notları. Istanbul: C ve
Sistem Programcıları Derneği.
Bovet, D. and Cesati, M. (2005). Understanding the Linux Kernel. Oreilly &
Associates Inc.
ISO/IEC. (2003). 9945-2:2003(E), Information techonolgy – Portable Operating
System Interface (POSIX) – Part 2: System Interfaces.
Raymond, E. S. (2003). The Art of UNIX Programming. Pearson Education.
Richter, J. M. (1999). Programming Applications for Microsoft Windows with Cdrom.
4th. Redmond, Washinton: Microsoft Press.
Rochkind, M. J. (2004). Advanced UNIX Programming (2nd Edition). Addison Wesley
Longman Publishing Co., Inc.
Stevens, R., Rago, S. A.
(2005). Advanced Programming in the UNIX(R)
Environment (2nd Edition). Addison-Wesley Professional.
10
Kaan Aslan Makale Arşivi – www.kaanaslan.net

Benzer belgeler

Blog Kaydını PDF Olarak İndir

Blog Kaydını PDF Olarak İndir oluşturabilme anlamındadır.Bir dizin içerisinde bir dosyayı yaratabilmemiz için dizin üzerinde ‘w’ hakkına sahip olmamız gerekir. ‘w’ hakkına sahip olmadığımız bir dizinde dosya yaratmak istendiğim...

Detaylı