Search code examples
cmmap

Is it safe to modify file in place when replacement is same size as original


I want to do something similar to sed -i 's/abc/def/' file but without temp file. In my case match and replacement are of same length; is the following safe:

fd = open(file, O_RDWR);
fstat(fd, &sbuf);
mm = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
i = 0;
while (i < sbuf.st_size) {
   memcpy(tmpbuf, mm + i, BUFSIZ);  // read from mem to tmpbuf (BUFSIZ at a time)
   if ((p = strstr(tmpbuf, needle))) { // match found
     memcpy(mm + i + (p - tmpbuf), replace, strlen(replace)); // strlen(replace) == strlen(needle)
   }
   i += BUFSIZ;
}
munmap(mm, sbuf.st_size);
fsync(fd);
close(fd);

(err handling omitted for brevity)

Also, not sure if mmap is making this any faster!


Solution

  • It depends on what you mean by "safe". Unlike use of a temp file and atomic rename over top of the old file after finishing, there is no atomicity to this operation; other processes could see the file in an intermediate, partially-modified state. And moreover there is not any ordering between the stores; they could see the end of the replacement before they see the beginning of it, or see them in any other conceivable order, and possibly even in inconsistent ones if also using mmap and not using any memory barriers. Note that there's really nothing special about mmap; you could do the same thing with write too.

    If none of these constitute "unsafety" for you, then the operation is totally safe. In particular it won't truncate the file or anything like that.