Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

system call to map memory to a file descriptor (inverse mmap)?

I want to be able to map memory to a file descriptor so I can use some existing functions that need a file descriptor. Here's essentially what I'm looking for:

void do_operation1(int fd);

char data[DATA_MAX] = { /* embedded binary data */ };
int fd = addr_to_fd(data, DATA_MAX);

do_operation1(fd);
/* ... operate on fd ... */

What system call, or calls, can I use to accomplish this?

like image 552
Kaleb Pederson Avatar asked May 12 '10 19:05

Kaleb Pederson


4 Answers

Some implementations have fmemopen(). (Then of course you have to call fileno()).

If yours doesn't, you can build it yourself with fork() and pipe().

like image 138
Randy Proctor Avatar answered Sep 29 '22 01:09

Randy Proctor


You should Check out shm_open().

like image 36
Enquimot Avatar answered Sep 29 '22 02:09

Enquimot


Sure, just open(argv[0], ...), scan through the file to find where your binary data starts, lseek() there and done. That file won't have the length of your binary data of course.

like image 24
Maxim Egorushkin Avatar answered Sep 29 '22 02:09

Maxim Egorushkin


You cannot map "some existing memory buffer" to a file descriptor. As said in a comment above, the fmemopen() function associates a memory buffer with a "FILE *" stream pointer which can be manipulated with the libc-provided streams functions. No file descriptor is allocated: the "FILE *" stream is a high-level abstraction and is NOT compatible with a file descriptor which is a low-level handle.

Instead, you may want to allocate a new shared memory buffer and map it to a file descriptor. This is widely used and known as a "memory-mapped file" in the Linux jargon.

You can use a file descriptor obtained with open() that refers to a file or a file descriptor obtained with shm_open() that refers to a shared memory object. Any file descriptor handle will do the job. You can then invoke mmap() to map the file descriptor to a shared memory buffer.

Note: mmap() will fail if the file descriptor refers to a non-regular file such as a pipe, a socket or a character device file (e.g., /dev/ttys001). Due to this, you cannot usually create a memory-mapped file for the STDIN, STDOUT or STDERR file descriptors.

You can manipulate the memory buffer in an array-like fashion and modifications to the memory-mapped file are committed to disk. The opposite is also true, with any modifications made to the file (e.g., with a write() syscall) committed to memory as well.


The following snippet opens a file of your choice and maps it into memory. It will print the first 256 characters and replace them with "*" in the original file. Compile it with cc mmap_test.c -o mmap_test on a POSIX-compliant system.

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

int main(int ac, char *av[])
{
    int pagesize, fd;
    unsigned char *data;

    if ( ac < 2 ) {
        printf("Usage: %s <filepath>\n", av[0]);
        return 1;
    }

    pagesize = getpagesize();

    if ( (fd = open(av[1], O_RDWR)) == -1 ) {
        perror("Error: cannot open file for reading");
        return 1;
    }

    if ( (data = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED ) {
        perror("Error: cannot create memory-mapped file");
        return 1;
    }

    write(1, data, 256);
    memset(data, '*', 256);

    return 0;
}
like image 41
explogx Avatar answered Sep 29 '22 01:09

explogx