diff --git a/packages/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences_windows/lib/shared_preferences_windows.dart index c8f53cfe..8257c53f 100644 --- a/packages/shared_preferences_windows/lib/shared_preferences_windows.dart +++ b/packages/shared_preferences_windows/lib/shared_preferences_windows.dart @@ -427,7 +427,29 @@ Future _writePreferences( staged.parent.createSync(recursive: true); } staged.writeAsStringSync(stringMap, flush: true); - staged.renameSync(localDataFile.path); + try { + staged.renameSync(localDataFile.path); + } on FileSystemException { + // PLEZY DELTA: a reader that denies delete sharing vetoes every rename + // over the document. `MoveFileExW` with MOVEFILE_REPLACE_EXISTING — and + // even a POSIX-semantics rename — fails while an open handle on the + // destination lacks FILE_SHARE_DELETE, and dart:io's own `File.open` + // produces exactly such a handle (`_wopen` shares read/write only), as + // do some antivirus and indexing services. The atomic path is not slow + // there; it is unavailable. + // + // Fall back to the upstream in-place rewrite: the sharing mode that + // blocks the rename still admits opening the document for write. This + // reintroduces the truncate window only while such a reader holds the + // store — a brief loss of crash-atomicity beats turning every + // preference write into a silent no-op on exactly the machines whose + // scanners are most likely to have damaged the store in the first + // place. + localDataFile.writeAsStringSync(stringMap, flush: true); + // The staging copy holds the whole document, credentials included, and + // was not consumed by a rename, so it must not outlive the write. + _removeStagingFile(localDataFile); + } } catch (e) { debugPrint('Error saving preferences to disk: $e'); return false;