Как я могу определить, что несколько форматов пути к файлу указывают на одно и то же физическое местоположение

Возможный дубликат:
Лучший способ определить, является ли ссылка двух ссылок на один и тот же файл на С#

Существует несколько способов указать расположение каталога.

Например:
\\имя_компьютера\с $\ ROOTPATH ​​\ Subpath
\\имя_компьютера\shareName (общий доступ к subPath)
C:\ROOTPATH ​​\ Subpath
subPath (относительный путь, если он уже находится в C:\rootPath

Мне нужно определить, что все эти пути "равны" друг другу (на самом деле это то же физическое местоположение на жестком диске).

Есть ли способ сделать это на С#?

Ответ 1

В качестве Oded состояний это сложно сделать в .Net. Вы можете обмануть (в зависимости от ваших точных требований и разрешений и т.д.), Написав файл с длинным произвольно сгенерированным именем файла в этом месте, а затем посмотрев, сможете ли вы увидеть его из другого места. Я считаю, что это довольно звуковой тест, а не полагаться на разрешение подключенных дисков и т.д.

Хорошо, много извинений для VB - все, что у меня есть на этом крошечном нетбуке... С# не будет слишком отличаться...

использование, например

If sameLocation("\\machineName\c$\rootPath\subPath","\\machineName\shareName") Then...

Public Function sameLocation(ByVal sPath1 As String, ByVal sPath2 As String) As TriState
    Dim sFile As String = randomFilename()
    Dim sFullPath1 As String = sPath1 & "\" & sFile
    Dim sFullPath2 As String = sPath2 & "\" & sFile
    Dim bReturn As Boolean = False
    Try
        Dim fs As New FileStream(sFullPath1, FileMode.CreateNew)
        fs.Close()
    Catch ex As Exception
        Return TriState.UseDefault
    End Try

    Try
        bReturn = File.Exists(sFullPath2)
    Catch ex As Exception
        Return TriState.UseDefault
    End Try

    File.Delete(sFullPath1)
    Return bReturn
End Function

Public Function randomFilename() As String
    Dim r As New Random
    Randomize(My.Computer.Clock.TickCount)
    Dim sb As New StringBuilder
    Dim chars As Int16 = 100
    While chars > 0
        chars -= 1
        sb.Append(Chr(r.Next(26) + 65))
    End While
    Return sb.ToString
End Function

Вы можете добавить дополнительную безопасность, то есть прочитать метку времени и т.д.

Ответ 2

Вам нужно использовать GetFileInformationByHandle.
Просмотрите ответ в файле StackOverflow и MSDN.

Вот метод, который я написал, который работает с каталогами:

using System;
using System.Runtime.InteropServices;

namespace CompareByPath    
{    
  public static class DirectoryHelper  
  {
    // all user defined types copied from 
    // http://pinvoke.net/default.aspx/kernel32.CreateFile
    // http://pinvoke.net/default.aspx/kernel32.GetFileInformationByHandle
    // http://pinvoke.net/default.aspx/kernel32.CloseHandle

    public const short INVALID_HANDLE_VALUE = -1;

    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;
    }

    [Flags]
    public enum EFileAccess : uint
    {
      GenericRead = 0x80000000,
      GenericWrite = 0x40000000,
      GenericExecute = 0x20000000,
      GenericAll = 0x10000000
    }

    [Flags]
    public enum EFileShare : uint
    {
      None = 0x00000000,
      Read = 0x00000001,
      Write = 0x00000002,
      Delete = 0x00000004
    }

    [Flags]
    public enum EFileAttributes : uint
    {
      Readonly = 0x00000001,
      Hidden = 0x00000002,
      System = 0x00000004,
      Directory = 0x00000010,
      Archive = 0x00000020,
      Device = 0x00000040,
      Normal = 0x00000080,
      Temporary = 0x00000100,
      SparseFile = 0x00000200,
      ReparsePoint = 0x00000400,
      Compressed = 0x00000800,
      Offline = 0x00001000,
      NotContentIndexed = 0x00002000,
      Encrypted = 0x00004000,
      Write_Through = 0x80000000,
      Overlapped = 0x40000000,
      NoBuffering = 0x20000000,
      RandomAccess = 0x10000000,
      SequentialScan = 0x08000000,
      DeleteOnClose = 0x04000000,
      BackupSemantics = 0x02000000,
      PosixSemantics = 0x01000000,
      OpenReparsePoint = 0x00200000,
      OpenNoRecall = 0x00100000,
      FirstPipeInstance = 0x00080000
    }

    public enum ECreationDisposition : uint
    {
      New = 1,
      CreateAlways = 2,
      OpenExisting = 3,
      OpenAlways = 4,
      TruncateExisting = 5
    }

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

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    public static bool CompareDirectories(string d1, string d2)
    {
      bool result = false;

      BY_HANDLE_FILE_INFORMATION info1;
      BY_HANDLE_FILE_INFORMATION info2;

      IntPtr fileHandle1 = CreateFile(d1, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
      if (fileHandle1.ToInt32() != INVALID_HANDLE_VALUE)
      {
        bool rc = GetFileInformationByHandle(fileHandle1, out info1);
        if ( rc )
        {
          IntPtr fileHandle2 = CreateFile(d2, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
          if (fileHandle2.ToInt32() != INVALID_HANDLE_VALUE)
          {
            rc = GetFileInformationByHandle(fileHandle2, out info2);
            if ( rc )
            {
              if (( info1.FileIndexHigh == info2.FileIndexHigh) &&
                  ( info1.FileIndexLow == info2.FileIndexLow) &&
                  ( info1.VolumeSerialNumber == info2.VolumeSerialNumber))
              {
                result = true;
              }
            }
          }

          CloseHandle(fileHandle2);
        }
      }

      CloseHandle(fileHandle1);

      return result;
    }
  }
}

Ответ 3

В Windows существует много схем псевдонимов:

  • короткие и длинные имена
  • символические ссылки и жесткие ссылки
  • Имена UNC и сопоставленные диски
  • несколько подключенных дисков к одному и тому же сетевому пути
  • d:\folder\paths против \?\d\folder\paths
  • Точки монтирования NTFS

И любой из них может отображаться на любом уровне в дереве каталогов. В .NET вы можете разрешить некоторые из них, но не другие.

Как хакерский подход, попробуйте блокировку/разблокировку. Заблокируйте файл как имя 1, попробуйте открыть его как имя 2, убедитесь, что он сработал. Затем разблокируйте, попробуйте снова открыть, убедитесь, что он преуспел. И так далее, несколько раз, чтобы избежать ложных срабатываний. В отличие от способа El Ronnoco, этот детектирует как псевдонимы уровня, так и уровня файла.

В некоторых сетевых файловых системах блокировка может вообще не поддерживаться. Кроме того, это может занять некоторое время - каждая операция блокировки/разблокировки/открытия является обходной сетью.

Но это действительно зависит от ваших требований. Если короткие/длинные имена - это все, с чем вам приходится иметь дело, это перебор.

EDIT: дополнительные осложнения, если файл доступен только для чтения или уже открыт кем-то другим.

Ответ 4

В .NET нет собственного способа сделать это - это слишком низкий уровень.

Вы можете использовать API окон для этого (глядя на индексный каталог каталога или какой-либо другой идентификатор), но я не знаю, какой API будет раскрывать это.

Ответ 5

AKAIK вы даже можете сопоставить один и тот же диск со многими буквами дисков или подкаталогами. Также можно разделить сетевые общие каталоги, и вы никогда не знаете, являются ли они одинаковыми или нет.

Возможно, вы могли бы добавить информацию, почему вам нужно это знать.

Ответ 6

Хороший вопрос, может быть, не будет изящного ответа.

Лучшее, что я могу найти, чтобы указать вам на ваш путь, - это оператор командной строки net share. Если вы можете программно отображать и перерабатывать текст, созданный этой командой, вы можете сопоставить сетевые ресурсы 1:1 с их локальными папками назначения. Затем вы можете искать экземпляры этих общих карт в заданном пути и заменять их эквивалентами локальной папки перед выполнением базового сравнения строк.