Dosya erişim kontrolü şöyle yapılır.
- Önce Open
fonksiyonunu çağıran prosesin root olup olmadığına bakılır. root ise
hiçbir kontrol yapılmaz. Erişim kabul edilir.
- Değil
ise ikinci erişim istenen processin etkin UserID'sinin dosyanın UserID'si
ile ayni olup olmadığına bakılır. Eğer aynı ise erişim haklarından owner
kısmı dikkate alınır. Değil ise 3. maddeye geçilir.
- Erişmek
isteyen prosesin etkin grupid'sinin dosyanın grupid'si ile aynı olup
olmadığına bakılır. Aynı ise grup haklar dikkate alınır. Değil
ise 4. maddeye geçilir.
- Bu
durumda dosyanın other bilgileri dikkate alınır.
Belirli bir yıldan sonra bir prosesin tek bir gruba ait olması
yetersiz görülmüştür. Çünkü bir kişi birden fazla projede çalışabilmektedir.
işte bu durumda ek grupid kavramı ortaya çıkmıştır. Bugünkü sistemde bir
prosesin bir tane gerçek grupid'si ve etkin grupid'si vardır. Fakat birden
fazla ek gruba da sahiptir.
Ek gruplar tamamen yukarıdaki 3. madde sırasında prosesin
etkin grupid ile dosyanın grupid'si karşılaştırılırken etkin grupid ile ayni
değerde karşılaştırılmaktadır. Kullanıcının ek gruplari /etc/group dosyasında
belirtilmektedir.
POSIX Programlamada Kullanılan Önemli Bazı Bilgiler
POSIX fonksiyonları standart C fonksiyonları ile birlikte
glibc/libc diye bilinen kütüphanenin içerisindedir ve GCC sistemi bu
kütüphaneye bakmaktadır. Fakat fonksiyonların prototipleri çeşitli baslık
dosyası içinde olabilir. Bunların ayrıca include edilmedi gerekmektedir.
POSIX Fonksiyonlarının çok büyük bolumu basari durumunda 0
başarısızlık durumunda -1 değerine geri dönerler. Programcı programın
başarısızlığını test etmelidir. Tabi başarısızlığın da bir sebebi vardır. iste
başarısızlığın nedeni int türden global errno isimli bir
değişkene yerleştirilmiştir. Fonksiyon basarisiz olduğunda bu değişkenin içine
bakarsak neden basarisiz olduğunu anlayabiliriz. Tüm başarısızlık değerleri
errno.h dosyası içinde EXXX bicimde sembolik sabitlerle define edilmiştir.
Programı isterse doğrudan bu sembolik sabitleri kullanabilir.
if( open(.........) ){
if(errno == ENOENT)
{
......
}
}
POSIX Standartlarında her posix fonksiyonu için başarısızlık
durumunda her fonksiyon için errno değişkeninin alabileceği tüm değerler
listelenmiştir.
Fonksiyon basarisiz olduğunda uygun mesajın verilmesi
zahmetli olabilir. Bunun için perror ve strerror fonksiyonları bulunmaktadır.
perror bizden bir yazı alır önce o yazıyı yazdırır. Sonra bir iki nokta üst
üste karakteri yazdırır sonra da o anki errno değerine bakarak ona karsı gelen
yazıyı yazdırır (stderr dosyasina). stderror fonksiyonu ise bizden bir hata
kodunu alarak. Ona karşı gelen yazıyı verir. Bu durumda tipik kontrol su
şekilde yapılabilir.
if(open(...) == -1){
perror("open");
exit(EXIT_FAILURE);
}
Dosya İşlemleri Yapan Temel POSIX Fonksiyonları
Open Fonksiyonu
#include <fcntl.h>
int open(const char *path, int oflags, ...);
Fonksiyonun birinci parametresi açılacak olan dosyanın
yolunu alır. İkinci parametresi açış modunu belirtir. Açış modu fcntl.h içerisinde
tanımlanmış olan O_XXXX biçimindeki sabitlerin bit OR işlemi
ile birleştirilmesi ile olur. Açış modu şunlardan yalnızca birini içermek
zorundadır.
- O_RDONLY
- O_WRONLY
- O_RDWR
O_CREAT, dosya yok ise yarat, var ise bir şey yapma
anlamına gelmektedir. O_TRUNC, O_RDONLY ya da O_RDWR ile
birlikte kullanılmak zorundadır. Bu durumda dosya varsa sıfırlanır ve
açılır. O_EXCL, O_CREAT ile birlikte kullanılmak
zorundadır. Bu birlikte kullanım sadece yeni bir dosya yaratmak ve açmak için
kullanılır. Dosya var ise open fonksiyonu başarısız
olur. O_APPEND, Tüm yapılan yazma işlemlerinin dosyanın sonuna
eklenmesi gerektiği anlamına gelmektedir. Bu durumda dosyanın herhangi bir
yerinden okuma yapılabilir. Fakat herhangi bir yerine yazılamaz. Her yazılan
sonuna eklenir.
Open fonksiyonunda ikici parametrede O_CREAT
kullanılmışsa bu durumda dosyanın yaratılması gibi bir durum oluşur. Artık
programcının da dosyanın erişim haklarını üçüncü parametresi belirtmesi
gerekir.
Fonksiyonun 3. parametresinde belirtilecek erişim hakları
sys/stat.h dosyasında belirtilen sembolik sabitlerin bit OR işlemi ile
birleştirilmesi ile oluşturulur. Bu sembolik sabitlerin isimleri su şekilde
oluşturulmuştur.
R
|
USR
|
|
S_I
|
W
|
GRP
|
X
|
OTH
|
Bu gösterimin kombinasyonları olacak şekilde olur. Örnegin;
S_IRUSR -> User'a read hakki verir
S_IXGRP -> Gruba calistirma haki verir
Örnek bir uygulama:
/*-----------------------------------------------------------------------------------
open fonksiyonunun kullanýmý
------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(void)
{
int fd;
if ((fd = open("a.dat",
O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
perror("open");
exit(EXIT_FAILURE);
}
printf("success...\n");
return 0;
}
Open fonksiyonu basari durumunda dosya betimleyicisi (file
descriptor) denilen bir handle değerine geri döner. Bu handle değeri diğer
fonksiyonlarda parametre olarak kullanılacaktır. Başarısızlık durumunda
fonksiyon -1 değerine geri döner.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcnlt.h>
#include <sys/stat.h>
int main(void)
{
int fd;
if((fd = open("a.dat", O_RDWR))
== -1){
fprintf(stderr,
"Error ")
}
return 0;
}
Close Fonksiyonu
#include <unistd.h>
int close(int fd);
Açılan her dosya bir biçim de kapatılmalıdır. Çünkü açım sırasında
bir takım kaynaklar tahsis edilmiş olur. Kapatma sırasında bu kaynaklar geri
bırakılır. Ancak dosyayı biz hiç kapatmasak bile process kapandığında bile
dosya kesinlikle kapatılmalıdır. Fakat artık kullanılmayacak olan bir dosyanın
kapatılması iyi bir tekniktir.
posix fonksiyonlarının bir çoğu unistd.h dosyası
içerisinde tanımlanmıştır.
Fonksiyon parametre olarak open fonksiyonu ile dosyanın
betimleyicisini alır. Başarılı ise 0 değil ise -1 ile geri dönüş yapar.
/*-------------------------------------------------------------------------------------
close fonksiyonu
-------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(void)
{
int fd;
if ((fd =
open("a.dat", O_RDWR)) == -1) {
perror("open");
exit(EXIT_FAILURE);
}
close(fd);
return 0;
}
Dosya Göstericisi Kavramı
Dosyadaki her bir byte'in bir ofset numarası vardır. Dosya
göstericisi imleç görevindedir. Bir ofset belirtir. Okuma ve yazma işleminin
dosyanın hangi noktasından itibaren yapılacağını belirtir. Dosya
açıldığında dosya göstericisi 0. ofsettedir. Okunan ya da yazılan miktar kadar
otomatik ilerletilir. Dosya göstericisinin dosyanın son byte’indan sonraki
byte’ı gösterme durumuna EOF durumu denir. Bu durumda okuma yapılamaz ancak
yazma yapılabilir. Bu dosyaya ekleme anlamına gelir.
Read ve Write Fonksiyonları
Read fonksiyonunun prototipi şu şekildedir
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
Fonksiyonun birinci parametresi dosya betimleyicisini,
ikinci parametresi okunan bilgilerin yerleştirileceği adresi, üçüncü
parametresi ise okunacak byte sayısını belirtir. Read fonksiyonu ile olandan
daha fazla okunmak istenebilir bu durumda fonksiyon okuyabildiği kadar byte'i
okur okuyabildiği byte sayısına geri döner. read IO hatası dolaysı ile hiç
okuma yapamaz ise -1 değerine EOF'dan dolayı hiçbir şey okuyamaz ise 0 değerine
geri döner.
/*-------------------------------------------------------------------------------------
read fonksiyonunun
kullanim ornegi
--------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(void)
{
int fd;
char buf[30 + 1];
ssize_t n;
if ((fd =
open("sample.c", O_RDONLY)) == -1) {
perror("open");
exit(EXIT_FAILURE);
}
if ((n = read(fd,
buf, 30)) == -1) {
perror("read");
exit(EXIT_FAILURE);
}
buf[n] = '\0';
puts(buf);
close(fd);
return 0;
}
Write fonksiyonunun prototipi şu şekildedir.
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
Fonksiyonun birinci parametresi dosya betimleyicisini,
ikinci parametresi dosyaya yazılacak bilgilerin bulunduğu bellek adresini,
üçüncü parametresi ise yazılacak byte miktarını belirtir. Fonksiyon başarılı
ise yazılabilen byte sayısına basarisiz ise -1 değerine geri döner.
/*-------------------------------------------------------------------------------------
Dosya kopyalama
-------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#define BUFSIZE 8192
int main(int argc, char *argv[])
{
int fds, fdd;
char buf[BUFSIZE];
ssize_t n;
if (argc < 3) {
fprintf(stderr, "wrong number of
argument!..\n");
fprintf(stderr, "usage: mycp <source fie>
<dest file>\n");
exit(EXIT_FAILURE);
}
if ((fds =
open(argv[1], O_RDONLY)) < 0) {
perror("open");
exit(EXIT_FAILURE);
}
if ((fdd =
open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))
< 0) {
perror("open");
exit(EXIT_FAILURE);
}
while ((n = read(fds,
buf, BUFSIZE)) > 0)
if (write(fdd, buf, n) < 0) {
perror("write");
exit(EXIT_FAILURE);
}
if (n < 0) {
perror("read");
exit(EXIT_FAILURE);
}
printf("1 file
copied...\n");
close(fds);
close(fdd);
return 0;
}
Bu örnekte okuma yaptigimiz konksiyonun yetkilerini alip
hedef dosyaya eklemek icin stat fonksiyonunu kullanmak gerekiyor.
lseek fonksiyonu
lseek fonksiyonunun prototipi su sekildedir
#include <sys/types.h> // bu dosya include edilmek
zorunda deiliz. Edilirse guzel olur.
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
Fonksiyonun birinci parametresi dosya betimleyicisi ikinci
parametresi konumlandırma ofseti, üçüncü parametresi konumlandırma orijinini
belirtir. Üçüncü parametre 3 değerden birini alabilir.
SEEK_SET (0) konumlandırmanın baştan itibaren yapılacağını
belirtir. Bu durumda ofset parametresi >= 0 olmak zorundadır. SEEK_CUR (1)
konumlandırmanın dosyanın göstericisinin konumu nerede ise ona göre yapılacağı
anlamına gelir. Bu durumda ikinci parametre pozitif, negatif ya da 0
olabilir. Nihayet SEEK_END (2) konumlandırmanın EOF pozisyonuna göre yapılacağı
anlamına gelmektedir. Bu durumda ikinci parametre =< 0 olmak
zorundadır. Fonksiyon basari durumunda dosya göstericisinin yeni konumuna
başarısızlık durumunda -1 değerine geri döner.
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int main()
{
int file=0;
if((file=open("testfile.txt",O_RDONLY)) < -1)
return 1;
char buffer[19];
if(read(file,buffer,19) != 19) return 1;
printf("%s\n",buffer);
if(lseek(file,10,SEEK_SET) < 0) return 1;
if(read(file,buffer,19) != 19) return 1;
printf("%s\n",buffer);
return 0;
}
Bu örnekde exitsys fonksiyonunu kendi yazdığımız
uygulamalarda direk kullanabiliriz.
lseek komutu ile örneğin 5 bayt uzunluğunda bir dosya 15.
bayttan itibaren veri yazabiliyoruz. Buna dosya deliği denilmektedir. (File
hole) Bu konu ile ilgili http://www.kaanaslan.com/resource/article/display_article.php?id=64 adresinden
ayrıntılı bilgi elde edilebilir.
Dosya baytlardan oluşmaktadır. Fakat halk arasında içinde
yalnızca yazı olan dosyalara text dosyalar, içinde yazının dışında başka şeyler
de olabilen dosyalara binary dosyalar denilmektedir. Ayrıca test dosyalarda her
bir karakterin hangi tablo ile kodlandığını bilmek gerekir. Buna karakter
kodlaması denilmektedir.
Unix / Linux
| Windows
a\nb | a\r\nb
LF | CR/LF
a\nb | a\r\nb
LF | CR/LF
Windows da test editörler aşağı satıra geçiş için CR ve LF
karakterlerini (0D ve 0A) kullanır. Fakat Unix/Linux’ta yalnızca LF karakteri
kullanılmaktadır. Bu da uyumsuzluğa yol açmaktadır. Bu karışıklığı çözmek için
ve özellikle text okuma ve yazmaları kolaylaştırmak için C ve bazı başka
dillerde dosyayı açarken text mode ve binari mode seklinde yapay seçenekler
oluşturulmuştur. Bir dosyayı text modda açtığımız zaman şunlar olur;
- Dosyadan
1 bayt okurken eğer dosya göstericisi Windows da CR karakterinin üzerinde
ise CR ve LF karakterlerinin ikisini de okur fakat bize fonksiyon LF
karakteri okumuş gibi geri döner.
- Biz
dosyaya text modda açılmışsa \n karakterini yazdırdığımızda aslında
Windows da aslında CR/LF biçiminde 2 byte yazılmaktadır.
Biz dosyayı binary modda açtığımız zaman hangi karakteri
yazdırırsak yalnızca onu yazar.
Görüldüğü gibi Unix/Linux sistemlerinde dosyanın text mode
veya binary modda açılması arastanda hiçbir fark yoktur.
Text Mode / Binary Mode Örnekleri
/*-------------------------------------------------------------------------------------
C'de
text mode / binary mode'
-------------------------------------------------------------------------------------*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE
*f;
if ((f
= fopen("a.txt", "w")) == NULL) {
fprintf(stderr,
"cannot open file!\n");
exit(EXIT_FAILURE);
}
fprintf(f,
"a\nb"); /*
Windows'ta 4 byte UNIX/Linux'ta 3 byte */
fclose(f);
return
0;
}
/*-----------------------------------------------------------------------------------
C'de
text mode / binary mode'
------------------------------------------------------------------------------------*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE
*f;
if ((f
= fopen("a.txt", "wb")) == NULL) {
fprintf(stderr,
"cannot open file!\n");
exit(EXIT_FAILURE);
}
fprintf(f,
"a\nb"); /*
Windows'ta 3 byte UNIX/Linux'ta 3 byte */
fclose(f);
return
0;
}
Dosya Sistemine İlişkin Yardımcı POSIX Fonksiyonları
chmod ve fchmod fonksiyonları
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
Yaratılmış bir dosyanın erişim hakları open fonksiyonunda
ilk kez belirlenir. Ancak bu fonksiyonlarla daha sonra değiştirilebilir. chmod
fonksiyonu yol ifadesinden hareketle fchmod fonksiyonu dosya betimleyicisinden
hareketle modu değiştirir.
Bir prosesin bir dosyanın erişim haklarını değiştirebilmesi
için ya root olması ya da prosesin etkin userid'sinin dosyanın sahibi ile ayni
olması gerekir.
root hakkı, ya hep ya hiç biçiminde bir haktır. Yani root
proses her şeyi yapabilir. Diğerleri sadece kendilerine yönelik şeyleri
yapabilir. Bu nedenle bazı sistemlerde proses root olmadığı halde bazı
işlemleri yapabilecek durum oluşturulmuştur. Prosesin bu yetkilendirme bilgisi
ilgili sistemlerde proses kontrol bloğunda saklanır. Fakat her sistem bunu
desteklememektedir.
> Ayrıca komut satırında chmod isimli bir komutta vardır.
> Ayrıca komut satırında chmod isimli bir komutta vardır.
/*--------------------------------------------------------------------------------------
chmod örneği
-------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
void exitsys(const char *msg);
int main(int argc, char *argv[])
{
int arights;
int i, k;
int aflags[] =
{S_IXOTH, S_IWOTH, S_IROTH, S_IXGRP, S_IWGRP,
S_IRGRP,
S_IXUSR, S_IWUSR, S_IRUSR};
int mflag;
if (argc < 3) {
fprintf(stderr, "wrong number of
arguments!..\n");
fprintf(stderr, "usage: mychmod <access
rights> <file>\n");
exit(EXIT_FAILURE);
}
sscanf(argv[1],
"%o", &arights);
for (i = 2; i <
argc; ++i) {
mflag = 0;
for (k = 0; k < 9; ++k)
if (arights & aflags[k])
mflag |= aflags[k];
if (chmod(argv[i], mflag) < 0)
exitsys("chmod");
}
return 0;
}
void exitsys(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
Hiç yorum yok:
Yorum Gönder