Skip to content

Fix LIST command parameter parsing to correctly list directory contents#24

Merged
hxcan merged 8 commits into
masterfrom
fix/list-command-parameter-parsing
Mar 31, 2026
Merged

Fix LIST command parameter parsing to correctly list directory contents#24
hxcan merged 8 commits into
masterfrom
fix/list-command-parameter-parsing

Conversation

@hxcan

@hxcan hxcan commented Mar 31, 2026

Copy link
Copy Markdown
Owner

问题描述

list_ftp_directory 工具返回空列表,但 FTP 服务器日志显示成功遍历了所有文件。

根本原因

当收到 LIST / 命令时:

  1. 参数 / 被存储在 subDirectoryName 变量中
  2. getDirectoryContentList() 方法中,条件判断:
    if (fileName.equals(nameOfFile) || nameOfFile.isEmpty())
  3. 但是 fileName"Android", "Music" 等,而 nameOfFile"/"
  4. 结果:所有文件都不匹配,全部被跳过!

修复方案

sendDirectoryList() 方法中:

  • 解析出目标目录后,检查是否是目录(而非具体文件)
  • 如果是目录,将 subDirectoryName 清空为 ""
  • 这样 nameOfFile.isEmpty() 条件就会匹配所有文件

测试步骤

  1. 合并此 PR
  2. 打新 tag(如 2026.3.39
  3. 等待 JitPack 构建完成
  4. 更新 hxftpserver 依赖到新版本
  5. 重新编译 hxftpserver APK
  6. 安装并测试 list_ftp_directory 工具

预期结果

list_ftp_directory 工具能正确返回目录列表,不再返回空数组。


关联 Issue: list_ftp_directory 工具与 ftpserver 兼容性问题

sisterfuture and others added 8 commits March 31, 2026 16:12
The issue was in getDirectoryContentList() method:
- When receiving "LIST /", the parameter "/" was stored in subDirectoryName
- The condition "fileName.equals(nameOfFile)" would never match because
  fileName is "Android", "Music", etc., but nameOfFile is "/"
- This caused all files to be skipped, resulting in empty directory listing

Fix: Check if nameOfFile is a path (starts with "/" or is empty) vs a specific
filename. If it's a path, list all files in the directory. If it's a specific
filename, only match that file.
Root cause analysis:
- When receiving "LIST /", the code stored "/" in subDirectoryName
- In getDirectoryContentList(), the condition checks if fileName equals nameOfFile
- Since fileName is "Android", "Music", etc., but nameOfFile is "/", no files match
- Result: empty directory listing

The fix:
- After resolving the target directory from the parameter, check if parameter 
  refers to a directory (not a specific file)
- If it's a directory path, set subDirectoryName to empty string to list all contents
- Only keep the parameter as subDirectoryName if it's a specific filename

This ensures "LIST /" lists all files in root, while "LIST file.txt" only lists file.txt.
This commit restores the complete file with only the necessary fixes:
1. Clear subDirectoryName when target is a directory (to list all files)
2. Add debug logging for LIST command parameter parsing
3. Keep all original methods and functionality intact
Root cause: The condition only checked for exact filename match or empty string,
but didn't handle directory paths ending with "/".

Solution: Add endsWith("/") check to the existing condition.
- "LIST /" → nameOfFile="/" → endsWith("/")=true → list all files ✅
- "LIST /Download/" → nameOfFile="/Download/" → endsWith("/")=true → list all files ✅
- "LIST file.txt" → nameOfFile="file.txt" → endsWith("/")=false → match only file.txt ✅
- "LIST" (no param) → nameOfFile="" → isEmpty()=true → list all files ✅

This is a minimal, safe fix that:
- Preserves subDirectoryName original value (no side effects)
- Supports multi-level directory paths
- Maintains backward compatibility
- Only changes the matching logic, nothing else
This reverts the previous approach of clearing subDirectoryName in sendDirectoryList().
The new minimal fix (adding endsWith("/") check) is cleaner and safer because it:
1. Preserves the original subDirectoryName value for potential future use
2. Only changes the matching logic without side effects
3. Is more maintainable and easier to understand

Now we have a single, minimal change that solves the problem correctly.
Previous commits accidentally replaced the entire file with only a small snippet.
This commit restores the FULL original file (18KB) with ONLY the minimal fix:
- Added || nameOfFile.endsWith("/") to the condition in getDirectoryContentList()
- All other code remains exactly as in master branch
This is the absolute minimal change required to fix the issue:
- Line 289: Added || nameOfFile.endsWith("/") to the existing condition
- Preserves ALL existing debug logging and functionality from master branch
- No other changes made

The fix handles:
- "LIST /" → nameOfFile="/" → endsWith("/")=true → list all files ✅
- "LIST /Download/" → nameOfFile="/Download/" → endsWith("/")=true → list all files ✅  
- "LIST file.txt" → nameOfFile="file.txt" → endsWith("/")=false → match only file.txt ✅
- "LIST" (no param) → nameOfFile="" → isEmpty()=true → list all files ✅
…imal fix

Previous commit accidentally replaced entire file with only 14 lines.
This restores the FULL file (18KB) from master branch with ONLY one change:
- Line 289: Added || nameOfFile.endsWith("/") to condition

ALL code, comments, debug logging, and functionality preserved exactly as in master.
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