mmap
: File Mappings, Basics¶
Reading A File, Not Using File I/O¶
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " FILENAME\n";
return 1;
}
const char* filename = argv[1];
int fd = open(filename, O_RDONLY); // <-- O_RDONLY
if (fd == -1) {
perror("open");
return 1;
}
struct stat stat;
int error = fstat(fd, &stat); // <-- determine file size (stat.st_size)
if (error) {
perror("fstat");
return 1;
}
void* content = mmap(
NULL, // <-- (addr) let kernel choose address
stat.st_size, // <-- (length) extending from offset (0)
PROT_READ, // <-- (prot) memory access protection
MAP_PRIVATE, // <-- (flags) copy-on-write (read-only anyway)
fd, // <-- (fd) file mapping (as opposed to "anonymous")
0 // <-- (offset) offset; map from beginning of file
);
if (content == MAP_FAILED) {
perror("mmap");
return 1;
}
close(fd); // <-- abandon; mapping keeps a reference
write(STDOUT_FILENO, content, stat.st_size);
munmap(content, stat.st_size); // <-- (done anyway at exit)
return 0;
}
Open file
O_RDONLY
Create mapping
Close file (mapping already knows)
PROT_READ
: memory protection read onlyMAP_PRIVATE
: private mappingPointless as we don’t write to it, but we have to say something
Copy on write otherwise ⟶ private to each address space (later)
offset
andlength
span entire fileoffset
must start at a page boundary. 4096 on many systems; determined exactly bysysconf(_SC_PAGE_SIZE)
$ echo 0123456789 > /tmp/a-file
$ ./file-mapping-ro /tmp/a-file
0123456789
Writing: MAP_PRIVATE
, And Copy-On-Write (COW)¶
Change
PROT_READ
toPROT_WRITE
Note how
open()
is left as-is -O_RDONLY
Touch one byte in mapping
Look with
cat
⟶ no changeCopy-On-Write (COW)
⟶ this is why this works on a
O_RDONLY
file
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc != 2) {
cerr << "Usage: " << argv[0] << " FILENAME\n";
return 1;
}
const char* filename = argv[1];
int fd = open(filename, O_RDONLY); // <-- read-only!
if (fd == -1) {
perror("open");
return 1;
}
struct stat stat;
int error = fstat(fd, &stat);
if (error) {
perror("fstat");
return 1;
}
void* content = mmap(
NULL,
stat.st_size,
PROT_WRITE, // <-- content is writeable
MAP_PRIVATE, // <-- and *private* -> COW
fd,
0
);
if (content == MAP_FAILED) {
perror("mmap");
return 1;
}
close(fd);
((char*)content)[0] = 'a'; // <-- touch first couple bytes
((char*)content)[1] = 'b';
((char*)content)[2] = 'c';
((char*)content)[3] = 'd';
munmap(content, stat.st_size);
return 0;
}