Write to a file mapped in memory (using mmap)

2

I'm trying to learn how to use mmap; I have managed to read from a file mapped in memory, however when trying to write I constantly get a "segmentation fault". The code (to write) that fails me is the following:

 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>

 int main()
 {
     FILE* punte;
     char* prueba;

     punte=fopen("prueba.txt","w");

     prueba=(char*)mmap(NULL,sizeof(char)*1,PROT_WRITE,MAP_SHARED,fileno(punte),0);

     prueba[0]='A';

     munmap(prueba,sizeof(char)*1);
     fclose(punte);

     return 0;
 }

It's code nonsense that only paints the letter 'A' in the text file, but I'm unable to make it work.

Solution (from @eferion):

 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <unistd.h>
 #include <fcntl.h>

 int main()
 {
     int file;
     char* prueba;

     file=open("prueba.txt", O_RDWR);    //<-- esto  SI funciona
     //file=open("prueba.txt", O_WRONLY); //<-- Pero esto no!

     lseek(file, 9, SEEK_SET);

     write(file, "", 1);

     prueba=(char*)mmap(NULL,sizeof(char)*10,PROT_WRITE,MAP_SHARED,file,0);

     prueba[0]='A';

     munmap(prueba,sizeof(char)*10);

     close(file);

     return 0;
 }
    
asked by Guillermo. D. S. 20.02.2018 в 13:23
source

1 answer

3

The problem is in the stream of the file:

punte=fopen("prueba.txt","w");

Here a file is opened and you receive a pointer to the stream of it ... that is, you do not physically write in the file but in a region of memory associated with it ... How big is that region of memory? Since the file has no content, its current size is 0.

prueba=(char*)mmap(NULL,sizeof(char)*1,PROT_WRITE,MAP_SHARED,fileno(punte),0);

... after you set mmap ...

prueba[0]='A';

... and the program exposes in this last line of code. The reason? The size of the stream of the file is still 0, then the position 0 does not belong to the stream .

The solution can be as " simple " as forcing a resizing of the stream . For this you have to execute three steps:

change fopen by open

mmap need an identifier instead of a pointer of type FILE . This identifier is provided, in this case, by the function open . On the other hand, while fopen offers you a pointer to an intermediate buffer, open allows you to work directly with the file ... and with mmap you intend to map the memory of the file ... not its intermediate buffer over the which you have no control An example:

int punte = open("prueba.txt", O_RDWR | O_CREAT | O_TRUNC);

And would not it work with O_WRONLY ?

int punte = open("prueba.txt", O_WRONLY);

No. and the reason is that O_WRONLY only provides write privileges (without read privileges) and for this case you can not handle memory over which you do not have read privileges.

Position the file cursor

In this way the file will be resized. This operation is necessary to guarantee that the memory associated with the file allows us to work safely with mmap without writing out of it:

size_t size = 10; // pongamos de momento un tamaño razonable

if (lseek(punte, size-1, SEEK_SET) == -1)
{
  close(punte);
  exit(EXIT_FAILURE);
}

Write something in the file

I'm not sure if this step is necessary, since I can not test the code.

In this case we will save an empty string, that is, the file will only travel the %code% . Note that this character will be stored after the 10 characters that we reserved in the previous step.

if (write(punte, "", 1) == -1)
{
    close(punte);
    exit(EXIT_FAILURE);
}

And that's it. Now the stream has space so that you can write to it without writing out the memory associated with it.

    
answered by 20.02.2018 / 13:53
source