/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using Alphaleonis.Win32.Filesystem;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Path = Alphaleonis.Win32.Filesystem.Path;
namespace Alphaleonis.Win32.Network
{
/// Provides static methods to retrieve network resource information from a local- or remote host.
public static partial class Host
{
#region GetUncName
/// Return the host name in UNC format, for example: \\hostname.
/// The unc name.
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
[SecurityCritical]
public static string GetUncName()
{
return string.Format(CultureInfo.InvariantCulture, "{0}{1}", Path.UncPrefix, Environment.MachineName);
}
/// Return the host name in UNC format, for example: \\hostname.
/// Name of the computer.
/// The unc name.
[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
[SecurityCritical]
public static string GetUncName(string computerName)
{
return Utils.IsNullOrWhiteSpace(computerName)
? GetUncName()
: (computerName.StartsWith(Path.UncPrefix, StringComparison.OrdinalIgnoreCase)
? computerName.Trim()
: Path.UncPrefix + computerName.Trim());
}
#endregion // GetUncName
#region Internal Methods
private delegate uint EnumerateNetworkObjectDelegate(
FunctionData functionData, out SafeGlobalMemoryBufferHandle netApiBuffer, [MarshalAs(UnmanagedType.I4)] int prefMaxLen,
[MarshalAs(UnmanagedType.U4)] out uint entriesRead, [MarshalAs(UnmanagedType.U4)] out uint totalEntries,
[MarshalAs(UnmanagedType.U4)] out uint resumeHandle);
/// Structure is used to pass additional data to the Win32 function.
private struct FunctionData
{
public int EnumType;
public string ExtraData1;
public string ExtraData2;
}
[SecurityCritical]
private static IEnumerable EnumerateNetworkObjectCore(FunctionData functionData, Func createTStruct, EnumerateNetworkObjectDelegate enumerateNetworkObject, bool continueOnException)
{
Type objectType;
int objectSize;
bool isString;
switch (functionData.EnumType)
{
// Logical Drives
case 1:
objectType = typeof(IntPtr);
isString = true;
objectSize = Marshal.SizeOf(objectType) + UnicodeEncoding.CharSize;
break;
default:
objectType = typeof(TNative);
isString = objectType == typeof(string);
objectSize = isString ? 0 : Marshal.SizeOf(objectType);
break;
}
uint lastError;
do
{
uint entriesRead;
uint totalEntries;
uint resumeHandle;
SafeGlobalMemoryBufferHandle buffer;
lastError = enumerateNetworkObject(functionData, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle);
using (buffer)
switch (lastError)
{
case Win32Errors.NERR_Success:
case Win32Errors.ERROR_MORE_DATA:
if (entriesRead > 0)
{
for (int i = 0, itemOffset = 0; i < entriesRead; i++, itemOffset += objectSize)
yield return (TStruct) (isString
? buffer.PtrToStringUni(itemOffset, 2)
: (object) createTStruct(buffer.PtrToStructure(itemOffset), buffer));
}
break;
case Win32Errors.ERROR_BAD_NETPATH:
break;
// Observed when SHARE_INFO_503 is requested but not supported/possible.
case Win32Errors.RPC_X_BAD_STUB_DATA:
yield break;
}
} while (lastError == Win32Errors.ERROR_MORE_DATA);
if (lastError != Win32Errors.NO_ERROR && !continueOnException)
throw new NetworkInformationException((int) lastError);
}
/// This method uses level to retieve full REMOTE_NAME_INFO structure.
/// A structure.
/// AlphaFS regards network drives created using SUBST.EXE as invalid.
///
///
///
///
/// The local path with drive name.
/// suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.
[SecurityCritical]
internal static NativeMethods.REMOTE_NAME_INFO GetRemoteNameInfoCore(string path, bool continueOnException)
{
if (Utils.IsNullOrWhiteSpace(path))
throw new ArgumentNullException("path");
path = Path.GetRegularPathCore(path, GetFullPathOptions.CheckInvalidPathChars, false);
// If path already is a network share path, we fill the REMOTE_NAME_INFO structure ourselves.
if (Path.IsUncPathCore(path, true, false))
return new NativeMethods.REMOTE_NAME_INFO
{
lpUniversalName = Path.AddTrailingDirectorySeparator(path, false),
lpConnectionName = Path.RemoveTrailingDirectorySeparator(path, false),
lpRemainingPath = Path.DirectorySeparator
};
uint lastError;
// Use large enough buffer to prevent a 2nd call.
uint bufferSize = 1024;
do
{
using (var buffer = new SafeGlobalMemoryBufferHandle((int) bufferSize))
{
// Structure: UNIVERSAL_NAME_INFO_LEVEL = 1 (not used in AlphaFS).
// Structure: REMOTE_NAME_INFO_LEVEL = 2
lastError = NativeMethods.WNetGetUniversalName(path, 2, buffer, out bufferSize);
switch (lastError)
{
case Win32Errors.NO_ERROR:
return buffer.PtrToStructure(0);
case Win32Errors.ERROR_MORE_DATA:
//bufferSize = Received the required buffer size, retry.
break;
}
}
} while (lastError == Win32Errors.ERROR_MORE_DATA);
if (!continueOnException && lastError != Win32Errors.NO_ERROR)
throw new NetworkInformationException((int) lastError);
// Return an empty structure (all fields set to null).
return new NativeMethods.REMOTE_NAME_INFO();
}
internal struct ConnectDisconnectArguments
{
/// Handle to a window that the provider of network resources can use as an owner window for dialog boxes.
public IntPtr WinOwner;
/// The name of a local device to be redirected, such as "F:". When is or string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
public string LocalName;
/// A network resource to connect to/disconnect from, for example: \\server or \\server\share
public string RemoteName;
/// A instance. Use either this or the combination of and .
public NetworkCredential Credential;
/// The user name for making the connection. If is , the function uses the default user name. (The user context for the process provides the default user name)
public string UserName;
/// The password to be used for making the network connection. If is , the function uses the current default password associated with the user specified by .
public string Password;
/// always pops-up an authentication dialog box.
public bool Prompt;
/// successful network resource connections will be saved.
public bool UpdateProfile;
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
public bool SaveCredentials;
/// indicates that the operation concerns a drive mapping.
public bool IsDeviceMap;
/// indicates that the operation needs to disconnect from the network resource, otherwise connect.
public bool IsDisconnect;
}
#endregion // Internal Methods
}
}