diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/executor/common.h b/executor/common.h index b98dd3fc1..9cd92983f 100644 --- a/executor/common.h +++ b/executor/common.h @@ -244,6 +244,19 @@ static void use_temporary_dir(void) #include <sys/stat.h> #include <sys/types.h> +#if GOOS_freebsd +// Unset file flags which might inhibit unlinking. +static void reset_flags(const char* filename) +{ + struct stat st; + if (lstat(filename, &st)) + exitf("lstat(%s) failed", filename); + st.st_flags &= ~(SF_NOUNLINK | UF_NOUNLINK | SF_IMMUTABLE | UF_IMMUTABLE); + if (lchflags(filename, st.st_flags)) + exitf("lchflags(%s) failed", filename); +} +#endif + // We need to prevent the compiler from unrolling the while loop by using the gcc's noinline attribute // because otherwise it could trigger the compiler warning about a potential format truncation // when a filename is constructed with help of snprintf. This warning occurs because by unrolling @@ -280,12 +293,28 @@ static void __attribute__((noinline)) remove_dir(const char* dir) remove_dir(filename); continue; } - if (unlink(filename)) + if (unlink(filename)) { +#if GOOS_freebsd + if (errno == EPERM) { + reset_flags(filename); + if (unlink(filename) == 0) + continue; + } +#endif exitf("unlink(%s) failed", filename); + } } closedir(dp); - if (rmdir(dir)) + while (rmdir(dir)) { +#if GOOS_freebsd + if (errno == EPERM) { + reset_flags(dir); + if (rmdir(dir) == 0) + break; + } +#endif exitf("rmdir(%s) failed", dir); + } } #endif #endif |
