MMAP reading and writing files - c

Im trying to use mmap to read in a file and then encrypt it and then write the encryption to the output file. I'm trying to also do this with mmap but when I run the code, it tells me that it was not able to unmmap due to "Invalid Argument".
//Open files initialy and obtain a handle to the file.
inputFile = open(inFileName, O_RDONLY, S_IREAD);
outputFile = open(outFileName, O_APPEND | O_CREAT | O_TRUNC | O_WRONLY, S_IWRITE);
//Allocate buffers for encrption.
from = (unsigned char*)malloc(blockSize);
to = (unsigned char*)malloc(blockSize);
mmapWriteBuff = (unsigned char*)malloc(blockSize);
mmapReadBuff = (unsigned char*)malloc(blockSize);
memset(to, 0, blockSize);
memset(from, 0, blockSize);
memset(mmapWriteBuff, 0, blockSize);
memset(mmapReadBuff, 0, blockSize);
//Make sure we have permission to read the file provided.
setFilePermissions(inFileName, PERMISSION_MODE);
setFilePermissions(outFileName, PERMISSION_MODE);
if(encriptParam)
{
printf("*Encripting file: %s *\n", inFileName);
do//Go through the entire file.
{
if(memParam)
{
currAmt = lseek(inputFile, blockSize, SEEK_SET);
mmapReadBuff = mmap(0, blockSize, PROT_READ, MAP_SHARED, inputFile, 0);
/*
*This is how you encrypt an input char* buffer "from", of length "len"
*onto output buffer "to", using key "key". Jyst pass "iv" and "&n" as
*shown, and don't forget to actually tell the function to BF_ENCRYPT.
*/
BF_cfb64_encrypt(mmapReadBuff, mmapWriteBuff, blockSize, &key, iv, &n, BF_ENCRYPT);
if(currAmt < blockSize)
{
writeAmt = lseek(outputFile, currAmt, SEEK_SET);
mmapWriteBuff = mmap(0, currAmt, PROT_WRITE, MAP_SHARED, outputFile, 0);
if(errno == EINVAL)
{
perror("MMAP failed to start write buffer: ");
exit(MMAP_IO_ERROR);
}
}
else
{
writeAmt = lseek(outputFile, blockSize, SEEK_SET);
mmapWriteBuff = mmap(0, blockSize, PROT_WRITE, MAP_SHARED, outputFile, 0);
if(errno == EINVAL)
{
perror("MMAP failed to start write buffer: ");
exit(MMAP_IO_ERROR);
}
}
mmapWriteBuff = to;
}
else
{
currAmt = read(inputFile, from, blockSize);
/*
*This is how you encrypt an input char* buffer "from", of length "len" *onto output buffer "to", using key "key". Jyst pass "iv" and "n" as
*shown, and don't forget to actually tell the function to BF_ENCRYT.
*/
BF_cfb64_encrypt(from, to, blockSize, &key, iv, &n, BF_ENCRYPT);
if(currAmt < blockSize)
{
writeAmt = write(outputFile, to, currAmt);
}
else
{
writeAmt = write(outputFile, to, blockSize);
}
}
if(memParam)
{
//if(currAmt < blockSize)
//{
// if(munmap(mmapWriteBuff, currAmt) == -1)
// {
// perror("MMAP failed to unmap itself: ");
//
// exit(MMAP_IO_ERROR);
// }
//
// if(munmap(mmapReadBuff, currAmt) == -1)
// {
// perror("MMAP failed to unmap itself: ");
//
// exit(MMAP_IO_ERROR);
// }
//}
//else
//{
if(munmap(mmapReadBuff, blockSize) == -1)
{
perror("MMAP Read Buffer failed to unmap itself: ");
exit(MMAP_IO_ERROR);
}
if(munmap(mmapWriteBuff, blockSize) == -1)
{
perror("MMAP Write Buffer failed to unmap itself: ");
exit(MMAP_IO_ERROR);
}
//}
}
memset(to, 0, strlen((char *)to));
memset(from, 0, strlen((char *)from));
memset(mmapReadBuff, 0, strlen((char*)mmapReadBuff));
memset(mmapWriteBuff, 0, strlen((char*)mmapWriteBuff));
}
while(currAmt > 0);
printf("*Saving file: %s *\n", outFileName);
}

Generally speaking, it seems like you might want to try setting up the outputFile file descriptor without the O_WRONLY flag. Using the O_WRONLY flag for mmap() isn't sufficient.
Thus, you may need to change this:
outputFile = open(outFileName, O_APPEND | O_CREAT | O_TRUNC | O_WRONLY, S_IWRITE);
to this:
outputFile = open(outFileName, O_APPEND | O_CREAT | O_TRUNC | O_RDWR, S_IWRITE);
I am not an expert with mmap(), but I know that you might want to give it both read and write permissions when opening the file descriptor.
EDIT:
Also you want want to try casting every mmap() call to (int*) like so:
mmapReadBuff = (int*)mmap(0, blockSize, PROT_READ, MAP_SHARED, inputFile, 0);

Related

Pipe does not give the same result every time in C

I am trying to read a file by the parent process, send the content to two child processes and child processes write content to a shared memory segment. However, at each run, I get different outputs and I cannot figure out why.
I use two named pipes and after writing to shared memory, the parent process opens the shared memory and reads the content of each memory.
The first child writes to memory as it gets but the second child converts to hexadecimal.
Here is my main function; assume that stringtohex() works correctly.
int main()
{
pid_t pid_1, pid_2;
int fd, sd; // pipes
const int SIZE = 4096;
const char infile[] = "in.txt";
FILE *tp; // file pointers
pid_1 = fork();
if (pid_1 < 0)
{
fprintf(stderr, "Fork 1 failed");
return(1);
}
if (pid_1 > 0)
{
pid_2 = fork();
if (pid_2 < 0)
{
fprintf(stderr, "Fork 2 failed");
return(1);
}
if (pid_2 > 0) // parent
{
tp = fopen(infile, "r");
if (tp == 0)
{
fprintf(stderr, "Failed to open %s for reading", infile);
return(1);
}
mknod(PIPE_NAME_1, S_IFIFO | 0666, 0);
mknod(PIPE_NAME_2, S_IFIFO | 0666, 0);
fd = open(PIPE_NAME_1, O_WRONLY);
sd = open(PIPE_NAME_2, O_WRONLY);
if (fd > 0 && sd > 0)
{
char line[300];
while (fgets(line, sizeof(line), tp))
{
int len = strlen(line);
int num_1 = write(fd, line, len);
int num_2 = write(sd, line, len);
if (num_1 != len || num_2 != len)
perror("write");
else
printf("Ch 1: wrote %d bytes\n", num_1);
printf("Ch 2: wrote %d bytes\n", num_2);
}
close(fd);
close(sd);
}
fclose(tp);
wait(NULL);
int shm_fd = shm_open("Ch_1", O_RDONLY, 0666);
if (shm_fd == -1)
{
fprintf(stderr, "Failed: Shared Memory 1");
exit(-1);
}
int shm_sd = shm_open("Ch_2", O_RDONLY, 0666);
if (shm_sd == -1)
{
fprintf(stderr, "Failed: Shared Memory 2");
exit(-1);
}
void *ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed 1\n");
return -1;
}
void *ptr2 = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_sd, 0);
if (ptr2 == MAP_FAILED)
{
printf("Map failed 2\n");
return -1;
}
fprintf(stdout, "Normal input: \n%s\n", ptr);
fprintf(stderr, "Hexadecimal: \n%s\n", ptr2);
}
else // second child
{
// open shared memory segment
int shm_child_2 = shm_open("Ch_2", O_CREAT | O_RDWR, 0666);
// configure the size of the shared memory segment
ftruncate(shm_child_2, SIZE);
// map the pointer to the segment
void *ptr_child_2 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_2, 0);
if (ptr_child_2 == MAP_FAILED)
{
printf("Map failed 3\n");
return -1;
}
// configure named pipe
mknod(PIPE_NAME_2, S_IFIFO | 0666, 0);
sd = open(PIPE_NAME_2, O_RDONLY);
if (sd > 0) // reading from pipe
{
int num;
char s[300];
while ((num = read(sd, s, sizeof(s))) > 0)
{
// convert to hexadecimal
char hex[strlen(s) * 2 + 1];
stringtohex(s, hex);
// write into segment
sprintf(ptr_child_2, "%s", hex);
ptr_child_2 += strlen(s) * 2;
}
close(sd);
}
exit(0);
}
}
else // first child
{
// create shared memory segment
int shm_child_1 = shm_open("Ch_1", O_CREAT | O_RDWR, 0666);
// configure the size of the shared memory segment
ftruncate(shm_child_1, SIZE);
// map the pointer to the segment
void *ptr_child_1 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_1, 0);
if (ptr_child_1 == MAP_FAILED)
{
printf("Map failed 4\n");
return -1;
}
// configure named pipe
mknod(PIPE_NAME_1, S_IFIFO | 0666, 0);
fd = open(PIPE_NAME_1, O_RDONLY);
if (fd > 0) // reading from pipe
{
int num;
char s[300];
while ((num = read(fd, s, strlen(s))) > 0)
{
// write into segment
sprintf(ptr_child_1, "%s", s);
ptr_child_1 += strlen(s);
}
close(fd);
}
exit(0);
}
return 0;
}
For example input file has:
Harun
sasmaz
59900
1234
Aaaa
Results are:
Normal input:
HARUN
sasmaz
59900
1234
Aaaa4
Hexadecimal:
484152554E0A7361736D617A0A35393930300A313233340A41616161
or
Normal input:
HARUN
sasmaz
asmaz59900
1234
Aaaa
Hexadecimal:
484152554E0A7361736D617A0A35393930300A0A313233340A41616161FF03

mmap file not syncing

Hello I am trying to back up a vector by mmap.
However, I have tried msync then munmap but it doesn't work. After I write to the (char *) then munmap the file, the file has no content. The mmap file is also created with flag MAP_SHARED. Would really appreciate it if anyone can help.
//update file descriptor
if ((fd = open(filename.c_str(), O_RDWR | S_IRWXU)) < 0) { //| O_CREAT
printf("ERROR opening file %s for writing", filename.c_str());
exit(1);
}
//lseek create a file large enough
off_t i = lseek(fd, frontier_size * URL_MAX_SIZE, SEEK_SET);
if (i != frontier_size * URL_MAX_SIZE) {
cout << "failed to seek";
}
//reposition and write 3 bytes to the file else will failed to read
char buff[3] = "ta";
ssize_t kk = lseek(fd, 0, SEEK_SET);
if (kk < 0) {
cout << "failed to reposition";
}
ssize_t temp_write = write(fd, (void *)& buff, 2);
if (temp_write < 0) {
cout << "failed to write";
cout << temp_write;
}
//reposition to begining
ssize_t k = lseek(fd, 0, SEEK_SET);
if (k < 0) {
cout << "failed to reposition";
}
char * map = (char *)mmap(0, frontier_size * URL_MAX_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
printf("failed mmap");
exit(1);
}
mmap_frontier = map;
//write to frontier
for (int i = 0; i < frontier.size(); ++i) {
strcpy(mmap_frontier, frontier[i].c_str());
mmap_frontier += URL_MAX_SIZE;
}
mmap_frontier -= frontier.size() * URL_MAX_SIZE;
ssize_t k = lseek(fd, 0, SEEK_SET);
if (k < 0) {
cout << "failed to reposition";
}
int sync = msync((void *)0, frontier.size() * URL_MAX_SIZE, MS_ASYNC);
if (sync < 0 ) {
cout << "failed to sync";
}
int unmap = munmap((void *)0, frontier.size() * URL_MAX_SIZE);
if (unmap < 0) {
cout << "failed to unmap";
}
There are quite a few problems with your code, and with the question:
S_IRWXU is the 3rd argument to open(), not a flag for the 2nd parameter.
mmap() won't work correctly if the file is too small. You can use ftruncte() to set the file size correctly. You tried to seek past the total size of the mapping and write a couple of bytes ("ta"), but before doing that you issued the seek lseek(fd, 0, SEEK_SET) which means the file size was set to 3 rather than mapping_size+3.
You're not backing the vector with an mmapped file, the vector has nothing to do with it, the vector uses its own memory that isn't related in any way to this mapping (please edit your question...).
You called msync() with the address (void *)0, so the actual address which needs to be synced, map, is not being synced.
Likewise, you called munmap() with the address (void *)0, so the actual address which needs to be unmapped is not being unmapped.
You called msync() with MS_ASYNC, which means there's no guarantee that the sync happens before you read the file's contents.
Here's what's working for me (error handling omitted for brevity):
unsigned frontier_size = 2;
const unsigned URL_MAX_SIZE = 100;
int fd = open("data", O_RDWR);
loff_t size = frontier_size * URL_MAX_SIZE;
ftruncate(fd, size);
char *map = (char *)mmap(0, size, PROT_WRITE, MAP_SHARED, fd, 0);
strcpy(map, "hello there");
msync(map, size, MS_SYNC);
munmap(map, size);
close(fd);

How to detect which piece of my code is generating "Fatal error: glibc detected an invalid stdio handle" error?

I'm trying to code a simple program to copy a file into another using 2 processes.
I want to use shared memory to open both files and get a piece of shared memory of 1Byte to be used as exchange memory in a mutually exclusive way.
So the main process should open both files and put them in shared memories;
fork twice, I obtain 2 processes A and B.
Process A should read 1 byte of the first file, put it in the shared exchange memory and unlock the mutex for process B.
Process B should copy the file from the shared exchange memory and put it in its file and unlock the mutex for process A.
And so on.
#define SIZE 4096
void reader_process(FILE* fptr,char*exch, sem_t*mut){
while(1){
sem_wait(mut);
*exch = (char) getc(fptr);
sem_post(mut+1);
}
}
void writer_process(FILE* fptr,char*exch, sem_t*mut){
if(*exch == EOF){
printf("done\n");
exit(0);
}
while(1){
sem_wait(mut);
putc((int)*exch,fptr);
sem_post(mut-1);
}
}
int main(int argc, char *argv[]){
FILE* shared_f_ptr[2];
pid_t pid;
//2 files name.
char *files[2];
int fd[2];
//open files.
files[0] = argv[1];
printf("%s\n",files[0]);
FILE* fpointer1 = fopen(files[0],"r+");
if (fpointer1 == NULL){
perror("fopen\n");
exit(-1);
}
fd[0] = fileno(fpointer1);
files[1] = argv[2];
printf("%s\n",files[1]);
FILE* fpointer2 = fopen(files[1],"r+");
if (fpointer2 == NULL){
perror("fopen\n");
exit(-1);
}
fd[1] = fileno(fpointer2);
//shared File pointers.
shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[0], 0);
if (shared_f_ptr[0] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[1], 0);
if (shared_f_ptr[1] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
//shared mem for 1B exchange.
char *shared_exchange = (char*)mmap(NULL, sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
-1, 0);
if (shared_exchange == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
//mutex.
sem_t *mut = (sem_t*)mmap(NULL, 2*sizeof(sem_t),
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
-1, 0);
sem_init(&mut[0],1,0);
sem_init(&mut[1],1,0);
//fork.
pid = fork();
if (pid == 0) {
reader_process(shared_f_ptr[0],
shared_exchange, &mut[0]);
}
if (pid == -1){
perror("fork\n");
exit(-1);
}
else pid = fork();
if (pid == 0) writer_process(shared_f_ptr[1],
shared_exchange, &mut[1]);
if (pid == -1){
perror("fork\n");
exit(-1);
}
else{
sem_post(&mut[0]);
}
}
I don't expect the error i am getting Fatal error: glibc detected an invalid stdio handle but i don't really know how to find what's causing the problem.
Don't do this:
//shared File pointers.
shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[0], 0);
if (shared_f_ptr[0] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[1], 0);
if (shared_f_ptr[1] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
Use this instead:
shared_f_ptr[0] = fpointer1;
shared_f_ptr[1] = fpointer2;
Don't use the file descriptors underlying each FILE. Instead, simply use the FILE itself.
Also, instead of using fpointer1 and fpointer2, just use shared_f_ptr[0] and shared_f_ptr[1].
This is a possible definition of the FILE structure:
typedef struct _IO_FILE
{
int __fd;
int __flags;
int __unget;
char *__buffer;
struct {
size_t __orig;
size_t __size;
size_t __written;
} __bufsiz;
fpos_t __fpos;
} FILE;
As you can see, it's a structure, not just a flat pointer.

Why (ftruncate+mmap+memcpy) is faster than (write)?

I found a different way to write data, which is faster than normal unix write function.
Firstly, ftruncate the file to the length we need, then mmap this block of file, finally, using memcpy to flush the file content. I will give the example code below.
As I known, mmap can load the file into the process address space, accelerating by ignoring the page cache. BUT, I don't have any idea why it can fast up the writing speed.
Whether I write a wrong test case or it can be a kind of opti trick?
Here is the test code. Some of its written in ObjC, but no matter. WCTTicker is just a statistics class using gettimeofday.
//find a dir to test
NSString* document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString* dir = [document stringByAppendingPathComponent:#"testDir"];
//remove all existing test
if ([[NSFileManager defaultManager] fileExistsAtPath:dir]) {
if (![[NSFileManager defaultManager] removeItemAtPath:dir error:nil]) {
NSLog(#"fail to remove dir");
return;
}
}
//create dir to test
if (![[NSFileManager defaultManager] createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil]) {
NSLog(#"fail to create dir");
}
//pre-alloc memory
const int length = 10000000;
const int count = 100;
char* mem = (char*)malloc(length);
memset(mem, 'T', length);
{
//start testing mmap
// ftruncate && mmap(private) &&memcpy
NSString* mmapFileFormat = [dir stringByAppendingPathComponent:#"privateMmapFile%d"];
[WCTTicker tick];
for (int i = 0; i < count; i++) {
NSString* path = [[NSString alloc] initWithFormat:mmapFileFormat, i];
int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
if (fd<0) {
NSLog(#"fail to open");
}
int rc = ftruncate(fd, length);
if (rc<0) {
NSLog(#"fail to truncate");
}
char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_PRIVATE, fd, 0);
if (!map) {
NSLog(#"fail to mmap");
}
memcpy(map, mem, length);
close(fd);
}
[WCTTicker stop];
}
{
//start testing write
// normal write
NSString* writeFileFormat = [dir stringByAppendingPathComponent:#"writeFile%d"];
[WCTTicker tick];
for (int i = 0; i < count; i++) {
NSString* path = [[NSString alloc] initWithFormat:writeFileFormat, i];
int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
if (fd<0) {
NSLog(#"fail to open");
}
int written = (int)write(fd, mem, length);
if (written!=length) {
NSLog(#"fail to write");
}
close(fd);
}
[WCTTicker stop];
}
{
//start testing mmap
// ftruncate && mmap(shared) &&memcpy
NSString* mmapFileFormat = [dir stringByAppendingPathComponent:#"sharedMmapFile%d"];
[WCTTicker tick];
for (int i = 0; i < count; i++) {
NSString* path = [[NSString alloc] initWithFormat:mmapFileFormat, i];
int fd = open(path.UTF8String, O_CREAT | O_RDWR, S_IRWXG | S_IRWXU | S_IRWXO);
if (fd<0) {
NSLog(#"fail to open");
}
int rc = ftruncate(fd, length);
if (rc<0) {
NSLog(#"fail to truncate");
}
char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (!map) {
NSLog(#"fail to mmap");
}
memcpy(map, mem, length);
close(fd);
}
[WCTTicker stop];
}
Here is the test result:
2016-07-05 11:44:08.425 TestCaseiOS[4092:1070240]
0: 1467690246.689788, info: (null)
1: 1467690248.419790, cost 1.730002, info: (null)
2016-07-05 11:44:14.126 TestCaseiOS[4092:1070240]
0: 1467690248.427097, info: (null)
1: 1467690254.126590, cost 5.699493, info: (null)
2016-07-05 11:44:14.814 TestCaseiOS[4092:1070240]
0: 1467690254.126812, info: (null)
1: 1467690254.813698, cost 0.686886, info: (null)
You have mmap() without corresponding munmap()
From mmap manual page (linux)
MAP_SHARED Share this mapping. Updates to the mapping are visible
to other processes that map this file, and are carried through to the
underlying file. The file may not actually be updated until msync(2)
or munmap() is called.
Perhaps you should run your tests again so that there is a call to munmap:
char* map = (char*)mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (!map) {
NSLog(#"fail to mmap");
}
memcpy(map, mem, length);
munmap(map, length);
close(fd);
Even with the munmap (or msync) added, I think this should be faster at least for big data transfers because write() results in a copy operation while mmap and access to the map do not.

Is it possible to map just part of a file using mmap?

I have a input file which has a header like this:
P6\n
width\n
height\n
depth\n
and then a struct is writen, pixel*, into this file, which is going to be mapped.
So, I want to skip the header and make my mmap function return the ptr to that structure. How can I do this? with lseek perhaps? Could you please exemplify?
I will leave part of my code here:
printf("Saving header to output file\n");
if (writeImageHeader(h, fpout) == -1) {
printf("Could not write to output file\n");
return -1;
}
last_index = (int)ftell(fpout);
//printf("offset after header= %d\n",last_index);
//alloc mem space for one row (width * size of one pixel struct)
row = malloc(h->width * sizeof (pixel));
/*Create a copy of the original image to the output file, which will be inverted*/
printf("Starting work\n");
for (i = 0; i < h->height; i++) {
printf("Reading row... ");
if (getImageRow(h->width, row, fpin) == -1) {
printf("Error while reading row\n");
}
printf("Got row %d || ", (i + 1));
printf("Saving row... ");
if (writeRow(h->width, row, fpout) == -1) {
printf("Error while reading row\n");
}
printf("Done\n");
}
/*Open file descriptor of the ouput file.
* O_RDWR - Read and Write operations both permitted
* O_CREAT - Create file if it doesn't already exist
* O_TRUNC - Delete existing contents of file*/
if ((fdout = open(argv[2], O_RDWR, FILE_MODE)) < 0) {
fprintf(stderr, "Can't create %s for writing\n", argv[2]);
exit(1);
}
/*Get size of the output file*/
if (fstat(fdout, &sbuf) == -1) {
perror("Stat error ---------->\n");
exit(1);
}
//printf("Size of output file: %d\n",(int)sbuf.st_size);
/*Maps output file to memory*/
if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == (caddr_t) (-1)) {
perror("Error mmaping");
exit(EXIT_FAILURE);
}
As you see, right now my ppm image is mapped to char* data, but I want to skip the header and map just to the pixel* part.
Here's my code with the suggestion of using 2 pointers, a char* from mmap and another one equals that + offset.
main
c functions
header
makefile
If you read the man page for mmap, you wil find that its final parameter is off_t offset. The description:
... continuing or at most 'len' bytes to be mapped from the object described by 'fd', starting at byte offset 'offset'.
I suspect if you pass your offset in as that parameter, it will do what you want.
You can't if the amount you need to skip is less than the system page size, since offset must be a multiple of the page size on some systems.
You just need to keep 2 pointers - the pointer to the start of the mmap'd block, and the pointer to the start of the data you want inside there. As in:
unsigned char *block = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
unsigned char *data = block + offset;
where offset is the offset in the file to the data you want.
So, from what I understand, can I do something like this?
off_t offset_after_header = lseek(fdout, last_index, SEEK_SET);
printf("Pointer is on %d\n",(int)offset_after_header);
/*Maps output file to memory*/
if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, offset_after_header)) == (caddr_t) (-1)) {
perror("Error mmaping");
exit(EXIT_FAILURE);
}
and, from that, I could map my file to whatever type I want, in this case the pixel*
If this is ok, what cautions should I take? For example, like those Ignacio Vazquez-Abrams said
Um, you did notice the 'offset' parameter that you are supplying with a zero? Assuming you know the absolute offset of what you want, you pass it.

Resources