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
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...