> Unix/Linux sistemlerinde dosya işlemleri "Case-Sensitive" şeklindedirler. Yani "study" ile "Study" isimli dosyalar birbirinden farklı dosyalardır. Fakat Windows sistemler "Case-Sensitive" değillerdir. > Yeni bir dizin oluşturduğumuz zaman, "root" dizini hariç, bütün dizinlerin içerisinde "." ve ".." isminde birer adet dizin oluşturulur. Bu dizinler sırasıyla o anki dizinin yerini ve bir üst dizinin yerini tutarlar. Ek olarak bu iki dosya SİLİNEMEZ. > Aşağıda temel dizinlere ilişkin bilgiler aşağıdaki gibidir: >> "bin" dizini, komut satırında kullanabileceğimiz komutların "executable" hallerini barındırmaktadır. Örneğin, "ls" komutu bu dizinin de altındadır. >> "boot" dizini, sistemin "boot" edilebilmesi için gereken dosyaları barındırmaktadır. Bizler, "kernel" i derlediğimiz zaman, kernel'e ait "image" dosyasını buraya yerleştireceğiz. >> "cdrom" dizini, CD-Rom'un "mount" edildiği yer. >> "dev" dizini, "device driver" dosyalarının bulunduğu dizin. Bu konuya ilerleyen zamanlarda değineceğiz. >>> "/dev" dizinin altında "zero" isimli bir aygıt sürücüsü bulunmaktadır. Aygıt sürücüleri de bir nevi dosya olarak işlem görmektedir. Bu dosyadan kaç bayt okursak, o bayt ededince sıfır elde ederiz. Bu dizinde EOF konumuna gelinmez, dolayısıyla sonsuz büyüklükte düşünebiliriz. * Örnek 1, #include "stdio.h" #include "stdlib.h" #include "fcntl.h" #include "sys/stat.h" #include "unistd.h" void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* # OUTPUT # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ int fd; unsigned char buffer[100]; if((fd = open("/dev/zero", O_RDONLY)) == -1) exit_sys("open"); read(fd, buffer, 100); for(int i = 0; i < 100; ++i) printf("%02X%c", buffer[i], i % 16 == 15 ? '\n' : ' '); printf("\n"); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>> "/dev" dizinin altındaki bir başka aygıt sürücüsü de "full" isimli aygıt sürücüsüdür. Bu dosyaya bir şey yazmak istediğimiz zaman diskin dolu olduğu etkisini göstermektedir. * Örnek 1, #include "stdio.h" #include "stdlib.h" #include "string.h" #include "fcntl.h" #include "sys/stat.h" #include "unistd.h" void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* # OUTPUT # write: No space left on device */ int fd; unsigned char buffer[100] = "I am Ahmopasa"; if((fd = open("/dev/full", O_WRONLY)) == -1) exit_sys("open"); if(write(fd, buffer, strlen(buffer)) == -1) exit_sys("write"); //for(int i = 0; i < 100; ++i) printf("%02X%c", buffer[i], i % 16 == 15 ? '\n' : ' '); //printf("\n"); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>> "/dev" dizini altındaki bir diğer aygıt sürücüsü de "NULL" isimli aygıt sürücüsü. Buraya yazılan her şey kayboluyor. Altı boş bir sepet olarak düşünebiliriz. >>> "/dev" dizini altındaki bir diğer aygıt sürücüsü de "random" isimli olandır. Buradan okuma yaptığımız zaman rastgele baytlar okuyor olacağız. * Örnek 1, #include "stdio.h" #include "stdlib.h" #include "fcntl.h" #include "sys/stat.h" #include "unistd.h" void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* # OUTPUT # 09 0B F5 80 F2 9A AC 58 B6 D8 DD 20 26 32 8A 47 B5 2F E8 75 64 63 CF 90 65 5F 2C E9 03 C8 59 5E 48 D9 8C E8 0F 91 0C 52 70 21 0C E3 89 FE 29 63 74 4B 20 1A 66 86 3A 52 D1 51 8E C5 9A D2 8F C4 46 FC A3 76 6E 87 56 CB 08 DC 13 63 97 E0 EA 3D 0D 90 89 99 DF 1E 16 C4 75 F8 AD A5 96 79 A7 B4 A1 CE 34 9E */ int fd; unsigned char buffer[100]; if((fd = open("/dev/random", O_RDONLY)) == -1) exit_sys("open"); read(fd, buffer, 100); for(int i = 0; i < 100; ++i) printf("%02X%c", buffer[i], i % 16 == 15 ? '\n' : ' '); printf("\n"); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>> "/dev/zero" aygıt sürücüsünden okuma yapılması: Bu aygıt sürücüsünden okunan her bayt sıfır olarak okunur. Ek olarak, bu aygıt sürücüsüne yazılanlar da atılacaktır. * Örnek 1, #include #include #include #include void exit_sys(const char* msg); int main() { /* # OUTPUT # 0 0 0 0 0 0 0 0 0 0 */ FILE* f; if((f = fopen("/dev/zero", "rb")) == NULL) { fprintf(stderr, "cannot open the file!...\n"); exit(EXIT_FAILURE); } int ch; for(int i = 0; i < 10; ++i) { if((ch = fgetc(f)) == EOF) { fprintf(stderr, "cannot read from the file!...\n"); exit(EXIT_FAILURE); } fprintf(stdout, "%d ", ch); fflush(stdout); } fclose(f); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>> "/dev/random" aygıt sürücüsünden okuma yapılması: Döngünün her turunda ilgili aygıt sürücüsünden rastgele bayt okunmaktadır. * Örnek 1, #include #include #include #include void exit_sys(const char* msg); int main() { /* # OUTPUT # 39 - 57 B8 - 184 AE - 174 39 - 57 D8 - 216 BD - 189 AD - 173 F8 - 248 72 - 114 58 - 88 */ FILE* f; if((f = fopen("/dev/random", "rb")) == NULL) { fprintf(stderr, "cannot open the file!...\n"); exit(EXIT_FAILURE); } int ch; for(int i = 0; i < 10; ++i) { if((ch = fgetc(f)) == EOF) { fprintf(stderr, "cannot read from the file!...\n"); exit(EXIT_FAILURE); } fprintf(stdout, "%02X - %d\n", ch, ch); fflush(stdout); } fclose(f); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, #include #include #include #include void exit_sys(const char* msg); int main() { /* # OUTPUT # 1F 3F F5 10 4E A5 2C 83 B3 85 45 B2 0D BC BC 15 91 BA FC 54 60 9E 78 63 B7 BF 37 80 DC 85 19 86 07 53 3C 5C FC C9 6C C1 EA 71 A0 92 C9 42 14 55 11 30 79 F7 E3 BB E2 D9 64 56 C0 3E 4C 82 33 5F D1 09 EA A1 BD 86 59 84 6C C0 74 75 0B 7B EA 4A E8 A3 9E 3E 7E 45 35 AE 85 6C 87 27 10 75 75 4B 6E DC D8 02 07 B7 7A 6B 4E 7B CA 7D 28 6B 11 C0 14 AC AF 4A 9C 87 02 91 E1 53 91 AD FE 2B F4 8C 5B 18 E2 9C DF CD F0 0D 7B 02 6B F8 F1 A0 57 80 7F 29 E3 F3 06 BB F1 A1 0C F3 0B FA A8 DE 23 F9 A6 CC B8 D1 19 36 6F A7 28 2B C7 C2 F6 F9 BE 4A D5 1E 8F 0F D3 9E B4 10 2D 57 8F 8B 4B 12 9A 98 51 8F 15 98 84 71 C7 50 FC EC 71 36 67 C0 F1 DE F2 CE 28 FF 20 9D 70 0A A7 82 B7 54 4D 82 DA 73 2D C3 E3 34 32 82 E7 97 F9 1D CD 97 EC BE 8E F6 64 A4 3B 83 F1 2E 89 BE 6F B9 81 21 05 5A D3 22 */ FILE* f; if((f = fopen("/dev/random", "rb")) == NULL) { fprintf(stderr, "cannot open the file!...\n"); exit(EXIT_FAILURE); } int ch; for(int i = 0; i < 256; ++i) { if((ch = fgetc(f)) == EOF) { fprintf(stderr, "cannot read from the file!...\n"); exit(EXIT_FAILURE); } fprintf(stdout, "%02X%c",ch, i % 16 == 15 ? '\n' : ' '); fflush(stdout); } fclose(f); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>> Linux sistemlerinde /dev dizinini altında "loopN" (N burada bir sayıdır) isimli "loopback aygıtı" denilen ilginç bir blok aygıt sürücüsü vardır. Bu loopback aygıtı aslında bir dosyayı disk gibi kullanmak için düşünülmüştür. Bu aygıt sürücünün tipik kullanımı şöyledir: -> Önce aygıtı temsil eden bir dosya yaratılır. Mademki bu dosya bir disk yerine geçecektir. O zaman bu dosya belli bir sektör uzunluğunda dd komutuyla oluşturulabilir: dd if=/dev/zero of=mydisk.dat bs=512 count=2880 Burada toplam 2880 * 512 byte uzunlukta içi 0'larla dolu bir dosya oluşturulmuştur. -> Şimdi losetup isimli programla bu dosyanın bir loopback aygıt sürücüsü ile ilişkilendirilmesi gerekmektedir. Örneğin: $ sudo losetup /dev/loop0 mydisk.dat Artık biz /dev/loop0 blok aygıt sürücüsü ile işlem yaptığımızda bu aygıt sürücü hedef olarak mydisk.dat dosyasını kullanacaktır. -> Artık dosya sistemini mkfs ile formatlayabiliriz: $ sudo mkfs -t ext2 /dev/loop0 -> Artık mount işlemi yapabiliriz: $ mkdir mydisk $ sudo mount /dev/loop0 mydisk Artık mydisk dizini bizim için adeta bir disk volümü gibidir. Ancak orada yapacağımız işlemler aslında yalnızca mydisk.dat dosyasını etkileyecektir. Bu işlemler şöyle geri alınmaktadır -> Önce volüm umont yapılır: $ sudo umount mydisk -> Şimdi /dev/loop0 ile dosya (yani mydisk.dat) arasında bağlantı losetup -d komutuyla koparılır >> "etc" dizini, sistemle ilgili önemli konfigürasyon dosyalarının bulunduğu dizin. >> "home" dizini bizim için en önemli dizinlerden bir tanesidir. Sistemde oluşturulan her bir kullanıcı için, bu dizin altında yeni bir klasör oluşturmaktadır. >> "lib" dizinleri ise sistemin kullandığı ama statik ama dinamik kütüphane dosyalarını içerir. >> "media" dizini tipik olarak "media" aygıtlarının "mount" edildiği yer olarak kullanılmakta. >> "mnt" dizini ise genel olarak bir "mount point" şeklinde kullanılıyor. "mount" işlemine de yine ileride değineceğiz. >> "opt", üçüncü parti yazılımların yüklendiği alternatif dizinlerden bir tanesidir. >> "proc", "proc" dosya sistemine ait bir dizindir. İleride değineceğiz. >> "root" dizinin kendisi ise bir "super-user" dizinidir. Aslında "root" ismindeki kullanıcının "home" dizinidir. >> "sbin" dizisinde ise "super-user" kişilerin kullanabileceği komutları içeren dizindir. >> "sys" ise daha modern bir dosya sistemini bünyesinde barındırmaktadır. >> "tmp" dizini ise "temporary" dosya açan uygulamalar için varsayılan bir dizin olarak kullanılmakta. >> "usr" ise kullanıcının yüklediği programların bulunduğu en genel dizinlerden bir tanesidir. > Yol İfadeleri (Path Names): Bir dosyanın hangi dizin içerisinde olduğunu belirten ifadelere denmektedir. >> UNIX/Linux dünyasında yol ifadeleri "Case-Sensitive" şeklindedir. Örneğin, "home/kaan/Study/sample.c" ile "home/kaan/study/sample.c" farklı yol ifadeleridir ya da "Sample.c" ile "sample.c" birbirinden farklı dosyalardır. >> UNIX/Linux dünyasında yol ifadelerindeki "/" sembolleri, Windows dünyasındaki yol ifadelerindeki "\" sembolleri arasındakiler yol ifadelerinin bileşenleri olarak adlandırılmıştır. Örneğin, yukarıdaki yol ifadesinde "home", "kaan" vs. birer bileşendir. Yol ifadeleri içerisinde iş bu sembolleri birden fazla kullanmakta herhangi bir sakınca yoktur. >> Yol ifadeleri, temelde ikiye ayrılmaktadırlar; >>> İfadenin başında "/" olması durumunda, ilgili yol ifadesi Mutlak Yol İfadesi olarak adlandırılır. Kök dizinden itibaren yer belirtmektedirler. Yani "/" ifadesi aslında kök dosyadan itibaren aranmayı sağlamaktadır. Unutulmamalıdır ki bir prosesin kökü varsayılan olarak "root" dizinidir. "/" ifadesi ile "root" dizini içerisinde aramaya başlar. Eğer bu kök dizini "home/kaan" yaparsak, artık "kaan" dizini içerisinden aramaya başlayacaktır. İlgili prosesin kök bilgisi de yine "Process Control Block" içerisinde saklanmaktadır. >>> İfadenin başında "/" olmaması durumunda ise ilgili ifade Göreli Yol İfadesi olarak adlandırılır. Her bir prosesin kontrol bloğunda (bkz. Process Control Block) "Current Working Directory" bilgisi tutulmaktadır. Türkçesi o anki çalışma dizini. İş bu Göreli Yol İfadeleri ise ilgili prosesin "Current Working Directory" konumundan itibaren yer belirtiyor. Örneğin, bizim prosesimizin o anki çalışma dizini "home/kaan" olsun. "ali/veli/sample.txt" yol ifadesi aslında "home/kaan/ali/veli/sample.txt" anlamına gelmektedir. Bir diğer örnek, "test.txt" şeklindeki yol ifadesi Göreli Yol İfadesi olduğundan, prosesin o anki çalışma dizini içerisinde aranacaktır. >>>> Proseslerin "Current Working Directory" bilgisi de yine üst prosesten alt prosese aktarılmaktadır. "pwd" komutu ile prosesin o anki çalışma dizin bilgisini temin edebiliriz. "Bash" programındaki yol ifadesinin başında yer alan "~" sembolü sadece "Bash" programı içindir ve "home/kaan" dizinini işaret eder. Bizler yol ifadesi verirken "home/kaan" şeklinde yazmalıyız. * Örnek 1, "ahmopasa@ahmopasa:~/Desktop/LearnLinux/Examples/wd$ pwd" şeklindeki satırın çıktısı "/home/ahmopasa/Desktop/LearnLinux/Examples/wd" şeklinde. Görüldüğü üzere "~" sembölü "home/ahmopasha" ifadesine denk gelmektedir. * Örnek 2, Aşağıdaki örnekte ilgili dosya "Current Working Directory" içerisinde arandığı gösterilmiştir: #include "stdio.h" #include "stdlib.h" int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples/wd$ ./wd ~/Desktop/LearnLinux/Examples$ wd/wd */ /* # OUTPUT # Success!.. Error opening file! */ FILE *f; if((f = fopen("test.txt", "r") ) == NULL) { fprintf(stderr, "Error opening file!\n"); exit(EXIT_FAILURE); } printf("Success!..\n"); return 0; } * Örnek 3, Aşağıdaki örnekte ise "Current Working Directory" konumundan itibaren arama sağlayacak şekilde bir yol ifadesi geçilmiştir: #include "stdio.h" #include "stdlib.h" int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples$ wd/wd */ /* # OUTPUT # Success!.. */ FILE *f; if((f = fopen("wd/test.txt", "r") ) == NULL) { fprintf(stderr, "Error opening file!\n"); exit(EXIT_FAILURE); } printf("Success!..\n"); return 0; } >>>> Bir prosesin "Current Working Directory" bilgisini "getcwd" fonksiyonu ile temin edebiliriz. Bu bir POSIX fonksiyonudur. Birincil parametre olarak yazının yazılacağı adres, ikincil parametre olarak ise karakter adedi. İş bu fonksiyon başarısız olması halinde "errno" değişkeninin değerini değiştiriyor ve NULL değeri ile geri dönüyor. Başarı durumunda ise ilk parametredeki adrese yazıyı yazmaktadır. Yeteri kadar büyük karakter adedi için Linux sistemlerinde tanımlı "PATH_MAX" sembolik sabitini kullanabiliriz ki bu sabit "limits.h" başlık dosyasında bildirilmiştir. Yazının sonuna gelecek olan '\0' karakteri de bu adetlere dahildir. Bu sembolik 4096 rakamına tekabül etmektedir. Fakat UNIX sistemlerinde bu PATH_MAX sembolik sabitinin tanımlanması zorunlu değildir. Böyle bir senaryoda "pathconf()" fonksiyonunu çağırabiliriz. İş bu fonksiyon "Absolute Path" bilgisini vermektedir, yani "Mutlak Yol İfadesi". * Örnek 1, #include "stdio.h" #include "stdlib.h" #include "limits.h" #include "unistd.h" void exit_sys(const char* msg); int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples/wd$ ./wd */ /* # OUTPUT # /home/ahmopasa/Desktop/LearnLinux/Examples/wd */ char buffer[PATH_MAX]; /* * @param PATH_MAX, UNIX sistemlerinde tanımlı olması bir zorunluluk olmadığından, * ilgili fonksiyonun geri dönüş değerini kontrol etmeliyiz. */ if (getcwd(buffer, PATH_MAX) == NULL) { exit_sys("getcwd"); } puts(buffer); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, Our Bash Program(version 2): #include "stdio.h" #include "stdlib.h" #include "string.h" #include "unistd.h" #include "limits.h" #define MAX_CMD_LINE 4096 #define MAX_CMD_PARAMS 128 char parse_cmd_line(void); void dir_proc(void); void clear_proc(void); void pwd_proc(void); void exit_sys(const char* msg); typedef struct tagCMD{ char* name; void (*proc)(void); } CMD; CMD g_cmds[] = { {"dir", dir_proc}, {"clear", clear_proc}, {"pwd", pwd_proc}, {NULL, NULL} }; char g_cmdline[MAX_CMD_LINE]; char* g_params[MAX_CMD_PARAMS]; int g_nparams; char g_cwd[PATH_MAX]; int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples/wd$ ./wd */ /* # OUTPUT # CSD: /home/ahmopasa/Desktop/LearnLinux/Examples/wd> */ char* str; int i; if(!getcwd(g_cwd, PATH_MAX)) exit_sys("getcwd"); for (;;) { fprintf(stdout, "CSD: %s> ", g_cwd); if (fgets(g_cmdline, MAX_CMD_LINE, stdin) == NULL) continue; if ((str = strchr(g_cmdline, '\n')) != NULL) *str = '\0'; parse_cmd_line(); if(g_nparams == 0) continue; if(!strcmp(g_params[0], "exit")) break; for(i = 0; g_cmds[i].name != NULL; ++i) if(!strcmp(g_params[0], g_cmds[i].name)) { g_cmds[i].proc(); break; } if(g_cmds[i].name == NULL) fprintf(stderr, "bad command: %s\n", g_params[0]); } return 0; } char parse_cmd_line(void) { char* str; g_nparams = 0; for(str = strtok(g_cmdline, " \t"); str != NULL; str = strtok(NULL, " \t")) { g_params[g_nparams++] = str; } } void dir_proc(void) { fprintf(stdout, "dir command executing...\n"); } void clear_proc(void) { system("clear"); } void pwd_proc(void) { if (g_nparams > 1) { fprintf(stdout, "pwd command must be used w/o an argument!\n"); return; } char cwd[4096]; getcwd(cwd, 4096); fprintf(stdout, "%s\n", cwd); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >>>> Bir prosesin "Current Working Directory" bilgisini değiştirmek için "chdir" isimli POSIX fonksiyonunu kullanabiliriz. "Bash" programı üzerinden "cd" ya da "chdir" komutlarını da kullanabiliriz. İş bu fonksiyona göreli ya da mutlak yol ifadesi geçebiliriz. Başarı durumunda sıfıra, başarısızlık durumunda eksi bir değerini döndürmektedir. İlgili yol ifadesini bulamadığı zaman başarısız olacaktır. * Örnek 1, "chdir" fonksiyonunun başarısız olması: #include "stdio.h" #include "stdlib.h" #include "limits.h" #include "unistd.h" void exit_sys(const char* msg); int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples/wd$ ./wd */ /* # OUTPUT # /home/ahmopasa/Desktop/LearnLinux/Examples/wd chdir: No such file or directory */ char buffer[PATH_MAX]; if (getcwd(buffer, PATH_MAX) == NULL) { exit_sys("getcwd"); } puts(buffer); if (chdir("/usr/binxxx") == -1) { exit_sys("chdir"); } puts(buffer); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, Our Bash Program(version 3): #include "stdio.h" #include "stdlib.h" #include "string.h" #include "unistd.h" #include "limits.h" #include "errno.h" #define MAX_CMD_LINE 4096 #define MAX_CMD_PARAMS 128 char parse_cmd_line(void); void dir_proc(void); void clear_proc(void); void pwd_proc(void); void cd_proc(void); void exit_sys(const char* msg); typedef struct tagCMD{ char* name; void (*proc)(void); } CMD; CMD g_cmds[] = { {"dir", dir_proc}, {"clear", clear_proc}, {"pwd", pwd_proc}, {"cd", cd_proc}, {NULL, NULL} }; char g_cmdline[MAX_CMD_LINE]; char* g_params[MAX_CMD_PARAMS]; int g_nparams; char g_cwd[PATH_MAX]; int main(void) { /* # INPUT # ~/Desktop/LearnLinux/Examples/wd$ ./wd CSD: /home/ahmopasa/Desktop/LearnLinux/Examples/wd> cd .. CSD: /home/ahmopasa/Desktop/LearnLinux/Examples> cd /usr/bin CSD: /usr/bin> cd / */ /* # OUTPUT # CSD: /home/ahmopasa/Desktop/LearnLinux/Examples/wd> CSD: /home/ahmopasa/Desktop/LearnLinux/Examples> CSD: /usr/bin> CSD: /usr/bin> cd / */ char* str; int i; if(!getcwd(g_cwd, PATH_MAX)) exit_sys("getcwd"); for (;;) { fprintf(stdout, "CSD: %s> ", g_cwd); if (fgets(g_cmdline, MAX_CMD_LINE, stdin) == NULL) continue; if ((str = strchr(g_cmdline, '\n')) != NULL) *str = '\0'; parse_cmd_line(); if(g_nparams == 0) continue; if(!strcmp(g_params[0], "exit")) break; for(i = 0; g_cmds[i].name != NULL; ++i) if(!strcmp(g_params[0], g_cmds[i].name)) { g_cmds[i].proc(); break; } if(g_cmds[i].name == NULL) fprintf(stderr, "bad command: %s\n", g_params[0]); } return 0; } char parse_cmd_line(void) { char* str; g_nparams = 0; for(str = strtok(g_cmdline, " \t"); str != NULL; str = strtok(NULL, " \t")) { g_params[g_nparams++] = str; } } void dir_proc(void) { fprintf(stdout, "dir command executing...\n"); } void clear_proc(void) { system("clear"); } void pwd_proc(void) { if (g_nparams > 1) { fprintf(stdout, "pwd command must be used w/o an argument!\n"); return; } fprintf(stdout, "%s\n", g_cwd); } void cd_proc(void) { // DEFAULT if (g_nparams > 2) { printf("Too mang arguments!..\n"); return; } // APPROACH - I if (g_nparams == 1) { printf("Too few arguments!..\n"); return; } if (chdir(g_params[1]) == -1) { printf("%s!\n", strerror(errno)); return; } // APPROACH - II /* char* dir; if (g_nparams == 1) { if((dir = getenv("HOME")) == NULL) exit_sys("getenv"); } else dir = g_params[1]; if (chdir(dir) == -1) { printf("%s!\n", strerror(errno)); return; } */ // DEFAULT if(!getcwd(g_cwd, PATH_MAX)) exit_sys("getcwd"); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >> Pek çok dosya sistemi, boşluklu dosya isimlerine izin vermemektedir. * Örnek 1, "~/Desktop/LearnLinux/Examples/wd$ ls" komutu verildiğinde aşağıdaki çıktıyı almaktayız; 'ali veli' test.txt wd wd.c Fakat, aşağıdaki komutu çağırdığımız zaman "~/Desktop/LearnLinux/Examples/wd$ cd "ali veli" ", "~/Desktop/LearnLinux/Examples/wd/ali veli$ " şeklinde çıktı alıyoruz. Demek ki bizim dosya sistemimiz boşluklu dosya isimlerine izin veriyor. Gördüğünüz gibi komut satırı argümanlarını tırnak işareti içerisine aldığımız zaman tek bir argüman olarak değerlendirmektedir. >> Yol ifadelerinde "." ve ".." karakterlerinin anlamları sırasıyla o anki çalışma dizini ve bir üst dizin şeklindedir. Örneğin, "/ali/../veli/./selami" şeklinde bir yol ifademiz olsun. "/" ile başladığı için "root" dizini içindeki "ali" dizini, ".." geldiği için tekrardan bir üst dizine dönüyoruz. Yani yine "root" içine geldik. Devamında "/veli" olduğu için, "root" içindeki "veli" dizinine geçiyoruz. "/." ise o anki dizin anlamındadır, yani hala "veli" dizini içindeyiz. En son "selami" olduğundan, "veli" içindeki "selami" dizinine geçiyoruz. Özetle, yukarıdaki o yol ifadesi "/veli/selami" şeklindedir. Bu iki karakter hem göreli hem de mutlak yol ifadesinde kullanılabilir. * Örnek 1, "ali/.." yol ifadesi göreli bir yol ifadesidir. O anki çalışma dizininden bir üst dizine çıkacaktır. * Örnek 2, "/home/kaan/../veli" yol ifadesi ise mutlak bir yol ifadesidir. Önce "home" içindeki "kaan" dizinine geçilir. "/.." ile karşılaşınca bir üst dizine geri döner, yani tekrardan "home" içine. Sonrasında da "home" içerisinde "veli" dizinine geçer. > Dizinlerin erişim hakları; >> Normal dosyalarda "owner", "group" ve "other" ne manaya geliyorsa dizinler için de aynı manaya gelmektedir. >> Dizinlerde de, tıpkı dosyalarda olduğu gibi, erişim hakları vardır. "w" hakkı demek ilgili dizinde bir dosya oluşturulabileceği ya da silinebileceği anlamına gelmektedir. Bir dosyayı silebilmek için bu dosya üzerinde "w" hakkına sahip olmamıza gerek yoktur, iş bu dosyanın içinde bulunduğu dizin üzerinde "w" hakkında sahip olmamız gerekiyor. Bir dosya oluşturabilmek, ismini değiştirebilmek için de keza aynı şey geçerlidir. Çünkü işletim sistemi tarafından dizinler, o dizin içerisindeki dosya bilgilerini barındıran, birer dosya olarak değerlendiriliyorlar. * Örnek 1, "~/Desktop/LearnLinux$ ls -l Examples" komutunu çalıştırdığımı zaman karşımıza "Examples" dizini içindekilerin detaylı bilgileri çıkacaktır. Eğer, "~/Desktop/LearnLinux$ ls -l -d Examples" komutunu çalıştırırsak, işte bu sefer "Examples" dizininin kendisi hakkında detaylı bilgileri çıkartacaktır. >> İlgili dizinde "r" hakkına sahip olmamız demek, o dizinin içeriğinin okunabilmesi anlamına gelmektedir(bkz. ls komutu). >> İlgili dizinde "x" hakkında sahip olmak demek, ilgili dizinin içerisine girebilmek demektir. Bir yol ifadesini argüman olarak bir programa geçtiğimiz zaman, ilgili ifade önce bileşenlerin ayrılıyor ve bu bileşenlerin de birer dizin olduğu teyit ediliyor. Buna "Path Name Resolution" denmektedir. Bunun için de ilgili bileşenin "x" hakkını bizlere sunması gerekiyor ki o dizinin içine girebilelim. Eğer bir yol ifadesindeki bir dizinde "x" hakkını kaldırırsanız, o dizinden öteye "Path Name Resolution" yapılamaz, o dizinden öteye gidilemez. Dolayısıyla ilgili yol ifadesindeki bütün dizinler, ilgili prosese, "x" hakkını vermeli ki hedeflenen dosyaya erişim sağlanabilsin. Linux dökümanlarında bu hakka "Searc Permission" da denmektedir. Öte yandan "mkdir" komutu ile bir dizin oluşturduğumuz vakit bu hak otomatik olarak sunulur. Zaman zaman da bu hak dizin ağacında duvar örmek, ötesine geçişi engellemek için de kullanılabilinir. Dosyalarda kimseye "x" hakkı vermediğimiz zaman "root" kullanıcısı bile dosyayı çalıştıramıyor idi fakat dizinlerde böyle bir şey söz konusu değil. Hiç kimseye dahi bu hakkı vermeseniz, "root" kullanıcısı yine müdahale edebilir. * Örnek 1, "home/kaan/Study/C/sample.c" şeklinde bir yol ifademiz olsun. Hedeflenen dosya ise "sample.c" olsun. Hedefe ulaşabilmek için prosesimizin kim olduğu önce belirlenir. Yani "owner", "group" ya da "other" dan birisiyizdir. Sonrasında iş bu proses, sırasıyla "home", "kaan", "Study", "C" dizinlerinde "x" hakkına sahip olmalı ki "Path Name Resolution" başarıyla tamamlansın ve hedefe erişebilelim. > Hatırlatıcı Notlar: >> "proc" dosya sistemi bellekte oluşturulur. "kernel" tarafından yapılan işlemleri dış dünyaya bildirmek için kullanılır.