Add exponential backoff to rmdir() on Windows

This commit is contained in:
Justine Tunney 2021-01-29 21:46:23 -08:00
parent bf8b1623c8
commit eaca5b3e81
7 changed files with 38 additions and 16 deletions

View file

@ -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)) {

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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;