Professional Documents
Culture Documents
Unix Linux Sistemlerinde Dosya Betimleyicilerinin Anlami PDF
Unix Linux Sistemlerinde Dosya Betimleyicilerinin Anlami PDF
Kaan Aslan
14 Temmuz 2008
UNIX/Linux sistemlerinde her prosesin proses tablosu yoluyla erişilen bir dosya
betimleyici tablosu (file descriptor table) vardır. Dosya betimleyici tablosu bir gösterici
dizisi biçimindedir. Betimleyci tablo içersindeki her gösterici açılmış bir dosyanın
bilgilerinin tutulduğu ve ismine dosya nesnesi (file object) denilen bir veri yapısını
gösterir. open fonksiyonundan elde edilen dosya betimleyicisi (file descriptor)
prosesin dosya betimleyici tablosunda bir indeks belirtmektedir.
Dosya nesnesi dosya işlemlerini gerçekleştirmek için gerekli tüm bilgileri tutmaktadır.
Dosya betimleyicisi bir sistem fonksiyonuna parametre olarak geçirildiğinde ilgili
fonksiyon betimleyici tablosunun betimleyici değeri ile belirtilen indeksinden dosya
nesnesinin adresini elde eder ve açık olan dosyanın bilgilerine erişir. Her dosya açma
işlemi sonucunda yeni bir dosya nesnesi oluşturulmakta ve betimleyici tablosunda
yeni bir giriş tahsis edilmektedir. Örneğin yukarıdaki şekilde belirtilen durumda open
fonksiyonuyla yeni bir dosyayı daha açtığımızı düşünelim:
int fd;
...
fd = open("test.dat", O_RDONLY);
1
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Yeni yaratılan dosya nesnesini kesikli çizgilerle gösterdik. Şekilden de gördüğünüz
gibi dosya açma işlemi sonucunda open fonksiyonundan 5 numaralı betimleyici
değeri elde edilmiştir. Yani örneğimizde fd’nin içerisinde 5 değeri bulunacaktır.
Disk tabanlı bir dosya açıldığında işletim sistemi diskten dosya bilgilerini elde eder
ve dosyayı yönetebilmek için bellekte çeşitli veri yapılarını oluşturur. Yukarıda da
belirttiğimiz gibi, dosyalar üzerinde işlem yapabilmek için gerekli tüm bilgiler dosyanın
açılması sırasında işletim sistemi tarafından dosya nesnelerinin içerisine
yerleştirilmektedir. Dosya betimleyicilerinin yalnızca birer anahtar değer (handle)
işlevi gördüğüne dikkat ediniz. Şimdi farklı iki dosya betimleyicisinin aynı dosya
nesnesini gösterdiğini düşünelim. Bu durumda aslında her iki dosya betimleyicisi de
aynı dosyaya ilişkin olur değil mi? Örneğin, yukarıdaki şekilde 1 ve 2 numaralı
betimleyicileri aynı dosya nesnesini gösteriyor. O halde biz o dosya üzerinde işlem
yapmak için 1 numaralı betimleyiciyi de 2 numaralı betimleyiciyi de kullanabiliriz.
- Dosya işlemleri için gerekli dosyanın bloklarına ilişkin tüm disk bilgileri.
- Dosyanın sahiplik bilgileri ve erişim bilgileri.
- Dosya göstericisinin konumu.
- Dosya nesnesinin kullanım sayacı.
- ...
2
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Her prosesin ayrı bir proses tablosuna dolayısıyla da ayrı bir betimleyici tablosuna
sahip olduğunu belirtmiştik. İşte bu nedenle dosya betimleyicileri proses düzeyinde
anlamlı değerlerdir. Örneğin biz X prosesinde open fonksiyonuyla bir betimleyici elde
edip o betimleyicinin değerini Y prosesine proseslerarası haberleşme yöntemlerinden
biriyle göndermiş olalım. Bu betimleyicinin artık Y prosesinde bir anlamı olmayacaktır.
Çünkü bu betimleyici Y prosesinde kullanılırken artık Y prosesinin dosya betimleyici
tablosunda bir indeks belirtecektir. Bu nedenle gönderilen bu betimleyici Y prosesi
için ya başka bir dosyaya ilişkin betimleyici durumundadır ya da geçersiz bir
betimleyici durumundadır.
Aynı dosya open fonksiyonuyla birden fazla kez açılabilir. open fonksiyonu her
çağrıldığında yeni bir dosya nesnesi ve yeni bir betimleyici tahsis edilir. Böylesi bir
durum aynı dosya üzerinde birden fazla dosya nesnesi ile işlem yapmak anlamına
gelir. Dosya göstericisinin dosya nesnesinin içerisinde tutulduğunu anımsayınız. Bu
durumda iki betimleyicinin gösterdiği dosya nesnelerindeki dosya göstericileri farklı
konumlarda olabilirler değil mi? Örneğin:
3
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Burada fd1 ve fd2 betimleyicilerinin her ikisi de “test.dat” dosyasına ilişkindir. Biz fd1
betimleyici ile bu dosyanın 100 numaralı offset'inden, fd2 betimleyici ile de 200
numaralı offset'inden işlem yapabiliriz.
#include <unistd.h>
Fonksiyonun parametresi daha önce açılmış olan bir dosyaya ilişkin betimleyicidir.
Fonksiyon parametresiyle aldığı betimleyici ile aynı dosya nesnesini gösteren yeni bir
betimleyici tahsis eder ve bu betimleyici ile geri döner. dup fonksiyonunun da başarı
durumunda betimleyici tablosundaki ilk boş betimleyici ile geri döneceği POSIX
standartlarında garanti altına alınmıştır. Fonksiyon başarısızlık durumunda -1
değerine geri döner. Örneğin:
Burada fd1 ve fd2 aynı dosya nesnesini gösteren betimleyicilerdir. Oluşan durumu
aşağıdaki şekille gösterebiliriz:
4
Kaan Aslan Makale Arşivi – www.kaanaslan.net
dup fonksiyonu başarısız olduğunda errno değişkeninin alabileceği önemli değerler
şunlardır:
EBADEF : Fonksiyonun parametresi açık bir dosyaya ilişkin geçerli bir dosya
betimleyicisi değildir.
EINTR : Fonksiyon bir sinyalle sonlandırılmıştır.
... : ....
fd1 ve fd2'nin aynı dosya nesnesine ilişkin iki betimleyici olsun. close fonksiyonu ile
fd1 betimleyicisini kapatmış olalım. Bu durumda dosya nesnesi fd2 betimleyicisi
tarafından da kullanıldığı için yok edilmez. Bir dosya nesnesinin kaç betimleyici
tarafından kullanıldığı sistem tarafından dosya nesnesinin içerisindeki bir sayaç
yoluyla izlenmektedir. close fonksiyonu parametresiyle belirtilen betimleyiciyi boşaltır
ve dosya nesnesinin sayacını bir eksiltir. Ancak nesne sayacı sıfıra geldiğinde dosya
nesnesi yok edilmektedir.
open fonksiyonu ile “test.txt” isminde bir dosya açtığımızı ve fd isimli bir
betimleyici elde ettiğimizi varsayalım. Aşağıdaki kod parçası çalıştıktan sonra ne
olacaktır?
close(1);
dup(fd1);
printf("bu yazi nereye yazilacak?\n");
5
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Bir dosyaya ilişkin betimleyicinin başka bir dosya nesnesini gösterir duruma
getirilmesine yönlendirme (redirection) denilmektedir. Yukarıdaki örneğimizde stdout
dosyasını “test.txt” isimli bir dosyaya yönlendirmiş olduk. Aşağıdaki programı
çalıştırarak oluşturulan "test.txt" dosyasını inceleyiniz:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
int i;
close(1);
dup(fd);
close(fd);
return 0;
}
dup2 fonksiyonu close ile çiftleme işlemlerinin atomik bir biçimde yapıldığı daha
gelişmiş bir dup fonksiyonudur:
#include <unistd.h>
Fonksiyon önce fd2 betimleyicisi üzerinde close işlemi uygular. Daha sonra fd2
betimleyicisinin fd1 betimleyicisi ile aynı dosya nesnesini göstermesini sağlar. Yani
çağırma sonrasında fd2 betimleyicisi fd1 betimleyicisi ile aynı dosya nesnesini
gösteriyor olacaktır. Bu durumu şekilsel olarak şöyle açıklayabiliriz:
6
Kaan Aslan Makale Arşivi – www.kaanaslan.net
dup2 fonksiyonu size biraz karışık gelmiş olabilir. İşlevini şöyle aklınızda tutabilirsiniz:
dup2, fd1 betimleyicisini çiftlemektedir. Fakat elde edilen betimleyici en düşük
numaralı betimleyici değil fd2 numaralı betimleyici olur. Ayrıca dup2 fonksiyonunda
ikinci parametreyle belirtilen fd2 betimleyicnin açık bir dosyaya ilişkin olması da
gerekmemektedir. Yani fd2 boş bir betimleyici değerini belirtiyor olabilir. dup2
fonksiyonu eğer fd2 betimleyicisi boş değilse o betimleyiciyi kapatmaya
çalışmaktadır.
EBADEF : Fonksiyonun parametresi açık bir dosyaya ilişkin geçerli bir dosya
betimleyicisi değildir.
EINTR : Fonksiyon bir sinyalle sonlandırılmıştır.
... : ...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
int i;
if ((fd = open("test.txt",
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR)) < 0) {
perror("open");
exit(EXIT_FAILURE);
}
7
Kaan Aslan Makale Arşivi – www.kaanaslan.net
dup2(fd, 1);
close(fd);
return 0;
}
Linux sistemlerinde proses tablosu task_struct yapısı ile, proses dosya tablosu
files_struct yapısı ile ve dosya nesnesi de file yapısı ile temsil edilmektedir. Bu yapılar
üzerinde bazı temel bilgileri verelim:
struct task_struct {
/* ... */
struct files_struct *files;
/* ... */
};
8
Kaan Aslan Makale Arşivi – www.kaanaslan.net
struct files_struct {
atomic_t count;
struct fdtable *fdt;
struct fdtable fdtab;
Burada prosesin dosya bilgilerine erişmekte kullanılan ana eleman files_struct yapısı
içerisindeki fdt göstericisidir. Bu gösterici işin başında (yani fork işlemi sırasında) aynı
yapı içerisindeki fdtable türünden fdtab isimli yapı nesnesini gösterir duruma
getirilmektedir. fdtable yapısı şöyledir:
struct fdtable {
unsigned int max_fds;
struct file ** fd; /* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
struct fdtable *next;
};
9
Kaan Aslan Makale Arşivi – www.kaanaslan.net
Linux sistemlerindeki file yapısı ise aşağıdaki gibidir:
struct file {
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
u64 f_version;
#ifdef CONFIG_SECURITY
10
Kaan Aslan Makale Arşivi – www.kaanaslan.net
void *f_security;
#endif
void *private_data;
#ifdef CONFIG_EPOLL
struct list_head f_ep_links;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
Yapının f_mode dosyanın erişim bilgilerini, f_pos elemanı dosya göstericisinin yerini,
f_count elemanı nesne sayacını belirtmektedir. Bu yapının syrıntılı açıklaması için
başka kaynaklara başvurabilirsiniz.
Kaynaklar
Bovet, D. and Cesati, M. (2005). Understanding the Linux Kernel. Oreilly &
Associates Inc.
Maurice, B. (1986). The Design Of The UNIX Operating System. Prentice Hall: New
Jersey.
Rodriguez C., Fisher G., Smolski S. (2006). The Linux Kernel Primer. Prentice Hall.
11
Kaan Aslan Makale Arşivi – www.kaanaslan.net