forked from IUTInfoMontp-M2101/cours
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcours02.pug
368 lines (352 loc) · 14.2 KB
/
cours02.pug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
extends coursXX.pug
append preamble
- date = "2019-02-10";
- title = "Cours n°2 :<br>Appels systèmes<br>et entrée / sortie";
block document
section.single
h1 Système d'exploitation
div
ul
li Le système d'exploitation (OS) est le premier programme exécuté au démarrage de l'ordinateur
li C'est l'OS qui gère toute l'activité de l'ordinateur (mémoire, utilisateurs, processeur,
| périphériques, réseau, etc.)
li En cours : <em>Unix</em> (mais les autres sont similaires)
li Les programmes communiquent avec l'OS par l'intérmédiaire d'appels systèmes (<em>system
| call</em>)
section.single
h1 Appels systèmes
div Les appels systèmes ressemblent à des procédures (appels de fonction), avec toutefois des
| différences importantes :
ul
li Les appels systèmes sont très coûteux en ressources :
ul
li le système sauvegarde l'état
li l'OS prend le contrôle du CPU
li l'OS exécute une tâche spécifique
li l'OS sauvegarde son état
li le contrôle est rendu au processus qui a lancé l'appel
li Les appels systèmes dépendent du système d'exploitation
li Il ne faut pas les utiliser directement si le programme doit être portable
li La réalisation détaillée d'un appel système demande une connaissance précise des
| registres du processeur
li Il faut être très prudent pour ne pas provoquer d'erreurs
li On utilise en général une fonction qui se charge de faire l'appel
section.split
h1 Entrée / Sortie
.side
pre
code.cpp
| int <span class="highlight">open</span>(char *path, int flags[, int mode]);
| int <span class="highlight">close</span>(int fd);
| int <span class="highlight">read</span>(int fd, char *buf, int size);
| int <span class="highlight">write</span>(int fd, char *buf, int size);
| off_t <span class="highlight">lseek</span>(int fd, off_t offset, int whence);
.side
p Il existe 5 appels systèmes principaux pour manipuler des fichiers.
ul
li ressemblent à des procédures, mais sont envoyés directement au système
| souvent on utilise des fonctions qui font un appel système (ex : <code>fopen</code>
| qui appelle <code>open</code>)
li les entrées/sorties sont gérées par l'OS pour éviter que des erreurs dans les programmes
| aient des conséquences sur le système de fichiers
li chaque appel est décrit dans sa page de manuel (ex : <code>man 2 open</code>)
section.single
h1 man 2 open
div
pre
code.plaintext
| OPEN(2) BSD System Calls Manual OPEN(2)
|
| NAME
| <span class="highlight">open</span> -- open or create a file for reading or writing
| SYNOPSIS
| <span class="highlight">#include <fcntl.h></span>
| <span class="highlight">int open(const char *path, int oflag, ...);</span>
| DESCRIPTION
| The file name specified by path is opened for reading and/or writing, as specified by the argument oflag; the file descriptor is returned to the calling process.
|
| The oflag argument may indicate that the file is to be created if it does not exist (by specifying the O_CREAT flag). In this case, open requires a third argument mode_t mode; the file is created with mode mode as described in chmod(2) and modified by the process' umask value (see umask(2)).
section.split
h1 Open
.side
pre
code.cpp
| int <span class="highlight">open</span>(char *path, int flags[, int mode]);
hr
pre
code.cpp
| #include <fcntl.h>
|
| main() {
| int fd;
| fd = <span class="highlight">open</span>("test.txt", O_RDONLY);
| printf("%d\n", fd);
| }
.side
p L'appel <code>open</code> sert à demander l'accès à un fichier
ul
li <code>path</code> indique le chemin du fichier
li <code>flags</code> indique comment on veut manipuler le fichier
li <code>mode</code> définit les permissions à donner en cas de création d'un nouveau fichier
li le résultat est un entier correspondant à un descripteur de fichier (ou -1 en cas d'erreur)
li Tous les autres appels E/S utilisent un descripteur de fichier
section.split
h1 Open (flags)
.side
pre
code
| <span class="highlight">O_RDONLY</span> open for reading only
| <span class="highlight">O_WRONLY</span> open for writing only
| <span class="highlight">O_RDWR</span> open for reading and writing
| O_NONBLOCK do not block on open or for data to become available
| <span class="highlight">O_APPEND</span> append on each write
| <span class="highlight">O_CREAT</span> create file if it does not exist
| <span class="highlight">O_TRUNC</span> truncate size to 0
| O_EXCL error if O_CREAT and the file exists
| ...
.side
ul
li L'argument <code>flags</code> est un ou bit-à-bit de valeurs
li Les valeurs possibles sont définies dans <a href="cours02/fcntl.h"><code>/usr/include/sys/fcntl.h</code></a>
section.split
h1 Close
.side
pre
code.cpp
| int <span class="highlight">close</span>(int fd);
hr
pre
code.cpp
| #include <fcntl.h>
| #include <unistd.h>
| main() {
| int fd1, fd2;
| fd1 = <span class="highlight">open</span>("test.txt", O_RDONLY);
| if (fd1 < 0) {
| exit(1);
| }
| fd2 = <span class="highlight">open</span>("test.txt", O_RDONLY);
| if (fd2 < 0) {
| exit(1);
| }
| if (<span class="highlight">close</span>(fd1) < 0) {
| exit(1);
| }
| }
.side
p L'appel <code>close</code> permet de libérer un descripteur de fichier
ul
li Le résultat est 0 en cas de réussite, -1 en cas d'erreur
li Les descripteurs de fichier sont tous libérés à la fin d'un processus
li Le nombre de fichiers ouverts par un processus est limité (dépend du système, varie d'une centaine à
| plusieurs milliers)
section.split
h1 Read
.side
pre
code.cpp
| int <span class="highlight">read</span>(int fd, char *buf, int size);
hr
pre
code.cpp
| int main() {
| char *b;
| int fd, sz;
| b = malloc(sizeof(char) * 11);
| fd = <span class="highlight">open</span>("test.txt", O_RDONLY);
| if (fd < 0) {
| exit(1);
| }
| do {
| sz = <span class="highlight">read</span>(fd, b, 10);
| b[sz] = '\0';
| printf("lu: %s\n", b);
| } while (sz == 10);
| <span class="highlight">close</span>(fd);
| }
.side
p L'appel <code>read</code> sert à lire des octets dans un fichier
ul
li <code>fd</code> est le descripteur du fichier à lire
li <code>buf</code> est un pointeur vers un tableau où mettre les caractères lus
li <code>size</code> est le nombre d'octets à lire
li le résultat est le nombre d'octets effectivement lus (peut être inférieur à <code>size</code> si on est en fin de fichier)
section.split
h1 Write
.side
pre
code.cpp int <span class="highlight">write</span>(int fd, char *buf, int size);
hr
pre
code.cpp
| int main() {
| int fd, sz;
| char *txt;
|
| fd = <span class="highlight">open</span>("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
| if (fd < 0) {
| exit(1);
| }
|
| txt = "Bonjour\n";
| sz = <span class="highlight">write</span>(fd, txt, 8);
|
| <span class="highlight">close</span>(fd);
| }
.side
p L'appel <code>write</code> permet d'écrire des octets dans un fichier
ul
li <code>fd</code> est le descripteur du fichier où écrire
li <code>buf</code> est un pointeur vers un tableau de caractères à écrire
li <code>size</code> correspond au nombre de caractères du tableau <code>buf</code> à écrire
li le résultat est le nombre d'octets effectivement écrits (devrait toujours être égal à <code>size</code>)
section.split
h1 Pointeur de fichier
.side
pre
code.cpp
| int main() {
| char *c;
| int fd, sz;
| c = malloc(sizeof(char) * 10);
| fd = open("test.txt", O_RDWR | O_APPEND);
| if (fd < 0) {
| exit(1);
| }
|
| while(1) {
| sz = read(fd, c, 10);
| write(fd, c, sz);
| if (sz < 10) break;
| }
| close(fd);
| }
.side
p Les fichiers ouverts sont tous associés à un <em>pointeur de fichier</em> qui indique un emplacement dans le fichier
ul
li Initialement, le pointeur est au début du fichier
li Lorsque l'on utilise <code>read</code> ou <code>write</code>, la lecture et l'écriture se font au niveau du pointeur
li Le pointeur est automatiquement avancé par la lecture et l'écriture
section.split
h1 Ouvertures multiples
.side
pre
code.cpp.only(data-end=1)
| int main() {
| int fd1, fd2;
|
| fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC);
| fd2 = open("test.txt", O_WRONLY);
|
| write(fd1, "un ", 3);
| write(fd2, "deux ", 5);
| write(fd1, "trois ", 6);
| }
|
|
span.uncover(data-step=1) ⟶ deutrois
code.cpp.only(data-start=2)
| int main() {
| int fd1, fd2;
|
| fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | <span class="highlight">O_APPEND</span>);
| fd2 = open("test.txt", O_WRONLY | <span class="highlight">O_APPEND</span>);
|
| write(fd1, "un ", 3);
| write(fd2, "deux ", 5);
| write(fd1, "trois ", 6);
| }
|
|
span.uncover(data-step=3) ⟶ un deux trois
.side
p On peut ouvrir plusieurs fois un même fichier (même en écriture)
ul
li chaque descripteur a son propre pointeur de fichier
li les ouvertures en mode <code>O_APPEND</code> restent à la fin du fichier
section.split
h1 stdin, stdout, stderr
.side
pre
code.cpp
| main() {
| char c;
| while (read(0, & c, 1) == 1) {
| write(1, &c, 1);
| }
| }
.side
p Les trois premiers descripteurs de fichiers sont automatiquement attribués à chaque processus :
ul
li 0 : entrée standard (<code>stdin</code>)
li 1 : sortie standard (<code>stdout</code>)
li 2 : sortie d'erreur (<code>stderr</code>)
p On peut directement utiliser ces descripteurs de fichiers sans avoir à utiliser <code>open</code>.
section.split
h1 lseek
.side
pre
code.cpp
| int main() {
| char c[10];
| int fd, sz;
| fd = open("test.txt", O_RDWR);
| if (fd < 0) exit(1);
|
| int rp = 0;
| int wp = <span class="highlight">lseek</span>(fd, 0, SEEK_END);
| do {
| <span class="highlight">lseek</span>(fd, rp, SEEK_SET);
| sz = read(fd, c, 10);
| rp = <span class="highlight">lseek</span>(fd, 0, SEEK_CUR);
|
| <span class="highlight">lseek</span>(fd, wp, SEEK_SET);
| write(fd, c, sz);
| wp = <span class="highlight">lseek</span>(fd, 0, SEEK_CUR);
| } while (sz == 10);
| close(fd);
| }
.side
p <code>lseek</code> permet de déplacer manuellement le pointeur de fichier
ul
li <code>fd</code> désigne le descripteur de fichier
li <code>offset</code> indique le nombre d'octets de déplacement
li <code>whence</code> permet de décrire la référence du déplacement
ul
li <code>SEEK_SET</code> début du fichier
li <code>SEEK_CUR</code> position actuelle
li <code>SEEK_END</code> fin du fichier
li Le résultat est la position absolue du curseur après déplacement
p Il est possible de déplacer le curseur au-delà de la fin du fichier
section.split
h1 stdio.h
.side
pre
code.cpp
| int main() {
| <span class="highlight">FILE *fpin, *fpout;</span>
| int i=0;
|
| fpin = <span class="highlight">fopen</span>("test.txt", "r");
| fpout = <span class="highlight">fopen</span>("res.txt", "w");
| char s[80];
|
| while(<span class="highlight">fgets</span>(s, 80, fpin)) {
| <span class="highlight">fprintf</span>(fpout, "ligne %d: %s", i, s);
| i++;
| }
|
| <span class="highlight">fclose</span>(fpin);
| <span class="highlight">fclose</span>(fpout);
| }
.side
p En général, on n'appelle pas directement les appels systèmes mais on utilise des fonctions de la librairie C
| qui les appellent indirectement :
ul
li <code>fopen</code>, <code>fclose</code>
li <code>fgetc</code>, <code>fgets</code>, <code>fscanf</code>, etc.
li <code>fputc</code>, <code>fprintf</code>, <code>fputs</code>, etc.
br
p Ces fonctions manipulent les fichiers par l'intermédiaire de pointeurs de fichiers (<em>file pointers</em>)
| de type <code>FILE*</code> (structure contenant un descripteur de fichier, et des informations
| supplémentaires)