Como determinar se dois nomes de caminho de diretório são resolvidos para o mesmo destino

2

Estou tentando implementar uma função no PowerShell que pode me informar com segurança se os diretórios referenciados por dois nomes de caminho válidos são realmente os mesmos. Ele precisa ser capaz de lidar com diretórios que são referenciados por mapas, por caminhos UNC, por junções, possivelmente por junção no servidor de arquivos, etc. etc.

Devido à infinidade de maneiras de se referir a um diretório, parece que o método mais confiável de fazer isso é escrever um arquivo vazio no diretório usando um nome de caminho de diretório e usar o segundo nome de caminho para testar se o arquivo temporário pode ser encontrado sob o segundo nome de caminho. No entanto, isso pode não ser confiável.

Temos um servidor de arquivos com um diretório S:\ que é compartilhado como \server\share . No servidor, temos os diretórios S:\rootDir1 , S:\rootDir1\subDir , S:\rootDir2 e uma junção S:\rootDir2\subDir => S:\rootDir1\subDir .

Em um servidor de aplicativos, mapeio M:\ => \server\share , para que o servidor de aplicativos veja M:\rootDir1\subDir e M:\rootDir2\subDir

No powershell do appserver, eu crio um arquivo em M:\rootDir1\subDir via

 New-Item -ItemType File -Path 'M:\rootDir1\subDir\testFile.txt'

Em seguida, executamos imediatamente os dois testes

$l_ret1 = test-path 'M:\rootDir1\subDir\testFile.txt'
$l_ret2 = test-path 'M:\rootDir2\subDir\testFile.txt'

O resultado retornado $l_ret1 é consistentemente $true , enquanto o resultado $l_ret2 é inconsistente sem um atraso de tempo significativo entre a criação do arquivo de teste e o teste para ele. Existe alguma maneira de forçar o Windows para "atualizar" ou "atualizar" a informação é sobre arquivos em M:\rootDir2\subDir ? Eu percebo que isso pode ser culpa do servidor de arquivos (servidor de arquivos de janela), mas, em seguida, a questão apenas muda para, existe alguma maneira de forçar o servidor de arquivos para atualizar suas informações?

    
por David I. McIntosh 23.02.2015 / 18:46

2 respostas

2

Para determinar se são o mesmo diretório, tente usar:

GetFileInformationByHandle link

Observações seções lá diz "... Você pode comparar os membros VolumeSerialNumber e FileIndex retornados na estrutura BY_HANDLE_FILE_INFORMATION para determinar se dois caminhos mapeiam para o mesmo destino; por exemplo, você pode comparar dois caminhos de arquivo e determinar se eles mapear para o mesmo diretório ... "

    
por 24.02.2015 / 15:55
1

Expandindo a resposta de Warren: o seguinte código PowerHell pode ser usado no Powershell:

function Global:LoadCode()
{
    Add-Type -MemberDefinition @"

    [StructLayout(LayoutKind.Sequential)]
    public struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    };

    [DllImport("kernel32.dll", SetLastError = true)]
     private static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);

    [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)]
     public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
     IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);

    private static SafeFileHandle MY_GetFileHandle(string dirName)
    {
        const int FILE_ACCESS_NEITHER = 0;
        const int FILE_SHARE_READ = 1;
        const int FILE_SHARE_WRITE = 2;
        const int CREATION_DISPOSITION_OPEN_EXISTING = 3;
        const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
        return CreateFile(dirName, FILE_ACCESS_NEITHER, (FILE_SHARE_READ | FILE_SHARE_WRITE), System.IntPtr.Zero, CREATION_DISPOSITION_OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero);
    }

    private static BY_HANDLE_FILE_INFORMATION? MY_GetFileInfo(SafeFileHandle directoryHandle)
    {
        BY_HANDLE_FILE_INFORMATION objectFileInfo;
        if ((directoryHandle == null) || (!GetFileInformationByHandle(directoryHandle.DangerousGetHandle(), out objectFileInfo)))
        {
            return null;
        }
        return objectFileInfo;
    }

    public static bool MY_AreDirsEqual(string dirName1, string dirName2)
    { //
        bool bRet = false;
        //NOTE: we cannot lift the call to GetFileHandle into GetFileInfo, because we _must_
        // have both file handles open simultaneously in order for the objectFileInfo comparison
        // to be guaranteed as valid.
        using (SafeFileHandle directoryHandle1 = MY_GetFileHandle(dirName1), directoryHandle2 = MY_GetFileHandle(dirName2))
        {
            BY_HANDLE_FILE_INFORMATION? objectFileInfo1 = MY_GetFileInfo(directoryHandle1);
            BY_HANDLE_FILE_INFORMATION? objectFileInfo2 = MY_GetFileInfo(directoryHandle2);
            bRet = objectFileInfo1 != null
                    && objectFileInfo2 != null
                    && (objectFileInfo1.Value.FileIndexHigh == objectFileInfo2.Value.FileIndexHigh)
                    && (objectFileInfo1.Value.FileIndexLow == objectFileInfo2.Value.FileIndexLow)
                    && (objectFileInfo1.Value.VolumeSerialNumber == objectFileInfo2.Value.VolumeSerialNumber);
        }
        return bRet;
    }
"@ -Name Win32 -NameSpace System -UsingNamespace System.Text,Microsoft.Win32.SafeHandles,System.ComponentModel
}

function Global:Get_AreDirsEqual([string]$p_source, [string]$p_target)
{   Mcc
    if( ( ([System.Management.Automation.PSTypeName]'System.Win32').Type -eq $null)  -or ([system.win32].getmethod('MY_AreDirsEqual') -eq $null) )
    {
        LoadCode
    }
    [System.Win32]::MY_AreDirsEqual($p_source, $p_target)
}

Observe que isso basicamente implementa a funcionalidade em c #.

    
por 24.02.2015 / 19:25