wine下目前不支持smb下拷贝,目前遇到wine下某应用启动后升级需要拷贝目标smb文件至指定文件夹中
问题概述
启动升级失败,现象如下图
升级流程
与应用厂商沟通发现该应用升级首先调用
WNetAddConnection2A
函数wine启动增加mpr日志通道,日志输出如下,发现该函数调用三次
WNetAddConnection2: 函数与网络资源建立连接,并且可以将本地设备重定向到网络资源。在该流程中此函数是建立与smb的服务器连接,从而访问服务器文件。
学习wine下源码,发现该函数在
if (!providerTable || providerTable->numProviders == 0)
判断时已返回,而providerTable
是在wnetInit
函数中进行初始化,源码大致如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
DWORD size = 0;
RegQueryValueExW(hKey, L"ProviderOrder", NULL, NULL, NULL, &size);
if (size)
{
......
providerTable =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(WNetProviderTable)
+ (numToAllocate - 1) * sizeof(WNetProvider));
......
}打开wine下注册表发现
System\\CurrentControlSet\\Control\\NetworkProvider\\Order\\NetworkProvider
缺失,从window下注册表发现该项中LanmanWorkstation
这项存在,- LanmanWorkstation 是 Windows 操作系统中的一个服务,正式名称为 Workstation 服务。它的主要功能是管理客户端与网络资源(如文件共享和打印机共享)的连接。具体来说,Workstation 服务负责处理与 SMB(Server Message Block)协议相关的操作,使客户端能够访问远程服务器上的共享资源。
- LanmanWorkstation 是 Windows 操作系统中的一个服务,正式名称为 Workstation 服务。它的主要功能是管理客户端与网络资源(如文件共享和打印机共享)的连接。具体来说,Workstation 服务负责处理与 SMB(Server Message Block)协议相关的操作,使客户端能够访问远程服务器上的共享资源。
将该注册表与相关dll导入至wine容器中,发现无法启动报错。
调研开发原生的wine下smb服务实现时间较长,不符合现场项目速度要求,所以尝试其他快速平替方案,暂时将该函数不返回错误码,代码如下:
1
2
3
4
5
6
7
8
9
10@@ -2183,6 +2183,9 @@ DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
accessname, buffer_size, result );
+ if(userid && !strcmp(userid, "ZEMR_USER")){
+ return 0;
+ }
netresource_a_to_w(resource, &resourceW);
ctxt.hwndOwner = hwndOwner;在wine启动时增加file日志通道,发现升级时访问路径
\\192.0.1.80\\nurse.update时
,在wine中替换为UNC\\192.0.1.80\\nurse.update
路径- 在 Windows 系统中,UNC(Universal Naming Convention,通用命名约定) 是一种用于标识网络资源的标准化路径格式。UNC 路径通常用于访问网络共享资源,例如文件共享或打印机。
- UNC 路径的基本格式如下:\ServerName\ShareName\Path
具体方案
根据上述流程分析可以暂定一个方案,可以在系统开机时将目标服务器文件挂载至容器中,在wine中代码将
UNC+服务器地址
路径转换为本地路径中,细节交互图如下:由于mount必须提权才可挂载,所以需要使用自启动的server文件,才能对智业smb服务器下文件进行访问,该服务器需要在系统的
smbd
服务启动后才可启动,细节如下:1
2
3
4
5
6
7
8
9
10
11
12
13[Unit]
Description=mount zhiye smb file
After=smbd.service network.target
Requires=smbd.service
[Service]
ExecStart=/usr/sbin/mount_zhiyesmb.sh
Restart=on-failure
User=root
RestartSec=5s
[Install]
WantedBy=multi-user.target对于wine下代码修改如下,当检测到
192.0.1.80
路径时替换至容器路径,将开机字自启动的挂载目录软连接到容器中即可成功访问1
2
3
4
5
6
7
8
9
10
11
12
13
14
15@@ -272,8 +274,12 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U
switch (RtlDetermineDosPathNameType_U(ptr))
{
case UNC_PATH: /* \\foo */
- offset = 2;
+ offset = 2;
+ if(wcsstr(ptr,L"192.0.1.80")) {
+ wcscat(ntpath->Buffer, L"C:\\");
+ }else {
wcscat(ntpath->Buffer, L"UNC\\");
+ }
break;
case DEVICE_PATH: /* \\.\foo */
offset = 4;
--
验证
修改后启动后升级效果图如下:
其他方案
- 方案1:完成wine下的Workstation服务,让其支持容器下的smb连接
- 优点:能够完整的符合window逻辑,实现smb服务的启动与访问。
- 缺点:难度较大,实现时间较长。
- 方案2:在wine下访问unc路径时,使用C实现SMB下的文件夹访问/读取/拷贝
- 优点:难度中等,属于方案1的平替方案,可以间接补充wine下smb文件访问的代码,完成后有一定的代码通用性。
- 缺点:与window下的smb服务逻辑有出入,未实现window下的smb服务启动。