Consiglio Nazionale dell

Transcript

Consiglio Nazionale dell
Programmazione di Sistema
Massimo Bernaschi
Istituto per le Applicazioni del Calcolo “Mauro Picone”
Consiglio Nazionale delle Ricerche
Viale Manzoni, 30 - 00185 Rome - Italy
http://www.iac.cnr.it/
e-mail: [email protected]
M. Bernaschi: Sistemi Operativi II
Libreria C, Unix System Call, Win32 API
È importante capire le differenze concettuali e di utilizzo tra
• la libreria C
– funzioni nella libreria ANSI-C standard:
http://www.infosys.utas.edu.au/info/documentation/C/CStdLib.html
• le funzioni definite nello standard POSIX (Portable Operating
System Interface) 1003.1
– le funzioni POSIX che NON sono nella libreria C sono
elencate in:
http://cplus.kompf.de/posixlist.html
• le Application Programming Interface di Windows (Win32 API).
– Windows supporta la libreria ANSI-C.
– Windows sockets
2
M. Bernaschi: Sistemi Operativi II
– Remote Procedure Call
Una lista di FAQ su Win32 è disponibile su:
http://www.winprog.org/faq/
3
M. Bernaschi: Sistemi Operativi II
I principi di Win32
Alcune delle principali caratteristiche di Win32:
• Quasi tutte le risorse di sistema sono kernel object identificati e
referenziati da un handle. Questi handle giocano un ruolo simile
a quello dei file descriptor o process id in Unix.
– Notare come gli handle sono oggetti “opachi”. Non sono interi
allocati in ordine sequenziale. Ad esempio, il carattere speciale
dei descrittori 0, 1, 2 in Unix non ha analogo in Win32.
• La Win32 API non è object oriented ma i kernel object possono
essere manipolati solo con l’API ufficiali.
• Sono definiti come oggetti: file, processi, thread, pipe, memory
mapping, eventi. Gli oggetti hanno attributi di sicurezza.
• L’API di Win32 è molto ricca e flessibile (molte funzioni che
4
M. Bernaschi: Sistemi Operativi II
eseguono la stessa operazione con “varianti sul tema”).
• Win32 offre numerosi meccanismi di sincronizzazione e
comunicazione.
• L’unità fondamentale di esecuzione è il thread. Un processo può
contenere uno o più thread.
– I processi in Win32 non hanno nessuna relazione tipo
“padre-figlio” o di appartenenza ad un gruppo di processi.
• In genere i nomi delle funzioni dell’API Win32 sono lunghi e
“descrittivi”
• I tipi predefiniti richiesti da Win32 sono scritti a lettere
maiuscole e (cercano di essere) descrittivi:
– BOOL: elemento a 32 bit contenente un singolo valore logico;
– HANDLE;
5
M. Bernaschi: Sistemi Operativi II
– DWORD: “unsigned int” a 32 bit (uno dei tipi più diffusi);
– LPTSTR: puntatore a stringa di caratteri (8 o 16 bit);
– LPSECURITY ATTRIBUTES
• I tipi predefiniti evitano l’uso dell’operatore *;
• Anche se disegnata from scratch, la Win32 API mantiene
compatibilità con la Win16 API di Windows 3.1.
– Questa feature spiega la presenza di anacronismi come i tipi
LPTSTR e LPDWORD che fanno riferimento a long pointer.
• Gli include file interessanti sono: windows.h, winnt.h,
winbase.h
• In Windows l’end-of-line per i file di testo è rappresentata da
CR-LF mentre in Unix da LF.
• Capire quando usare le funzioni della libreria C (con il vantaggio
6
M. Bernaschi: Sistemi Operativi II
della portabilità) oppure le primitive della Win32 (o di Unix) è
uno degli scopi di questo corso.
7
M. Bernaschi: Sistemi Operativi II
Come copiare un file
Quattro implementazioni:
• libreria C standard (win32smp/chaptr01/cpC.c);
• stile Unix (POSIX) (win32smp/chaptr01/cpU.c);
• Win32 “base” (win32smp/chaptr01/cpW.c);
• Funzione di “convenienza” della Win32: CopyFile
(win32smp/chaptr01/cpCF.c);
8
M. Bernaschi: Sistemi Operativi II
Accesso ai file
Esistono diversi tipi di file system sia sotto Windows che sotto UNIX.
• Windows:
– due tipi di file: testo e binario.
– VFAT e FAT32, eredità del File Allocation Table del DOS.
– NTFS disponibile su Windows NT, 2000/3, XP, Vista,
Windows 7.
∗ Non limita rigidamente la lunghezza dei nomi di file;
∗ supporta i “large” file;
∗ fornisce attributi di sicurezza, compressione, recovery...,
cifratura;
– Win32 supporta la gerarchia del file system anche se mantiene
il concetto di drive (C:, D:,...,H:);
9
M. Bernaschi: Sistemi Operativi II
– come separatore di path può essere usato /.
– Esistono limitazioni all’insieme di caratteri che possono
costituire il nome di un file o di una directory (non possono
essere utilizzati, ad esempio i primi 31 caratteri ASCII).
– I nomi sono case-insensitive
– I nomi di file e directory sono limitati a 255 caratteri (è
possibile superare il limite ricorrendo all’estensione Unicode)
– Win32 non supporta il concetto di file link che permette di
indicare lo stesso file con due nomi distinti.
∗ in realtà esiste un supporto per il sottosistema POSIX ma è
ignorato da Win32.
– Esistono invece gli Alternate Data Stream, cioè flussi
indipendenti di dati che fanno riferimento allo stesso file.
Un incubo dal punto di vista della sicurezza!
10
M. Bernaschi: Sistemi Operativi II
• Unix:
– Ext2 ed Ext3 (Linux)
– JFS (AIX)
– XFS (IRIX)
– I nomi sono case-sensitive
– La lunghezza massima del nome dipende dall’implementazione
– Utilizza il concetto di link (hard o simbolico).
11
M. Bernaschi: Sistemi Operativi II
Operazioni elementari su file
Apertura, lettura, scrittura, chiusura;
• CreateFile: http://msdn.microsoft.com/en-us/library/default.aspx
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
12
M. Bernaschi: Sistemi Operativi II
• ReadFile:
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
Da notare che la funzione non fallisce se l’handle è posizionato
alla fine del file, piuttosto viene tornato un valore 0 in
lpNumberOfBytesRead
• WriteFile: sostanzialmente simmetrica alla ReadFile.
13
M. Bernaschi: Sistemi Operativi II
• CloseFile:
BOOL CloseHandle(HANDLE hObject);
Le funzioni UNIX equivalenti sono open, read, write, close.
Le funzioni nella libreria C equivalenti sono fopen, fread, fwrite,
fclose. Notare come queste ultime non prendono un singolo
argomento per specificare il numero di byte da trasferire ma,
piuttosto, la dimensione dell’“oggetto” ed il numero di “oggetti” da
trasferire
14
M. Bernaschi: Sistemi Operativi II
Standard Devices e I/O a console
Sia UNIX che Win32 hanno tre dispositivi “standard” per i flussi di
input, output ed error.
• Unix usa i primi 3 file descriptor (0, 1, 2)
• Win32 richiede degli handle e offre una funzione per ottenere gli
handle dai device standard:
HANDLE GetStdHandle(DWORD nStdHandle);
Per ridirezionare uno standard device è necessario usare:
BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle);
in cui hHandle è l’handle del file che deve sostituire lo standard
device.
nStdHandle deve avere uno dei tre seguenti valori:
15
M. Bernaschi: Sistemi Operativi II
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE.
È possibile accedere in ogni caso la console utilizzando i file speciali
CONIN$ e CONOUT$.
16
M. Bernaschi: Sistemi Operativi II
I/O a console
Per l’I/O a console esistono delle funzioni specifiche:
• ReadConsole:
BOOL ReadConsole(
HANDLE hConsoleInput,
LPVOID lpBuffer,
DWORD nNumberOfCharsToRead,
LPDWORD lpNumberOfCharsRead,
LPVOID lpReserved);
lpReserved deve essere NULL
• WriteConsole: simile a ReadConsole
17
M. Bernaschi: Sistemi Operativi II
• SetConsoleMode:
BOOL SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode);
l’handle deve avere accesso GENERIC READ anche se corrisponde
ad un device solo per l’output.
dwMode può assumere valori quali ENABLE LINE INPUT,
ENABLE ECHO INPUT, ENABLE QUICK EDIT MODE,...
L’equivalente funzione in Unix è la:
#include <termios.h>
int tcsetattr (int fd, int optional_actions, struct termios *termios_p);
18
M. Bernaschi: Sistemi Operativi II
• Esistono inoltre in Win32 le funzioni: BOOL FreeConsole() e
BOOL AllocConsole(). Notare come le applicazioni che usano
una GUI non hanno una console di default ed è quindi necessario
usare l’AllocConsole prima di poter usare funzioni come la
WriteConsole oppure la printf.
Esempi di utilizzo: win32smp/Win32Smp/chaptr02/cat.c
19
M. Bernaschi: Sistemi Operativi II
Funzioni di “convenienza”
Permettono di svolgere in maniera semplificata operazioni come:
• BOOL DeleteFile(LPCTSTR lpFileName);
• BOOL CopyFile( LPCTSTR lpExistingFileName, LPCTSTR
lpNewFileName, BOOL bFailIfExists);
• ...
• BOOL MoveFileEx( LPCTSTR lpExistingFileName, LPCTSTR
lpNewFileName, DWORD dwFlags);
Gli argomenti bFailIfExists e fdwFlags modificano il
comportamento nel caso in cui il file target esiste.
20
M. Bernaschi: Sistemi Operativi II
Gestione delle directory
La creazione di una directory può essere effettuata con
BOOL CreateDirectory(LPCTSTR lpPathName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes);
mentre la cancellazione richiede
BOOL RemoveDirectory(LPCTSTR lpPathName);
le funzioni BOOL SetCurrentDirectory(LPCTSTR lpPathName) e
DWORD GetCurrentDirectory(DWORD nBufferLength, LPTSTR lpBuffer);
permettono di definire e conoscere la working directory.
Esempi di utilizzo: win32smp/Win32Smp/chaptr02/pwda.c
Sotto Unix/Linux, Le funzioni di scan di una directory sono
opendir, readdir, closedir.
21
M. Bernaschi: Sistemi Operativi II
Non esistono funzioni per la gestione delle directory nella libreria C.
22
M. Bernaschi: Sistemi Operativi II
File e Directory: funzioni avanzate (1)
• Win32 è capace di gestire indirizzi di file a 64 bit anche se il
sistema stesso è 32 bit.
• La stragrande maggioranza dei sistemi Unix supporta large file
(indirizzi dei file a 64 bit) ed i sistemi stessi sono a 64 bit.
• Linux, pur avendo avuto nel passato come principale piattaforma
Intel 32, cioè un sistema a 32 bit:
– Supporta file di dimensione > 2 GB grazie alla
Large File Interface disponibile dal kernel 2.4 in poi.
23
M. Bernaschi: Sistemi Operativi II
File e Directory: funzioni avanzate (2)
Praticamente tutti i sistemi operativi e la libreria C supportano il
concetto di associare un pointer ad ogni file aperto per indicare la
posizione attuale all’interno del file.
• Le operazioni di lettura e scrittura iniziano dalla posizione
indicata dal file pointer ed incrementano il file pointer del
numero di byte trasferiti.
• È possibile modificare la posizione del file pointer usando:
– Libreria C: int fsetpos( FILE *stream, fpos t *pos) e
int fseek( FILE *stream, long offset, int whence)
– Linux/Unix: off t lseek(int fildes, off t offset, int
whence)
whence specifica il riferimento rispetto a cui effettuare lo
24
M. Bernaschi: Sistemi Operativi II
spostamento e può assumere uno di tre possibili valori:
SEEK_SET, SEEK_CUR, SEEK_END.
lseek ritorna direttamente la posizione corrente mentre con
la libreria C è necessario utilizzare la funzione
long ftell(FILE *stream).
– Win32:
DWORD SetFilePointer(HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod);
∗ Questa chiamata è particolarmente tricky perché, ad
esempio, lDistanceToMove va considerato come signed o
unsigned a seconda del valore di dwMoveMethod. Se
lpDistanceToMoveHigh è NULL, la funzione può operare
solo su file di lunghezza inferiore a 232 − 1.
25
M. Bernaschi: Sistemi Operativi II
dwMoveMethod specifica il punto di partenza in maniera
analoga al parametro whence.
∗ È possibile inoltre specificare la file position utilizzando la
struttura di overlap che costituisce l’ultimo argomento delle
primitive ReadFile e WriteFile.
Definendo gli opportuni valori nei campi Offset e
OffsetHigh l’operazione di I/O inizia alla posizione
specificata ma il file pointer non viene modificato.
Grande attenzione è richiesta per l’accesso a file la cui dimensione
supera i 2GB. Sotto Unix è possibile utilizzare lseek64 mentre nella
libreria C fseek64 oppure fseeko.
26
M. Bernaschi: Sistemi Operativi II
Dimensione di un file
La dimensione di un file può essere ottenuta in Win32 con la
chiamata:
DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
Se la dimensione supera i 2 GB, il valore di ritorno contiene la parte
meno significativa del numero a 64 bit che indica la dimensione
mentre lpFileSizeHigh punta alla variabile che contiene la parte più
significativa dello stesso numero.
In alternativa si può utilizzare:
BOOL GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
un LARGE_INTEGER è una struttura usata per rappresentare un intero
(quindi un numero con segno) a 64 bit.
27
M. Bernaschi: Sistemi Operativi II
Sotto Unix la dimensione di un file (e tutta una serie di altre
informazioni) può essere ottenuta con la chiamata stat oppure
fstat.
Notare come la libreria C non offra primitive per questo scopo.
28
M. Bernaschi: Sistemi Operativi II
Caratteristiche di file e directory
Le caratteristiche di un file possono essere accedute in Win32 con la
primitiva:
HANDLE FindFirstFile(LPCTSTR lpFileName,
LPWIN32_FIND_DATA lpFindFileData);
che torna un search handle da utilizzare in successive chiamate alla
BOOL FindNextFile(HANDLE hFindFile,
LPWIN32_FIND_DATA lpFindFileData);
• lpFileName punta ad una directory o un pathname che può
contenere wildcard come i caratteri * e ?.
• lpFindFileData punta alla struttura che contiene le
caratteristiche del file
29
M. Bernaschi: Sistemi Operativi II
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[MAX_PATH];
TCHAR cAlternateFileName[14]; /* DOS notation 8.3 */
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
Attenzione: non è possibile usare la CloseHandle per chiudere
l’handle. Usare la BOOL FindClose(HANDLE hFindFile).
30
M. Bernaschi: Sistemi Operativi II
• Molte di queste informazioni possono essere ottenute
direttamente tramite un handle su un file aperto. Ad esempio:
BOOL GetFileTime(
HANDLE hFile,
LPFILETIME lpCreationTime,
LPFILETIME lpLastAccessTime,
LPFILETIME lpLastWriteTime);
Il tempo in Win32 è misurato in unità di 100 nanosecondi a
partire dal 1/1/1601.
31
M. Bernaschi: Sistemi Operativi II
Sotto Unix la stat o fstat tornano le seguenti informazioni:
struct stat {
dev_t
st_dev;
ino_t
st_ino;
mode_t
st_mode;
nlink_t
st_nlink;
uid_t
st_uid;
gid_t
st_gid;
dev_t
st_rdev;
off_t
st_size;
unsigned long st_blksize;
unsigned long st_blocks;
time_t
st_atime;
time_t
st_mtime;
time_t
st_ctime;
};
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
device */
inode */
protection */
number of hard links */
user ID of owner */
group ID of owner */
device type (if inode device) */
total size, in bytes */
blocksize for filesystem I/O */
number of blocks allocated */
time of last access */
time of last modification */
time of last change */
32
M. Bernaschi: Sistemi Operativi II
Win32, Unix e la libreria C offrono funzioni per la creazione di nomi
per i file temporanei: GetTempFileName, mktemp e FILE *tmpfile
rispettivamente.
33
M. Bernaschi: Sistemi Operativi II
File locking in Win32
• Win32 permette di definire lock su file interi o su parti.
• In Win32 i lock sono di tipo mandatory e possono essere shared
(read-only) o exclusive (read-write).
• La funzione fondamentale è:
BOOL LockFileEx(HANDLE hFile,
DWORD dwFlags,
DWORD dwReserved,
DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped);
lpOverlapped è una struttura overlapped che viene utilizzata
come in precedenza per specificare la posizione (a 64 bit) della
regione di file che deve essere “controllata”.
34
M. Bernaschi: Sistemi Operativi II
typedef struct _OVERLAPPED {ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
Il campo dwFlags specifica diverse caratteristiche del lock
(esclusivo invece che condiviso e/o non-bloccante invece di
bloccante).
• I lock non sono ereditati da un nuovo processo creato
• L’operazione di unlock (UnlockFileEx()) deve agire esattamente
sullo stesso range di quella di lock.
35
M. Bernaschi: Sistemi Operativi II
File Locking in Unix/Linux
• “Advisory” e “Mandatory” locks
• Usare sempre la funzione POSIX.1 fcntl o la sua interfaccia
lockf()
int fcntl(int fd, int cmd, struct flock * lock);
struct flock {
short int l_type;
short int l_whence;
__off_t l_start;
__off_t l_len;
__pid_t l_pid;
};
/*
/*
/*
/*
/*
Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK */
Where ‘l_start’ is relative to */
Offset where the lock begins. */
Size of the locked area; zero means EOF */
Process holding the lock. */
• tre valori possibili per cmd: F_GETLK, F_SETLK, F_SETLKW;
• tre valori per l whence: SEEK SET, SEEK CUR, SEEK END;
36
M. Bernaschi: Sistemi Operativi II
La fcntl è usata per cinque diversi scopi:
• duplicare un descrittore esistente (cmd=F DUPFD)
• ottiene/definisce il flag di close-on-exec per un file descriptor
(cmd=F GETFD or F SETFD)
• ottiene/definisce i flag per il file status (cmd=F GETFL or
F SETFL). I flag possibili sono O_NONBLOCK, O_APPEND, O_ASYNC.
• ottiene/definisce l’ownership per l’I/O asincrono (cmd=F GETOWN
or F SETOWN)
• ottiene/definisce i record lock (cmd=F GETLK, F SETLK or
F SETLKW)
37
M. Bernaschi: Sistemi Operativi II
• F SETLKW è una versione bloccante di F SETLK. L’attesa è
interrotta se viene intercettato un segnale.
• I lock sono associati con un processo ed un file. Quando un
processo termina tutti i suoi lock sono rilasciati. Ogni volta che
un descrittore viene chiuso, tutti i lock sul file referenziato da
quel descrittore per quel processo sono rilasciati anche se sono
stati presi in sezioni diverse del processo!
• I locks non sono mai ereditati attraverso una fork.
• I locks possono essere ereditati da un nuovo programma
attraverso una exec.
38
M. Bernaschi: Sistemi Operativi II
Mandatory lock in Unix/Linux
• I lock mandatory sono stati aggiunti relativamente tardi in
Unix/Linux.
• POSIX non specifica nessuno schema per i lock mandatory.
• La soluzione adottata è stata quella di utilizzare la stessa
interfaccia (fcntl/lockf) ma su file appositamente “marcati” .
• I file sono marcati definendo il bit setgroup-id ma rimuovendo la
definizione del bit group-execute (chmod g+s file).
• Attenzione! Sotto Linux il file system deve esser montato con
l’opzion mand.
39
M. Bernaschi: Sistemi Operativi II
Il Registry in Windows
Il registry è un database centralizzato di tipo gerarchico che
contiene tutte le informazioni sulle applicazioni ed il sistema.
• L’accesso avviene tramite le registry keys che possono essere
descritte come delle directory.
• Una chiave può contenere altre chiavi o coppie nome/valore.
– Ogni chiave deve avere un valore di default.
• Il comando REGEDIT (o REGEDT32) permette di visualizzare e
modificare i contenuti del registry che includono informazioni su:
– Sistema operativo
– Applicazioni installate
– Hardware (tipo di processore, numero di processori, memoria)
– Utenti e Servizi
40
M. Bernaschi: Sistemi Operativi II
– ...
• I sistemi Unix/Linux mantengono tradizionalmente la maggior
parte di queste informazioni nella directory /etc (e
sottodirectory) in semplici file di testo.
Gli entry point del registry sono delle chiavi predefinite:
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_CLASSES_ROOT
41
M. Bernaschi: Sistemi Operativi II
API per il registry
LONG RegOpenKeyEx(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult);
apre una sottochiave. Partendo da una delle chiavi riservate
predefinite è possibile “attraversare” il registry ed ottenere un handle
per qualsiasi chiave subordinata.
Attenzione, le chiavi hanno un handle speciale (HKEY).
42
M. Bernaschi: Sistemi Operativi II
LONG RegEnumKeyEx(
HKEY hKey,
DWORD dwIndex,
LPTSTR lpName,
LPDWORD lpcName,
LPDWORD lpReserved,
LPTSTR lpClass,
LPDWORD lpcClass,
PFILETIME lpftLastWriteTime);
Enumera le sottochiavi di una data chiave aperta (simile alla
FindFirstFile, FindNextFile per le directory).
43
M. Bernaschi: Sistemi Operativi II
LONG RegCreateKeyEx(
HKEY hKey,
LPCTSTR lpSubKey,
DWORD Reserved,
LPTSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult,
LPDWORD lpdwDisposition);
Crea una nuova chiave lpSubKey di tipo lpClass.
Il parametro lpdwDisposition indica se la chiave già esisteva o è
stata creata.
44
M. Bernaschi: Sistemi Operativi II
LONG RegEnumValue(
HKEY hKey,
DWORD dwIndex,
LPTSTR lpValueName,
LPDWORD lpcValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
Enumera i valori della chiave hKey partendo dall’indice dwIndex
45
M. Bernaschi: Sistemi Operativi II
LONG RegSetValueEx(
HKEY hKey,
LPCTSTR lpValueName,
DWORD Reserved,
DWORD dwType,
const BYTE* lpData,
DWORD cbData);
Associa alla chiave hKey un nome lpValueName che viene posto
uguale a lpData ed ha tipo dwType.
46