mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 04:53:52 -06:00
fix: pin the large file inode just verified
_pin_verified returned an existing <sha1>/<name> link without checking its inode. A link whose cache name was gone had one link left, and the prune of the same download removed it after it was returned, so fetch_large_file handed out a path that no longer existed. The link is now replaced when it holds another inode, and a revision directory a prune removed before the link is made again.
This commit is contained in:
1 parent
0ec99cc771
commit
64ed86cd5f
2 files changed
+55
-15
No files matched your search
+25
-15
@@ -250,23 +250,33 @@ def _pin_verified(
|
||||
passed off as the one verified. None when the name moved in between.
|
||||
"""
|
||||
revision = os.path.join(dest_dir, VERIFIED_STORE, snapshot[0]["sha1"])
|
||||
os.makedirs(revision, exist_ok=True)
|
||||
final = os.path.join(revision, name)
|
||||
if os.path.isfile(final):
|
||||
return final
|
||||
scratch = os.path.join(revision, f".{os.getpid()}.{os.urandom(4).hex()}.tmp")
|
||||
try:
|
||||
os.link(path, scratch)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
try:
|
||||
if os.stat(scratch).st_ino != snapshot[2]:
|
||||
return None
|
||||
os.replace(scratch, final)
|
||||
return final
|
||||
finally:
|
||||
# A prune removes an empty revision directory: one that went between
|
||||
# makedirs and link is made again, once.
|
||||
for _attempt in range(2):
|
||||
os.makedirs(revision, exist_ok=True)
|
||||
# The link must hold the inode just verified. An older link left by a
|
||||
# copy that lost its cache name has one link left, and the prune of
|
||||
# this very download removed it after it was returned.
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.unlink(scratch)
|
||||
if os.stat(final).st_ino == snapshot[2]:
|
||||
return final
|
||||
scratch = os.path.join(revision, f".{os.getpid()}.{os.urandom(4).hex()}.tmp")
|
||||
try:
|
||||
os.link(path, scratch)
|
||||
except FileNotFoundError:
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
continue
|
||||
try:
|
||||
if os.stat(scratch).st_ino != snapshot[2]:
|
||||
return None
|
||||
os.replace(scratch, final)
|
||||
return final
|
||||
finally:
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
os.unlink(scratch)
|
||||
return None
|
||||
|
||||
|
||||
def _prune_verified(dest_dir: str) -> None:
|
||||
|
||||
Reference in new issue
Block a user