port, scp: distinguish end of directory from enumeration failure - #1242
Conversation
- WS_FindNextFileA_ex() takes a lastError out-parameter and carries the body of WS_FindNextFileA(), which now calls it with NULL. A failing return reports the FindNextFileW() error, or ERROR_NO_UNICODE_TRANSLATION when the name would not convert. - FindNextDirEntry() calls WS_FindNextFileA_ex() on Windows. An ERROR_NO_MORE_FILES result frees ctx->entry, sets it to NULL and returns WS_NEXT_ERROR so the caller pops the directory; every other error still returns WS_FATAL_ERROR. Issue: F-13316
- windows-sftp.yml generates an ecdsa key for testuser, authorizes it, and builds a source tree holding two files, a nested subdirectory and an empty one. - A new step pulls that tree with scp -O -r and fails unless every file and directory arrives. -O keeps OpenSSH on the legacy SCP protocol rather than SFTP. - The header comment lists the recursive SCP scenario.
There was a problem hiding this comment.
🟢 Approval recommended
The functional change correctly resolves the Windows SCP end-of-directory handling and is backed by a targeted CI regression test (only a minor doc nit noted).
Pull request overview
Fixes Windows recursive SCP (scp -r) directory enumeration by distinguishing “end of directory” (ERROR_NO_MORE_FILES) from real enumeration failures, preventing premature aborts/truncation in USE_WINDOWS_API builds.
Changes:
- Added
WS_FindNextFileA_ex()to returnGetLastError()-style detail via an out-parameter while keepingWS_FindNextFileA()’s public API unchanged. - Updated Windows
FindNextDirEntry()to translateERROR_NO_MORE_FILESintoWS_NEXT_ERRORand clearctx->entryso directory pop logic executes. - Extended Windows CI workflow to exercise legacy-protocol recursive SCP (
scp -O -r) and assert the full tree arrives (including an empty subdir).
File summaries
| File | Description |
|---|---|
wolfssh/port.h |
Declares internal WS_FindNextFileA_ex() API with lastError out-parameter. |
src/port.c |
Implements WS_FindNextFileA_ex() and keeps WS_FindNextFileA() as a wrapper for ABI stability. |
src/wolfscp.c |
Maps end-of-directory to WS_NEXT_ERROR on Windows so SCP send logic pops the directory instead of aborting. |
.github/workflows/windows-sftp.yml |
Adds a Windows recursive SCP regression test using scp -O -r and verifies the transferred tree. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1242
Scan targets checked: wolfssh-bugs, wolfssh-src
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
Problem
WS_FindNextFileA()returns0for both a real enumeration failure and the normalERROR_NO_MORE_FILESend-of-directory.FindNextDirEntry()mapped both toWS_FATAL_ERROR, which matches neither arm of the SCP send callback'sWS_SUCCESS || WS_NEXT_ERRORcheck, so the directory was never popped and the callback aborted the session instead.Any
scp -ragainst a server built withUSE_WINDOWS_API+WOLFSSH_SCPtruncates silently: entries enumerated before the first end-of-directory arrive, everything after is lost, and the only symptom is a partial tree. Recursive SCP send on Windows could never complete. POSIX builds are unaffected.Fix (
src/port.c)WS_FindNextFileA_ex()carries the body and adds alastErrorout-parameter.WS_FindNextFileA()becomes a wrapper passingNULL, so its signature andWOLFSSH_APItag are unchanged and the exported symbol keeps its contract.lastErroron a0returnERROR_NO_MORE_FILESERROR_NO_UNICODE_TRANSLATIONwcstombs_s()could not convert the nameFindNextFileW()errorThe value travels through an out-parameter rather than the return code because the return is boolean and
0already means failure, which is the value every caller tests.In
src/wolfscp.c,FindNextDirEntry()translatesERROR_NO_MORE_FILEStoWS_NEXT_ERRORand clearsctx->entry, so the caller's existingentry == NULLtest pops the directory. Every other error still returnsWS_FATAL_ERROR.Closes f-13316.
Tests (
.github/workflows/windows-sftp.yml)Windows CI already compiled this code but never ran it, and
scp-test.ymlis Linux only. A new step pulls a tree of two files, a nested subdirectory and an empty one, then fails unless all of it arrives.-Okeeps OpenSSH on the legacy SCP protocol; without it OpenSSH 9 and later transfer over SFTP and never reach this code..and...Verification
make check8 passed, 3 skipped, 0 failed.scp -O -ragainstechoserveron Windows 11: full tree, exit status 0.nested/gamma.txtnever transfers.Not covered: the two failure sentinels above are reachable only on a genuine Win32 error, which a test cannot force.