fix: validate upload date, close upload races (REQ-178)
This commit is contained in:
1 parent
712cdeabf1
commit
92360660c7
1 file changed
+19
-4
+19
-4
@@ -104,13 +104,17 @@ class LibraryConflict(LibraryError):
|
||||
|
||||
|
||||
def create_date(video_root: str, date: str) -> str:
|
||||
"""Make a YYYY-MM-DD folder; never touch an existing one (REQ-171)."""
|
||||
"""Make a YYYY-MM-DD folder; never touch an existing one (REQ-178)."""
|
||||
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", date):
|
||||
raise LibraryError("Folder name must be YYYY-MM-DD")
|
||||
folder = _safe_join(_effective_root(video_root), date)
|
||||
if os.path.exists(folder):
|
||||
raise LibraryConflict(f"Folder already exists: {date}")
|
||||
os.makedirs(folder)
|
||||
try:
|
||||
os.makedirs(folder)
|
||||
except FileExistsError:
|
||||
# Lost the race against a concurrent mkdir; same 409 as above.
|
||||
raise LibraryConflict(f"Folder already exists: {date}")
|
||||
return folder
|
||||
|
||||
|
||||
@@ -119,6 +123,8 @@ def upload_video(video_root: str, date: str, filename: str, chunks) -> str:
|
||||
name = os.path.basename(filename or "")
|
||||
if not name or name != filename or not name.lower().endswith(video.VIDEO_EXTS):
|
||||
raise LibraryError(f"Unsupported file: {filename}")
|
||||
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", date):
|
||||
raise LibraryError("Folder name must be YYYY-MM-DD")
|
||||
root = _effective_root(video_root)
|
||||
if not os.path.isdir(_safe_join(root, date)):
|
||||
raise LibraryError(f"No such date in the archive: {date}")
|
||||
@@ -127,13 +133,22 @@ def upload_video(video_root: str, date: str, filename: str, chunks) -> str:
|
||||
raise LibraryConflict(f"Already exists: {date}/{name}")
|
||||
part = dest + ".part"
|
||||
try:
|
||||
with open(part, "wb") as handle:
|
||||
fd = os.open(part, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
|
||||
except FileExistsError:
|
||||
raise LibraryConflict(f"Already exists: {date}/{name}")
|
||||
try:
|
||||
with os.fdopen(fd, "wb") as handle:
|
||||
for chunk in chunks:
|
||||
handle.write(chunk)
|
||||
if os.path.exists(dest):
|
||||
raise LibraryConflict(f"Already exists: {date}/{name}")
|
||||
os.replace(part, dest)
|
||||
except BaseException:
|
||||
if os.path.exists(part):
|
||||
os.unlink(part)
|
||||
try:
|
||||
os.unlink(part)
|
||||
except OSError:
|
||||
pass
|
||||
raise
|
||||
return f"{date}/{name}"
|
||||
|
||||
|
||||
Reference in new issue
Block a user