我有一个在 Windows VirtualBox VM 上运行的程序,并将数据存储在特定文件夹中。我想从这个文件夹到 Linux 服务器上的目录建立类似符号链接的东西,但我还没有想出可行的解决方案。我尝试将 Linux 文件夹结构映射到驱动器号,然后从“原始”Windows 文件夹到映射到驱动器号的文件夹建立连接,但 Windows 不允许我完成链接。我还尝试使用 SFTP 连接 Linux 目录,但也没有成功。
答案1
这是我所做的。
首先,我在 Linux 机器上安装了 SAMBA,并共享了我想要使用的驱动器。(这是一个完全不同的话题,但你可以找到很多关于如何做到这一点的描述。)
然后,在 Windows 框上,我创建了下面的 Python 3 类来建立链接。
它还可用于创建到 Windows 共享的链接。
但简短的回答是 - 在 Linux 机器上创建共享并在命令提示符中使用 mklink 创建符号链接。
警告:此代码仅用于概念验证。它尚在开发中,尚未完成。我并不认为这是最好的代码,甚至不是好的代码。
"""
@Author: J. Michael Adams
Please cite the author's name if you use any of this code.
Creates symlinks for share folders
It places all the symlinks in a local folder. The test code defines that folder
as C:\share_symlinks.
NOTE -
This program uses the "mklink" command of the Windows command shell.
That command normally requires elevated administrator privilege.
That requirement can be changed using the "secpol.msc" console under
Security Settings > Local Policies > User Rights Assignment > create symbolic links
It pipes in a list of shares from the "net view" command.
Each output line from net view has this format: share-name "Disk" other-info
If it does not contain " Disk ", then it does not have a share name.
We want to create a symlink for each share.
The links will be created in a particular directory.
You can specify a list of share names that will be excluded - that is, they will
not be linked to. A name can can contain wildcards.
Any share name that matches a name in the exclude list will be ignored.
"""
#TODO: create a config file: excludes, link_dir, remote_drive, notify always, email parms
#TODO: check the permission level
#TODO: check the value of comspec
#TODO: remove obsolete links - links that have the proper remote_drive
#TODO: create an email object for notification
#TODO: create an exception that emails a notification
import os
import subprocess
class LinkManager(object):
def __init__(self, remote_drive):
self.remote_drive = remote_drive
self.share_paths = {} # share_paths[share name] => full path to share
self.new_links = {}
self.all_links = {}
self.bad_links = {}
def get_shares(self, excludes=None):
""" returns a dict: key = share name, value = full path to the share
"""
import fnmatch
if type(excludes) is not list:
if excludes is None:
excludes = []
elif type(excludes) is str:
excludes = [excludes]
else:
raise Exception
# Always exclude shares that end with '$'. These are administrative shares in Windows.
excludes.append('*$')
# We want to ignore case when we compare strings in the excludes list.
# So we'll convert all share names to lower case.
excludes = [x.lower() for x in excludes]
## call net view for the share drive. This might produce "access denied".
# http://stackoverflow.com/questions/3005437/windowserror-error-5-access-is-denied
cmd = "net view {} /all".format(remote_drive)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=True, universal_newlines=True)
(out, err) = proc.communicate()
if err:
return out, err #TODO: should be an exception
## get the output of the command and parse the share names
# we'll convert all lines to lower case.
# Since this is Windows, file names are case insensitive.
# We do this so we can compare to the lower case names in the exclude list.
lines = out.lower().split('\n')
for line in lines:
# search for " disk " surrounded by a space, in case "disk" is a share name.
if " disk " not in line:
continue
share = line.split(' disk ')[0].strip()
# Check the share name against the exclude list.
# The list can have names with wildcards ('*' and '?'),
# so we'll use fnmatch() to check it.
found = False
for exclude in excludes:
if fnmatch.fnmatch(share, exclude):
found = True
break
if found:
continue
self.share_paths[share] = os.path.join(remote_drive, share)
return '', ''
def make_links(self, link_dir):
"""
link_dir is the full path to the directory that will contain the links
self.share_paths is a dict: share-name => target
returns 3 dicts:
new_links: a dict of all newly created links,
all_links: a dict of all links in the link directory
bad_links: links that do not point to the share base.
key = link (full path)
value = target (full path)
for bad_link: if the value is None, the link path is not a link
a dict of created links:
"""
result = []
for share, path in self.share_paths.items():
# Create a symlink to the link directory.
link = os.path.join(link_dir, share)
self.all_links[link] = path
# If it's already a link, it should point to the proper place
# If the link name exists, but it's not a link
# it's an error (or at least an issue).
if os.path.exists(link):
if os.path.islink(link):
relative_target = os.readlink(link)
target = os.path.realpath(relative_target)
if target != path:
self.bad_links[link] = target
else:
self.bad_links[link] = None
continue
proc = subprocess.Popen(["mklink", "/D", link, path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
shell=True)
(out, err) = proc.communicate()
#TODO: check the output. err should be empty. out should not be.
print("program output: ", out)
print("program err: ", err)
self.new_links[link] = path
result.append((out, err))
return
def remove_obsolete(self):
# for each link in the directory, see if the name is a share. If not, remove it.
#TODO: code it.
pass
def remove_link(self, link):
if os.path.islink(link):
# This removes the link, not the target
proc = subprocess.Popen(["rmdir", link], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
else:
out = ''
err = "{} is not a link".format(link)
return out, err
# send an email to server_notifications
############## TEST ############################
#############################
# define the shares that will not be linked to.
# The routine "get_shares() will add the entry '*$' to the
# exclude list.
#############################
excludes = ['trash', 'home', 'Users']
link_dir = r'C:\share_symlinks'
remote_drive = r'\\bilbao'
mgr = LinkManager(remote_drive)
mgr.get_shares(excludes)
mgr.make_links(link_dir)
testing = False
if testing:
for link, full_share in mgr.all_links.items():
sysout, syserr = mgr.remove_link(link)
# both err and out should be blank
print('rmdir out: {}'.format(sysout))
print('rmdir err: {}'.format(syserr))
continue
exit(0)
答案2
如果你无法在程序设置中更改文件夹,那么你可能什么也做不了,只能在 Linux PC 上创建 iSCSI 目标(文件目标可能,以保持分区完整)并使用 Windows VM 上的 iSCSI 启动器连接到它(MS iSCSI 启动器,StarWind iSCSI 启动器)。
或者,可以对程序进行十六进制编辑并将其指向映射的网络驱动器,但这需要一些技巧。
更新:我找到了一个解决方案,它看起来很有希望并且不需要处理 iSCSI:有没有办法将 UNC 路径映射到 Windows 2003 上的本地文件夹?。它看起来mklink
能够映射网络共享(真丢脸,我应该检查一下的),如果失败了,你可以尝试适用于 Windows XP 的符号链接驱动程序。