У меня есть программа, которая работает на виртуальной машине Windows VirtualBox, и хранит данные в определенной папке. Я хотел бы создать что-то вроде символической ссылки из этой папки на каталог на сервере Linux, но я не смог найти работающее решение. Я попытался сопоставить структуру папок Linux с буквой диска, а затем создать переход из «исходной» папки Windows в ту, которая сопоставлена с буквой диска, но Windows не позволяет мне завершить ссылку. Я также попытался подключить каталог Linux с помощью SFTP, но это тоже не сработало.
2 ответа
Если вы не можете изменить папку в настройках программы, то, вероятно, вы ничего не можете сделать, кроме создания цели iSCSI на вашем ПК с Linux (цель файла, вероятно, для сохранения ваших разделов в целости) и использования инициатора iSCSI на виртуальной машине Windows для подключиться к нему (инициатор MS iSCSI, инициатор StarWind iSCSI).
В качестве альтернативы можно отредактировать программу в шестнадцатеричном формате и указать ее на подключенном сетевом диске, но это требует определенных навыков.
ОБНОВЛЕНИЕ: я нашел решение, которое выглядит многообещающим и не требует вмешательства в iSCSI: есть ли способ сопоставить UNC-путь с локальной папкой в Windows 2003? , Похоже, что mklink
может отображать сетевые ресурсы (позор мне, я должен был это проверить), и в случае неудачи вы можете попробовать Symbolic Link Driver для Windows XP.
Вот что я сделал.
Сначала я установил SAMBA на коробку Linux и поделился дисками, которые хотел использовать. (Это целая другая тема, но вы можете найти множество описаний того, как это сделать.)
Затем в окне 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)