Skip to content

Commit

Permalink
Ensure that temporary file is used only by one process
Browse files Browse the repository at this point in the history
mkstemp(3) ensures that a unique file is created, but in the
previous implementation, there's a possibility that a process
uses the temporary file created by another process if mkstemp(3)
fails to create a file due to EEXIST. That has the same risk as
#174.

This commit will also resolve
#177 if the cause is
that multiple processes try to create a file with the same name
at the same time.
  • Loading branch information
abicky committed Jun 28, 2020
1 parent a7818b7 commit cfd28c3
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions ext/bootsnap/bootsnap.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#define KEY_SIZE 64

#define MAX_CREATE_TEMPFILE_ATTEMPT 3

/*
* An instance of this key is written as the first 64 bytes of each cache file.
* The mtime and size members track whether the file contents have changed, and
Expand Down Expand Up @@ -499,25 +501,32 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, cons
{
char template[MAX_CACHEPATH_SIZE + 20];
char * tmp_path;
int fd, ret;
int fd, ret, attempt;
ssize_t nwrite;

tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
strcat(tmp_path, ".tmp.XXXXXX");
for (attempt = 0; attempt < MAX_CREATE_TEMPFILE_ATTEMPT; ++attempt) {
tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
strcat(tmp_path, ".tmp.XXXXXX");

// mkstemp modifies the template to be the actual created path
fd = mkstemp(tmp_path);
if (fd < 0) {
if (mkpath(tmp_path, 0775) < 0) {
// mkstemp modifies the template to be the actual created path
fd = mkstemp(tmp_path);
if (fd > 0) break;

if (attempt == 0 && mkpath(tmp_path, 0775) < 0) {
*errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
return -1;
}
fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
if (fd < 0) {
*errno_provenance = "bs_fetch:atomic_write_cache_file:open";
return -1;
}
}
if (fd < 0) {
*errno_provenance = "bs_fetch:atomic_write_cache_file:mkstemp";
return -1;
}

if (chmod(tmp_path, 0644) < 0) {
*errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
return -1;
}

#ifdef _WIN32
setmode(fd, O_BINARY);
#endif
Expand Down

0 comments on commit cfd28c3

Please sign in to comment.