These changes work around a thread safety issue in our rmtree
implementation, which uses chdir to traverse the directory tree.
Using chdir resolves issues deleting paths longer than PATH_MAX, but
makes the code inherently unsafe in a threaded environment.
Now, the main rmtree function uses fork to perform the actions in a
dedicated process.
To avoid possible locking issues with the logging module, we introduce a
simple proxy logger for the subprocess.
Fixes: https://pagure.io/koji/issue/3755
For historical context see:
https://pagure.io/koji/issue/201https://pagure.io/koji/issue/2481https://pagure.io/koji/issue/2714
fixes: #2481
This approach is ugly, but just working.
ENOENT and ESTALE errors are catched in `chdir`, `listdir` calls to stomach the deletion by other process/thread
ENOTEMPTY is catched when calling `os.rmdir(path)` in `rmtree()` too. It happens when `path` is on an NFS like where ESTALE happens.
After we call listdir(), another thread or process might delete files
from the current directory. We cannot always expect lstat() to succeed
in a loop over the initial listdir entries.
If lstat() raises ENOENT, consider this file deleted and move on.
shutil.rmtree should be avoided in almost all cases
safe_rmtree has its usage in tasks module, but innards are replaced with
koji.util.rmtree, so we don't have two implementations of same task
Related: https://pagure.io/koji/issue/648