Existe uma maneira de criar algo como um link simbólico de uma pasta em uma máquina Windows para um diretório em um Linux?

1

Eu tenho um programa que é executado em uma VM do Windows VirtualBox, e armazena dados em uma pasta específica. Eu gostaria de criar algo como um link simbólico desta pasta para um diretório em um servidor Linux, mas não consegui chegar a uma solução funcional. Eu tentei mapear a estrutura de pastas do Linux para uma letra de unidade e, em seguida, fazer uma junção da pasta 'original' do Windows para a que está mapeada para a letra da unidade, mas o Windows não me permite concluir o link. Eu também tentei conectar o diretório Linux usando o SFTP e isso também não funcionou.

    
por g-man1066 02.04.2015 / 18:45

2 respostas

1

Veja o que eu fiz.

Primeiro, instalei o SAMBA na caixa do Linux e compartilhei as unidades que queria usar. (Esse é um tópico totalmente diferente, mas você pode encontrar muitas descrições sobre como fazer isso.)

Em seguida, na caixa do Windows, criei a classe Python 3 abaixo para criar os links.

Ele também pode ser usado para criar links para compartilhamentos do Windows.

Mas a resposta curta é - criar compartilhamentos na caixa linux e usar o mklink em um prompt de comando para criar um link simbólico.

Atenção: este código serve como prova de conceito. É um trabalho em andamento e está incompleto. Eu não afirmo que é o melhor código ou até mesmo um bom código.

"""    
@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)
    
por 02.04.2015 / 21:02
1

Se você não pode mudar a pasta nas configurações do programa, provavelmente não é nada que você possa fazer, a não ser criar um alvo iSCSI no seu PC com Linux (, para manter suas partições intactas) e usando o iniciador iSCSI em sua VM do Windows para se conectar a ele (Iniciador iSCSI do MS , Iniciador StarWind iSCSI ).

Como alternativa, pode-se editar o programa hexadecimais e apontá-lo para a unidade de rede mapeada, mas isso requer algumas habilidades.

ATUALIZAÇÃO: Encontrei uma solução que parece promissora e não requer mexer com o iSCSI: . Parece que mklink é capaz de mapear compartilhamentos de rede (pena que eu deveria ter verificado) e, se falhar, você pode tentar Driver de link simbólico para o Windows XP .

    
por 02.04.2015 / 19:00