Repository navigation
Conversation
Treat Windows error code 145 (ERROR_DIR_NOT_EMPTY) as a transient lock in ErrorHandlingFileSystem so recursive directory deletions (such as .plugin_symlinks during tooling setup or pub get) retry with exponential backoff when a child file is held in a delete-pending state or locked by background processes. If retries are exhausted, map it to a user-friendly ToolExit rather than crashing the tool. Fixes flutter#193358
… deletes - In ErrorHandlingDirectory.delete and deleteSync, add kSystemCodeDirNotEmpty to ignoreErrorCodes when recursive is false, preserving raw FileSystemException behavior for non-recursive directory deletions. - Assert attemptsLeft == 0 in retry-exhaustion test to verify full retry count. - Add regression test ensuring non-recursive directory deletions do not retry. - Use kSystemCodeDirNotEmpty named constant in all tests. - Maintain numeric ordering for error code constants.
There was a problem hiding this comment.
Code Review
This pull request introduces handling for the Windows error code 145 ('ERROR_DIR_NOT_EMPTY') during directory deletion in 'ErrorHandlingDirectory'. The error is treated as a transient lock, enabling retry attempts during recursive deletions, and is mapped to an error message indicating that the file is being used by another program. Additionally, unit tests are added to verify synchronous and asynchronous retry behavior, failure after maximum attempts, and that non-recursive deletions do not trigger retries. No review comments were provided, and there is no additional feedback.
Extract `createFileSystemWithTransientErrors` helper in `error_handling_io_test.dart` to eliminate duplicated `MemoryFileSystem.test` setup across transient lock retry tests.
mattkae
left a comment
There was a problem hiding this comment.
A question, but looks good overall
| '\n$e\n' | ||
| 'Free up space and try again.', | ||
| kSharingViolation || kLockViolation || kUserMappedSectionOpened => | ||
| kSharingViolation || kLockViolation || kUserMappedSectionOpened || kDirNotEmpty => |
There was a problem hiding this comment.
Should kDirNotEmpty give a different error message, maybe saying that the directory isn't empty so we couldn't make the deletion?
Treat Windows error code
145(ERROR_DIR_NOT_EMPTY) as a transient lock during recursive directory deletions inErrorHandlingFileSystem.On Windows NTFS, recursive directory deletion (such as cleaning up
.plugin_symlinksduringflutter pub getorcreatePluginSymlinks) requires deleting all child entries before removing the parent directory. When a child file is deleted while held open withFILE_SHARE_DELETEby background software (such as an antivirus scanner or search indexer), it enters a delete-pending state and is not immediately unlinked. Attempting to remove the parent directory before the child handle closes fails with Win32 error145(ERROR_DIR_NOT_EMPTY).This change:
kSystemCodeDirNotEmpty = 145to_isWindowsTransientLockso recursive directory deletions automatically retry up to 5 times with exponential backoff (50ms, 100ms, 200ms, 400ms, 800ms).if (!recursive) kSystemCodeDirNotEmptytoignoreErrorCodesinErrorHandlingDirectory.deleteanddeleteSyncso non-recursive deletions on non-empty directories continue to rethrowFileSystemExceptionimmediately without retrying.kDirNotEmptyin_handleWindowsExceptionto a user-friendlyToolExitmessage if all retries are exhausted.Fixes #193358
Pre-launch Checklist
///).