Reputation: 46479
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?
Upvotes: 6
Views: 3792
Reputation: 1399
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;
}
Upvotes: 1
Reputation: 136425
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.
Upvotes: 2
Reputation: 7544
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()
.
Upvotes: 7