Skip to content

Commit 4dd0c77

Browse files
committed
Handle EPERM errors when opening files with O_NOATIME.
``` EPERM The O_NOATIME flag was specified, but the effective user ID of the caller did not match the owner of the file and the caller was not privileged. ```
1 parent efb56e4 commit 4dd0c77

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
* Handle `EPERM` errors when opening files with `O_NOATIME`.
4+
35
# 1.18.0
46

57
* `Bootsnap.instrumentation` now receive `:hit` events.

ext/bootsnap/bootsnap.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ static ID instrumentation_method;
9696
static VALUE sym_hit, sym_miss, sym_stale, sym_revalidated;
9797
static bool instrumentation_enabled = false;
9898
static bool readonly = false;
99+
static bool perm_issue = false;
99100

100101
/* Functions exposed as module functions on Bootsnap::CompileCache::Native */
101102
static VALUE bs_instrumentation_enabled_set(VALUE self, VALUE enabled);
@@ -119,7 +120,7 @@ static int update_cache_key(struct bs_cache_key *current_key, int cache_fd, cons
119120
static void bs_cache_key_digest(struct bs_cache_key * key, const VALUE input_data);
120121
static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
121122
static VALUE bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler);
122-
static int open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance);
123+
static int open_current_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance);
123124
static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance);
124125
static uint32_t get_ruby_revision(void);
125126
static uint32_t get_ruby_platform(void);
@@ -413,17 +414,34 @@ bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
413414

414415
return bs_precompile(path, path_v, cache_path, handler);
415416
}
417+
418+
static int bs_open_noatime(const char *path, int flags) {
419+
int fd = 1;
420+
if (!perm_issue) {
421+
fd = open(path, flags | O_NOATIME);
422+
if (fd < 0 && errno == EPERM) {
423+
errno = 0;
424+
perm_issue = true;
425+
}
426+
}
427+
428+
if (perm_issue) {
429+
fd = open(path, flags);
430+
}
431+
return fd;
432+
}
433+
416434
/*
417435
* Open the file we want to load/cache and generate a cache key for it if it
418436
* was loaded.
419437
*/
420438
static int
421-
open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance)
439+
open_current_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance)
422440
{
423441
struct stat statbuf;
424442
int fd;
425443

426-
fd = open(path, O_RDONLY | O_NOATIME);
444+
fd = bs_open_noatime(path, O_RDONLY);
427445
if (fd < 0) {
428446
*errno_provenance = "bs_fetch:open_current_file:open";
429447
return fd;
@@ -491,9 +509,9 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
491509
int fd, res;
492510

493511
if (readonly) {
494-
fd = open(path, O_RDONLY | O_NOATIME);
512+
fd = bs_open_noatime(path, O_RDONLY);
495513
} else {
496-
fd = open(path, O_RDWR | O_NOATIME);
514+
fd = bs_open_noatime(path, O_RDWR);
497515
}
498516

499517
if (fd < 0) {

0 commit comments

Comments
 (0)