Work around copy_file_range() bug in eCryptFs

When programs like ar.ape and compile.ape are run on eCryptFs partitions
on Linux, copy_file_range() will fail with EINVAL which is wrong because
eCryptFs which doesn't support this system call, should raise EOPNOTSUPP

See https://github.com/jart/cosmopolitan/discussions/1305
This commit is contained in:
Justine Tunney 2024-09-29 16:31:48 -07:00
parent 12cc2de22e
commit fef24d622a
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
5 changed files with 9 additions and 3 deletions

View file

@ -83,9 +83,11 @@ static void copy_file_range_init(void) {
* @return number of bytes transferred, or -1 w/ errno * @return number of bytes transferred, or -1 w/ errno
* @raise EXDEV if source and destination are on different filesystems * @raise EXDEV if source and destination are on different filesystems
* @raise EBADF if `infd` or `outfd` aren't open files or append-only * @raise EBADF if `infd` or `outfd` aren't open files or append-only
* @raise EOPNOTSUPP if filesystem doesn't support this operation
* @raise EPERM if `fdout` refers to an immutable file on Linux * @raise EPERM if `fdout` refers to an immutable file on Linux
* @raise ECANCELED if thread was cancelled in masked mode * @raise ECANCELED if thread was cancelled in masked mode
* @raise EINVAL if ranges overlap or `flags` is non-zero * @raise EINVAL if ranges overlap or `flags` is non-zero
* @raise EINVAL on eCryptFs filesystems that have a bug
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded * @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
* @raise EFAULT if one of the pointers memory is bad * @raise EFAULT if one of the pointers memory is bad
* @raise ERANGE if overflow happens computing ranges * @raise ERANGE if overflow happens computing ranges

View file

@ -424,7 +424,6 @@ textwindows void __sig_generate(int sig, int sic) {
(1ull << (sig - 1))) { (1ull << (sig - 1))) {
return; return;
} }
BLOCK_SIGNALS;
_pthread_lock(); _pthread_lock();
for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) { for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) {
pt = POSIXTHREAD_CONTAINER(e); pt = POSIXTHREAD_CONTAINER(e);
@ -462,7 +461,6 @@ textwindows void __sig_generate(int sig, int sic) {
atomic_fetch_or_explicit(__sig.process, 1ull << (sig - 1), atomic_fetch_or_explicit(__sig.process, 1ull << (sig - 1),
memory_order_relaxed); memory_order_relaxed);
} }
ALLOW_SIGNALS;
} }
static textwindows char *__sig_stpcpy(char *d, const char *s) { static textwindows char *__sig_stpcpy(char *d, const char *s) {

View file

@ -32,6 +32,7 @@
* if the thread called pthread_exit(), or `PTHREAD_CANCELED` if * if the thread called pthread_exit(), or `PTHREAD_CANCELED` if
* pthread_cancel() destroyed the thread instead * pthread_cancel() destroyed the thread instead
* @return 0 on success, or errno on error * @return 0 on success, or errno on error
* @raise EBUSY if thread has not yet terminated
* @raise ECANCELED if calling thread was cancelled in masked mode * @raise ECANCELED if calling thread was cancelled in masked mode
* @cancelationpoint * @cancelationpoint
* @returnserrno * @returnserrno

View file

@ -298,6 +298,7 @@ static void CopyFileOrDie(const char *inpath, int infd, //
if (got != -1) { if (got != -1) {
exchanged = got; exchanged = got;
} else if (errno == EXDEV || // different partitions } else if (errno == EXDEV || // different partitions
errno == EINVAL || // possible w/ ecryptfs
errno == ENOSYS || // not linux or freebsd errno == ENOSYS || // not linux or freebsd
errno == ENOTSUP || // probably a /zip file errno == ENOTSUP || // probably a /zip file
errno == EOPNOTSUPP) { // technically the same errno == EOPNOTSUPP) { // technically the same

View file

@ -798,7 +798,11 @@ bool MovePreservingDestinationInode(const char *from, const char *to) {
rc = copy_file_range(fdin, 0, fdout, 0, remain, 0); rc = copy_file_range(fdin, 0, fdout, 0, remain, 0);
if (rc != -1) { if (rc != -1) {
remain -= rc; remain -= rc;
} else if (errno == EXDEV || errno == ENOSYS) { } else if (errno == EXDEV || // different partitions
errno == EINVAL || // possible w/ ecryptfs
errno == ENOSYS || // not linux or freebsd
errno == ENOTSUP || // no fs support for it
errno == EOPNOTSUPP) {
if (lseek(fdin, 0, SEEK_SET) == -1) { if (lseek(fdin, 0, SEEK_SET) == -1) {
res = false; res = false;
break; break;