diff --git a/tp/tp2/README.md b/tp/tp2/README.md new file mode 100644 index 0000000..f86922e --- /dev/null +++ b/tp/tp2/README.md @@ -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 +int stat(const char *restrict pathname, + struct stat *restrict statbuf); + +#include +int open(const char *pathname, int flags, ... + /* mode_t mode */ ); + +#include + +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 +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 + #include + + DIR *opendir(const char *name); + ``` + + ```c + #include + + 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 + #include + #include + + 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`. diff --git a/tp/tp2/src.tar.gz b/tp/tp2/src.tar.gz new file mode 100644 index 0000000..74b9262 Binary files /dev/null and b/tp/tp2/src.tar.gz differ diff --git a/tp/tp2/src/coherence.c b/tp/tp2/src/coherence.c new file mode 100644 index 0000000..f9023e5 --- /dev/null +++ b/tp/tp2/src/coherence.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include + +#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(); + } +} diff --git a/tp/tp2/src/copy.c b/tp/tp2/src/copy.c new file mode 100644 index 0000000..b45f423 --- /dev/null +++ b/tp/tp2/src/copy.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#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; +} + diff --git a/tp/tp2/src/fadvise.c b/tp/tp2/src/fadvise.c new file mode 100644 index 0000000..8dbc52e --- /dev/null +++ b/tp/tp2/src/fadvise.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#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; + +} diff --git a/tp/tp2/src/my_cp_map.c b/tp/tp2/src/my_cp_map.c new file mode 100644 index 0000000..c425b68 --- /dev/null +++ b/tp/tp2/src/my_cp_map.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +#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; +}