This commit is contained in:
Denis Monnerat 2024-09-12 13:30:05 +02:00
parent cfd590c9d2
commit c9329259c6
6 changed files with 507 additions and 0 deletions

151
tp/tp2/README.md Normal file
View File

@ -0,0 +1,151 @@
# TP2 : Fichiers
#### Ex1
Écrire deux versions d'un programme qui copie "octet par octet" un fichier source dans un fichier destination :
```
./copy infile outfile
```
en utilisant :
1. les appels systèmes linux : `open`, `read`, `write`, `close`.
2. les fonctions E/S standards (sdtio) : `fopen`, `fread`, `fwrite`, `fclose`.
Testez vos deux programmes sur un fichier volumineux (utilisez la commande `dd` le pseudo fichier `dev/urandom` pour
générer un contenu aléatoire) et expliquez pourquoi le deuxième programme est beaucoup plus rapide que le
premier.
Remarques :
- pour être dans les mêmes conditions, il faut être sur que le fichier à copier n'est pas en cache en mémoire. Générez un nouveau fichier de même taille, ou utilisez le programme [fadvise.c](./src/fadvise.c) qui permet de vider les blocs du cache pour un fichier quelconque.
- utilisez `strace` pour tracer les appels systèmes de vos deux programmes.
#### Ex2
Écrire un programme qui copie un fichier en utilisant `mmap`.
#### Ex3
Compilez et exécutez Le programme [coherence.c](./src/coherence.c). Qu'est ce que cela montre ?
#### Ex4
Le but est d'écrire en C un programme qui efface un fichier du disque de telle manière que le contenu effacé ne soit pas
récupérable. Pour des raisons physiques, on procédera de la manière suivante :
- Si l'inode correspondant au fichier à effacer a plusieurs références, on efface juste l'entrée du répertoire correspondant.
- Sinon, on réécrit les blocs de données :
- une première passe avec `0xff` pour tous les octets.
- une deuxième passe avec des valeurs aléatoires (on utilisera le pseudo-fichier `/dev/urandom`)
- enfin, avant d'effacer le fichier, on le renomera de manière aléatoire.
Toutes les E/S devront utilisées un cache.
Fonctions utiles :
```c
#include <sys/stat.h>
int stat(const char *restrict pathname,
struct stat *restrict statbuf);
#include <fcntl.h>
int open(const char *pathname, int flags, ...
/* mode_t mode */ );
#include <unistd.h>
ssize_t read(int fd, void buf[.count], size_t count);
ssize_t write(int fd, const void buf[.count], size_t count);
int unlink(const char *pathname);
int close(int fd);
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
```
#### Ex5
Le but est d'écrire une version simplifiée de la commande `ls -al`.
```bash
$./myls /
drwxr-xr-x 18 root root 4096 07 sept. 12:48 ..
drwxr-xr-x 6 root root 4096 03 nov. 09:40 srv
drwxr-xr-x 10 root root 4096 24 sept. 21:07 usr
dr-xr-xr-x 301 root root 0 18 sept. 07:10 proc
drwxr-xr-x 312 root root 258048 12 sept. 09:46 lib
drwxrwxrwt 25 root root 2140 27 sept. 13:02 tmp
drwxr-xr-x 18 root root 4096 07 sept. 12:48 .
drwxr-xr-x 5 root root 1024 07 sept. 12:57 boot
drwxr-xr-x 32 root root 760 27 sept. 09:57 run
drwxr-xr-x 11 root root 4096 25 juil. 18:14 opt
drwxr-x--- 32 root root 4096 25 sept. 13:49 root
drwxr-xr-x 122 root root 12288 27 sept. 09:57 etc
drwxr-xr-x 4 root root 4096 10 déc. 08:27 home
drwxr-xr-x 6 root root 151552 24 sept. 21:07 bin
drwxr-xr-x 6 root root 151552 24 sept. 21:07 sbin
drwxr-xr-x 23 root root 3580 27 sept. 09:57 dev
drwxr-xr-x 10 root root 4096 13 sept. 13:33 media
drwxr-xr-x 15 root root 4096 18 sept. 07:10 var
drwxr-xr-x 312 root root 258048 12 sept. 09:46 lib64
dr-xr-xr-x 13 root root 0 18 sept. 07:10 sys
drwx------ 2 root root 16384 02 sept. 11:30 lost+found
-rw-r--r-- 1 root root 2333 28 juin 20:49 fonts.conf
drwxr-xr-x 2 root root 4096 02 sept. 11:40 mnt
```
- pour parcourir les entrées du repertoire passé en argument :
```c
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
```
```c
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
```
- les autres informations sont accessibles grâce à la fonction :
```c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
```
Faire `man 7 inode`.

BIN
tp/tp2/src.tar.gz Normal file

Binary file not shown.

96
tp/tp2/src/coherence.c Normal file
View File

@ -0,0 +1,96 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/fcntl.h>
#define TESTFILE "coherence-test.txt"
void write_asr_c_pas_bien()
{
FILE* f = fopen(TESTFILE, "w");
fprintf(f, "L'asr, c'est pas bien!\n");
fclose(f);
}
void write_asr_c_bien()
{
FILE* f = fopen(TESTFILE, "w");
fprintf(f, "L'asr, c'est bien!!\n");
fclose(f);
}
void read_using_syscalls()
{
write_asr_c_pas_bien();
// open file descriptor
int fd = open(TESTFILE, O_RDONLY);
// read first 12 bytes
char buf[BUFSIZ];
ssize_t nr1 = read(fd, buf, 12);
assert(nr1 >= 0);
write_asr_c_bien();
// read rest of file, print to stdout
ssize_t nr2 = read(fd, buf + nr1, BUFSIZ - nr1);
close(fd);
fwrite(buf, 1, nr1 + nr2, stdout);
}
void read_using_stdio()
{
write_asr_c_pas_bien();
// open stdio file
FILE* f = fopen(TESTFILE, "r");
// read first 12 bytes
char buf[BUFSIZ];
size_t nr1 = fread(buf, 1, 12, f);
write_asr_c_bien();
// read rest of file, print to stdout
size_t nr2 = fread(buf + nr1, 1, BUFSIZ - nr1, f);
fclose(f);
fwrite(buf, 1, nr1 + nr2, stdout);
}
static void usage()
{
fprintf(stderr, "Usage: ./coherence -l (linux syscalls) or ./coherence -s (stdio)\n");
exit(1);
}
int main(int argc, char** argv)
{
int which = 0;
int opt;
while ((opt = getopt(argc, argv, "ls")) != -1) {
switch (opt) {
case 's':
which = 's';
break;
case 'l':
which = 'l';
break;
default:
usage();
}
}
if (which == 's') {
read_using_stdio();
} else if (which == 'l') {
read_using_syscalls();
} else {
usage();
}
}

35
tp/tp2/src/copy.c Normal file
View File

@ -0,0 +1,35 @@
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#define BLOCK_SIZE 1
int main(int argc, char *argv[])
{
int fin,
fout;
char buf[BLOCK_SIZE];
assert( argc == 3 );
fin = open(argv[1],O_RDONLY);
assert( fin >= 0 );
fout = open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,0600);
assert( fout >= 0 );
while(1){
ssize_t nb_read;
nb_read = read(fin,buf,BLOCK_SIZE);
if (nb_read <= 0)
break;
write(fout,buf,nb_read);
}
close(fin);
close(fout);
return 0;
}

155
tp/tp2/src/fadvise.c Normal file
View File

@ -0,0 +1,155 @@
#include <linux/falloc.h>
#include <linux/fadvise.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <asm/unistd_64.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
//#include <linux-ftools.h>
#define LINUX_FTOOLS_VERSION "1.0.0"
/**
SYNTAX: filename mode [offset] [,length]
Where mode can be:
POSIX_FADV_NORMAL No further special treatment.
POSIX_FADV_RANDOM Expect random page references.
POSIX_FADV_SEQUENTIAL Expect sequential page references.
POSIX_FADV_WILLNEED Will need these pages.
POSIX_FADV_DONTNEED Don't need these pages.
POSIX_FADV_NOREUSE Data will be accessed once.
Allows an application to to tell the kernel how it expects to use a file handle,
so that the kernel can choose appropriate read-ahead and caching techniques for
access to the corresponding file. This is similar to the POSIX version of the
madvise system call, but for file access instead of memory access. The
sys_fadvise64() function is obsolete and corresponds to a broken glibc API,
sys_fadvise64_64() is the fixed version. The following are the values for the
advice parameter:
FADV_NORMAL
No special treatment.
FADV_RANDOM
Expect page references in random order.
FADV_SEQUENTIAL
Expect page references in sequential order.
FADV_WILLNEED
Expect access in the near future.
FADV_DONTNEED
Do not expect access in the near future. Subsequent access of pages in this
range will succeed, but will result either in reloading of the memory contents
from the underlying mapped file or zero-fill-in-demand pages for mappings
without an underlying file.
FADV_NOREUSE
Access data only once.
*/
int main(int argc, char *argv[]) {
if ( argc < 3 ) {
fprintf( stderr, "%s version %s\n", argv[0], LINUX_FTOOLS_VERSION );
printf( "SYNTAX: fadvise filename mode [offset] [,length]\n" );
printf( "Where mode can be:\n\n" );
printf( " POSIX_FADV_NORMAL No further special treatment. \n" );
printf( " POSIX_FADV_RANDOM Expect random page references. \n" );
printf( " POSIX_FADV_SEQUENTIAL Expect sequential page references. \n" );
printf( " POSIX_FADV_WILLNEED Will need these pages. \n" );
printf( " POSIX_FADV_DONTNEED Don't need these pages. \n" );
printf( " POSIX_FADV_NOREUSE Data will be accessed once. \n" );
exit( 1 );
}
char* path = argv[1];
char* param_mode = argv[2];
printf( "Going to fadvise %s\n", path );
int flags = O_RDWR;
int fd = open( path, flags );
if ( fd == -1 ) {
perror( NULL );
return 1;
}
struct stat fd_stat ;
if ( fstat( fd, &fd_stat ) < 0 ) {
perror( "Could not stat file: " );
return 1;
}
loff_t offset = 0;
loff_t length = fd_stat.st_size;
if ( argc >= 4 ) {
offset = strtol( argv[3], NULL, 10 );
}
if ( argc >= 5 ) {
length = strtol( argv[4], NULL, 10 );
}
printf( "offset: %ld\n", offset );
printf( "length: %ld\n", length );
int mode = -1;
if ( strcmp( param_mode , "POSIX_FADV_NORMAL" ) == 0 ) {
mode = POSIX_FADV_NORMAL;
} else if ( strcmp( param_mode , "POSIX_FADV_RANDOM" ) == 0 ) {
mode = POSIX_FADV_RANDOM;
} else if ( strcmp( param_mode , "POSIX_FADV_SEQUENTIAL" ) == 0 ) {
mode = POSIX_FADV_SEQUENTIAL;
} else if ( strcmp( param_mode , "POSIX_FADV_WILLNEED" ) == 0 ) {
mode = POSIX_FADV_DONTNEED;
} else if ( strcmp( param_mode , "POSIX_FADV_DONTNEED" ) == 0 ) {
mode = POSIX_FADV_DONTNEED;
} else if ( strcmp( param_mode , "POSIX_FADV_NOREUSE" ) == 0 ) {
mode = POSIX_FADV_NOREUSE;
} else {
printf( "Invalid mode %s\n", param_mode );
exit( 1 );
}
printf( "mode: %s\n", param_mode );
long result = syscall( SYS_fadvise64, fd, offset, length , mode );
if ( result != 0 ) {
if ( result != -1 ) {
errno=result;
perror( "Unable to fadvise" );
} else {
printf( "Unable to fadvise: %ld\n" , result );
}
return 1;
}
printf( "WIN\n" );
close( fd );
return 0;
}

70
tp/tp2/src/my_cp_map.c Normal file
View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <sys/mman.h>
#define BUFSIZE 1024
static inline double tstamp(void)
{
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
return tv.tv_sec + tv.tv_nsec * 1.0e-9;
}
int main(int argc, char *argv[])
{
//char buf[BUFSIZE];
char * bufin = NULL,
* bufout = NULL;
int fin,
fout;
double start,
end;
size_t filesize = 0;
assert(argc == 3);
start = tstamp();
fin = open(argv[1],O_RDONLY);
assert(fin >=0);
fout = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
assert(fout >=0);
filesize = lseek(fin,0,SEEK_END);
ftruncate (fout,filesize);
bufin = mmap(NULL,filesize,PROT_READ,MAP_PRIVATE,fin,0);
assert(bufin != (void*)-1);
bufout = mmap(NULL,filesize,PROT_WRITE,MAP_SHARED,fout,0);
assert(bufout != (void*)-1);
memcpy(bufout,bufin,filesize);
//munmap(bufin,filesize);
//munmap(bufout,filesize);
//ssize_t nb_read = read(fin,buf,sizeof(buf));
close(fin);
close(fout);
end = tstamp();
printf("time = %.3lf\n",end - start);
return 0;
}