Skip to content

Fix FtpAdapter listing parser swallowing entries whose name ends in ":"#1899

Open
tomsommer wants to merge 1 commit into
thephpleague:3.xfrom
tomsommer:fix/ftp-listing-colon-name
Open

Fix FtpAdapter listing parser swallowing entries whose name ends in ":"#1899
tomsommer wants to merge 1 commit into
thephpleague:3.xfrom
tomsommer:fix/ftp-listing-colon-name

Conversation

@tomsommer

Copy link
Copy Markdown

Bug

FtpAdapter::normalizeListing() treats any listing line ending in : as a recursive-listing section header (./subdir: from ls -lR). The regex ^.*:$ also matches a regular ls -l row whose filename happens to end in : — e.g. a directory literally named C::

drwxr-xr-x   2 1000 1000  4096 May 19 07:32 C:

The line is mistaken for a header, the entry is silently dropped, and \$base is set to the entire raw ls -l text. Every subsequent item in the same listing then yields with a garbage prefix like:

drwxr-xr-x   2 1000 1000  4096 May 19 07:32 C/sibling.txt

Following one of those paths back into listContents() either returns an empty list or throws InvalidListResponseReceived from the next parse.

Fix

Tighten the regex to ^\S+:$. Real recursive-listing section headers never contain whitespace (./somedir:, ./somedir/subdir:, .:); regular ls -l rows always do. Existing recursive-listing behaviour is unchanged; directories whose names end in : now round-trip correctly.

Reproducer

\$adapter = new FtpAdapter(\$options);
\$adapter->createDirectory('parent/C:', new Config());
\$contents = iterator_to_array(\$adapter->listContents('parent', false), false);
// Before: \$contents is empty.
// After:  \$contents contains a DirectoryAttributes for 'parent/C:'.

Test

Added a parser test in FtpAdapterTestCase alongside the existing receiving_a_unix_listing test, using the same mock_function('ftp_rawlist', ...) pattern.

The section-header regex `^.*:$` in FtpAdapter::normalizeListing() was
intended to catch recursive-listing headers like `./subdir:` from
`ls -lR`, but also matches a regular `ls -l` row whose filename ends
in `:` — e.g. a directory literally named `C:`:

    drwxr-xr-x   2 1000 1000  4096 May 19 07:32 C:

The entry is mistaken for a header, silently dropped, and $base is
set to the raw `ls -l` text. Every subsequent item in the same
listing then yields with a garbage prefix.

Real recursive-listing section headers never contain whitespace, so
restrict the regex to `^\S+:$`. Existing recursive-listing behaviour
is unchanged; directories whose names end in `:` now round-trip.

Adds a parser test alongside the existing receiving_a_unix_listing
test using the same mock_function('ftp_rawlist', ...) pattern.
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.

1 participant