/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ //------------------------------------------------------------------------------ // // Provide access to native APIs in Netapi32.dll // //------------------------------------------------------------------------------ namespace Microsoft.Hpc.Dsc.Internal { using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Runtime.InteropServices; using System.Text; /// /// Return codes from the Netapi32.dll pinvoke calls /// internal enum NetShareError { /// /// Success /// NERR_Success = 0, /// /// The user does not have access to the requested information. /// ERROR_ACCESS_DENIED = 5, /// /// Not enough storage is available to process this command /// ERROR_NOT_ENOUGH_MEMORY = 8, /// /// The network path was not found /// ERROR_BAD_NETPATH = 53, /// /// The specified parameter is not valid. /// ERROR_INVALID_PARAMETER = 87, /// /// The value specified for the level parameter is not valid. /// ERROR_INVALID_LEVEL = 124, /// /// The provided buffer was too small to hold the entire value /// ERROR_MORE_DATA = 234, /// /// The filename, directory name, or volume label syntax is incorrect /// ERROR_INVALID_NAME = 123, /// /// The device or directory does not exist /// NERR_UnknownDevDir = 2116, /// /// The share name is already in use on this server /// NERR_DuplicateShare = 2118, /// /// The client request succeeded. More entries are available. The buffer size that is specified by PreferedMaximumLength was too small to fit even a single entry /// NERR_BufTooSmall = 2123, /// /// The share name does not exist /// NERR_NetNameNotFound = 2310, /// /// The operation is not valid for a redirected resource. The specified device name is assigned to a shared resource /// NERR_RedirectedPath = 2117 } // // Provide access to native APIs in Netapi32.dll // internal static class NetShareWrapper { /// /// Specifies information about the shared resource, including the name of the resource, /// type and permissions, and number of connections. /// The buf parameter points to a SHARE_INFO_2 structure. /// private static UInt32 _InfoLevel = 2; /// /// Disk drive /// private static UInt32 _STYPE_DISKTREE = 0; /// /// Permission to read a resource and, by default, execute the resource. /// private static UInt32 _PERM_FILE_READ = 1; /// /// Permission to write to a resource. /// private static UInt32 _PERM_FILE_WRITE = 2; /// /// Permission to create a resource; data can be written when creating the resource. /// private static UInt32 _PERM_FILE_CREATE = 4; /// /// Contains information about the shared resource, including name of the resource, type and permissions, and the number of current connections /// [StructLayout(LayoutKind.Sequential)] private struct _SHARE_INFO_2 { /// /// Pointer to a Unicode string specifying the share name of a resource /// [MarshalAs(UnmanagedType.LPWStr)] public string shi2_netname; /// /// A bitmask of flags that specify the type of the shared resource /// [MarshalAs(UnmanagedType.U4)] public UInt32 shi2_type; /// /// Pointer to a Unicode string that contains an optional comment about the shared resource /// [MarshalAs(UnmanagedType.LPWStr)] public string shi2_remark; /// /// Specifies a DWORD value that indicates the shared resource's permissions for servers running with share-level security /// [MarshalAs(UnmanagedType.U4)] public UInt32 shi2_permissions; /// /// Specifies a DWORD value that indicates the maximum number of concurrent connections that the shared resource can accommodate. /// The number of connections is unlimited if the value specified in this member is �1. /// [MarshalAs(UnmanagedType.U4)] public UInt32 shi2_max_uses; /// /// Specifies a DWORD value that indicates the number of current connections to the resource /// [MarshalAs(UnmanagedType.U4)] public UInt32 shi2_current_uses; /// /// Pointer to a Unicode string specifying the local path for the shared resource /// [MarshalAs(UnmanagedType.LPWStr)] public string shi2_path; /// /// Pointer to a Unicode string that specifies the share's password when the server is running with share-level security /// [MarshalAs(UnmanagedType.LPWStr)] public string shi2_passwd; } /// /// Shares a server resource. /// /// Pointer to a string that specifies the DNS or NetBIOS name of the remote server on which the function is to execute. If this parameter is NULL, the local computer is used. /// Specifies the information level of the data /// Pointer to the buffer that specifies the data /// Pointer to a value that receives the index of the first member of the share information structure that causes the ERROR_INVALID_PARAMETER error. If this parameter is NULL, the index is not returned on error /// [DllImport("Netapi32.dll")] private static extern Int32 NetShareAdd( [MarshalAs(UnmanagedType.LPWStr)] string ServerName, [MarshalAs(UnmanagedType.U4)] UInt32 InfoLevel, [MarshalAs(UnmanagedType.Struct)] ref _SHARE_INFO_2 ShareInfo, ref IntPtr OutputBuffer); /// /// Deletes a share name from a server's list of shared resources, disconnecting all connections to the shared resource. /// /// Pointer to a string that specifies the DNS or NetBIOS name of the remote server on which the function is to execute. If this parameter is NULL, the local computer is used /// Pointer to a string that specifies the name of the share to delete. /// Reserved, must be zero. /// If the function succeeds, the return value is NERR_Success [DllImport("Netapi32.dll")] private static extern Int32 NetShareDel( [MarshalAs(UnmanagedType.LPWStr)] string ServerName, [MarshalAs(UnmanagedType.LPWStr)] string ShareName, UInt32 ParameterReserved); /// /// Retrieves information about a particular shared resource on a server. /// /// Pointer to a string that specifies the DNS or NetBIOS name of the remote server on which the function is to execute. If this parameter is NULL, the local computer is used /// Pointer to a string that specifies the name of the share for which to return information /// Specifies the information level of the data /// Pointer to the buffer that receives the data /// If the function succeeds, the return value is NERR_Success. [DllImport("Netapi32.dll")] private static extern Int32 NetShareGetInfo( [MarshalAs(UnmanagedType.LPWStr)] string ServerName, [MarshalAs(UnmanagedType.LPWStr)] string ShareName, [MarshalAs(UnmanagedType.U4)] UInt32 InfoLevel, ref IntPtr OutputBuffer); /// /// The NetApiBufferFree function frees the memory that the NetApiBufferAllocate function allocates /// /// A pointer to a buffer returned previously by another network management function or memory allocated by calling the NetApiBufferAllocate function /// [DllImport("Netapi32", CharSet = CharSet.Auto)] private static extern Int32 NetApiBufferFree(IntPtr InputBuffer); /// /// Prints out the error based on the error code /// /// Error code returned by pinvoke call private static void PrintError(Int32 ErrorCode) { switch ((NetShareError)ErrorCode) { case NetShareError.ERROR_ACCESS_DENIED: Console.Error.WriteLine("Access to share denied."); break; case NetShareError.ERROR_NOT_ENOUGH_MEMORY: Console.Error.WriteLine("Not enough memory available."); break; case NetShareError.ERROR_INVALID_PARAMETER: Console.Error.WriteLine("Invalid parameter specified."); break; case NetShareError.ERROR_INVALID_LEVEL: Console.Error.WriteLine("Invalid level specified."); break; case NetShareError.ERROR_MORE_DATA: Console.Error.WriteLine("More data available and not large enough buffer specified."); break; case NetShareError.ERROR_INVALID_NAME: Console.Error.WriteLine("The filename, directory name, or volume label syntax is incorrect"); break; case NetShareError.NERR_UnknownDevDir: Console.Error.WriteLine("Unknown device specified."); break; case NetShareError.NERR_DuplicateShare: Console.Error.WriteLine("Duplicate share specified."); break; case NetShareError.NERR_BufTooSmall: Console.Error.WriteLine("Not large enough buffer specified."); break; case NetShareError.NERR_NetNameNotFound: Console.Error.WriteLine("Share name not found."); break; case NetShareError.NERR_RedirectedPath: Console.Error.WriteLine("The operation is not valid for a redirected resource. The specified device name is assigned to a shared resource."); break; case NetShareError.ERROR_BAD_NETPATH: Console.Error.WriteLine("The network path was not found."); break; default: Console.Error.WriteLine(String.Format(CultureInfo.CurrentCulture, "Unknown error occured (Error Code {0}).", ErrorCode)); break; } } /// /// Create a net share /// /// Server hosting share /// name of share /// path to share /// description of share /// success/failure internal static int CreateShare(string ServerName, string ShareName, string SharePath, string ShareDescription) { // // Ensure UNC path formatting at start // if (!ServerName.StartsWith(@"\\")) { if (!ServerName.StartsWith(@"\")) { ServerName = @"\\" + ServerName; } else { ServerName = @"\" + ServerName; } } // // Build share information // _SHARE_INFO_2 ShareInfo = new _SHARE_INFO_2(); ShareInfo.shi2_netname = ShareName; ShareInfo.shi2_type = _STYPE_DISKTREE; ShareInfo.shi2_remark = ShareDescription; ShareInfo.shi2_permissions = _PERM_FILE_READ | _PERM_FILE_WRITE | _PERM_FILE_CREATE; ShareInfo.shi2_max_uses = UInt32.MaxValue; ShareInfo.shi2_current_uses = 0; ShareInfo.shi2_path = SharePath; ShareInfo.shi2_passwd = String.Empty; IntPtr OutputBuffer = IntPtr.Zero; // // Create the share and report success or failure // Int32 ErrorCode = NetShareAdd(ServerName, _InfoLevel, ref ShareInfo, ref OutputBuffer); if (ErrorCode != (Int32)NetShareError.NERR_Success) { PrintError(ErrorCode); } return ErrorCode; } /// /// Deletes an existing share /// /// Server hosting share /// name of share /// success/failure internal static bool DeleteShare(string ServerName, string ShareName) { // // Ensure UNC path formatting at start // if (!ServerName.StartsWith(@"\\")) { if (!ServerName.StartsWith(@"\")) { ServerName = @"\\" + ServerName; } else { ServerName = @"\" + ServerName; } } // // Attempt to delete the share and report success/failure // Int32 ErrorCode = NetShareDel(ServerName, ShareName, 0); if (ErrorCode == (Int32)NetShareError.NERR_Success) { return (true); } else { PrintError(ErrorCode); } return (false); } /// /// Get the drive where a share is hosted /// /// Server hosting share /// Name of share /// drive letter (empty string if unsuccessful) internal static string GetLocalDrive(string ServerName, string ShareName) { // // Ensure UNC path formatting at start // if (!ServerName.StartsWith(@"\\")) { if (!ServerName.StartsWith(@"\")) { ServerName = @"\\" + ServerName; } else { ServerName = @"\" + ServerName; } } string ShareDrive = String.Empty; string SharePath = String.Empty; IntPtr OutputBuffer = IntPtr.Zero; // // Attempt to get the share information. Report error if unsuccessful // Int32 ErrorCode = NetShareGetInfo(ServerName, ShareName, _InfoLevel, ref OutputBuffer); if (ErrorCode == (Int32)NetShareError.NERR_Success) { _SHARE_INFO_2 ShareInfo = (_SHARE_INFO_2)Marshal.PtrToStructure(OutputBuffer, typeof(_SHARE_INFO_2)); SharePath = ShareInfo.shi2_path; NetApiBufferFree(OutputBuffer); } else { PrintError(ErrorCode); return (ShareDrive); } if (!String.IsNullOrEmpty(SharePath)) { // // If a share path was returned, attempt to parse out the drive letter // int Index = SharePath.IndexOf(':'); if (Index > 0) { ShareDrive = SharePath.Substring(0, Index + 1); } } return (ShareDrive); } // TODO: Sync Dryad GM and vertex with new version that returns error code internal static string GetLocalPath(string ServerName, string ShareName) { string SharePath; int err = GetLocalPath(ServerName, ShareName, out SharePath); if (err != (int)NetShareError.NERR_Success) { Console.Error.WriteLine("GetLocalPath failed: server {0}, share {1}", ServerName, ShareName); PrintError(err); } return SharePath; } /// /// Returns the local path to a share on the specified server /// /// Server the path resides on /// Share to find path to /// Local path to share or empty string if failure internal static int GetLocalPath(string ServerName, string ShareName, out string SharePath) { // // Ensure UNC path formatting at start // if (!String.IsNullOrEmpty(ServerName) && !ServerName.StartsWith(@"\\")) { if (!ServerName.StartsWith(@"\")) { ServerName = @"\\" + ServerName; } else { ServerName = @"\" + ServerName; } } IntPtr OutputBuffer = IntPtr.Zero; SharePath = String.Empty; // // Get share info structure // Int32 ErrorCode = NetShareGetInfo(ServerName, ShareName, _InfoLevel, ref OutputBuffer); if (ErrorCode == (Int32)NetShareError.NERR_Success) { // // If successful, get the local path to the resource and free the buffer // _SHARE_INFO_2 ShareInfo = (_SHARE_INFO_2)Marshal.PtrToStructure(OutputBuffer, typeof(_SHARE_INFO_2)); SharePath = ShareInfo.shi2_path; NetApiBufferFree(OutputBuffer); } return ErrorCode; } } }