mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-11 17:00:22 +00:00
fix(sftp): omit stale listing size after re-stat failure
When source re-stat fails, clear child totalBytes/mtime so startStreamTransfer omits an explicit snapshot and the bridge re-stats on the dedicated session instead of truncating to the stale listing size. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
This commit is contained in:
3 files changed
+26
-3
No files matched your search
@@ -111,6 +111,8 @@ test("transferDiscoveredFiles does not skip when source re-stat fails", async ()
|
||||
} as MutableRefObject<Map<string, Set<string>>>;
|
||||
let transfers = transfersRef.current;
|
||||
let transferCalls = 0;
|
||||
let transferredTotalBytes: number | undefined;
|
||||
let transferredSourceLastModified: number | undefined;
|
||||
const mtime = 1_700_000_000_000;
|
||||
|
||||
await transferDiscoveredFiles({
|
||||
@@ -140,8 +142,10 @@ test("transferDiscoveredFiles does not skip when source re-stat fails", async ()
|
||||
},
|
||||
waitWhileTransferPaused: async () => {},
|
||||
isPauseLatched: () => false,
|
||||
transferFile: async () => {
|
||||
transferFile: async (task) => {
|
||||
transferCalls += 1;
|
||||
transferredTotalBytes = task.totalBytes;
|
||||
transferredSourceLastModified = task.sourceLastModified;
|
||||
},
|
||||
tryStatTarget: async () => ({
|
||||
size: 10,
|
||||
@@ -152,6 +156,12 @@ test("transferDiscoveredFiles does not skip when source re-stat fails", async ()
|
||||
});
|
||||
|
||||
assert.equal(transferCalls, 1, "missing fresh source meta must not skip");
|
||||
assert.equal(transferredTotalBytes, 0, "must not pass stale listing size after re-stat failure");
|
||||
assert.equal(
|
||||
transferredSourceLastModified,
|
||||
undefined,
|
||||
"must clear stale listing mtime after re-stat failure",
|
||||
);
|
||||
});
|
||||
|
||||
test("transferDiscoveredFiles skips only when fresh source still matches", async () => {
|
||||
|
||||
@@ -147,6 +147,12 @@ export async function transferDiscoveredFiles(
|
||||
lastModified: skipSourceLastModified,
|
||||
});
|
||||
freshSourceOk = true;
|
||||
} else {
|
||||
// Do not pass stale pre-scan size as an explicit snapshot (Codex P2).
|
||||
// Child totalBytes 0 is omitted at startStreamTransfer via `|| undefined`,
|
||||
// so the dedicated transfer session re-stats the source itself.
|
||||
skipSourceSize = 0;
|
||||
skipSourceLastModified = 0;
|
||||
}
|
||||
}
|
||||
if (skipUnchanged && !file.isSymlink && freshSourceOk) {
|
||||
@@ -224,7 +230,7 @@ export async function transferDiscoveredFiles(
|
||||
progressMode: "bytes",
|
||||
parentTaskId: rootTaskId,
|
||||
totalBytes: skipSourceSize,
|
||||
sourceLastModified: skipSourceLastModified,
|
||||
sourceLastModified: skipSourceLastModified || undefined,
|
||||
directoryEntryIndex,
|
||||
directoryEntryIdentity,
|
||||
retryable: rootTask.retryable,
|
||||
|
||||
@@ -895,6 +895,13 @@ export function useSftpDirectoryTransferOps({
|
||||
lastModified: transferLastModified,
|
||||
});
|
||||
freshSourceOk = true;
|
||||
} else {
|
||||
// Do not pass stale listing size as an explicit snapshot: the
|
||||
// dedicated transfer session may still read a grown file (Codex P2).
|
||||
// Child totalBytes 0 is omitted at startStreamTransfer via
|
||||
// `|| undefined`, so the bridge re-stats instead of truncating.
|
||||
transferSize = 0;
|
||||
transferLastModified = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -984,7 +991,7 @@ export function useSftpDirectoryTransferOps({
|
||||
progressMode: "bytes",
|
||||
parentTaskId: rootTaskId,
|
||||
totalBytes: transferSize,
|
||||
sourceLastModified: transferLastModified,
|
||||
sourceLastModified: transferLastModified || undefined,
|
||||
directoryEntryIndex,
|
||||
directoryEntryIdentity,
|
||||
// Inherit retryable from parent - downloadToLocal sets retryable: false
|
||||
|
||||
Reference in new issue
Block a user