cstamigo-droid opened a new pull request, #801: URL: https://github.com/apache/commons-vfs/pull/801
https://issues.apache.org/jira/browse/VFS-865 `SftpFileObject` passes decoded paths to `ChannelSftp`. JSch expands `*` and `?` in the last path component (backslash is its escape character), so a file whose name contains them is treated as a glob pattern. Deleting a listed `a*.txt` also deletes `abc.txt`. Resolving the missing `del?.txt` matches `delA.txt`, which `delete()` then removes. Read, write and rename fail with `is not unique`. Listing a folder named `d*` returns its siblings. Separately, `doListChildrenResolved()` encodes child names with `UriParser.encode(name)`, which only escapes `%`. A child named `v2?final.txt` is then parsed as `v2` plus a query string. Changes in `SftpFileObject`: - New `escapeGlob(String)` escapes `\`, `*` and `?` with a backslash. It is applied to the paths given to `rm`, `rmdir`, `stat`, `get` (both call sites), `put`, `ls`, `cd`, `rename` (both paths) and `setStat`. These are the `ChannelSftp` methods that expand wildcards and unquote the result. `mkdir` does neither, so its path is left as is. - Child names are encoded with `UriParser.encode(name, {'?'})`. This matches `URLFileNameParser.encodeCharacter()`, so `getName().getBaseName()` returns `v2%3Ffinal.txt`, the same way a name with `%` is returned as `%25`. Tests: new `SftpFileNameWildcardTest` uses the embedded server. Eight of its tests fail on master and pass with this change: delete a file, delete an empty folder named `d*` (on master it looks non-empty and is not deleted), resolve, list with `?`, read, write, rename, and list a folder named `d*`. The ninth test covers `escapeGlob`. The class is disabled on Windows, where file names cannot contain `*` or `?`. Behaviour I checked in the JSch sources (0.1.55 and `com.github.mwiede:jsch` 2.28.7, same code paths): `rm`, `rmdir` and `setStat` act on every match. `stat`, `get`, `put`, `cd` and the source of `rename` require exactly one match. `ls` and the target of `rename` glob and unquote. Paths without these characters reach the server unchanged. Behaviour change: code that relied on VFS passing wildcards through to JSch, for example `resolveFile("…/*.log").delete()` to delete every log file, now operates on the file literally named `*.log`. The documented way to match wildcards in VFS is `WildcardFileFilter` with `findFiles()`, which matches on the client side. Server-side expansion through JSch is undocumented, so I treated it as a bug. I can add a `changes.xml` entry if you want one. `mvn` (default goal) passes locally on Linux with Java 21. I also re-ran the downstream reproduction from the ticket with a jar built from this branch (Kestra plugin-fs, `atmoz/sftp`): only the named files are deleted, and the files literally named `del?.csv` and `b*.csv` can now be deleted. AI disclosure, per the [ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html): I used Claude (Anthropic) through Claude Code to investigate the JSch sources, write the change and the tests, and draft this description. I reviewed and ran everything, and the commit carries a `Co-Authored-By` trailer. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
