Sameer
Sameer

Reputation: 3183

Convert UNC path to local path in C#

Is there a way to do get local path from UNC path?

For eg: \\server7\hello.jpg should give me D:\attachments\hello.jpg

I am trying to save attachments to the UNC path after applying the windows file name and full path length restrictions . Here I am applying the restrictions by taking UNC path length as reference. But local path length is longer than UNC path and i think because of this I am getting the below exception.

System.IO.PathTooLongException occurred HResult=-2147024690
Message=The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. Source=mscorlib
StackTrace: at System.IO.PathHelper.GetFullPathName() at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths) at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode) at Presensoft.JournalEmailVerification.EmailVerification.DownloadFailedAttachments(EmailMessage msg, JournalEmail journalEmail) in D:\Source\ProductionReleases\Release_8.0.7.0\Email Archiving\Presensoft.JournalEmailVerification\EmailVerification.cs:line 630 InnerException:

Upvotes: 6

Views: 15220

Answers (3)

WhoIsRich
WhoIsRich

Reputation: 4153

I was in need of this myself, although for DirQuota setting purposes. As my code will be running as a server admin, the WMI query example was easiest, just re-wrote it to be more readable:

public static string ShareToLocalPath(string sharePath)
{
    try
    {
        var regex = new Regex(@"\\\\([^\\]*)\\([^\\]*)(\\.*)?");
        var match = regex.Match(sharePath);
        if (!match.Success) return "";

        var shareHost = match.Groups[1].Value;
        var shareName = match.Groups[2].Value;
        var shareDirs = match.Groups[3].Value;

        var scope = new ManagementScope(@"\\" + shareHost + @"\root\cimv2");
        var query = new SelectQuery("SELECT * FROM Win32_Share WHERE name = '" + shareName + "'");

        using (var searcher = new ManagementObjectSearcher(scope, query))
        {
            var result = searcher.Get();
            foreach (var item in result) return item["path"].ToString() + shareDirs;
        }

        return "";
    }
    catch (Exception)
    {
        return "";
    }
}

Behind the scenes, this is reading the server registry key:

'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Shares'

If you need to convert paths without admin on the target server, check out the 'NetShareEnum' function of Netapi32.dll. Although you don't normally see it, hidden shares and local paths are broadcast to regular users. The code is a little more complex as it requires DllImport, but there are examples, and then just like above you would need to match the share name.

Upvotes: 0

squid
squid

Reputation: 1

This also works for most cases. A little simpler than system management.

public static string MakeDiskRootFromUncRoot(string astrPath)
{
    string strPath = astrPath;
    if (strPath.StartsWith("\\\\"))
    {
        strPath = strPath.Substring(2);
        int ind = strPath.IndexOf('$');
        if(ind>1 && strPath.Length >= 2)
        {
            string driveLetter = strPath.Substring(ind - 1,1);
            strPath = strPath.Substring(ind + 1);
            strPath = driveLetter + ":" + strPath;
        }

    }
    return strPath;
}

Upvotes: 0

HABJAN
HABJAN

Reputation: 9328

Take a look at this blog article: Get local path from UNC path

The code from article. This function will take a UNC path (for example \server\share or \server\c$\folder and return the local path (for example c:\share or c:\folder).

using System.Management;

public static string GetPath(string uncPath)
{
  try
  {
    // remove the "\\" from the UNC path and split the path
    uncPath = uncPath.Replace(@"\\", "");
    string[] uncParts = uncPath.Split(new char[] {'\\'}, StringSplitOptions.RemoveEmptyEntries);
    if (uncParts.Length < 2)
      return "[UNRESOLVED UNC PATH: " + uncPath + "]";
    // Get a connection to the server as found in the UNC path
    ManagementScope scope = new ManagementScope(@"\\" + uncParts[0] + @"\root\cimv2");
    // Query the server for the share name
    SelectQuery query = new SelectQuery("Select * From Win32_Share Where Name = '" + uncParts[1] + "'");
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);

    // Get the path
    string path = string.Empty;
    foreach (ManagementObject obj in searcher.Get())
    {
      path = obj["path"].ToString();
    }

    // Append any additional folders to the local path name
    if (uncParts.Length > 2)
    {
      for (int i = 2; i < uncParts.Length; i++)
        path = path.EndsWith(@"\") ? path + uncParts[i] : path + @"\" + uncParts[i];
    }

    return path;
  }
  catch (Exception ex)
  {
    return "[ERROR RESOLVING UNC PATH: " + uncPath + ": "+ex.Message+"]";
  }
}

The function uses the ManagementObjectSearcher to search for shares on the network server. If you do not have read access to this server, you will need to log in using different credentials. Replace the line with the ManagementScope with the following lines:

ConnectionOptions options = new ConnectionOptions();
options.Username = "username";
options.Password = "password";
ManagementScope scope = new ManagementScope(@"\\" + uncParts[0] + @"\root\cimv2", options);

Upvotes: 8

Related Questions