Controlla se un file è reale o un link simbolico

C’è un modo per dire usando C # se un file è reale o un collegamento simbolico?

Ho scavato attraverso i documenti MSDN W32 ( http://msdn.microsoft.com/en-us/library/aa364232(VS.85).aspx ), e non riesco a trovare nulla per verificare questo. Sto usando CreateSymbolicLink da qui, e sta funzionando bene.

Ho un codice sorgente per i link simbolici pubblicati sul mio blog che ti permetteranno di:

  • creare collegamenti simbolici
  • controlla se un percorso è un link simbolico
  • recuperare la destinazione di un collegamento simbolico

Contiene anche casi di test NUnit, che potresti voler estendere.

Il meaty bit è:

private static SafeFileHandle getFileHandle(string path) { return CreateFile(path, genericReadAccess, shareModeAll, IntPtr.Zero, openExisting, fileFlagsForOpenReparsePointAndBackupSemantics, IntPtr.Zero); } public static string GetTarget(string path) { SymbolicLinkReparseData reparseDataBuffer; using (SafeFileHandle fileHandle = getFileHandle(path)) { if (fileHandle.IsInvalid) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } int outBufferSize = Marshal.SizeOf(typeof(SymbolicLinkReparseData)); IntPtr outBuffer = IntPtr.Zero; try { outBuffer = Marshal.AllocHGlobal(outBufferSize); int bytesReturned; bool success = DeviceIoControl( fileHandle.DangerousGetHandle(), ioctlCommandGetReparsePoint, IntPtr.Zero, 0, outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero); fileHandle.Close(); if (!success) { if (((uint)Marshal.GetHRForLastWin32Error()) == pathNotAReparsePointError) { return null; } Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } reparseDataBuffer = (SymbolicLinkReparseData)Marshal.PtrToStructure( outBuffer, typeof(SymbolicLinkReparseData)); } finally { Marshal.FreeHGlobal(outBuffer); } } if (reparseDataBuffer.ReparseTag != symLinkTag) { return null; } string target = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer, reparseDataBuffer.PrintNameOffset, reparseDataBuffer.PrintNameLength); return target; } 

Questo è:

  • Apri il file con CreateFile()
  • Chiama DeviceIoControl() per ottenere i dati del punto di analisi (NOTA: potrebbe essere un punto di giunzione!)
  • Controlla la struttura dei dati restituiti per ispezionarli. Il tag di reparse ti dirà se si tratta di un punto di giunzione o di un collegamento simbolico. Questo potrebbe essere tutto quello che vuoi fare.
 private bool IsSymbolic(string path) { FileInfo pathInfo = new FileInfo(path); return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint); } 

Ecco un esempio di differenziazione di file e directory da collegamenti a file e collegamenti a directory.

I collegamenti a file o directory mantengono i loro attributi (data di creazione, permessi) separati dai loro obiettivi.

I collegamenti ai file possono essere cancellati (ad es. Usando “del”) senza influenzare il file di destinazione.

I collegamenti della directory possono essere rimossi (ad esempio “rmdir”) senza influire sulla directory di destinazione. Fai attenzione quando usi “rd / s”. Questo rimuoverà la destinazione del collegamento alla directory.

Il flag Chiave FileAttributes per il check in sia FileInfo che DirectoryInfo è FileAttributes.ReparsePoint .

 static void Main( string[] args ) { FileInfo file_info = new FileInfo(args[0]); DirectoryInfo directory_info = new DirectoryInfo(args[0]); bool is_file = file_info.Exists; bool is_directory = directory_info.Exists; if (is_file) { Console.WriteLine(file_info.ToString() + " is a file"); if ( file_info.Attributes.HasFlag(FileAttributes.ReparsePoint) ) Console.WriteLine(args[0] + " is a Windows file link"); } else if (is_directory) { Console.WriteLine(directory_info.ToString() + " is a directory"); if ( directory_info.Attributes.HasFlag(FileAttributes.ReparsePoint) ) Console.WriteLine(args[0] + " is a Windows directory link"); } 

In base a questa risposta alla domanda Stack Overflow Verificare se un file è un collegamento simbolico in PowerShell , ottenere System.IO.FileAttributes per il file (tramite File.GetAttributes ) e il test per il bit ReparsePoint, funziona. Se il bit è impostato, è un collegamento simbolico o un punto di giunzione. In caso contrario, è un file normale (o hardlink).

GetFileInformationByHandle riempie una struttura BY_HANDLE_FILE_INFORMATION che ha un campo dwFileAttributes cui i bit sono impostati con informazioni sugli attributi del file (dettagli qui ). In particolare, guarda il bit alla maschera …:

FILE_ATTRIBUTE_REPARSE_POINT 1024 0x0400

Un file o una directory con un punto di analisi associato o un file che è un collegamento simbolico.

Dimostra che le risposte di cui sopra non sono affidabili. Finalmente ho trovato la soluzione giusta da MSDN :

Per determinare se una directory specificata è una cartella montata, chiamare prima la funzione GetFileAttributes e ispezionare il flag FILE_ATTRIBUTE_REPARSE_POINT nel valore restituito per verificare se la directory ha un punto di analisi associato. In tal caso, utilizzare le funzioni FindFirstFile e FindNextFile per ottenere il tag di analisi nel membro dwReserved0 della struttura WIN32_FIND_DATA. Per determinare se il punto di analisi è una cartella montata (e non un’altra forma di punto di analisi), verificare se il valore del tag è uguale al valore IO_REPARSE_TAG_MOUNT_POINT. Per ulteriori informazioni, consultare Punti di analisi.