99from __future__ import annotations
1010
1111import copy
12+ import errno
1213import hashlib
1314import json
1415import os
@@ -102,23 +103,46 @@ def _load_core_command_names() -> frozenset[str]:
102103CORE_COMMAND_NAMES = _load_core_command_names ()
103104
104105
106+ def _fsync_fd (fd : int ) -> None :
107+ """Sync a file descriptor, raising on real storage errors."""
108+ try :
109+ os .fsync (fd )
110+ except AttributeError :
111+ return
112+ except NotImplementedError :
113+ return
114+ except OSError as exc :
115+ if exc .errno in {errno .ENOTSUP , errno .EOPNOTSUPP , errno .EINVAL , errno .EBADF }:
116+ return
117+ raise
118+
119+
105120def _fsync_directory (path : Path ) -> None :
106- """Best-effort fsync for a directory path ."""
121+ """Sync a directory when the platform supports it ."""
107122 if not path .exists ():
108123 return
109124 try :
110125 dir_fd = os .open (str (path ), os .O_RDONLY | getattr (os , "O_DIRECTORY" , 0 ))
111- except (AttributeError , OSError , NotImplementedError ):
126+ except (AttributeError , NotImplementedError ):
127+ return
128+ except OSError as exc :
129+ if exc .errno in {errno .ENOTSUP , errno .EOPNOTSUPP , errno .EINVAL , errno .EBADF }:
130+ return
112131 try :
113132 dir_fd = os .open (str (path ), os .O_RDONLY )
114- except (AttributeError , OSError , NotImplementedError ):
133+ except (AttributeError , NotImplementedError ):
115134 return
135+ except OSError as exc2 :
136+ if exc2 .errno in {errno .ENOTSUP , errno .EOPNOTSUPP , errno .EINVAL , errno .EBADF }:
137+ return
138+ raise
116139 try :
117- os .fsync (dir_fd )
118- except (AttributeError , OSError , NotImplementedError ):
119- pass
140+ _fsync_fd (dir_fd )
120141 finally :
121- os .close (dir_fd )
142+ try :
143+ os .close (dir_fd )
144+ except OSError :
145+ pass
122146
123147
124148class ExtensionError (Exception ):
@@ -1515,10 +1539,7 @@ def install_from_directory(
15151539 staged .chmod (stat .S_IMODE (mode ))
15161540 except (NotImplementedError , OSError ):
15171541 pass # Best-effort; chmod may not be supported on all platforms.
1518- try :
1519- os .fsync (fd )
1520- except (AttributeError , OSError , NotImplementedError ):
1521- pass
1542+ _fsync_fd (fd )
15221543 finally :
15231544 os .close (fd )
15241545 # Write the completion marker only after every staged file is
@@ -1529,9 +1550,7 @@ def install_from_directory(
15291550 0o600 ,
15301551 )
15311552 try :
1532- os .fsync (marker_fd )
1533- except (AttributeError , OSError , NotImplementedError ):
1534- pass
1553+ _fsync_fd (marker_fd )
15351554 finally :
15361555 os .close (marker_fd )
15371556 _fsync_directory (rescue_staging_dir )
@@ -1566,11 +1585,27 @@ def _restore_stranded_config_file(
15661585 ) as tmp :
15671586 tmp_path = Path (tmp .name )
15681587 tmp .write (content )
1588+ tmp .flush ()
1589+ _fsync_fd (tmp .fileno ())
15691590 try :
15701591 tmp_path .chmod (stat .S_IMODE (preserved_mode ))
15711592 except (NotImplementedError , OSError ):
15721593 pass # Best-effort; chmod may not be supported on all platforms.
15731594 os .replace (tmp_path , target )
1595+ try :
1596+ target_fd = os .open (str (target ), os .O_RDONLY )
1597+ except (AttributeError , OSError , NotImplementedError ):
1598+ target_fd = None
1599+ try :
1600+ if target_fd is not None :
1601+ _fsync_fd (target_fd )
1602+ finally :
1603+ if target_fd is not None :
1604+ try :
1605+ os .close (target_fd )
1606+ except OSError :
1607+ pass
1608+ _fsync_directory (target .parent )
15741609 except BaseException :
15751610 if tmp_path is not None and tmp_path .exists ():
15761611 tmp_path .unlink ()
0 commit comments