İşletim Sistemleri İşletim Sistemleri Dr. Binnur Kurt binnur.kurt@gmail.com Omega Eğitim ve Danışmanlık http://www.omegaegitim.com Bölüm 10 Dosya Sistemi 1|Sayfa İşletim Sistemleri İÇİNDEKİLER 1. İşletim Sistemi 2. Kabuk 3. Prosesler 4. İplikler 5. İplikler Arası Eş Zamanlama 6. Prosesler Arası İletişim 7. İş Sıralama 8. Prosesler Arası Eş zamanlama 9. Bellek Yönetimi 10. Dosya Sistemi 11. Soket Haberleşme Bölüm 10 Dosya Sistemi 2|Sayfa İşletim Sistemleri BÖLÜM 10 Dosya Sistemi Bölümün Amacı Bölüm sonunda aşağıdaki konular öğrenilmiş olacaktır: ► Dosya organizasyon biçimleri ► Dosya erişim hakları ► Java platformunda NIO.2 ile Dosyalama Sistemiyle çalışmak ► Dosya sistemi gerçekleme yaklaşımları Bölüm 10 Dosya Sistemi 3|Sayfa İşletim Sistemleri 10.1 Giriş Bellekte sakladığımız verilere uygulama sona erdiğinde ya da makinayı kapattığımızda tekrar ulaşamayız. Bellek kalıcı bir depolama ortamı değildir. Verileri kalıcı olarak saklamak istediğimizde dosya sisteminden yararlanıyoruz. Dosya sistemini ayrıca uygulamaları biri birleri ile tümleştirmek için de kullanabiliriz. Bir uygulama aktarmak istediği veriyi dosyaya yazar, diğer uygulama ise bu verileri aynı dosyadan okur. Dosya burada paylaşılan bir kaynak işlevi görür. Verileri dosyada uygulamanın ihtiyaçlarına göre farklı şekillerde organize edilebilir. Bir dosya sisteminin, verilerin dosyalarda organize edilmesi dışında başka temel görevleri daha bulunur: Dosya yaratma Dosya silme Dosya açma Dosya kapatma Dosyayı koruma ve paylaşım Dosyaya okuma ve yazma 10.2 Dosya Tipleri Verileri diskte iki farklı şekilde organize edebiliriz: Karakter dizisi Verileri dosyaya karakter dizisi olarak yazdığımızda, diskte kaç bayt yer kaplayacağını, verinin tipi değeri belirler. Örneğin C’de int tipinden bir veri bellekte 32 bit yer kaplar. Ancak bu tipten bir değişkenin değeri 42 ise diskte 2 bayt, değişkenin değeri 1.000.000 ise 7 bayt yer kaplar. Karakter dizisi olarak diske yazılan veriyi herhangi bir metin editörü ile açıp okuyabilir içeriğini düzenleyebilirsiniz. 1000 tane tamsayı değeri diske yazıp, daha sonra tekrar okumak istediğinizde sorun yaşarsınız. Örneğin {4, 8, 15, 16, 23, 42} dizisini diske yazdığınızda, dizinin elemanları diskte 4815162342 olarak ardışık bir şekilde dizilecektir. Problem dizinin herhangi bir değerini diskten okumak istediğinizde ortaya çıkar. Dizinin ilk elemanı 4 mü? 48 mi? 481 mi? Bu şekilde yazdığımız değerleri tekrar okuyup ayrıştıramıyoruz. Problemi, araya normal veri içinde gözükmen bir ayıraç karakterini kullanarak çözebiliriz. Örneğin, yukarıdaki problem için diske yazılacak değerler 4,8,15,16,23,42 olarak dizilir. Ancak bu sefer de herhangi bir elemanı (n. eleman) ayrıştırmak için ilk olarak n-1 elemanın ayrıştırılması gerekecektir. Bu da rastgele erişim başarımını düşürecektir. Bu yöntem, dosyanın tüketicisi bir insan ya da veriye çoğu zaman ardışıl olarak erişileceği durumlarda kullanılabilir. Sekizli dizisi Verileri dosyaya bayt dizisi olarak yazdığımızda, bellekte kaç bayt yer kaplıyor ise veriler diskte de o kadar bayt yer kaplar. Ancak bu sefer dosyanın içeriğini bir metin editörü ile açıp okuyamazsınız. Eğer dosyanın tüketicisi bir yazılım ise bu yöntemi tercih edebilirsiniz. Bölüm 10 Dosya Sistemi 4|Sayfa İşletim Sistemleri Dosya diskte iki bölümden oluşur: Veriler: Karakter dizisi ya da sekizli dizisi olarak organize edilmiş olabilir İndeks bölümü: dosyanın tipi, verilerin saklandığı blokların disk üzerindeki fiziksel konumları, haklar, dosyanın sahibi, dosyanın boyutu gibi bilgileri kapsar. Dosyaya okumak ya da yazmak amaçlarıyla erişildiğinde, dosya için bir tanımlayıcı oluşturulur. Dosya tanımlayıcılarına birer tamsayı iliştirilir. Örneğin, her proses için üç tane varsayılan olarak yaratılan tanımlayıcılar şunlardır: 0 değeri klavye, 1 ve 2’de konsolu gösterir. Her dosyanın bir adı vardır. Bu adı kullanarak dosyaya erişebilirsiniz. Bunun dışında istenirse sembolik başka isimler de verilebilinir. Dosya sistemi hiyerarşik olarak düzenlenmiştir. Dosyalar dizinlere dağıtılmıştır. Bir dizin için başka dizinler ve sıradan dosyalar yer alır. Linux işletim sisteminde boş bir dosya oluşturmak için touch ve boş bir dizin oluşturmak için ise mkdir komutları kullanılabilir (Şekil-10.1 (a)). ln komutu kullanılarak da sembolik link oluşturulabilir (Şekil-10.1 (b)). (a) Bölüm 10 Dosya Sistemi 5|Sayfa İşletim Sistemleri (b) Şekil-10.1 Unix’de dosya ve dizin komutları: (a) touch, mkdir,ls (b) ln Dosya sistemi yaratılan her dosya ile ilgili bir dizi kayıt tutar (Tablo- 10.1). Birçok komut dosya ile ilgili işlemleri yaparken bu öznitelikleri kullanır ya da değiştirir. Tablo 10.1 Dosyanın öznitelikleri Dosya Özniteliği Açıklama Dosyanın sahibi, ait olduğu gruptaki kullanıcılar e geriye Erişim hakları kalan tüm kullanıcılar için dosyayı okuma, yazma ve çalıştırma yetkileri Yaratıcı Dosyayı yaratan kullanıcı Sahibi Dosyanın sahibi kullanıcı Kilit bayrakları Dosya kilitinin durumunu gösterir bayraklar Dosya boyu Maksimum dosya boyu Yaratılma zamanı Dosyanın yaratılma zamanı Son erişim zamanı Dosyaya son erişim zamanı Son değişiklik zamanı Dosyada son değişikliğin yapıldığı zaman Bu dosya özniteliklerine stat() çağrısı kullanılarak erişilebilinir: #include <stdio.h> #include <sys/stat.h> int main(int argc, char *argv[]) { struct stat buf; if (stat(argv[1], &buf)) { perror ("Dosya bilgilerine ulaşamıyorum!"); } else { if (S_ISDIR(buf.st_mode)) { printf("Bu bir dizindir!\n"); } else if (S_ISREG(buf.st_mode)){ printf("Bu bir dosyadır!\n"); } else if (S_ISLNK(buf.st_mode)){ printf("Bu bir sembolik linktir!\n"); } Bölüm 10 Dosya Sistemi 6|Sayfa İşletim Sistemleri } return 0; } Java 7’de gelen NIO2 ile birlikte platformdan bağımsız olarak POSIX uyumlu dosya sistemlerinde dosya özniteliklerine erişebiliyoruz: package com.example; import import import import import import import import java.io.IOException; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; java.nio.file.attribute.FileTime; java.nio.file.attribute.PosixFileAttributes; java.text.DateFormat; java.util.Date; public class FileAttributes { public static void main(String[] args) { PosixFileAttributes attrs = null; Path file = Paths.get(args[0]); try { attrs = Files.readAttributes(file, PosixFileAttributes.class); } catch (IOException e) { System.out.println("Exception reading attributes of the file"); } System.out.println(file); System.out.println("Creation time: " + toDate(attrs.creationTime())); System.out.println("Last Modified: " + toDate(attrs.lastModifiedTime())); System.out.println("Last Access: " + toDate(attrs.lastAccessTime())); if (!attrs.isDirectory()) { System.out.println("Size (K Bytes):" + (attrs.size() / 1024)); } System.out.println("POSIX File information:"); System.out.format("Owner: %s\n",attrs.owner().getName()); System.out.format("Group: %s\n",attrs.group().getName()); System.out.format("Permissions: %s\n",attrs.permissions()); System.out.format("Regular file: %b Directory: " + "%b Sembolic Link: %b\n", attrs.isRegularFile(), attrs.isDirectory(), attrs.isSymbolicLink()); } // Utility method to print a better formatted time stamp public static String toDate(FileTime ft) { return DateFormat.getInstance() .format(new Date(ft.toMillis())) .toString(); } } Bölüm 10 Dosya Sistemi 7|Sayfa İşletim Sistemleri POSIX standardında dosyanın hakları ile ilgili olarak 12 tanım bulunur (Şekil-10.2). Dosyanın sahibi, grup kullanıcıları ve geriye kalan tüm kullanıcılar için okuma (r), yazma (w) ve çalıştırma (x) haklarını gösteren bayraklar yer alır. Çalıştırılan tüm komutlar, o komutu çalıştıranın hakları ile çalıştırılır. Ancak bazen komutun komutunun çalıştıranın değil de, komutun sahibinin hakları ile çalıştırılması istenir. Örneğin Unix’de parolayı değiştirmek için passwd komutu kullanılır. Parolalar Unix işletim sisteminde /etc/shadow dosyasında saklanır. Bu dosyanın özelliklerine bakıldığında, dosyanın sahibinin root ve hiçbir hakkın ise tanımlı olmadı görülür: [student@server1 ~]$ ls -l /etc/shadow ----------. 1 root root 1086 Dec 5 17:55 /etc/shadow Peki, bu durumda passwd komutunu sıradan bir kullanıcı çalıştırdığında parolasını nasıl değiştirecek? Cevap setuid ve setgid erişim haklarında gizli. Eğer bir komut için setuid ve setgid bayrakları çekilmiş ise komut, komutu çalıştıranın değil, komutun sahibinin hakları ile çalıştırılır. Şimdi passwd komutunun dosya özelliklerine bakalım: [root@server1 ~]$ ls -l /usr/bin/passwd -rwsr-xr-x. 1 root root 30768 Feb 22 2012 passwd Görüldüğü gibi passwd komutunun setuid bayrağı çekilmiş durumdadır. Bu hak, eğer komutta bir hata (=bug) varsa güvenlik açığına neden olabilir, bu nedenle dikkatli kullanılmalıdır. Şimdi ise /tmp dizinin haklarına bakalım: [student@server1 ~]$ ls -ld /tmp drwxrwxrwt. 16 root root 4096 Dec 29 11:10 /tmp Çıktıda x görmemiz gereken yerde t etiketini görüyoruz. Bu bayrak Sticky bayrağı olarak adlandırılır. /tmp dizini sıradan bir dizin değil, ortak paylaşılan bir dizin. Burada herkes dosya yaratabilir. Eğer herkes dosya yaratabilsin istiyorsanız, normalde dizine tüm hakları tanımlarsınız. Ancak bu durumda bir problemimiz var: Ali kullanıcısının yarattığı dosyayı Veli kullanıcısı silebilir. Bunu istemiyoruz. /tmp dizininde Ali’nin yarattığı dosyaları sadece Ali kullanıcısı silebilmelidir, benzer şekilde Veli’nin dosyalarını da sadece Veli kullanıcısı silebilmelidir. İşte Sticky tanımı bu işe yarıyor. Şekil-10.2 POSIX dosya sisteminde dosya hakları Dosya haklarını değiştirebilmek için chmod komutundan yararlanıyoruz: [student@server1 ~]$ touch apple [student @server1 ~]$ ls -n apple -rw-rw-r--. 1 500 500 0 Dec 29 11:28 apple [student @server1 ~]$ chmod g-rwx apple [student @server1 ~]$ ls -n apple -rw----r--. 1 500 500 0 Dec 29 11:28 apple [student @server1 ~]$ chmod o-wx apple Bölüm 10 Dosya Sistemi 8|Sayfa İşletim Sistemleri [student @server1 ~]$ chmod o+r apple [student @server1 ~]$ ls -n apple -rw----r--. 1 500 500 0 Dec 29 11:28 apple Dosya haklarını değiştirirken, bir hakkı açmak için + sembolünü ve kaldırmak için ise - sembolünü kullanıyoruz. Dosyanın sahibi için u karakterini, grup için g karakterini ve diğer kullanıcılar için ise o karakterini kullanıyoruz. Yine yazma hakkı için w karakterinden, okuma hakkı için r karakterinden ve çalıştırma hakkı için ise x karakterinden faydalanıyoruz. NIO.2’de nihayet POSIX dosya hakları ile çalışabiliyoruz. Aşağıdaki örnekte "rwxr-x---" hakları ile bir dosya yaratılıyor. Path p = Paths.get(args[0]); Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---"); FileAttribute<Set<PosixFilePermission>> attrs = PosixFilePermissions.asFileAttribute(perms); try { Files.createFile(p, attrs); } catch (FileAlreadyExistsException f) { System.out.println("FileAlreadyExists" + f); } catch (IOException i) { System.out.println("IOException:" + i); } 10.3 Java Platformunda NIO.2 ile Dosya İşlemleri Java platformunda tarihsel nedenlerle üç adet biri birini tamamlayan giriş çıkış kütüphanesi yer alır. İlk Java sürümü ile birlikte gelen java.io paketiyle dosyadan okumak ve dosyaya yazmak gibi temel dosya işlemleri yapılabilinir. Java 1.4 ile birlikte New IO anlamına gelen NIO Kütüphanesi geldi. NIO ile gelen en önemli özellik tıkanmasız (=non-blocking) giriş çıkış yeteneğidir. NIO ile birlikte gelen tıkanmasız soket ve Selector kullanılarak yüksek başarımlı ağ yazılımları geliştirilebilinir. Bu konu 11. Bölümde çalışılacaktır. Java SE 7 ile birlikte ise New New IO’nun kısaltması olarak kullanılan NIO.2 kütüphanesi geldi. Java platform bağımsız bir programlama dili olsa da iş dosyalama sistemi ile ilgili bir iş yapmaya geldiğinde bu özelliğini kaybettiğini görüyoruz. Makinanın diskinde kaç adet bölümleme olduğu, bu bölümlerin kapasitesi, kullanım miktarı, boş alan kapasitesi gibi basit ve temel bilgilere erişilmek istenildiğinde Java SE içinden çıkan hazır bir çözüm bulunmamaktaydı. NIO.2 ile birlikte ağırlıklı olarak dosyalama sistemi ile çalışmaya yönelik yeteneklerin geldiğini görüyoruz. Bu bölümde NIO.2 ile gelen dosyalama sistemiyle çalışmaya yönelik bu yenilikler incelenecektir. 10.3.1 FileStore FileStore sınıfı ile diskin bölümlerine ilişkin bilgilere ulaşılabilinir: Kaç adet bölüm var? Bölümlerin kapasitesi ve doluluk oranları: package com.example; import java.io.IOException; Bölüm 10 Dosya Sistemi 9|Sayfa İşletim Sistemleri import import import import import java.nio.file.FileStore; java.nio.file.FileSystem; java.nio.file.FileSystems; java.nio.file.Files; java.nio.file.Paths; public class DiskUsage { static final long K = 1024; static void printFileStore(FileStore store) throws IOException { long total = store.getTotalSpace() / K; long used = (store.getTotalSpace()-store.getUnallocatedSpace())/ K; long avail = store.getUsableSpace() / K; System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail); } public static void main(String[] args) throws IOException { System.out.format("%-20s %12s %12s %12s\n", "Filesystem", "kbytes", "used", "avail"); if (args.length == 0) { FileSystem fs = FileSystems.getDefault(); for (FileStore store : fs.getFileStores()) { printFileStore(store); } } else { for (String file : args) { FileStore store = Files.getFileStore(Paths.get(file)); printFileStore(store); } } } } 10.3.2 DirectoryStream Java.io.File sınıfındaki list() metodu, dizindeki tüm dosyaların bilgilerini oluşturup bir dizi olarak döner. Ancak bu davranış eğer dizin kalabalık ise performans problemlerine neden olur. NIO.2 ile birlikte gelen java.nio.file.DirectoryStream sınıfı ile kalabalık dizinlerde performans problemlerine neden olmaksızın dizin içeriği üzerinde çalışılabilinir. Üstelik dosya adı üzerinde düzenli ifade kullanarak filtre tanımlanabilir: package com.example; import import import import import import import java.io.IOException; java.nio.file.DirectoryIteratorException; java.nio.file.DirectoryStream; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; java.util.regex.PatternSyntaxException; Bölüm 10 Dosya Sistemi 10 | S a y f a İşletim Sistemleri public class ListDirectory { public static void main(String[] args) { Path dir = Paths.get(args[0]); String filter = "*.png"; if (args.length == 2) { filter = args[1]; } System.err.println("Reading directory stream..."); try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { for (Path file : stream) { System.out.println(file.getFileName()); } } catch (PatternSyntaxException | DirectoryIteratorException | IOException x) { System.err.println(x); } } } 10.3.3 Files.walkFileTree() Bir dizinin altında ne kadar dosya ya da dizin varsa, hepsi üzerinde ortak bir işlem yapmak istediğimizde, artık kod yazmadan bu işlemi Files yardımcı sınıfındaki walkFileTree() metodunu kullanarak gerçekleştirebiliriz. Bu çözümde tasarım kalıplarından bildiğimiz, ziyaretçi kalıbı kullanılmaktadır: package com.example; import import import import import com.example.util.PrintTree; java.io.IOException; java.nio.file.Files; java.nio.file.Path; java.nio.file.Paths; public class WalkFileTreeTest { public static void main(String[] args) { Path path = Paths.get(args[0]); if (!Files.isDirectory(path)) { System.out.println(args[0] + " must be a directory!"); System.exit(-1); } try { Files.walkFileTree(path, new PrintTree()); } catch (IOException e) { System.out.println("Exception: " + e); } } } Bölüm 10 Dosya Sistemi 11 | S a y f a İşletim Sistemleri package com.example.util; import import import import import import java.io.IOException; java.nio.file.FileVisitResult; java.nio.file.Path; java.nio.file.FileVisitor; java.nio.file.attribute.BasicFileAttributes; static java.nio.file.FileVisitResult.*; public class PrintTree implements FileVisitor<Path> { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attr) { System.out.print("preVisitDirectory: "); if (attr.isDirectory()) { System.out.format("Directory: %s ", dir); } else { System.out.format("Other: %s ", dir); } System.out.println("(" + attr.size() + " bytes)"); return CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attr) { System.out.print("visitFile: "); if (attr.isSymbolicLink()) { System.out.format("Symbolic link: %s ", file); } else if (attr.isRegularFile()) { System.out.format("Regular file: %s ", file); } else { System.out.format("Other: %s ", file); } System.out.println("(" + attr.size() + " bytes)"); return CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { System.out.print("postVisitDirectory: "); System.out.format("Directory: %s%n", dir); return CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.out.print("vistiFileFailed: "); System.err.println(exc); return CONTINUE; } } Bölüm 10 Dosya Sistemi 12 | S a y f a İşletim Sistemleri 10.3.4 java.noi.file.WatchService() İki uygulama arasında tümleştirmede uygulanabilecek en basit yöntem dosya kullanmaktır: yazılımlardan biri dosyaya yazar diğer uygulama ise bu dosyayı okur. Ancak bu çözümde çözülmesi gereken en önemli problem, dosyayı okuyacak yazılımın dosyanın oluşturulduğundan haberdar olmasıdır. Bunun için yoklamalı olarak çalışabilir. Eğer dosya oluşturulur oluşturulmaz uygulama tarafından işlenmesi gibi bir gereklilik varsa o zaman yoklama süresini kısaltmak gerekir. Bu durumda ise işletim sistem ve dosyalama sistemini gereksiz meşgul etmek anlamına gelir. İdeal çözüm ise dosyanın yaratıldığının uygulama haber verilmesini sağlayacak olay temelli çözümdür. Tüm güncel dosya sistemleri bu tür olay temelli çalışmayı destekler. Java ise NIO.2 ile birlikte ancak bu tür uygulamalar geliştirebiliyoruz. Uygulama izlemek istediği dizine haberdar olmak istediği olay için kayıt yaptırır. Kayıt yaptırdığı olay gerçekleştiğinde dosya sistemi uygulamaya haber verir: package com.example; import import import import import import java.nio.file.*; static java.nio.file.StandardWatchEventKinds.*; static java.nio.file.LinkOption.*; java.nio.file.attribute.*; java.io.*; java.util.*; /** * Example to watch a directory (or tree) for changes to files. */ public class WatchDir { private private private private final WatchService watcher; final Map<WatchKey, Path> keys; final boolean recursive; boolean trace = false; // An example of a Generic method @SuppressWarnings("unchecked") static <T> WatchEvent<T> cast(WatchEvent<?> event) { return (WatchEvent<T>) event; } /** * Register the given directory with the WatchService */ private void register(Path dir) throws IOException { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY); if (trace) { Path prev = keys.get(key); if (prev == null) { System.out.format("register: %s\n", dir); } else { if (!dir.equals(prev)) { System.out.format("update: %s -> %s\n", prev, dir); } } Bölüm 10 Dosya Sistemi 13 | S a y f a İşletim Sistemleri } keys.put(key, dir); } /** * Register the given directory, and all its sub-directories, with the * WatchService. */ private void registerAll(final Path start) throws IOException { // register directory and sub-directories Files.walkFileTree(start, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { register(dir); return FileVisitResult.CONTINUE; } }); } /** * Creates a WatchService and registers the given directory */ WatchDir(Path dir, boolean recursive) throws IOException { this.watcher = FileSystems.getDefault().newWatchService(); this.keys = new HashMap<>(); this.recursive = recursive; if (recursive) { System.out.format("Scanning %s ...\n", dir); registerAll(dir); System.out.println("Done."); } else { register(dir); } // enable trace after initial registration this.trace = true; } /** * Process all events for keys queued to the watcher */ void processEvents() { for (;;) { // wait for key to be signalled WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { return; } Path dir = keys.get(key); Bölüm 10 Dosya Sistemi 14 | S a y f a İşletim Sistemleri if (dir == null) { System.err.println("WatchKey not recognized!!"); continue; } for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); // TBD - provide example of how OVERFLOW event is handled if (kind == OVERFLOW) { continue; } WatchEvent<Path> ev = cast(event); Path name = ev.context(); Path child = dir.resolve(name); System.out.format("%s: %s\n", event.kind().name(), child); // if directory is created, and watching recursively, then // register it and its sub-directories if (recursive && (kind == ENTRY_CREATE)) { try { if (Files.isDirectory(child, NOFOLLOW_LINKS)) { registerAll(child); } } catch (IOException x) { // ignore to keep sample readbale } } } // reset key & remove from set if directory no longer accessible boolean valid = key.reset(); if (!valid) { keys.remove(key); // all directories are inaccessible if (keys.isEmpty()) { break; } } } } public static void main(String[] args) throws IOException { Path dir = Paths.get(args[0]); new WatchDir(dir, true).processEvents(); } } Bölüm 10 Dosya Sistemi 15 | S a y f a İşletim Sistemleri 10.4 Dosya Sistemi Gerçekleme Diskte dosyalar bloklar halinde organize edilir. İşletim sisteminde dosya sisteminin görevlerinden biri de dosyaya yeni bir veri yazılmak istendiğinde, diskteki boş bloklardan birini atamaktır. Bu durumda dosya sisteminin diskteki boş blokların bir kaydını tutması gerekir. Bunun için çeşitli yaklaşımlar bulunur. Bu bölümde bu farklı teknikler incelenecektir. 10.4.1 Ardışık Yer Ayırma Bu yöntemde dosya yaratılırken, dosya için ardışık bloklar ayrılır. Her dosya için sadece iki bilgi tutulur: başlangıç blok numarası ve dosya boyu (Şekil-10.3 (a)). Bu yöntemde ardışık dosya işlemleri son derece hızlı gerçekleşir. Ancak dosya silme işlemleri sonrasında dış parçalanma gerçekleşir (Şekil-10.3 (b)). Şekil-10.3 Ardışık yerleştirme örneği (a) 7 dosyanın ardışık yerleşimi (b) D ve F dosyalarının silinmesi sonrasındaki durum 10.4.2 Bağlantılı Liste Kullanımı Bu yöntemde blok ayırma işlemi, bir önceki yöntemdeki gibi dosya yaratılırken değil, her yeni blok ihtiyacında, blok seviyesinde gerçekleştirilir. Her blok kendinden sonraki bloğa bir bağlantı içerir (Şekil-10.4). Bu yöntemde dosya silme işlemi sonrasında, boşalan bloklar tekrar kullanılabilir. Her dosya için sadece başlangıç blok numarası tutulur. Bu yöntemde dosyadaki verilere sıralı erişim kolay, ancak bağlantılı liste yapısından dolayı rasgele erişim zordur. Bölüm 10 Dosya Sistemi 16 | S a y f a İşletim Sistemleri Şekil-10.4 Bağlantılı liste kullanan yerleştirmede A ve B dosyalarının diske yerleşimi 10.4.3 Dosya Tablosu Kullanımı Bu yöntemde işaretçiler diskteki bloklarda değil bellekte tabloda, FAT (File Allocation Table), tutulur (Şekil-10.5). Böylelikle rasgele erişim daha kolay gerçekleştirilir. Her dosya için sadece başlangıç blok numarasının bilinmesi yeterli olur. Başarım için tüm tablonun bellekte olması gerekir. Tablonun boyu ise disk boyuna ve blok boyuna bağlıdır. Örneğin 1TB’lık bir disk ve 4K blok boyu için tablonun boyu 256MB olur. 10.4.4 İndeks Kullanımı Bu yöntemde her dosyaya ilişkin bir indeks düğümü (i-node, index-node) oluşturulur. i-node içinde dosyanın özellikleri ve dosyanın bloklarının disk adresleri yer alır. Sadece açık dosyaların i-node yapıları bellekte tutulur. Toplam bellek alanı aynı anda açık olmasına izin verilen maksimum dosya sayısı ile orantılıdır. Bölüm 10 Dosya Sistemi 17 | S a y f a İşletim Sistemleri Şekil-10.5 Bellekte dosya tablosu kullanan yerleştirmede A ve B dosyaları için dosya tablosunun içeriği Bölüm 10 Dosya Sistemi 18 | S a y f a