Skip to content

scp: return directory entries from the Zephyr entry walk - #1245

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_13315
Open

scp: return directory entries from the Zephyr entry walk#1245
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_13315

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Problem

The WOLFSSH_ZEPHYR branch of FindNextDirEntry() ended in while (1), discarding every entry fs_readdir() returned. It could only reach return WS_FATAL_ERROR or return WS_NEXT_ERROR — the shared return WS_SUCCESS was unreachable on Zephyr.

That function is called only from the WOLFSSH_SCP_RECURSIVE_REQUEST arm of wsScpSendCallback(), and the caller reads WS_NEXT_ERROR as end-of-directory. A peer running scp -r user@host:dir . against a Zephyr server got the directory header and an immediate exit, so every directory transferred empty. Single-file SCP was unaffected. Functional only — no overflow or leak, and the loop always terminated, since fs_readdir() signals end-of-directory with name[0] = 0.

Fix (src/wolfscp.c)

Skip . and .. and fall through to return WS_SUCCESS, matching the POSIX and Windows branches:

    } while (((WSTRLEN(ctx->entry.name) == 1) &&
              (WSTRNCMP(ctx->entry.name, ".", 1) == 0)) ||
             ((WSTRLEN(ctx->entry.name) == 2) &&
              (WSTRNCMP(ctx->entry.name, "..", 2) == 0)));

The skip is not cosmetic everywhere:

Zephyr FS Reports . / ..? Effect
FAT (ELM FatFs) No — dir_read() filters leading . Skip is a no-op
littlefs Yes — lfs_dir_read_() synthesizes both Without it, . is a directory and ScpPushDir() re-descends the same directory unboundedly

Closes f-13315.

Tests (tests/api.c)

test_wolfSSH_SCP_SendRecursiveEntry() stages a one-file directory and drives three WOLFSSH_SCP_RECURSIVE_REQUEST calls through wsScpSendCallback(), asserting enter-dir, then the entry name/size/bytes, then final exit. Driving the callback directly is the only route in — the example client cannot issue scp -r -f. It needs no threads, sockets, mkdtemp or symlinks, so unlike every other SCP test it is not gated !defined(WOLFSSH_ZEPHYR) and runs in the Zephyr CI.

Verification

  • Host make check: 8 passed, 3 skipped, 0 failed.
  • gcc-13 -Werror sweep: 6/6 configs clean.
  • Zephyr qemu_x86 (4.4.99, SDK 1.0.1), FAT RAM disk: Zephyr wolfSSH tests passed.
  • Negative controls: with while (1) restored, the Zephyr run fails at the new assertion (-1047 instead of 64 bytes); with the POSIX dot-skip disabled, it fails with -1045, having descended into ..

Not in this PR

Nested-subdirectory descent (the non-final WS_SCP_EXIT_DIR) and the empty-directory case stay uncovered — both pre-existing gaps, flagged in review and deferred.

- The WOLFSSH_ZEPHYR branch of FindNextDirEntry() loops while the
  entry name is "." or "..", matching the POSIX and Windows
  branches, in place of while (1).
- tests/api.c gains test_wolfSSH_SCP_SendRecursiveEntry(), staging a
  directory holding one file and driving three
  WOLFSSH_SCP_RECURSIVE_REQUEST calls through wsScpSendCallback(),
  checking the entry name, size, and bytes placed in buf.  dirPath
  is rooted at CONFIG_WOLFSSH_SFTP_DEFAULT_DIR under WOLFSSH_ZEPHYR
  and at "./scp_recur_entry" otherwise.
- The test is gated on WOLFSSH_SCP, with WOLFSSH_SCP_USER_CALLBACKS,
  NO_FILESYSTEM and NO_WOLFSSH_DIR unset, carries an empty stub
  otherwise, and is called from wolfSSH_ApiTest().
- scpStageRecurFile() writes that fixture file.

Issue: F-13315
@yosuke-wolfssl yosuke-wolfssl self-assigned this Sep 8, 2026
Copilot AI lite review requested due to automatic review settings September 8, 2026 06:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change corrects an unreachable-success logic path on Zephyr and adds a deterministic test that exercises the fixed behavior without introducing interface or behavioral risk elsewhere.

Pull request overview

This PR fixes recursive SCP directory traversal on Zephyr by making FindNextDirEntry() return actual directory entries (instead of looping until end-of-directory) and adds a focused API-level test to prevent regressions in Zephyr CI.

Changes:

  • Fix Zephyr FindNextDirEntry() to skip . / .. and fall through to WS_SUCCESS, aligning behavior with other platforms.
  • Add test_wolfSSH_SCP_SendRecursiveEntry() that directly drives wsScpSendCallback() through enter-dir → one file entry → final exit, including dot-entry skipping behavior.
File summaries
File Description
src/wolfscp.c Makes Zephyr directory entry walking return real entries by skipping ./.. and allowing WS_SUCCESS to be reached.
tests/api.c Adds a Zephyr-capable recursive-send callback-level test to validate directory entry iteration and completion signaling.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor Author

CI issues would be gone once PR #1242 is merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants