Reputation: 183
Having this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main (void) {
int fd = open("./sometext.txt", O_RDONLY);
struct stat sb;
if(fstat(fd,&sb)) perror("in function fstat");
printf("file size is %ld bytes\n\n",sb.st_size);
char* file_p = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
printf("printing file as an array of chars \n\n");
for(int i =0; i<sb.st_size ; i++){
if(file_p[i]=='a') //cannot do this
file_p[i]='5'; //string/char is read-only, but then how?
printf("%c",file_p[i]);
}
munmap(file_p, sb.st_size);
close(fd);
return 0;
}
As I found from other questions, to change string literal, which is read-only by defaul, I have to either have array storage (char arr[] = "sometext_to_change_in_loop"
) or make another pointer, malloc
need space and then copy the first address of the string that pointer from malloc. But how to change the string "in-line" without doing either of those?
EDIT:
Yes, the main issue was I did not bitwise ORed the int prot
argument in mmap
call. However, how it possible that only that is sufficient?
1) - I do not change int flags
in open
call, so why does it work when open
ed with O_RDONLY
and not with O_RDWD
which makes the same file writeable as well (which I am doing by file_p[i] = '5'
: writting).
2)How can be actually changes saved when in mmap
I have in argument int flags
MAP_PRIVATE
, but I want to save changes, so I should have MAP_SHARED
? according to this tutorial : enter link description here where both - the open flag and the mmap flag were changed as I write. I need to explain this as well.
EDIT2: from the tutorial. It is indeed needed in case of different writing to the file:
for(int i =0; i<sb.st_size ; i++){
file_p[i] = toupper(file_p[i]);
printf("%c",file_p[i]);
}
This will REQUIRED to have set open
flag to O_RDWR
and mmap
flag to MAP_SHARED
. But WHY? Why is one change to file file_p[i]='5'
different in another change file_p[i]=toupper(file_p[i])
? Why does not one change requires to set the two flags (the first case), but the other does require it (second case)? It is confusing for me now.
Upvotes: 0
Views: 929
Reputation: 181149
You seem to ask two completely different questions, one about mmap()
and one about string literals. Taking the latter first:
to change string literal, which is read-only by defaul, I have to either have array storage (char arr[] = "sometext_to_change_in_loop") or make another pointer, malloc need space and then copy the first address of the string that pointer from malloc. But how to change the string "in-line" without doing either of those?
Echoing my comments on the question, there is no defined way to modify a string literal. Any attempt to do so produces undefined behavior. Many strings are not literals, however, and if they have elements of modifiable type and are stored in writable storage then they can be modified via various string and I/O functions and by ordinary accesses to the arrays in which they reside. In particular, the contents of a string literal can be copied into such a space, and the resulting separate string then modified.
As for the mmap()
question(s), the overarching one seems to be how to map a file so that the contents can be modified via the mapping. That is already addressed by your other answer, which observes that the allowed accesses to the mapping are controlled by the bitmask passed as mmap()
's third argument, as described by POSIX. There are separate bits for read, write, and execute access to the contents of the mapping.
You go on to ask for clarifications:
1) - I do not change
int flags
inopen
call, so why does it work whenopen
ed withO_RDONLY
and not withO_RDWD
[sic] which makes the same file writeable as well
I can understand how that observation might come as a surprise. The mapping established by mmap()
does not access the underlying object via the provided file descriptor, so the descriptor's mode is irrelevant. The file descriptor serves only as (partial) identification of the data to be mapped. Permissions for access via the mapping are defined by the arguments to mmap()
alone, and the mmap()
call will fail if the process does not have sufficient privilege on the mapped object to access it in the requested modes.
How can be actually changes saved when in
mmap
I have in argumentint flags
MAP_PRIVATE
, but I want to save changes, so I should haveMAP_SHARED
?
You are conflating two different things. The access modes already discussed determine whether you can write to the mapping. MAP_PRIVATE
vs. MAP_SHARED
controls whether other processes can see such writes, either in their own copy of the mapping or in the underlying file. POSIX expresses this as being about the disposition of writes to the mapping. With MAP_SHARED
, they modify the underlying object. With MAP_PRIVATE
, they do not modify the underlying object, and they are visible only to the process that performed the write.
It's not entirely clear what you are asking about in the second edit, but I think it's about writing to the underlying object via the file descriptor and trying to observe the changes via the mapping. Naturally, the file descriptor needs to be open in a mode that permits writing if you want to use it to write to the file. Furthermore, however, to see the changes via an already-established memory mapping, that mapping should be configured as a shared one.
As POSIX puts it: "It is unspecified whether modifications to the underlying object done after the MAP_PRIVATE mapping is established are visible through the MAP_PRIVATE mapping." This is pretty much the flip side of the already-discussed semantics of MAP_PRIVATE
: not only are writes to the mapping not reflected in the underlying object, but modifications to the underlying object may not be visible through the mapping, either. Remember, again, that he mapping established by mmap()
does not access the underlying object via the provided file descriptor.
Upvotes: 0
Reputation: 41046
Try changing
char* file_p = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
to
char* file_p = mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
Upvotes: 1