Как определить, разрешают ли два пути каталога одну и ту же цель

2

Я пытаюсь реализовать функцию в powershell, которая может надежно сказать мне, действительно ли каталоги, на которые ссылаются два допустимых пути, одинаковы. Он должен уметь обрабатывать каталоги, на которые ссылаются карты, пути UNC, соединения, возможно, соединение на файловом сервере и т. Д. И т. Д. И т. Д.

Учитывая множество способов обращения к каталогу, кажется, что наиболее надежный способ сделать это - записать пустой файл в каталог, используя одно имя каталога, а затем использовать второй путь, чтобы проверить, можно ли найти временный файл в второй путь. Однако оказывается, что это может быть ненадежно.

У нас есть файловый сервер с каталогом S:\ это разделяется как \\server\share, На сервере у нас есть каталоги S:\rootDir1, S:\rootDir1\subDir, S:\rootDir2и перекресток S:\rootDir2\subDir => S:\rootDir1\subDir,

На сервере приложений я сопоставляю M:\ => \\server\shareтак что сервер приложений видит M:\rootDir1\subDir а также M:\rootDir2\subDir

В powershell на сервере приложений я создаю файл в M:\rootDir1\subDir с помощью

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

Затем мы немедленно выполняем два теста

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

Возвращенный результат $l_ret1 последовательно $trueпока результат $l_ret2 несовместимо без значительной задержки между созданием тестового файла и его тестированием. Есть ли способ заставить Windows «обновить» или «обновить» информацию о файлах в M:\rootDir2\subDir? Я понимаю, что это может быть ошибка файлового сервера (файлового сервера окна), но тогда вопрос просто меняется, есть ли способ заставить файловый сервер обновить свою информацию?

David I. McIntosh
источник

Ответы:

2

Чтобы определить, являются ли они одним каталогом, попробуйте использовать:

GetFileInformationByHandle https://msdn.microsoft.com/en-us/library/aa364952(v=vs.85).aspx

В разделе «Примечания» говорится «... Вы можете сравнить элементы VolumeSerialNumber и FileIndex, возвращенные в структуре BY_HANDLE_FILE_INFORMATION, чтобы определить, соответствуют ли два пути одной цели; например, можно сравнить два пути к файлам и определить, соответствуют ли они одному и тому же каталогу. ...»

Warren Stevens
источник
Работает как шарм.
David I. McIntosh
1

Расширение ответа Уоррена: в Powershell можно использовать следующий код 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)
}

Обратите внимание, что это по существу реализует функциональность в C #.

David I. McIntosh
источник