İşletim Sistemleri

advertisement
İşletim Sistemleri
İşletim Sistemleri
Dr. Binnur Kurt
[email protected]
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
Download