Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions rnfs/fsutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ def _temp_path(directory: str) -> str:
def write_atomic(path: str, data: bytes, *, mode: int = 0o644, durable: bool = True, exclusive: bool = False):
"""Replace path with data, so a crash or power loss leaves the old or the new file whole. Raises OSError.

data goes to a new temporary file in path's directory (O_EXCL and O_NOFOLLOW: never an existing file or
symlink, created with mode, which the umask can only narrow), synced to disk and renamed over path (retried
on Windows while path is in use); a symlink at path is replaced, not written through. If durable, the
data goes to a new temporary file in path's directory (O_EXCL, plus O_NOFOLLOW where it exists, i.e. not on
Windows: never an existing file or symlink; created with mode, which the umask can only narrow), synced to
disk and renamed over path (retried on Windows while path is in use); a symlink at path is replaced, not
written through. If durable, the
directory is then synced so the rename survives a power loss too. With exclusive, an existing path is kept
and FileExistsError raised instead. On any failure before the rename the temporary file is removed and path
is left as it was.
Expand Down
3 changes: 2 additions & 1 deletion tests/test_fsutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ def test_symlink_at_path_is_replaced_not_followed(self):
self.assertFalse(os.path.islink(self.path))
self.assert_only_file(b"new")

@unittest.skipUnless(CAN_SYMLINK, "symlinks")
# Windows has no O_NOFOLLOW, and O_EXCL there creates a dangling symlink's target (as mkstemp would)
@unittest.skipUnless(CAN_SYMLINK and fsutil.O_NOFOLLOW, "symlinks and O_NOFOLLOW")
def test_refuses_a_symlink_at_the_temporary_name(self):
# Someone able to guess the name plants a symlink there: it is neither followed nor removed
temp = os.path.join(self.tmp.name, fsutil.PARTIAL_PREFIX + "planted")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ def test_remote_pin_within_quota(self):
self.assertTrue(self.a.backend.remote_pin(IDENTITY, Cid.parse(cid), True))
source = remote_source(IDENTITY)
self.assertTrue(self.wait_for(lambda: source in self.a.storage.pins().get(Cid.parse(cid), set())))
self.assertIn(Cid.parse(cid), self.a.publisher.provided())
# The worker refreshes the publisher just after pinning
self.assertTrue(self.wait_for(lambda: Cid.parse(cid) in self.a.publisher.provided()))
self.assertTrue(self.a.backend.remote_pin(IDENTITY, Cid.parse(cid), False))
self.assertEqual(self.a.storage.pins(), {})

Expand Down
Loading