UNIX-Schnittstelle
==================
7. Filesystem
=============
Alle Beispiel-Quellen mittels SVN unter:
https://svn.informatik.hu-berlin.de/svn/unix-2014/File
|
| next | back | 2017 - 1 |
7.1 Vorbemerkungen
------------------
Für Nutzer wichtige Kennzeichen für ein Filesystem
- Wie werden Files erzeugt?
- Wie werden Files benannt?
- Wie werden Files geschützt?
- Welche Operationen über Files gibt es?
- Detailfragen:
- Abspeicherung von Files auf Medien
- Freispeicherverwaltung
Prinzipielle Möglichkeiten der Datenspeicherung
1. Bildung von Segmenten (maximale Länge 2^32 Bytes)
Ein Startprozess verwaltet die Segmente. Programme
haben feste Segmentnummern. Bestimmte Segmente werden
als Directories benutzt (Verweise auf andere Segmente).
Daten werden in Segmenten gespeichert. Reuckgabe von
Segmenten möglich.
negativ: unpraktisch, statisch, störanfällig
positiv: Daten als Teil des Adressraumes - schnell
2. Files sind benannte Objekte, die Daten, Programme und Sonstiges
beinhalten können. Sie gehören nicht zum Adressraum
des Prozesses.
positiv: dynamisch
|
| next | back | 2017 - 2 |
6.1.1 externe Aspekte von Filesystemen
a) Fileorganisation (für Nutzer sichtbar)
1. Bytefolge (UNIX)
2. Blockfolge (CP/M)
3. Baumstruktur (ISAM - Indexed Sequential Access Method)
Records werden entsprechen eines Schlüssels (key) in einem
Baum einsortiert.
FL1
Files sollen gerätunabhängig sein!!!!!
D.h. Anwederprogramme sollen nicht berücksichtigen müssen,
wo und wie das File gespeichert ist.
Musterbeispiel: UNIX (Trick: mount)
Weniger gut: MS DOS: a:\xyz\x.dat
CP/M: a:xyz.dat
RSX/11M: dk0:[100,50]delta.xyz;3
Namesraum von Files möglichst frei wählbar.
b) Directories (für Nutzer sichtbar)
Mehrere Files werden in einer Directory zusammengefasst.
Pro File ein Record in der Directory.
In manchen Systemen sind die Directories ebenfalls Files.
Ein Filesystem kann strukturiert sein. FL2,FL3,FL6
|
| next | back | 2017 - 3 |
7.1.2 Interne Aspekte von Filesystemen
--------------------------------------
7.1.2.1. Plattenspeichermanagement
Files werden normalerweise auf Platten gespeichert, d.h. File-
systeme verwalten Plattenspeicher.
2 Strategien:
1. Files werden als zusammenhängende Folge von Bytes gespeichert
problematisch: Speicherzuweisung, Condens
2. Files als Folge von Blöcken gespeichert, die nicht notwendig
zusammenhängend auf der Platte stehen.
momentan realisiert.
Probleme: Grösse der Blöcke
(Zugriffszeit <--> Plattenauslastung)
optimale Blockgrösse:
512 (physische Blockgrösse auf Platte) ....
4096 (Blockgrösse für HS-Managment) IO7
Freispeicherverwaltung
1. Verkettet Liste, in der die Blocknummern der freien
Blöcke enthalten sind
Vorteil: - je weniger freie Blöcke je weniger Platz
wird benötigt
- schnell (max. 20 MB = 40 Blöcke)
2. Bitmapping: pro Block ein Bit (0-belegt, 1-frei)
Problem: Speicherplatz (20 MB = 3 Blöcke,
2 GB = 300 Blöcke!!)
Sicherheit
langsam
Vorteil: einfache Verwaltung FL4
|
| next | back | 2017 - 4 |
7.1.2.2. Organisation der Filespeicherung
Problem: File besteht aus Blöcken. Wie kann die Reihefolge der
zu einem File gehörenden Blöcke gespeichert werden?
1. Verkettete List:
Blocklänge: 1024: Datenlänge 1022 + 2 Byte Pointer zum nächsten
Block
Nachteil: Blocklänge keine 2er Potenzen
- Direktzugriff schwer
- Probleme bei E/A-Fehler
2. FAT - File Allocation Table (DOS)
Pro Block eine Pointer zum nächsten in einer zentralen Tabelle
Probleme: - ganze FAT ist notwendig um ein File zu bestimmen
bei grossen Platten - grosse Speicherbereiche im HS
notwendig
Disketten: 12-Bit-Blocknummer, 4096 Blöcke möglich
Harddisk: 16-Bit-Blocknummer, 32-MB Platte maximal FL5
3. i-node (UNIX)
10+256+256*256 +256*256*256 = 16.843.008 Blöcke
FL8
7.1.2.3. Directory Struktur
1. CP/M
2. MS-DOS
3. UNIX
FL9,FL10,FL11,FL12
|
| next | back | 2017 - 5 |
7.1.2.4. File-System Wiedererstellung/Sicherung
Probleme der Datensicherheit (gegen Verluste)
1. Badblocks
finden, gegen Benutzung sperren (format)
2. dynamisches Backup
Spiegelung von Platten (aufwendig, teuer aber sicher)
3. statisches Backup zu festen Zeiten auf Backupmedium
(Kapazität, Zeit, Backuplevel)
4. Filesystemkonsistenz
Hilfsprogramme. die die Konsistenz des Filesystems Prüfen
a) Filekonsistenz
b) Blockkonsistenz
Aktionen: - Prüffeld auf 0
- alle i-nodes lesen und Blocks eintragen
- Freiblockliste lesen
- testen
|
| next | back | 2017 - 6 |
mögliche Situationen
1. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 1 0 1 0 1 1 1 1 0 0 1 1 1 0 0 blocks in use
0 0 1 0 1 0 0 0 0 1 1 0 0 0 1 1 free blocks
Konsistent
2. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 1 0 1 0 1 1 1 1 0 0 1 1 1 0 0 blocks in use
0 0 0 0 1 0 0 0 0 1 1 0 0 0 1 1 free blocks
^ missing block - ergänzen
3. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 1 0 1 0 1 1 1 1 0 0 1 1 1 0 0 blocks in use
0 0 1 0 2 0 0 0 0 1 1 0 0 0 1 1 free blocks
^ doppelter Block in freelist - neu
4. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 1 0 1 0 2 1 1 1 0 0 1 1 1 0 0 blocks in use
0 0 1 1 1 0 0 0 0 1 1 0 0 0 1 1 free blocks
^ ^ doppelter Dateblock - kompliziert
Files kopieren, Files streichen, Freiblockliste neu
|
| next | back | 2017 - 7 |
7.1.2.5. Filesystemdurchsatz
Das Lesen eines Blockes von der Platte ist ca. 10000 mal langsamer
als das Lesen aus dem HS.
--> Pufferverwaltung ist sinnvoll, d.h. bestimmte Blöcke sind in
internen Puffern zu halten und nicht sofort zu transportieren
(cache)
Problem: Austauschalgorithmus wenn Cache voll ist:
z.B. FIFO oder LRU
LRU sinnvoll aber Spezifika des FS
berücksichtigen
- kritische Blöcke: modifizierte i-nodes
- notwendige Blöcke für nächsten Zugriff
(doppelt indirekte Blöcke)
- volle/halbvolle Datenblöcke
sync-Systemruf
7.1.2.6. Sicherheitsfragen
Einteilung in: Nutzer
Nutzergruppen
other
Vergabe unterschiedlicher Zugriffsrechte:
read
write
execute
Passwortschutz
Kerberos, ACL
|
| next | back | 2017 - 8 |
7.2 Systemrufe Filesystem
=========================
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode-t mode);
Erzeugen eines neuen Files mit dem Filenamen *pathname.
Identisch mit:
open(pathname,0-WRONLY|O_CREAT|O_TRUNC,mode);
Bestehende Files werden gelöscht und die Länge auf 0 gesetzt,
Mode und Eigentümer bleiben erhalten.
mode spezifiziert die späteren Zugriffsrechte, wenn das File
neu erzeugt wurde.
Früher: Error, wenn File vorher existierte
Rückkehrwert:
>=0 - Filedescriptor
<0 - Fehler - siehe open
|
| next | back | 2017 - 9 |
#include <unistd.h>
int dup(int filedes)
int dup2(int filedes, int filedes2);
Doppeln des Filedescriptors fieldes. Neuer Filedescriptor wird
durch den Rückkehrkode bereitgestellt. Es ist der nächste
freie Filedescriptor. Der neue Filedescriptor representiert
das gleiche File am gleichen Zugriffspunkt.
dup2() ist in POSIX nicht enthalten. dup2() benutzt als neuen
Filedescriptor den durch filedes2 spezifizierten. Sollte sich
hinter filedes2 ein eröffnetes File verbergen, so wird dies
vorher geschlossen (close). Äuivalent mit:
fcntl(filedes1, F-DUPFD, fieldes2).
Rückkehrwert:
>=0 -,neuer Filedescriptor
<0 - Fehler
EBADF filedes oder filedes2 unzulässig
EMFILE kein freier Filedescriptor mehr
|
| next | back | 2017 - 10 |
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence);
lseek() positioniert den den Zugriffspunkt des eröffneten Files
filedes an die durch offset und whence spezifizierte Stelle.
Bei lssek() wird kein E/A-Operation ausgeführt. Die physische
Positionieroperation erfolgt erst bei der nächsten read() bzw.
write() Operation.
whence spezifiziert den Basiswert für die Positionieroperation:
SEEK_SET - offset gibt die Anzahl der Bytes vom
Fileanfang an
SEEK_CUR - offset gibt die Anzahl der Bytes vom momentanen
Wert des Zugriffspunkts an (offset: +, -)
SEEK_END - offset gibt die Anzahl der Bytes vom Ende
Files an (offset:
Rückkehrwert:
>=0 - momentane Position des Zugriffspunktes
<0 - Fehler
EBADF - File nicht eröffnet
EINVAL - whence ist unzulässig
ESPIPE - Pipe
Beispiele:
currpos = lseek(fd,O,SEEK_CUR);
filelength = lseek(fd,O,SEEK_END);
|
| next | back | 2017 - 11 |
Beispiel:
Anwendung von seek auf verschiedene Files
Quelle:
seek.c
Ausführung:
./seek </etc/motd
cat /etc/motd | ./seek
mkfifo FIFO
./seek < FIFO # bleibt stehen
./seek < FIFO &
cp /etc/motd FIFO
|
| next | back | 2017 - 12 |
Beispiel:
Holes File erzeugen und dieses File mit verschiedenen Programmen
kopieren.
Quelle:
hole.c
Ausführung:
./hole
ls -lisa file.hole
od -bc file.hole
ls -l file.hole
du file.hole
cp file.hole xxx
du xxx
tar cvf file.hole.tar file.hole
ls -l file.hole.tar
du file.hole.tar
tar xvf file.hole.tar
|
| next | back | 2017 - 13 |
#include <unistd.h>
int symlink(char *actualpath, char *sympath);
symlink() erzeugt einen neuen Directory-Eintrag sympath für das
File actualpath. Das File actualpath muss dabei nicht existieren.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES - kein Zugriff zu sympath
EDQUOT - keine Quota bei Directory-Erweiterung
EEXIST - File sympath existiert bereits
EFAULT - unzulässiger Parameter (Adresse)
EIO - E/A-Fehler
ELOOP - zu viele symbolislche Links
ENAMETOOLONG - Name zu lang
ENOSPC - Filesystem ist voll
ENOTDIR - kein Directory
EROFS - read-only-Filesystem
|
| next | back | 2017 - 14 |
#include <unistd.h>
int pipe(int filedes[2]);
pipe() eröffnet zwei Filedescriptoren, die miteinander verbunden
sind. filedes[0] ist dabei zum Lesen eröffnet und filedes[1] ist
zum Schreiben geöffnet. Mit Hilfe von fildes[0] können die Daten
gelesen werden, die mit filedes[1] in die Pipe geschrieben wurden.
Der Pipe-Mechanismus ist eine Halb-Duplex-Verbindung zwischen
verwandten Prozessen (Vater-Sohn). Für die Kommunikation wird ein
Puffer zur Verfügung gestellt, so dass ein Schreiben erst bei vollem
Puffer zum Blockieren des schreibenden Prozesses führt. Wird der
lesende Prozess beendet, so erhält der schreibende Prozess ein
Signal SIGPIPE. EOF beim Lesen wird erst bei close() des
schreibenden Prozesses erkannt,
Pufergröße pro Pipe: ca. 4 - 64 KB
Rückkehrwert:
0 - ok
-1 - Fehler
EFAULT - Falscher Parameter (Adresse)
EMFILE - zu viele Filedescriptoren belegt
ENFILE - Systemtable full
|
| next | back | 2017 - 15 |
Beispiele:
Aufruf des Programms pwd zur Bestimmung des
Working Directories
Quelle:
pipe.c mit dup2
Ausführung:
./pipe
Quelle:
pipef.c mit fcntl
Ausführung:
./pipef
|
| next | back | 2017 - 16 |
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int filedes, int cmd);
int fcntl(int filedes, int cmd, long arg);
int fcntl(int filedes, int cmd, struct flock *arg);
fcntl() ermöglicht die Ausführung einer Reihe von Steuer- und
Abfrageoperationen über dem eröffneten File filedes.
cmd spezifiziert dabei das Komando und arg enthält weitere
Informationen für das Komando.
cmd:
F_DUPPD - dup2: newfd=fcntl(fd,F_DUPFD,fdn) !!!!!!
F_GETFD - holen des close-on-exec-Flags
F_SETFD - setzen des close-on-exec-Flags ( arq=1 )
F_GETPL - holen der Status-Flags für filedes (Rückkehrwert)
F_SETPL - setzen der Status-Flags für filedes ( arg )
0_RDONLY, 0_WRONLY, 0_RDWR,
0_APPEND, 0_NONBLOCK, O_SYNC, O_ASYNC
F GETLK holen des 1.Lockdescriptors ( Adresse in arg)
struct flock {
short l_type; /* F_RDLCK,F_WRLCK,F _UNLCK*/
short l_whence; /* flag for starting offset*/
off_t l_start; /* relative start offset */
off_t l_len; /* length in byte*/
pid_t l_pid; /* pid which lock F_GETLK*/
|
| next | back | 2017 - 17 |
cmd:
F_SETLK - lock ein Filesegment (ohne warten)
F_SETLKW - wie F-SETLK mit Warten, wenn lock nicht ausgeführt, wie flock
werden kann.
F_RSETLK - NFS
F_RSERLKW - NFS
F_RGETLK - NFS
Rückkehrwert:
>=0 - ok, eventuell Wert:
F_DUPFD - neuer Filedescriptor
F_GETFD - close-on-exec-Flag
F_GETFL - Status-Flag
<0 - Fehler
EACCES, EBADF, EDEADLK
EFAULT, EINTR, EINVAL,
EMFILE, ENOLCK
|
| next | back | 2017 - 18 |
Beispiel:
Zugriffsrechte mit fcntl bestimmen
Quelle:
fileflags.c
Ausführung:
fileflags 0
./fileflags 0
./fileflags 1
./fileflags 2
./fileflags 0 <fileflags.c
./fileflags 0 </dev/tty
|
| next | back | 2017 - 19 |
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
stat() liefert Informationen über das durch den Pfadname *pathname
spezifizierte File.
fstat() liefert Informationen über das eröffnete File mit dem
Filedescriptor filedes.
lstat(0 liefert Informationen über das durch den Pfadnamen
*pathname spezifiziert File. Eventuelle symbolische Links werden
nicht verfolgt.
Die Informationen werden immer in einem Puffer mit der Struktur stat
abgelegt.
Rückkehrwert:
0 - ok
-1 - Fehler
stat(), lstat():
EACCES, EFAULT, EIO, ELOOP,
ENAMETOOLONG, ENOENT, ENOTDIR
fstat:
EBADF, EFAULT, EIO
|
| next | back | 2017 - 20 |
struct stat { /* SUNOS 4.1.3 */
dev_t st_dev; /* devicenumber (filesystem)*/
ino_t st_ino; /* i-node number */
mode_t st_mode; /* file-type, permissions */
short st_nlink; /* number of links */
uid_t st_uid; /* UID of owner */
gid_t st_gid; /* GID of owner */
dev_t st_rdev; /* device number of special files */
off_t st_size; /* size in bytes of regulare files */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modify */
time_t st_ctime; /* time of last file status change */
long st_blksize;/* best I/O blocksize */
long st_blocks; /*number of allocated blocks */
};
|
| next | back | 2017 - 21 |
Beispiele:
Tatsächlie Filegröße bestimmen mit lstat
Quelle
filesize.c
mit lstat
Ausführung:
./filesize file.hole
./hole
./filesize file.hole
Filetype bestimmen mit lstat
Quelle:
filetype.c
Ausführung:
./filetype .
./filetype .
./filetype filetype.c
./filetype filetype
./filetype /dev/tty
./filetype /dev/hda
|
| next | back | 2017 - 22 |
#include <unistd.h>
int access(const char *pathname, int mode);
access() prüft für das durch Pfadnamen *pathname spezifizierte
File ob die durch mode geforderten Zugriffsrechte vorhanden sind.
mode:
R_OK - Test auf Lesen
W_OK - Test auf Schreiben
X_OK - Test auf Ausführen
F_OK - Test auf Existenz
Rückkehrwert:
0 - ok, Zugriffsrechte vorhanden
-1 - Fehler
EACCES - keine Zugriffsrechte
EFAULT, EINVAL, EIO, ELOOP,
ENAMETOOLONG, ENOENT, ENOTDIR, EROFS
|
| next | back | 2017 - 23 |
Beispiel:
Zugriffsrecht bestimmen mit access
Quelle
access.c
Ausführung:
./access access
./access /etc/passwd
./access /etc/shadow
diff access access1
./access1 /etc/shadow
|
| next | back | 2017 - 24 |
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t cmask);
umask() setzt die Filecreation-Maske. In cmask werden die
Bits gesetzt, für die später bei der Filecreation kein Zugriff
erlaubt werden soll. Folgende Bits sind für cmask zulässig:
S_IRWXU /* read, write, execute: owner */
S_IRUSR /* read permission: owner */
S_IWUSR /* write permission: owner */
S_IXUSR /* execute permission: owner */
S_IRWXG /* read, write, execute: group */
S_IRGRP /* read permission: group */
S_IWGRP /* write permission: group */
S_IXGRP /* execute permission: group */
S_IRWXO /* read, write, execute: other */
S_IROTH /* read permission: other */
S_IWOTH /* write permission: other */
S_IXOTH /* execute permission: other */
Rückkehrwert:
alte Filecreation-Maske
|
| next | back | 2017 - 25 |
Beispiel:
Wirkung von umask
Quelle
umask.c
Ausführung:
./umask
ls -lisa bar foo
|
| next | back | 2017 - 26 |
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
chmod() und fchmod erlauben es die Zugriffsrechte mode für
das durch *pathname bzw. filedes spezifizierte File zu
setzen. Dies darf nur der Eigentümer des Files bzw. der SU tun.
Für mode sind die gleichen Werte wie bei umask() zulässig,
zusätzlich die Werte:
S_ISUID - set-user-ID on execution
S_ISGID - set-group-ID on execution
S_ISVTX - saved-text
Rückkehrwerte:
0 - ok
-1 - Fehler
EACCES, EFAULT, EINVAL, EIO, ELOOP, ENOENT,
ENOTDIR, EPERM, EBADF
|
| next | back | 2017 - 27 |
Beispiel:
Wirkung von chmod
Quelle:
changemod.c
Ausführung:
./umast
ls -lisa bar foo
./changemod
ls -lisa bar foo
|
| next | back | 2017 - 28 |
#include <sys/types.h>
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
Die Systemrufe chown, fchown(), lchown() erlauben es den
Eigentümer-ID und den Gruppen-ID eines Files zu ändern.
Das File kann mittels Filename (chown,lchown) oder Filedescriptor
(fchown - eröffnetes File) spezifiziert werden.
Ist das spezifizierte File ein symbolischer Link, so wird durch
die Funktion lchown() lediglich der UID und der GID des
symbolischen Links modifiziert.
Diese Systemrufe können nur vom Eigentümer des Files bzw.
dem Superuser ausgeführt werden.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCESS, EFAULT, EIO, ELOOP,
ENAMETOOLONG, ENOENT, ENOTDIR,
EPERM, EROFS, EBADF, EINVAL,
|
| next | back | 2017 - 29 |
#include <sys/stat.h>
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
Die Systemrufe ftruncate() und truncate() können die Länge eines
Files festlegen. Das File kann dabei verkürzt oder verlängert werden.
Bei einer Verlängerung werden beim Lesen des Files für die Daten
des verlängerten Bereiches 0-Bytes geliefert. Das File kann mittels
Filename oder Filedescriptor spezifiziert werden. Bei ftruncate muss
das File zum Schreiben eröffnet sein.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCESS, EFAULT, EIO, EISDIR,
ELOOP, ENAMETOOLONG, ENOENT,
ENOTDIR, EROFS, EINVAL
|
| next | back | 2017 - 30 |
#include <unistd.h>
int link(const char *existingpath, const char *newpath);
Der Systemruf link() erzeugt für das bestehende File
*existingpath einen neuen Directory-Eintrag *newpath.
Wenn das File *newpath bereits existiert, wird ein Fehler
angezeigt. link() ist nur zulässig, wenn *newpath und
*existingpath auf das gleiche Filesystem verweisen.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCESS, EDQUOT, EEXIST,
EFAULT, EIO, ELOOP, EMLINK,
ENAMETOOLONG, ENOENT, ENOSPC,
ENOTDIR, EPERM, EROFS, EXDEV
|
| next | back | 2017 - 31 |
#include <unistd.h>
int unlink(const char *pathname);
Der Systemruf unlink() löscht den Directory-Eintrag für
das File *pathname. Wenn der Directory-Eintrag der letzte für
diese File war, so werden ebenfalls die zugehörigen Daten
gelöscht. Der Löschvorgang wird erst dann ausgelöst, wenn kein
Prozess mehr das File eröffnet hat.
Der Systemruf unlink() kann nur von Nutzern ausgeführt werden, die
Schreibzugriff und Execution-Zugriff zum Directory haben.
unlink() für einen symbolischen Link bewirkt das Löschen des
symbolischen Links selbst.
Rückkehrwert:
0 - ok
-1 - Fehler
EACESS, EBUSY, EFAULT, EINVAL,
EIO, ELOOP, ENAMETOOLONG,
ENOENT, ENOTDIR, EPERM, EROFS
|
| next | back | 2017 - 32 |
Beispiel:
Demonstration von unlink, Speicherfreigabe erst nach close
Quelle:
unlink.c
Ausführung:
# großes File big1 erzeugen
ls -lisa big1
df -k .
./unlink big1 &
ls -lisa big1
df -k .
|
| next | back | 2017 - 33 |
#include <unistd.h>
int rmdir(const char *pathname);
Die Systemfunktion rmdir() realisiert das Streichen einer
Directory mit dem Namen *pathname. Die Directory muss leer sein
und darf z.Z. nicht von anderen Prozessen benutzt werden. Die
zugehörigen Datenblöcke werden freigegeben.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EBUSY, EFAULT, EINVAL,
EIO, ELOOP, ENAMETOOLONG, ENOENT,
ENOTDIR, ENOTEMPTY, EROFS
#include <unistd.h>
int remove(const char *pathname);
Streichen von Files und Directories (ANSI-C). Funktion wie unlink und rmdir.
Rückkehrwert:
0 - ok
-1 - siehe oben
|
| next | back | 2017 - 34 |
#include <stdio.h>
int rename(const char *oldname, const char *newname);
Der Systemruf rename() erlaubt das Umbenennen von Files und Directories.
Ist *oldpath ein File, so muss *newname nicht existieren bzw. kann auf ein
File verweisen, das dann gelöscht wird. Ist *oldpath eine Directory,
so muss *newname nicht existieren bzw. kann auf eine leere Directory verweisen,
die dann gelöscht wird. Der Prozess muss Execution- und Schreibzugriff
zu den Directories haben, in denen das File/Directory momentan steht
bzw. stehen wird.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EBUSY, EDQUOT, EFAULT,
EINVAL, EIO, EISDIR, ELOOP,
ENAMETOOLONG, ENOENT, ENOSPC,
ENOTDIR, ENOTEMPTY, EROFS, EXDEV
|
| next | back | 2017 - 35 |
#include <unistd.h>
int readlink(const char *pathname, char *buff, int buffsize);
Die Systemfunktion readlink() erlaubt das Lesen eines symbolischen
Links *pathname in den Puffer *buff mit er Länge buffsize.
Dieser Ruf vereinigt open(), read() und close().
Rückkehrwert:
>=0 - Anzahl der in den Puffer gelesenen Zeichen.
-1 - Fehler
EACCES, EFAULT, ELOOP, EINVAL, EIO,
ENAMETOOLONG, ENOENT
Folgende Systemrufe folgen symbolischen Links:
access, chdir, chmod, chown, creat, exec, link, mkdir, mkfifo,
mknod, open, opendir, pathconf, stat, truncate
Folgende Systemrufe wirken direkt auf symbolische Links:
lchown, lstat, readlink, remove, rename, unlink
|
| next | back | 2017 - 36 |
Beispiele:
$ mkdir bell1
$ touch bell1/xxxx
$ ln -s ../bell1 bell1/dir
$ ls -l bell1
total 1
lrwxrwxrwx 1 bell 8 Jan 25 17:43 dir -> ../bell1
-rw-r--r-- 1 bell 0 Jan 25 17:42 xxxx
$ cd bell1/dir
$ pwd
/tmp/bell/bell1
$ ls
dir xxxx
$ cd dir
$ ls
dir xxxx
$ ls -l
total 1
lrwxrwxrwx 1 bell 8 Jan 25 17:43 dir -> ../bell1
-rw-r--r-- 1 bell 0 Jan 25 17:42 xxxx
$
$ ln -s /tmp/no/file file
$ ls file
file
$ cat file
cat: file: No such file or directory
$ ls -lisa file
11377 1 lrwxrwxrwx 1 bell 12 Jan 25 17:45 file -> /tmp/no/file
$
|
| next | back | 2017 - 37 |
#include <sys/types.h>
#include <utime.h>
int utime(const char *pathname, const struct utimebuf *times);
struct utimebuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
}
#include <sys/time.h>
int utimes(const char *pathname, const struct timeval times[2]);
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
}
Die Systemrufe utime() und utime() ermöglichen es Zugriffszeit und
Modifikationszeit eines Files zu ändern. Wenn *times der NULL-Pointer
ist wird die aktuelle Zeit als Zugriffs- und Modifikationszeit einge-
tragen. Der effektive UID des Prozesses muss zum Ändern identisch mit
dem Eigentümer UID sein oder 0 (Superuser).
utimes() hat eine Genauigkeit von einer Mikrosekunde.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EFAULT, EIO, ELOOP, ENOENT, ENOTDIR, EPERM, EROFS
|
| next | back | 2017 - 38 |
Beispiel:
Umsetzen der Modifikationszeit mittels utime()
Quelle:
zap.c
Ausführung:
cat yyy.c
ls -l yyy.c
./zap yyy.c
ls -l yyy.c
ls -lc yyy.c
|
| next | back | 2017 - 39 |
#include <sys/types.h>
#include <sys/stat.h>
int mknod(const char *pathname, int mode, int dev);
int mkfifo(const char *pathname, int mode);
Der Systemruf mknod() dient zum erzeugen von Specialfiles
(Block- und Characterdevices), FIFO's (named pipes), Directories und
gewönlichen Files. Der Name des zu erzeugenden Objekts wird durch
*pathname festgelegt. Die Art des Objektes durch mode :
S_IFDIR 0040000 /* directory */
S_IFCHR 0020000 /* character special */
S_IFBLK 0060000 /* block special */
S_IFREG 0100000 /* regular */
S_IFIFO 0010000 /* fifo */
festgelegt. dev dient zur Spezifikation der Geräte(Major- und
Minornummer). Die Zugriffsrechte werden durch die Filecreationmaske
bestimmt. mknode() kann nur durch den Superuser ausgeführt werden.
Der normale Nutzer darf lediglich FIFO's und reguläre Files erzeugen.
Der Systemruf mkfifo() ist eine abgerüstete Variante von mknod().
Er dient lediglich zum Erzeugen von FIFO's.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EDQUOT, EEXIST, EFAULT, EIO, EISDIR,
ELOOP, ENAMETOOLONG, ENOENT, ENOSPC, ENOTDIR,
EPERM, EROFS
|
| next | back | 2017 - 40 |
Beispiel:
Major und Minor-Nummber mittels lstat()
Quelle:
devrdev.c
Ausführung:
./devrdev / /usr/ /dev/ttyS[01]
ls -ld /dev/hda7 /dev/ttyS[01]
|
| next | back | 2017 - 41 |
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
Der Systemruf mkdir() erzeugt eine neue Directory mit den
in mode spezifizierten Zugriffsrechten. Filecreationmaske wird
berücksichtigt. Achtung: Execution-Bits setzen für Suchen.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EDQUOT, EEXIST,
EFAULT, EIO, ELOOP,
ENAMETOOLONG, ENOENT,
ENOSPC, ENOTDIR, EOFS
|
| next | back | 2017 - 42 |
Funktionen zur Unterstützung des Directoryzugriffs
--------------------------------------------------
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *pathname);
struct dirent *readdir(DIR *dp);
void rewinddir(DIR *dp);
int closedir(DIR *dp);
Die Funktionen opendir(), rewinddir(), readdir() und closedir() dienen
zum systemunabhängigen Lesen von Directories. open erröffnet ein
Directory. readdir() liest einen Directoryeintrag in die standardi-
sierte Struktur dirent. rewinddir() setzt die den Lesezeiger von
readdir() auf den Anfang der Directory. closedir() schliesst die
Directory.
struct dirent {
ino_t d_ino; /* i-node number */
char d_name[NAME_MAX]; /* null-terminated filename */
}
|
| next | back | 2017 - 43 |
Beispiel:
Anzeigen einer Directory mit opendir, readdir
ls1.c
Rekursives anzeigen von Directories
ftw2.c
Rekursives anzeigen von Directories + Statistik
ftw3.c
|
| next | back | 2017 - 44 |
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
Jeder Prozess hat ein aktuelles Arbeitsdirectory, das benutzt wird,
wenn ein Filename nicht mit einem "/" anfängt. Die Systemrufe
chdir() und fchdir() erlauben das Setzen des aktuellen Arbeits-
directories. chdir() verlangt die Spezifikation des Directories in
Form des Pfadname *pathname und fchdir verlangt die Spezifikation
des Directories als Filedescriptorpointer fieldes. Für die Directory
muss der Prozess Lese- und Ausführungsrechte besitzen.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, ENAMETOOLONG, ENOENT, ENOTDIR
|
| next | back | 2017 - 45 |
Beispiel:
Wirkung von Change Directory demonstrieren
Quelle:
mycd.c
cdpwd.c
Ausführung:
pwd
./mycd
pwd
./cdpwd
pwd
|
| next | back | 2017 - 46 |
int chroot(char *dirname);
int fchroot(int filedes);
Die Systemrufe chroot() und fchroot() dienen dem Superuser zum
Ändern des Root-Verzeichnisses für den aktuellen Prozess. Die Lage
des neuen Root-Verzeichnisses wird durch die Parameter *dirname bzw.
filedes bestimmt. Nach Ausführung der Systemrufe hat der aktuelle
Prozess nur noch Zugriff auf Files und Directories, die unterhalb
des als neues Root-Directory liegen.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EBADF, EFAULT, EINVAL, EIO, ELOOP,
ENAMETOOLONG, ENOENT, ENOTDIR, EPERM
|
| next | back | 2017 - 47 |
#include <sys/mount.h>
int mount(char *type, char *dir, int flags, caddr_t data); /*BSD*/
int mount(char *spec, char *dir, int rdonly); /* System V */
int mount(const char *source, const char *target, const char *filesystemtype,
unsigned long mountflags, const void *data); /*linux*/
Der Systemruf mount() dient für das Eingliedern eines
blockorientierten Gerätes in das bestehende Filesytem. Auf dem
Gerät muss vorher ein Filesystem installiert sein. Der Mountpoint wird
durch den Parameter *dir festgelegt. data bzw. *spec spezifizieren
das blockorientierte Gerät das "eingemountet" werden soll. Durch *type
wird die Art des Filesystems spezifiziert, das "eingebunden werden soll,
z.B. 4.2, nfs, rfs, hsfs. Für die verschiedenen Filesystemtypen muss
eine entsprechende Datenstruktur data bereitgestellt werden. Der
Parameter flags spezifiziert Zugriffsrechte:
M_RDONLY - nur lesen M_NOSUID - ignoriere Set-UID-Bit
M_NEWTYPE - immer gesetzt M_GRPID - BSD-Filecreation
M_REMOUNT - ändern M_NOSUB - keine Submounts
Rückkehrwerte:
0 - ok
-1 - Fehler
EACCES, EBUSY, EFAULT, ELOOP, ENAMETOOLONG, ENODEV, ENOENT,
ENOTDIR, EPERM, EINVAL, EIO, EMFILE, ENOMEM, ENOTBLK, ENXIO
|
| next | back | 2017 - 48 |
(nach Volker Grabsch)
Mounten der Festplatte 2 in das Filesystem der Festplatte 1
(Mountpunkt-Direktory /mnt/p3 ist leer)
Festplatte 1
____________________________
| |
| / |
| : |
| ......:...... |
| : : : |
| usr etc mnt |
| : | Festplatte 2
| .....:..... | _____________________
| : : : | mount | |
| p1 p2 p3 <---|-------|--------- / |
|____________________________| | : |
| .......:....... |
| : : : |
| data1 data2 data3 |
|_____________________|
|
| next | back | 2017 - 49 |
Mounten der Festplatte 2 in das Filesystem der Festplatte 1
(Mountpunkt-Direktory /mnt ist nicht leer)
Festplatte 1
____________________________
| |
| / |
| : | Festplatte 2
| ......:...... | _____________________
| : : : | mount | |
| usr etc mnt <--------|-------|--------- / |
| | | : |
| .....*..... | | .......:....... |
| : : : | | : : : |
| p1 p2 p3 | | data1 data2 data3 |
|____________________________| |_____________________|
Achtung!! nach dem Mounten sind die Directories/Files p1, p2, p3
nicht mehr sichtbar. Nach dem Entmounten sind sie wieder sichtbar.
|
| next | back | 2017 - 50 |
int unmount(char *dir); /* BSD */
int unmount(char *special); /* System V */
int umount2(const char *target, int flags); /*Linux, Solaris*/
Der Systemruf unmount() gliedert ein zuvor mit mount() einge-
gliederte blockorientiertes Gerät aus dem Filesystem aus. Als
Parameter muss der Name des Special-Files in *special bzw. die
Directory in *dir angegeben werden. Der Systemruf erfodert
Superuserrechte. Das auszugliedernde Filesystem darf von keinem
anderen Prozess z.Z. genutzt werden.
Rückkehrwert:
0 - ok
-1 - Fehler
EACCES, EBUSY, EFAULT, EIO, ELOOP, ENAMETOOLONG,
ENOENT, ENOTDIR, ENOTBLK, ENXIO
|
| next | back | 2017 - 51 |
int sync(void);
Der Systemruf sync() synchronisiert das Filesystem. Alle modifizierten
Blöcke, die bisher noch nicht auf die Platte gebracht wurden, werden
auf die Platte geschrieben, einschliesslich Superblock.
Rückkehrwert:
0 - ok
int fsync(int filedes);
Der Systemruf fsync() synchronisiert alle Blöcke, die zu dem File
gehören, das durch den Filedescriptor filedes spezifizierten wird.
Der Systemruf fsync() realisiert damit sync() für ein File.
Rückkehrwert:
0 - ok
-1 - Fehler
EBADF, EINVAL, EIO
|
| next | back | 2017 - 52 |
#include <sys/file.h>
int flock(int filedes, int operation);
Der Systemruf flock() erlaubt es ein eröffnetes File gegen Zugriff
zu schützen. filedes spezifiziert den Filedescriptor des Files und
operation gibt die Art des Lockzugriffs an:
LOCK_SH 1 - shared lock
LOCK_EX 2 - exclusive lock
LOCK_NB 4 - don't block when locking
LOCK_UN 8 - unlock
Rückkehrwert:
0 - ok
-1 - Fehler
EBADF, EOPNOTSUPP, EWOULDBLOCK
|
| next | back | 2017 - 53 |
Beispiel :
"nonblocking" write
Quelle:
nonblockw.c
Ausführung:
ls -lisa /etc/termcap
./nonblockw < /etc/termcap
./nonblockw < /etc/termcap 2>xxx
ls -l xxx
more xxx
Quelle:
flock.c
Ausführung:
./flock r xxx &
./flock r xxx &
./flock w xxx &
./flock w xxx &
Quelle:
flock1.c
Ausführung:
./flock1 w xxx &
./flock1 w xxx &
./flock1 r xxx &
./flock1 r xxx &
|
| next | back | 2017 - 54 |
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
int select(int maxfdpl, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *tvptr);
Der Systemruf select() erlaubt es auf mehrere E/A-Bedingungen
gleichzeitig zu warten bzw. zu testen ob E/A-Anforderungen ausge-
führt würden. maxfdl spezifiziert den Wert des höchsten File-
descriptors. Durch die Mengen fd_set werden die Filedescriptoren
und die Art der E/A-Operationen festgelegt, die berücksichtigt
werden sollen. Die einzelnen Mengen legen dabei die Art der E/A-
Operation fest, die mit dem entsprechenden Filedescriptor ausgeführt
wird:
readfs - Descriptoren für Leseoperationen
writefds - Descriptoren für Schreiboperationen
exceptfds - Descriptoren für Ausnahmebedingungen
Die Mengen werden mit Hilfe folgender Funktionen manipuliert:
FD_ZERO(fd_set *fdset); /* clear fdset */
FD_SET(int fd, fd_set *fdset); /* set bit for fd in fdset */
FD_CLR(int fd, fd_set *fdset); /* clear bit for fd in fdset */
int FD_ISSET(int fd, fd_set *fdset);/* test bit for fd in fdset */
|
| next | back | 2017 - 55 |
Ausserdem kann mittels *tvptr festgelegt werden, wie lange gewartet
werden soll. *tvptr hat folgenden Aufbau:
struct timeval {
long tv_sec; /* seconds */
long tv_usec */
}
Ist tvptr==NULL, so wird gewartet, bis ein Filedescriptor das Ende
einer E/A-Operation meldet. Ist tvptr->tv_sec==0 und
tvptr->tv_usec==0, wird nicht gewartet. Ansonsten wird die
spezifizierte Zahl von Sekunden gewartet.
Wenn select() zurückkehrt, sind in den einzelnen Descriptormengen
die Filedescriptoren eingetragen (Bit gesetzt), für die eine E/A-
Operation beendet wurde.
Rückkehrwert:
>0 - Anzahl der Filedescriptoren, die das Ende einer
E/A-Operation gemeldet haben
=0 - Timeout, keine E/A-Operation wurde beendet
<0 - Fehler
EBADF, EFAULT, EINTR, EINVAL
|
| next | back | 2017 - 56 |
Beispiel:
Bestimmen der Blockgröße einer Pipe mittels select
Quelle:
selectpipe.c
Ausführung:
$
$ ./selectpipe
pipe capacity = 61441
$
|
| next | back | 2017 - 57 |
#include <stropts.h>
#include <poll.h>
int poll(struct pollfd fdarray[], unsigned long nfds, int timeout);
Der Systemruf poll() erlaubt es auf mehrer E/A-Ereignisse gleich-
zeitig zu warten. Jedes Ereignis muss einzeln in fdarray
spezifiziert werden. Die Zahl der Ereignisse wird durch nfds ange-
geben. Mittels timeout kann eine Wartezeit spezifiziert werden.
Die Struktur pollfd hat folgenden Aufbau:
struct pollfd {
int fd; /* filedescriptor to check */
short events /* events of interested on fd */
short revents; /* events that occurred on fd */
}
value | events | revents | Description
--------+--------+---------+---------------------------
POLLIN | x | x | normal data can be read
POLLPRI | x | x | priority data can be read
POLLOUT | x | x | normal data can be write
POLLERR | | x | an error has occurred
POLLHUP | | x | a hangup has occurred
POLLNVAL| | x | filedescriptor not open
|
| next | back | 2017 - 58 |
timeout spezifiziert die Wartezeit in Millisekunden.
timeout==0 - nicht warten
timeout==-1 - warten bis zum
timeout> 0 - Wartezeit in Millisekunden
Rückkehrwert:
>0 - Zahl der Filedescriptoren, für die ein Ereignis
eingetreten ist
=0 - Timeout, kein Ereignis eingetreten
<0 - Fehler
EAGAIN, EFAULT, EINTR, EINVAL
|
| next | back | 2017 - 59 |
Beispiel:
Bestimmung der Größe einer Pipe mittels poll()
Quelle:
pollpipe.c
Abarbeitung:
$
$ ./pollpipe
pipe capacity = 61441
$
$
|
| next | back | 2017 - 60 |
#include <sys/types.h>
#include <sys/uio.h>
size_t readv(int filedes, const struct iovec iov[], int iovcnt);
size_t writev(int filedes, const struct iovec iov[], int iovcnt);
Die Systemrufe readv() bzw. writev() ermöglichen das Lesen
bzw. Schreiben in/aus verschiedenen Puffern mit jeweils verschienen
Längen aus/in ein File. Das File wird durch den Filedescriptor
fildes bestimmt. iov adressiert ein Feld von Strukturen des
Types iovec. iovcnt gibt die Anzahl der Strukturen (Anzahl der
Puffer) an.
struct iovec {
void *iov_base; /* starting address of buffer */
size_t iov_len; /* size of buffer */
}
Rückkehrwert:
>=0 - Anzahl der gelesenen bzw. geschriebenen Bytes
<0 - Fehler
EAGAIN, EBADF, EBADMSG, EFAULT, EINTR, EINVAL,
EIO, EISDIR, EWOULDBLOCK, EDQUOT, EFBIG, ENOSPC,
ENXIO, EPIPE, ERANGE
|
| next | back | 2017 - 61 |
#include <sys/types.h>
#include <sys/mman.h>
caddr_t mmap(caddr_t addr, size_t len, int prot, int flag,
int filedes, off_t off);
Der Systemruf mmap() dient zum Einblenden eines Teils eines
eröffneten Files in den Adressraum des Prozesses. addr spezifiziert
die Adresse innerhalb des Adressraums des Prozesses, an der die
Einblendung beginnen soll. Ist addr==NULL, wird die nächste frei
Adresse benutzt. len gibt die Länge des Speicherbereiches an.
filedes spezifiziert das eröffnete File, das eingeblendet werden soll.
off gibt die Stelle im File an, ab der die Daten des Files einge-
blendet werden sollen. prot spezifiziert die Zugriffsrechte:
PROT_READ - Lesen
PROT_WRITE - Schreiben
PROT_EXEC - Ausführen
flag gibt zusätliche Eigenschaften an:
MAP_FIXED - Einblendung muss an Adresse addr erfolgen
MAP_SHARED - Änderung im Speicherbereich sind ebenfalls im
File zu realisieren (write)
MAP_PRIVATE- Änderungen sind nur im Speicher durchzuführen
Rückkehrwert:
!=NULL - Adresse, an der die Einblendung beginnt
=NULL - Fehler
EACCES, EAGAIN, EINVAL, ENODEV, ENOMEN, ENXIO
|
| next | back | 2017 - 62 |
#include <sys/mman.h>
int munmap(caddr_t addr, int len);
Der Systemruf munmap() hebt eine zuvor mit mmap() gemachte Einblendung
eines Fileabschnittes in den Speicher wieder auf. addr spezifiziert die
Adresse (Rückkehrwert von mmap) und len gibt die Länge des Bereiches
an.
Rückkehrwert:
0 - ok
-1 - Fehler
EINVAL
|
| next | back | 2017 - 63 |
Beispiel:
Kopieren eines Files ohne read und write ueber mmap.
Quelle:
mcopy.c
Ausführung:
$
$ ./mcopy mcopy test
$ ls -lisa mcopy test
7607 24 -rwxr-xr-x 1 bell 24576 Feb 1 20:59 mcopy
7605 24 -rwxr-xr-x 1 bell 24576 Feb 1 21:00 test
$ ./test mcopy test1
$ ls -lisa mcopy test1
7607 24 -rwxr-xr-x 1 bell 24576 Feb 1 20:59 mcopy
7608 24 -rwxr-xr-x 1 bell 24576 Feb 1 21:00 test1
$
|
| back | 2017 - 64 |