From eaca5b3e81940472a78c3698ef341d553233e006 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 29 Jan 2021 21:46:23 -0800 Subject: [PATCH] Add exponential backoff to rmdir() on Windows --- libc/calls/chdir-nt.c | 5 +++-- libc/calls/hefty/dirstream.c | 6 ++---- libc/calls/rmdir-nt.c | 31 +++++++++++++++++++++++++------ libc/calls/touch.c | 1 - libc/sysv/consts.sh | 2 +- libc/sysv/consts/ENOTEMPTY.s | 2 +- libc/x/rmrf.c | 7 ++++++- 7 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libc/calls/chdir-nt.c b/libc/calls/chdir-nt.c index 36767025b..86ec65a00 100644 --- a/libc/calls/chdir-nt.c +++ b/libc/calls/chdir-nt.c @@ -25,8 +25,9 @@ textwindows int chdir$nt(const char *path) { int len; char16_t path16[PATH_MAX]; if ((len = __mkntpath(path, path16)) == -1) return -1; - if (path16[len - 1] != u'/' && path16[len - 1] != u'\\') { - path16[len + 0] = u'/'; + if (path16[len - 1] != u'\\') { + if (len + 1 + 1 > PATH_MAX) return enametoolong(); + path16[len + 0] = u'\\'; path16[len + 1] = u'\0'; } if (SetCurrentDirectory(path16)) { diff --git a/libc/calls/hefty/dirstream.c b/libc/calls/hefty/dirstream.c index 5f835e223..8632e1574 100644 --- a/libc/calls/hefty/dirstream.c +++ b/libc/calls/hefty/dirstream.c @@ -92,10 +92,8 @@ static textwindows noinline DIR *opendir$nt(const char *name) { char16_t name16[PATH_MAX]; if ((len = __mkntpath(name, name16)) == -1) return NULL; if (len + 2 + 1 > PATH_MAX) return PROGN(enametoolong(), NULL); - if (name16[len - 1] == u'/' || name16[len - 1] == u'\\') { - name16[--len] = u'\0'; - } - name16[len++] = u'/'; + while (name16[len - 1] == u'\\') name16[--len] = u'\0'; + name16[len++] = u'\\'; name16[len++] = u'*'; name16[len] = u'\0'; if (!(res = calloc(1, sizeof(DIR)))) return NULL; diff --git a/libc/calls/rmdir-nt.c b/libc/calls/rmdir-nt.c index 92ea7563f..bf2d625db 100644 --- a/libc/calls/rmdir-nt.c +++ b/libc/calls/rmdir-nt.c @@ -17,15 +17,34 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/nt/errors.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" +#include "libc/nt/synchronization.h" +#include "libc/sysv/errfuns.h" textwindows int rmdir$nt(const char *path) { - uint16_t path16[PATH_MAX]; - if (__mkntpath(path, path16) == -1) return -1; - if (RemoveDirectory(path16)) { - return 0; - } else { - return __winerr(); + int e, ms, len; + char16_t path16[PATH_MAX]; + if ((len = __mkntpath(path, path16)) == -1) return -1; + while (path16[len - 1] == u'\\') path16[--len] = u'\0'; + if (len + 2 + 1 > PATH_MAX) return enametoolong(); + for (ms = 1;; ms *= 2) { + if (RemoveDirectory(path16)) return 0; + /* + * Files can linger, for absolutely no reason. + * Possibly some Windows Defender bug on Win7. + * Sleep for up to one second w/ expo backoff. + * Alternative is use Microsoft internal APIs. + * Never could have imagined it'd be this bad. + */ + if ((e = GetLastError()) == kNtErrorDirNotEmpty && ms <= 512) { + Sleep(ms); + continue; + } else { + break; + } } + errno = e; + return -1; } diff --git a/libc/calls/touch.c b/libc/calls/touch.c index 526644341..f3b32fc14 100644 --- a/libc/calls/touch.c +++ b/libc/calls/touch.c @@ -30,6 +30,5 @@ int touch(const char *file, uint32_t mode) { int fd; if ((fd = open(file, O_CREAT | O_WRONLY, mode)) == -1) return -1; - fsync(fd); /* TODO(jart): do we need it? */ return close(fd); } diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 1acb9694d..1dd6339ed 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -63,7 +63,7 @@ syscon errno ERANGE 34 34 34 34 -1 # bsd consensus syscon errno EDEADLK 35 11 11 11 1131 # bsd consensus & kNtErrorPossibleDeadlock syscon errno ENAMETOOLONG 36 63 63 63 0x274f # bsd consensus & WSAENAMETOOLONG syscon errno ENOLCK 37 77 77 77 -1 # bsd consensus -syscon errno ENOTEMPTY 39 66 66 66 0x2752 # bsd consensus & WSAENOTEMPTY +syscon errno ENOTEMPTY 39 66 66 66 145 # bsd consensus & kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 0x2752) syscon errno ELOOP 40 62 62 62 0x274e # bsd consensus & WSAELOOP syscon errno ENOMSG 42 91 83 90 -1 syscon errno EIDRM 43 90 82 89 -1 diff --git a/libc/sysv/consts/ENOTEMPTY.s b/libc/sysv/consts/ENOTEMPTY.s index 9d069b870..d806960f0 100644 --- a/libc/sysv/consts/ENOTEMPTY.s +++ b/libc/sysv/consts/ENOTEMPTY.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon errno ENOTEMPTY 39 66 66 66 0x2752 +.syscon errno ENOTEMPTY 39 66 66 66 145 diff --git a/libc/x/rmrf.c b/libc/x/rmrf.c index 849f88f44..cbf16fd69 100644 --- a/libc/x/rmrf.c +++ b/libc/x/rmrf.c @@ -37,7 +37,12 @@ static int rmrfdir(const char *dirpath) { if (!strcmp(e->d_name, "..")) continue; if (strchr(e->d_name, '/')) abort(); path = xjoinpaths(dirpath, e->d_name); - if ((e->d_type == DT_DIR ? rmrfdir(path) : unlink(path)) == -1) { + if (e->d_type == DT_DIR) { + rc = rmrfdir(path); + } else { + rc = unlink(path); + } + if (rc == -1) { free(path); closedir(d); return -1;