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? Я понимаю, что это может быть ошибка файлового сервера (файлового сервера окна), но тогда вопрос просто меняется, есть ли способ заставить файловый сервер обновить свою информацию?

2 ответа2

2

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

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

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

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 #.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .