Closed
Description
On Windows 7 my incremental builds produce following warnings:
warning: Failed to garbage collect finalized incremental compilation session directory `\\?\D:\Work\<skip>\target\debug\incre
mental\<skip>-h0ku3qc8pde\s-gc3wk9dfjy-13pdd9o-11auxo9w4xmty`: The directory is not empty. (os error 145)
I tracked this issue down to a bug in std::fs::remove_dir_all()
(here). This function tries "posix delete" each file and if it fails -- falls back to "windows delete". Problem is that it does not restart enumeration in fallback -- thus first batch of filenames end up being skipped (and subsequent "delete directory" fails because dir is not empty). See this (note false
is always passed as restart parameter). Enumeration state is stored within underlying kernel object, not handle -- duplicating handle won't reset it.
I suggest ReOpenFile()
before fallback or better yet -- reuse DirBuf returned on first iteration.
$ cargo --version
cargo 1.64.0-nightly (8827baaa7 2022-07-14)
General notes:
- 1kb DirBuf used by
std::fs
is way too small (it takes about 5-10 files) -- enumerating directory with 1 mil files will take ages, I suggest 64kb (or better yet -- make it a parameter) - If you need an object model that "fits" both Posix and Win32 FS API I suggest smth like this:
- have a
Dir
object that represents "open" directory and allows access to other objects using relative path. It should also have:
fn enumerate(&self, local_path, buf_sz) -> DirEnum; <-- will call ReOpenFile() (or it's equivalent from NT API) fn enumerate_self(self, buf_sz) -> DirEnum; <-- note this consumes self (no need to ReOpenFile, just move underlying HANDLE)
- have a DirEnum object that represents open directory with active enumeration going on and has same interface plus:
fn done(&self) -> bool; fn next_batch(&self, restart: bool) -> DirEntryBatch; <-- this should use syscall(SYS_getdents) on Linux (to perform) and returned object can be empty (all entries marked as deleted) without done() being true
- have a