Fix: Expand env vars in V2 file receive path

V2 upload to a remote directory picked via the quick-icon shortcuts
(Desktop / Downloads / Home) landed files in a literal "%USERPROFILE%"
folder instead of the real profile. The shortcuts set m_Remote_Path to an
unexpanded "%USERPROFILE%\..." template (FileManagerDlg.cpp
OnRemoteDesktop/Downloads/Home), and the V2 receive path handed that
filename straight to RecvFileChunkV2 (prebuilt FileUpload lib), which writes
it verbatim. V1 upload already expanded env vars in COMMAND_FILE_SIZE
(client/FileManager.cpp ExpandPath), so this is a V2-only regression.

Expand the filename's environment variables in CKernelManager::OnReceive's
COMMAND_SEND_FILE_V2 branch before RecvFileChunkV2, rebuilding the packet
only when the expanded length differs; other packet types pass through
unchanged.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxianganddeepseek-v4-pro committed 2026-10-08 17:56:18 +02:00
1 parent 59fead7b5f
commit c7f7b7b29b
1 file changed
+35 -1
+35 -1
View File
@@ -1488,7 +1488,41 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
s_v2RecvInited = true;
}
// C2C/V2 文件接收(RecvFileChunkV2 内部会打印进度)
int n = RecvFileChunkV2((char*)szBuffer, ulLength, m_conn,
// 展开文件名中的环境变量(如 %USERPROFILE%),与 V1 的 COMMAND_FILE_SIZE 保持一致。
// 快捷图标定位远程目录时,主控端下发的 targetDir 仍含未展开的 %USERPROFILE%
// (server/2015Remote/FileManagerDlg.cpp OnRemoteDesktop/Downloads/Home),
// 若不在接收端展开,RecvFileChunkV2 会按字面量建目录(如 CWD\%%USERPROFILE%%\...)。
char* recvBuf = (char*)szBuffer;
size_t recvLen = ulLength;
std::vector<uint8_t> rebuilt;
if (ulLength >= sizeof(FileChunkPacketV2) && szBuffer[0] == COMMAND_SEND_FILE_V2) {
const FileChunkPacketV2* pkt = (const FileChunkPacketV2*)szBuffer;
if (ulLength >= sizeof(FileChunkPacketV2) + pkt->nameLength + pkt->dataLength) {
// 文件名未必以 '\0' 结尾,先构造出以 '\0' 结尾的副本
std::string name((const char*)szBuffer + sizeof(FileChunkPacketV2), (size_t)pkt->nameLength);
char expanded[MAX_PATH * 2] = { 0 };
DWORD n = ExpandEnvironmentStringsA(name.c_str(), expanded, (DWORD)sizeof(expanded));
if (n > 0 && n < (DWORD)sizeof(expanded)) {
std::string newName(expanded, n - 1); // n 含末尾 '\0'
if (newName.size() != pkt->nameLength) {
// 展开后长度变化,重建包:[header][展开后的 name][data]
size_t newLen = sizeof(FileChunkPacketV2) + newName.size() + pkt->dataLength;
rebuilt.resize(newLen);
memcpy(rebuilt.data(), szBuffer, sizeof(FileChunkPacketV2));
FileChunkPacketV2* newPkt = (FileChunkPacketV2*)rebuilt.data();
newPkt->nameLength = newName.size();
memcpy(rebuilt.data() + sizeof(FileChunkPacketV2), newName.data(), newName.size());
memcpy(rebuilt.data() + sizeof(FileChunkPacketV2) + newName.size(),
(const char*)szBuffer + sizeof(FileChunkPacketV2) + pkt->nameLength,
(size_t)pkt->dataLength);
recvBuf = (char*)rebuilt.data();
recvLen = newLen;
}
}
}
}
int n = RecvFileChunkV2(recvBuf, recvLen, m_conn,
nullptr, m_hash, m_hmac, m_MyClientID);
if (n) {
Mprintf("[C2C] RecvFileChunkV2 failed: %d\n", n);