// This code is derived from jcifs smb client library // Ported by J. Arturo // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using SharpCifs.Dcerpc; using SharpCifs.Dcerpc.Msrpc; using SharpCifs.Netbios; using SharpCifs.Util; using SharpCifs.Util.Sharpen; namespace SharpCifs.Smb { /// This class represents a resource on an SMB network. /// /// This class represents a resource on an SMB network. Mainly these /// resources are files and directories however an SmbFile /// may also refer to servers and workgroups. If the resource is a file or /// directory the methods of SmbFile follow the behavior of /// the well known /// Sharpen.FilePath /// class. One fundamental difference /// is the usage of a URL scheme [1] to specify the target file or /// directory. SmbFile URLs have the following syntax: ///
    /// smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]
    /// 
/// This example: ///
    /// smb://storage15/public/foo.txt
    /// 
/// would reference the file foo.txt in the share /// public on the server storage15. In addition /// to referencing files and directories, jCIFS can also address servers, /// and workgroups. ///

/// Important: all SMB URLs that represent /// workgroups, servers, shares, or directories require a trailing slash '/'. /// ///

/// When using the java.net.URL class with /// 'smb://' URLs it is necessary to first call the static /// jcifs.Config.registerSmbURLHandler(); method. This is required /// to register the SMB protocol handler. ///

/// The userinfo component of the SMB URL (domain;user:pass) must /// be URL encoded if it contains reserved characters. According to RFC 2396 /// these characters are non US-ASCII characters and most meta characters /// however jCIFS will work correctly with anything but '@' which is used /// to delimit the userinfo component from the server and '%' which is the /// URL escape character itself. ///

/// The server /// component may a traditional NetBIOS name, a DNS name, or IP /// address. These name resolution mechanisms and their resolution order /// can be changed (See Setting Name /// Resolution Properties). The servername and path components are /// not case sensitive but the domain, username, and password components /// are. It is also likely that properties must be specified for jcifs /// to function (See Setting /// JCIFS Properties). Here are some examples of SMB URLs with brief /// descriptions of what they do: ///

[1] This URL scheme is based largely on the SMB /// Filesharing URL Scheme IETF draft. ///

/// /// /// /// /// /// /// /// /// /// /// /// /// /// ///
SMB URL Examples
URLDescription
smb://users-nyc;miallen:mypass@angus/tmp/ /// This URL references a share called tmp on the server /// angus as user miallen who's password is /// mypass. ///
/// smb://Administrator:P%40ss@msmith1/c/WINDOWS/Desktop/foo.txt /// A relativly sophisticated example that references a file /// msmith1's desktop as user Administrator. Notice the '@' is URL encoded with the '%40' hexcode escape. ///
smb://angus/ /// This references only a server. The behavior of some methods is different /// in this context(e.g. you cannot delete a server) however /// as you might expect the list method will list the available /// shares on this server. ///
smb://myworkgroup/ /// This syntactically is identical to the above example. However if /// myworkgroup happends to be a workgroup(which is indeed /// suggested by the name) the list method will return /// a list of servers that have registered themselves as members of /// myworkgroup. ///
smb:// /// Just as smb://server/ lists shares and /// smb://workgroup/ lists servers, the smb:// /// URL lists all available workgroups on a netbios LAN. Again, /// in this context many methods are not valid and return default /// values(e.g. isHidden will always return false). ///
smb://angus.foo.net/d/jcifs/pipes.doc /// The server name may also be a DNS name as it is in this example. See /// Setting Name Resolution Properties /// for details. ///
smb://192.168.1.15/ADMIN$/ /// The server name may also be an IP address. See <a /// href="../../../resolver.html">Setting Name Resolution Properties /// for details. ///
/// smb://domain;username:password@server/share/path/to/file.txt /// A prototypical example that uses all the fields. ///
smb://myworkgroup/angus/ <-- ILLEGAL /// Despite the hierarchial relationship between workgroups, servers, and /// filesystems this example is not valid. ///
/// smb://server/share/path/to/dir <-- ILLEGAL /// URLs that represent workgroups, servers, shares, or directories require a trailing slash '/'. ///
/// smb://MYGROUP/?SERVER=192.168.10.15 /// SMB URLs support some query string parameters. In this example /// the SERVER parameter is used to override the /// server name service lookup to contact the server 192.168.10.15 /// (presumably known to be a master /// browser) for the server list in workgroup MYGROUP. ///
///

A second constructor argument may be specified to augment the URL /// for better programmatic control when processing many files under /// a common base. This is slightly different from the corresponding /// java.io.File usage; a '/' at the beginning of the second /// parameter will still use the server component of the first parameter. The /// examples below illustrate the resulting URLs when this second contructor /// argument is used. ///

/// /// /// /// /// /// /// /// /// /// /// /// ///
/// Examples Of SMB URLs When Augmented With A Second Constructor Parameter
/// First ParameterSecond ParameterResult
/// smb://host/share/a/b/ /// /// c/d/ /// /// smb://host/share/a/b/c/d/ ///
/// smb://host/share/foo/bar/ /// /// /share2/zig/zag /// /// smb://host/share2/zig/zag ///
/// smb://host/share/foo/bar/ /// /// ../zip/ /// /// smb://host/share/foo/zip/ ///
/// smb://host/share/zig/zag /// /// smb://foo/bar/ /// /// smb://foo/bar/ ///
/// smb://host/share/foo/ /// /// ../.././.././../foo/ /// /// smb://host/foo/ ///
/// smb://host/share/zig/zag /// /// / /// /// smb://host/ ///
/// smb://server/ /// /// ../ /// /// smb://server/ ///
/// smb:// /// /// myworkgroup/ /// /// smb://myworkgroup/ ///
/// smb://myworkgroup/ /// /// angus/ /// /// smb://myworkgroup/angus/ <-- ILLEGAL
(But if you first create an SmbFile with 'smb://workgroup/' and use and use it as the first parameter to a constructor that accepts it with a second String parameter jCIFS will factor out the 'workgroup'.) ///
///

Instances of the SmbFile class are immutable; that is, /// once created, the abstract pathname represented by an SmbFile object /// will never change. /// /// Sharpen.FilePath public class SmbFile : UrlConnection { internal const int ORdonly = 0x01; internal const int OWronly = 0x02; internal const int ORdwr = 0x03; internal const int OAppend = 0x04; internal const int OCreat = 0x0010; internal const int OExcl = 0x0020; internal const int OTrunc = 0x0040; ///

/// When specified as the shareAccess constructor parameter, /// other SMB clients (including other threads making calls into jCIFS) /// will not be permitted to access the target file and will receive "The /// file is being accessed by another process" message. /// /// /// When specified as the shareAccess constructor parameter, /// other SMB clients (including other threads making calls into jCIFS) /// will not be permitted to access the target file and will receive "The /// file is being accessed by another process" message. /// public const int FileNoShare = 0x00; /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to read from the target file while /// this file is open. /// /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to read from the target file while /// this file is open. This constant may be logically OR'd with other share /// access flags. /// public const int FileShareRead = 0x01; /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to write to the target file while /// this file is open. /// /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to write to the target file while /// this file is open. This constant may be logically OR'd with other share /// access flags. /// public const int FileShareWrite = 0x02; /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to delete the target file while /// this file is open. /// /// /// When specified as the shareAccess constructor parameter, /// other SMB clients will be permitted to delete the target file while /// this file is open. This constant may be logically OR'd with other share /// access flags. /// public const int FileShareDelete = 0x04; /// /// A file with this bit on as returned by getAttributes() or set /// with setAttributes() will be read-only /// public const int AttrReadonly = 0x01; /// /// A file with this bit on as returned by getAttributes() or set /// with setAttributes() will be hidden /// public const int AttrHidden = 0x02; /// /// A file with this bit on as returned by getAttributes() or set /// with setAttributes() will be a system file /// public const int AttrSystem = 0x04; /// /// A file with this bit on as returned by getAttributes() is /// a volume /// public const int AttrVolume = 0x08; /// /// A file with this bit on as returned by getAttributes() is /// a directory /// public const int AttrDirectory = 0x10; /// /// A file with this bit on as returned by getAttributes() or set /// with setAttributes() is an archived file /// public const int AttrArchive = 0x20; internal const int AttrCompressed = 0x800; internal const int AttrNormal = 0x080; internal const int AttrTemporary = 0x100; internal const int AttrGetMask = 0x7FFF; internal const int AttrSetMask = 0x30A7; internal const int DefaultAttrExpirationPeriod = 5000; internal static readonly int HashDot = ".".GetHashCode(); internal static readonly int HashDotDot = "..".GetHashCode(); //internal static LogStream log = LogStream.GetInstance(); public LogStream Log { get { return LogStream.GetInstance(); } } internal static long AttrExpirationPeriod; internal static bool IgnoreCopyToException; static SmbFile() { // Open Function Encoding // create if the file does not exist // fail if the file exists // truncate if the file exists // share access // file attribute encoding // extended file attribute encoding(others same as above) /*try { Sharpen.Runtime.GetType("jcifs.Config"); } catch (TypeLoadException cnfe) { Sharpen.Runtime.PrintStackTrace(cnfe); }*/ AttrExpirationPeriod = Config.GetLong("jcifs.smb.client.attrExpirationPeriod", DefaultAttrExpirationPeriod ); IgnoreCopyToException = Config.GetBoolean("jcifs.smb.client.ignoreCopyToException" , true); Dfs = new Dfs(); } /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a regular file or directory. /// public const int TypeFilesystem = 0x01; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a workgroup. /// public const int TypeWorkgroup = 0x02; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a server. /// public const int TypeServer = 0x04; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a share. /// public const int TypeShare = 0x08; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a named pipe. /// public const int TypeNamedPipe = 0x10; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a printer. /// public const int TypePrinter = 0x20; /// /// Returned by /// GetType() /// if the resource this SmbFile /// represents is a communications device. /// public const int TypeComm = 0x40; private string _canon; private string _share; private long _createTime; private long _lastModified; private int _attributes; private long _attrExpiration; private long _size; private long _sizeExpiration; private bool _isExists; private int _shareAccess = FileShareRead | FileShareWrite | FileShareDelete; private bool _enableDfs = Config.GetBoolean("jcifs.smb.client.enabledfs", false); private SmbComBlankResponse _blankResp; private DfsReferral _dfsReferral; protected internal static Dfs Dfs; internal NtlmPasswordAuthentication Auth; internal SmbTree Tree; internal string Unc; internal int Fid; internal int Type; internal bool Opened; internal int TreeNum; public bool EnableDfs { get { return _enableDfs; } set { _enableDfs = value; } } /// /// Constructs an SmbFile representing a resource on an SMB network such as /// a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such as /// a file or directory. See the description and examples of smb URLs above. /// /// A URL string /// /// If the parent and child parameters /// do not follow the prescribed syntax /// public SmbFile(string url) : this(new Uri(url)) { } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. The second parameter is a relative path from /// the parent SmbFile. See the description above for examples /// of using the second name parameter. /// /// A base SmbFile /// A path string relative to the parent paremeter /// /// If the parent and child parameters /// do not follow the prescribed syntax /// /// If the server or workgroup of the context file cannot be determined /// public SmbFile(SmbFile context, string name) : this(context.IsWorkgroup0 () ? new Uri("smb://" + name) : new Uri(context.Url.AbsoluteUri + name), context.Auth) { this._enableDfs = context.EnableDfs; if (!context.IsWorkgroup0()) { Addresses = context.Addresses; if (context._share != null) { Tree = context.Tree; _dfsReferral = context._dfsReferral; } } } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. The second parameter is a relative path from /// the parent. See the description above for examples of /// using the second chile parameter. /// /// A URL string /// A path string relative to the context paremeter /// /// If the context and name parameters /// do not follow the prescribed syntax /// /*public SmbFile(string context, string name) : this(new Uri(new Uri(null, context), name)) { }*/ public SmbFile(string context, string name) : this(new Uri(context + name)) { } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// A URL string /// The credentials the client should use for authentication /// If the url parameter does not follow the prescribed syntax /// public SmbFile(string url, NtlmPasswordAuthentication auth) : this(new Uri(url, UriKind.RelativeOrAbsolute), auth) { } /// Constructs an SmbFile representing a file on an SMB network. /// /// Constructs an SmbFile representing a file on an SMB network. The /// shareAccess parameter controls what permissions other /// clients have when trying to access the same file while this instance /// is still open. This value is either FILE_NO_SHARE or any /// combination of FILE_SHARE_READ, FILE_SHARE_WRITE, /// and FILE_SHARE_DELETE logically OR'd together. /// /// A URL string /// The credentials the client should use for authentication /// Specifies what access other clients have while this file is open. /// /// If the url parameter does not follow the prescribed syntax /// public SmbFile(string url, NtlmPasswordAuthentication auth, int shareAccess) : this (new Uri(url), auth) { // Initially null; set by getUncPath; dir must end with '/' // Can be null // For getDfsPath() and getServerWithDfs() // Cannot be null // Initially null // Initially null; set by getUncPath; never ends with '/' // Initially 0; set by open() if ((shareAccess & ~(FileShareRead | FileShareWrite | FileShareDelete)) != 0) { throw new RuntimeException("Illegal shareAccess parameter"); } this._shareAccess = shareAccess; } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. The second parameter is a relative path from /// the context. See the description above for examples of /// using the second name parameter. /// /// A URL string /// A path string relative to the context paremeter /// The credentials the client should use for authentication /// /// If the context and name parameters /// do not follow the prescribed syntax /// public SmbFile(string context, string name, NtlmPasswordAuthentication auth) : this (new Uri(context + name) , auth) { } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. The second parameter is a relative path from /// the context. See the description above for examples of /// using the second name parameter. The shareAccess /// parameter controls what permissions other clients have when trying /// to access the same file while this instance is still open. This /// value is either FILE_NO_SHARE or any combination /// of FILE_SHARE_READ, FILE_SHARE_WRITE, and /// FILE_SHARE_DELETE logically OR'd together. /// /// A URL string /// A path string relative to the context paremeter /// The credentials the client should use for authentication /// Specifies what access other clients have while this file is open. /// /// /// If the context and name parameters /// do not follow the prescribed syntax /// public SmbFile(string context, string name, NtlmPasswordAuthentication auth, int shareAccess) : this(new Uri(context + name), auth) { if ((shareAccess & ~(FileShareRead | FileShareWrite | FileShareDelete)) != 0) { throw new RuntimeException("Illegal shareAccess parameter"); } this._shareAccess = shareAccess; } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory. The second parameter is a relative path from /// the context. See the description above for examples of /// using the second name parameter. The shareAccess /// parameter controls what permissions other clients have when trying /// to access the same file while this instance is still open. This /// value is either FILE_NO_SHARE or any combination /// of FILE_SHARE_READ, FILE_SHARE_WRITE, and /// FILE_SHARE_DELETE logically OR'd together. /// /// A base SmbFile /// A path string relative to the context file path /// Specifies what access other clients have while this file is open. /// /// /// If the context and name parameters /// do not follow the prescribed syntax /// /// public SmbFile(SmbFile context, string name, int shareAccess) : this(context.IsWorkgroup0() ? new Uri("smb://" + name) : new Uri( context.Url.AbsoluteUri + name), context.Auth) { if ((shareAccess & ~(FileShareRead | FileShareWrite | FileShareDelete)) != 0) { throw new RuntimeException("Illegal shareAccess parameter"); } if (!context.IsWorkgroup0()) { this.Addresses = context.Addresses; if (context._share != null || context.Tree != null) { Tree = context.Tree; _dfsReferral = context._dfsReferral; } } this._shareAccess = shareAccess; this._enableDfs = context.EnableDfs; } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory from a URL object. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory from a URL object. /// /// The URL of the target resource protected SmbFile(Uri url) : this(url, new NtlmPasswordAuthentication(url.GetUserInfo ())) { } /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory from a URL object and an /// NtlmPasswordAuthentication object. /// /// /// Constructs an SmbFile representing a resource on an SMB network such /// as a file or directory from a URL object and an /// NtlmPasswordAuthentication object. /// /// The URL of the target resource /// The credentials the client should use for authentication public SmbFile(Uri url, NtlmPasswordAuthentication auth) { this.Auth = auth ?? new NtlmPasswordAuthentication(url.GetUserInfo()); Url = url; GetUncPath0(); } /// /// /*internal SmbFile(Jcifs.Smb.SmbFile context, string name, int type, int attributes , long createTime, long lastModified, long size) : this(context.IsWorkgroup0() ? new Uri(null, "smb://" + name + "/") : new Uri(context.url, name + ((attributes & ATTR_DIRECTORY) > 0 ? "/" : string.Empty)))*/ internal SmbFile(SmbFile context, string name, int type, int attributes , long createTime, long lastModified, long size) : this(context.IsWorkgroup0() ? new Uri("smb://" + name + "/") : new Uri(context.Url.AbsoluteUri + name + ((attributes & AttrDirectory) > 0 ? "/" : string.Empty))) { Auth = context.Auth; if (context._share != null) { Tree = context.Tree; _dfsReferral = context._dfsReferral; } int last = name.Length - 1; if (name[last] == '/') { name = Runtime.Substring(name, 0, last); } if (context._share == null) { Unc = "\\"; } else { if (context.Unc.Equals("\\")) { Unc = '\\' + name; } else { Unc = context.Unc + '\\' + name; } } if (!context.IsWorkgroup0()) { Addresses = context.Addresses; } this._enableDfs = context.EnableDfs; this.Type = type; this._attributes = attributes; this._createTime = createTime; this._lastModified = lastModified; this._size = size; _isExists = true; _attrExpiration = _sizeExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; } private SmbComBlankResponse Blank_resp() { if (_blankResp == null) { _blankResp = new SmbComBlankResponse(); } return _blankResp; } /// internal virtual void ResolveDfs(ServerMessageBlock request) { if (!_enableDfs) { Connect0(); return; } if (request is SmbComClose) { return; } Connect0(); DfsReferral dr = Dfs.Resolve(Tree.Session.transport.TconHostName, Tree.Share, Unc , Auth); if (dr != null) { string service = null; if (request != null) { switch (request.Command) { case ServerMessageBlock.SmbComTransaction: case ServerMessageBlock.SmbComTransaction2: { switch (((SmbComTransaction)request).SubCommand & 0xFF) { case SmbComTransaction.Trans2GetDfsReferral: { break; } default: { service = "A:"; break; } } break; } default: { service = "A:"; break; } } } DfsReferral start = dr; SmbException se = null; do { try { if (Log.Level >= 2) { Log.WriteLine("DFS redirect: " + dr); } UniAddress addr = UniAddress.GetByName(dr.Server); SmbTransport trans = SmbTransport.GetSmbTransport(addr, Url.Port); trans.Connect(); Tree = trans.GetSmbSession(Auth).GetSmbTree(dr.Share, service); if (dr != start && dr.Key != null) { dr.Map.Put(dr.Key, dr); } se = null; break; } catch (IOException ioe) { if (ioe is SmbException) { se = (SmbException)ioe; } else { se = new SmbException(dr.Server, ioe); } } dr = dr.Next; } while (dr != start); if (se != null) { throw se; } if (Log.Level >= 3) { Log.WriteLine(dr); } _dfsReferral = dr; if (dr.PathConsumed < 0) { dr.PathConsumed = 0; } else { if (dr.PathConsumed > Unc.Length) { dr.PathConsumed = Unc.Length; } } string dunc = Runtime.Substring(Unc, dr.PathConsumed); if (dunc.Equals(string.Empty)) { dunc = "\\"; } if (!dr.Path.Equals(string.Empty)) { dunc = "\\" + dr.Path + dunc; } Unc = dunc; if (request != null && request.Path != null && request.Path.EndsWith("\\") && dunc .EndsWith("\\") == false) { dunc += "\\"; } if (request != null) { request.Path = dunc; request.Flags2 |= SmbConstants.Flags2ResolvePathsInDfs; } } else { if (Tree.InDomainDfs && !(request is NtTransQuerySecurityDesc) && !(request is SmbComClose ) && !(request is SmbComFindClose2)) { throw new SmbException(NtStatus.NtStatusNotFound, false); } if (request != null) { request.Flags2 &= ~SmbConstants.Flags2ResolvePathsInDfs; } } } /// internal virtual void Send(ServerMessageBlock request, ServerMessageBlock response ) { for (; ; ) { ResolveDfs(request); try { Tree.Send(request, response); break; } catch (DfsReferral dre) { if (dre.ResolveHashes) { throw; } request.Reset(); } } } internal static string QueryLookup(string query, string param) { char[] instr = query.ToCharArray(); int i; int ch; int st; int eq; st = eq = 0; for (i = 0; i < instr.Length; i++) { ch = instr[i]; if (ch == '&') { if (eq > st) { string p = new string(instr, st, eq - st); if (Runtime.EqualsIgnoreCase(p, param)) { eq++; return new string(instr, eq, i - eq); } } st = i + 1; } else { if (ch == '=') { eq = i; } } } if (eq > st) { string p = new string(instr, st, eq - st); if (Runtime.EqualsIgnoreCase(p, param)) { eq++; return new string(instr, eq, instr.Length - eq); } } return null; } internal UniAddress[] Addresses; internal int AddressIndex; /// internal virtual UniAddress GetAddress() { if (AddressIndex == 0) { return GetFirstAddress(); } return Addresses[AddressIndex - 1]; } /// internal virtual UniAddress GetFirstAddress() { AddressIndex = 0; string host = Url.GetHost(); string path = Url.AbsolutePath; string query = Url.GetQuery(); if (Addresses != null && Addresses.Length > 0) { return GetNextAddress(); } if (query != null) { string server = QueryLookup(query, "server"); if (!string.IsNullOrEmpty(server)) { Addresses = new UniAddress[1]; Addresses[0] = UniAddress.GetByName(server); return GetNextAddress(); } string address = QueryLookup(query, "address"); if (!string.IsNullOrEmpty(address)) { byte[] ip = Extensions.GetAddressByName(address).GetAddressBytes(); Addresses = new UniAddress[1]; //addresses[0] = new UniAddress(IPAddress.Parse(host, ip)); Addresses[0] = new UniAddress(IPAddress.Parse(host)); return GetNextAddress(); } } if (host.Length == 0) { try { NbtAddress addr = NbtAddress.GetByName(NbtAddress.MasterBrowserName, 0x01, null); Addresses = new UniAddress[1]; Addresses[0] = UniAddress.GetByName(addr.GetHostAddress()); } catch (UnknownHostException uhe) { NtlmPasswordAuthentication.InitDefaults(); if (NtlmPasswordAuthentication.DefaultDomain.Equals("?")) { throw; } Addresses = UniAddress.GetAllByName(NtlmPasswordAuthentication.DefaultDomain, true ); } } else { if (path.Length == 0 || path.Equals("/")) { Addresses = UniAddress.GetAllByName(host, true); } else { Addresses = UniAddress.GetAllByName(host, false); } } return GetNextAddress(); } internal virtual UniAddress GetNextAddress() { UniAddress addr = null; if (AddressIndex < Addresses.Length) { addr = Addresses[AddressIndex++]; } return addr; } internal virtual bool HasNextAddress() { return AddressIndex < Addresses.Length; } /// internal virtual void Connect0() { try { Connect(); } catch (UnknownHostException uhe) { throw new SmbException("Failed to connect to server", uhe); } catch (SmbException se) { throw; } catch (IOException ioe) { throw new SmbException("Failed to connect to server", ioe); } } /// internal virtual void DoConnect() { SmbTransport trans; UniAddress addr; addr = GetAddress(); if (Tree != null && Tree.Session.transport.Address.Equals(addr)) { trans = Tree.Session.transport; } else { trans = SmbTransport.GetSmbTransport(addr, Url.Port); Tree = trans.GetSmbSession(Auth).GetSmbTree(_share, null); } string hostName = GetServerWithDfs(); if (_enableDfs) { Tree.InDomainDfs = Dfs.Resolve(hostName, Tree.Share, null, Auth) != null; } if (Tree.InDomainDfs) { Tree.ConnectionState = 2; } try { if (Log.Level >= 3) { Log.WriteLine("doConnect: " + addr); } Tree.TreeConnect(null, null); } catch (SmbAuthException sae) { NtlmPasswordAuthentication a; SmbSession ssn; if (_share == null) { // IPC$ - try "anonymous" credentials ssn = trans.GetSmbSession(NtlmPasswordAuthentication.Null); Tree = ssn.GetSmbTree(null, null); Tree.TreeConnect(null, null); } else { if ((a = NtlmAuthenticator.RequestNtlmPasswordAuthentication(Url.ToString(), sae) ) != null) { Auth = a; ssn = trans.GetSmbSession(Auth); Tree = ssn.GetSmbTree(_share, null); Tree.InDomainDfs = Dfs.Resolve(hostName, Tree.Share, null, Auth) != null; if (Tree.InDomainDfs) { Tree.ConnectionState = 2; } Tree.TreeConnect(null, null); } else { if (Log.Level >= 1 && HasNextAddress()) { Runtime.PrintStackTrace(sae, Log); } throw; } } } } /// It is not necessary to call this method directly. /// /// It is not necessary to call this method directly. This is the /// URLConnection implementation of connect(). /// /// public void Connect() { SmbTransport trans; SmbSession ssn; UniAddress addr; if (IsConnected()) { return; } GetUncPath0(); GetFirstAddress(); for (; ; ) { try { DoConnect(); return; } catch (SmbAuthException sae) { throw; } catch (SmbException se) { // Prevents account lockout on servers with multiple IPs if (GetNextAddress() == null) { throw; } else { RemoveCurrentAddress(); } if (Log.Level >= 3) { Runtime.PrintStackTrace(se, Log); } } } } internal virtual bool IsConnected() { return Tree != null && Tree.ConnectionState == 2; } /// internal virtual int Open0(int flags, int access, int attrs, int options) { int f; Connect0(); if (Log.Level >= 3) { Log.WriteLine("open0: " + Unc); } if (Tree.Session.transport.HasCapability(SmbConstants.CapNtSmbs)) { SmbComNtCreateAndXResponse response = new SmbComNtCreateAndXResponse(); SmbComNtCreateAndX request = new SmbComNtCreateAndX(Unc, flags, access, _shareAccess , attrs, options, null); if (this is SmbNamedPipe) { request.Flags0 |= 0x16; request.DesiredAccess |= 0x20000; response.IsExtended = true; } Send(request, response); f = response.Fid; _attributes = response.ExtFileAttributes & AttrGetMask; _attrExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; _isExists = true; } else { SmbComOpenAndXResponse response = new SmbComOpenAndXResponse(); Send(new SmbComOpenAndX(Unc, access, flags, null), response); f = response.Fid; } return f; } /// internal virtual void Open(int flags, int access, int attrs, int options) { if (IsOpen()) { return; } Fid = Open0(flags, access, attrs, options); Opened = true; TreeNum = Tree.TreeNum; } internal virtual bool IsOpen() { bool ans = Opened && IsConnected() && TreeNum == Tree.TreeNum; return ans; } /// internal virtual void Close(int f, long lastWriteTime) { if (Log.Level >= 3) { Log.WriteLine("close: " + f); } Send(new SmbComClose(f, lastWriteTime), Blank_resp()); } /// internal virtual void Close(long lastWriteTime) { if (IsOpen() == false) { return; } Close(Fid, lastWriteTime); Opened = false; } /// internal virtual void Close() { Close(0L); } /// /// Returns the NtlmPasswordAuthentication object used as /// credentials with this file or pipe. /// /// /// Returns the NtlmPasswordAuthentication object used as /// credentials with this file or pipe. This can be used to retrieve the /// username for example: /// /// String username = f.getPrincipal().getName(); /// /// The Principal object returned will never be null /// however the username can be null indication anonymous /// credentials were used (e.g. some IPC$ services). /// public virtual Principal GetPrincipal() { return Auth; } /// Returns the last component of the target URL. /// /// Returns the last component of the target URL. This will /// effectively be the name of the file or directory represented by this /// SmbFile or in the case of URLs that only specify a server /// or workgroup, the server or workgroup will be returned. The name of /// the root URL smb:// is also smb://. If this /// SmbFile refers to a workgroup, server, share, or directory, /// the name will include a trailing slash '/' so that composing new /// SmbFiles will maintain the trailing slash requirement. /// /// /// The last component of the URL associated with this SMB /// resource or smb:// if the resource is smb:// /// itself. /// public virtual string GetName() { GetUncPath0(); if (_canon.Length > 1) { int i = _canon.Length - 2; while (_canon[i] != '/') { i--; } return Runtime.Substring(_canon, i + 1); } if (_share != null) { return _share + '/'; } if (Url.GetHost().Length > 0) { return Url.GetHost() + '/'; } return "smb://"; } /// /// Everything but the last component of the URL representing this SMB /// resource is effectivly it's parent. /// /// /// Everything but the last component of the URL representing this SMB /// resource is effectivly it's parent. The root URL smb:// /// does not have a parent. In this case smb:// is returned. /// /// /// The parent directory of this SMB resource or /// smb:// if the resource refers to the root of the URL /// hierarchy which incedentally is also smb://. /// public virtual string GetParent() { string str = Url.Authority; if (str.Length > 0) { StringBuilder sb = new StringBuilder("smb://"); sb.Append(str); GetUncPath0(); if (_canon.Length > 1) { sb.Append(_canon); } else { sb.Append('/'); } str = sb.ToString(); int i = str.Length - 2; while (str[i] != '/') { i--; } return Runtime.Substring(str, 0, i + 1); } return "smb://"; } /// Returns the full uncanonicalized URL of this SMB resource. /// /// Returns the full uncanonicalized URL of this SMB resource. An /// SmbFile constructed with the result of this method will /// result in an SmbFile that is equal to the original. /// /// The uncanonicalized full URL of this SMB resource. public virtual string GetPath() { return Url.ToString(); } internal virtual string GetUncPath0() { if (Unc == null) { char[] instr = Url.LocalPath.ToCharArray(); char[] outstr = new char[instr.Length]; int length = instr.Length; int i; int o; int state; state = 0; o = 0; for (i = 0; i < length; i++) { switch (state) { case 0: { if (instr[i] != '/') { return null; } outstr[o++] = instr[i]; state = 1; break; } case 1: { if (instr[i] == '/') { break; } if (instr[i] == '.' && ((i + 1) >= length || instr[i + 1] == '/')) { i++; break; } if ((i + 1) < length && instr[i] == '.' && instr[i + 1] == '.' && ((i + 2) >= length || instr[i + 2] == '/')) { i += 2; if (o == 1) { break; } do { o--; } while (o > 1 && outstr[o - 1] != '/'); break; } state = 2; goto case 2; } case 2: { if (instr[i] == '/') { state = 1; } outstr[o++] = instr[i]; break; } } } _canon = new string(outstr, 0, o); if (o > 1) { o--; i = _canon.IndexOf('/', 1); if (i < 0) { _share = Runtime.Substring(_canon, 1); Unc = "\\"; } else { if (i == o) { _share = Runtime.Substring(_canon, 1, i); Unc = "\\"; } else { _share = Runtime.Substring(_canon, 1, i); Unc = Runtime.Substring(_canon, i, outstr[o] == '/' ? o : o + 1); Unc = Unc.Replace('/', '\\'); } } } else { _share = null; Unc = "\\"; } } return Unc; } /// Retuns the Windows UNC style path with backslashs intead of forward slashes. /// /// Retuns the Windows UNC style path with backslashs intead of forward slashes. /// /// The UNC path. public virtual string GetUncPath() { GetUncPath0(); if (_share == null) { return "\\\\" + Url.GetHost(); } return "\\\\" + Url.GetHost() + _canon.Replace('/', '\\'); } /// /// Returns the full URL of this SMB resource with '.' and '..' components /// factored out. /// /// /// Returns the full URL of this SMB resource with '.' and '..' components /// factored out. An SmbFile constructed with the result of /// this method will result in an SmbFile that is equal to /// the original. /// /// The canonicalized URL of this SMB resource. public virtual string GetCanonicalPath() { string str = Url.Authority; GetUncPath0(); if (str.Length > 0) { return "smb://" + Url.Authority + _canon; } return "smb://"; } /// Retrieves the share associated with this SMB resource. /// /// Retrieves the share associated with this SMB resource. In /// the case of smb://, smb://workgroup/, /// and smb://server/ URLs which do not specify a share, /// null will be returned. /// /// The share component or null if there is no share public virtual string GetShare() { return _share; } internal virtual string GetServerWithDfs() { if (_dfsReferral != null) { return _dfsReferral.Server; } return GetServer(); } /// Retrieve the hostname of the server for this SMB resource. /// /// Retrieve the hostname of the server for this SMB resource. If this /// SmbFile references a workgroup, the name of the workgroup /// is returned. If this SmbFile refers to the root of this /// SMB network hierarchy, null is returned. /// /// /// The server or workgroup name or null if this /// SmbFile refers to the root smb:// resource. /// public virtual string GetServer() { string str = Url.GetHost(); if (str.Length == 0) { return null; } return str; } /// Returns type of of object this SmbFile represents. /// Returns type of of object this SmbFile represents. /// /// TYPE_FILESYSTEM, TYPE_WORKGROUP, TYPE_SERVER, TYPE_SHARE, /// TYPE_PRINTER, TYPE_NAMED_PIPE, or TYPE_COMM. /// /// public new virtual int GetType() { if (Type == 0) { if (GetUncPath0().Length > 1) { Type = TypeFilesystem; } else { if (_share != null) { // treeConnect good enough to test service type Connect0(); if (_share.Equals("IPC$")) { Type = TypeNamedPipe; } else { if (Tree.Service.Equals("LPT1:")) { Type = TypePrinter; } else { if (Tree.Service.Equals("COMM")) { Type = TypeComm; } else { Type = TypeShare; } } } } else { if (string.IsNullOrEmpty(Url.Authority)) { Type = TypeWorkgroup; } else { UniAddress addr; try { addr = GetAddress(); } catch (UnknownHostException uhe) { throw new SmbException(Url.ToString(), uhe); } if (addr.GetAddress() is NbtAddress) { int code = ((NbtAddress)addr.GetAddress()).GetNameType(); if (code == 0x1d || code == 0x1b) { Type = TypeWorkgroup; return Type; } } Type = TypeServer; } } } } return Type; } /// internal virtual bool IsWorkgroup0() { if (Type == TypeWorkgroup || Url.GetHost().Length == 0) { Type = TypeWorkgroup; return true; } GetUncPath0(); if (_share == null) { UniAddress addr = GetAddress(); if (addr.GetAddress() is NbtAddress) { int code = ((NbtAddress)addr.GetAddress()).GetNameType(); if (code == 0x1d || code == 0x1b) { Type = TypeWorkgroup; return true; } } Type = TypeServer; } return false; } /// internal virtual IInfo QueryPath(string path, int infoLevel) { Connect0(); if (Log.Level >= 3) { Log.WriteLine("queryPath: " + path); } if (Tree.Session.transport.HasCapability(SmbConstants.CapNtSmbs)) { Trans2QueryPathInformationResponse response = new Trans2QueryPathInformationResponse (infoLevel); Send(new Trans2QueryPathInformation(path, infoLevel), response); return response.Info; } else { SmbComQueryInformationResponse response = new SmbComQueryInformationResponse(Tree .Session.transport.Server.ServerTimeZone * 1000 * 60L); Send(new SmbComQueryInformation(path), response); return response; } } /// Tests to see if the SMB resource exists. /// /// Tests to see if the SMB resource exists. If the resource refers /// only to a server, this method determines if the server exists on the /// network and is advertising SMB services. If this resource refers to /// a workgroup, this method determines if the workgroup name is valid on /// the local SMB network. If this SmbFile refers to the root /// smb:// resource true is always returned. If /// this SmbFile is a traditional file or directory, it will /// be queried for on the specified server as expected. /// /// /// true if the resource exists or is alive or /// false otherwise /// /// public virtual bool Exists() { if (_attrExpiration > Runtime.CurrentTimeMillis()) { return _isExists; } _attributes = AttrReadonly | AttrDirectory; _createTime = 0L; _lastModified = 0L; _isExists = false; try { if (Url.GetHost().Length == 0) { } else { if (_share == null) { if (GetType() == TypeWorkgroup) { UniAddress.GetByName(Url.GetHost(), true); } else { UniAddress.GetByName(Url.GetHost()).GetHostName(); } } else { if (GetUncPath0().Length == 1 || Runtime.EqualsIgnoreCase(_share, "IPC$")) { Connect0(); } else { // treeConnect is good enough IInfo info = QueryPath(GetUncPath0(), Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); _attributes = info.GetAttributes(); _createTime = info.GetCreateTime(); _lastModified = info.GetLastWriteTime(); } } } _isExists = true; } catch (UnknownHostException) { } catch (SmbException se) { switch (se.GetNtStatus()) { case NtStatus.NtStatusNoSuchFile: case NtStatus.NtStatusObjectNameInvalid: case NtStatus.NtStatusObjectNameNotFound: case NtStatus.NtStatusObjectPathNotFound: { break; } default: { throw; } } } _attrExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; return _isExists; } /// /// Tests to see if the file this SmbFile represents can be /// read. /// /// /// Tests to see if the file this SmbFile represents can be /// read. Because any file, directory, or other resource can be read if it /// exists, this method simply calls the exists method. /// /// true if the file is read-only /// public virtual bool CanRead() { if (GetType() == TypeNamedPipe) { // try opening the pipe for reading? return true; } return Exists(); } // try opening and catch sharing violation? /// /// Tests to see if the file this SmbFile represents /// exists and is not marked read-only. /// /// /// Tests to see if the file this SmbFile represents /// exists and is not marked read-only. By default, resources are /// considered to be read-only and therefore for smb://, /// smb://workgroup/, and smb://server/ resources /// will be read-only. /// /// /// true if the resource exists is not marked /// read-only /// /// public virtual bool CanWrite() { if (GetType() == TypeNamedPipe) { // try opening the pipe for writing? return true; } return Exists() && (_attributes & AttrReadonly) == 0; } /// Tests to see if the file this SmbFile represents is a directory. /// /// Tests to see if the file this SmbFile represents is a directory. /// /// true if this SmbFile is a directory /// public virtual bool IsDirectory() { if (GetUncPath0().Length == 1) { return true; } if (!Exists()) { return false; } return (_attributes & AttrDirectory) == AttrDirectory; } /// Tests to see if the file this SmbFile represents is not a directory. /// /// Tests to see if the file this SmbFile represents is not a directory. /// /// true if this SmbFile is not a directory /// public virtual bool IsFile() { if (GetUncPath0().Length == 1) { return false; } Exists(); return (_attributes & AttrDirectory) == 0; } /// /// Tests to see if the file this SmbFile represents is marked as /// hidden. /// /// /// Tests to see if the file this SmbFile represents is marked as /// hidden. This method will also return true for shares with names that /// end with '$' such as IPC$ or C$. /// /// true if the SmbFile is marked as being hidden /// public virtual bool IsHidden() { if (_share == null) { return false; } if (GetUncPath0().Length == 1) { if (_share.EndsWith("$")) { return true; } return false; } Exists(); return (_attributes & AttrHidden) == AttrHidden; } /// /// If the path of this SmbFile falls within a DFS volume, /// this method will return the referral path to which it maps. /// /// /// If the path of this SmbFile falls within a DFS volume, /// this method will return the referral path to which it maps. Otherwise /// null is returned. /// /// public virtual string GetDfsPath() { ResolveDfs(null); if (_dfsReferral == null) { return null; } string path = "smb:/" + _dfsReferral.Server + "/" + _dfsReferral.Share + Unc; path = path.Replace('\\', '/'); if (IsDirectory()) { path += '/'; } return path; } /// Retrieve the time this SmbFile was created. /// /// Retrieve the time this SmbFile was created. The value /// returned is suitable for constructing a /// System.DateTime /// object /// (i.e. seconds since Epoch 1970). Times should be the same as those /// reported using the properties dialog of the Windows Explorer program. /// For Win95/98/Me this is actually the last write time. It is currently /// not possible to retrieve the create time from files on these systems. /// /// /// The number of milliseconds since the 00:00:00 GMT, January 1, /// 1970 as a long value /// /// public virtual long CreateTime() { if (GetUncPath0().Length > 1) { Exists(); return _createTime; } return 0L; } /// /// Retrieve the last time the file represented by this /// SmbFile was modified. /// /// /// Retrieve the last time the file represented by this /// SmbFile was modified. The value returned is suitable for /// constructing a /// System.DateTime /// object (i.e. seconds since Epoch /// 1970). Times should be the same as those reported using the properties /// dialog of the Windows Explorer program. /// /// /// The number of milliseconds since the 00:00:00 GMT, January 1, /// 1970 as a long value /// /// public virtual long LastModified() { if (GetUncPath0().Length > 1) { Exists(); return _lastModified; } return 0L; } /// List the contents of this SMB resource. /// /// List the contents of this SMB resource. The list returned by this /// method will be; ///
    ///
  • files and directories contained within this resource if the /// resource is a normal disk file directory, ///
  • all available NetBIOS workgroups or domains if this resource is /// the top level URL smb://, ///
  • all servers registered as members of a NetBIOS workgroup if this /// resource refers to a workgroup in a smb://workgroup/ URL, ///
  • all browseable shares of a server including printers, IPC /// services, or disk volumes if this resource is a server URL in the form /// smb://server/, ///
  • or null if the resource cannot be resolved. ///
///
/// /// A String[] array of files and directories, /// workgroups, servers, or shares depending on the context of the /// resource URL /// /// public virtual string[] List() { return List("*", AttrDirectory | AttrHidden | AttrSystem, null, null); } /// List the contents of this SMB resource. /// /// List the contents of this SMB resource. The list returned will be /// identical to the list returned by the parameterless list() /// method minus filenames filtered by the specified filter. /// /// a filename filter to exclude filenames from the results /// # @return An array of filenames /// public virtual string[] List(ISmbFilenameFilter filter) { return List("*", AttrDirectory | AttrHidden | AttrSystem, filter, null); } /// /// List the contents of this SMB resource as an array of /// SmbFile objects. /// /// /// List the contents of this SMB resource as an array of /// SmbFile objects. This method is much more efficient than /// the regular list method when querying attributes of each /// file in the result set. ///

/// The list of SmbFiles returned by this method will be; ///

    ///
  • files and directories contained within this resource if the /// resource is a normal disk file directory, ///
  • all available NetBIOS workgroups or domains if this resource is /// the top level URL smb://, ///
  • all servers registered as members of a NetBIOS workgroup if this /// resource refers to a workgroup in a smb://workgroup/ URL, ///
  • all browseable shares of a server including printers, IPC /// services, or disk volumes if this resource is a server URL in the form /// smb://server/, ///
  • or null if the resource cannot be resolved. ///
///
/// /// An array of SmbFile objects representing file /// and directories, workgroups, servers, or shares depending on the context /// of the resource URL /// /// public virtual SmbFile[] ListFiles() { return ListFiles("*", AttrDirectory | AttrHidden | AttrSystem, null, null); } /// /// The CIFS protocol provides for DOS "wildcards" to be used as /// a performance enhancement. /// /// /// The CIFS protocol provides for DOS "wildcards" to be used as /// a performance enhancement. The client does not have to filter /// the names and the server does not have to return all directory /// entries. ///

/// The wildcard expression may consist of two special meta /// characters in addition to the normal filename characters. The '*' /// character matches any number of characters in part of a name. If /// the expression begins with one or more '?'s then exactly that /// many characters will be matched whereas if it ends with '?'s /// it will match that many characters or less. ///

/// Wildcard expressions will not filter workgroup names or server names. ///

        /// winnt> ls c?o
        /// clock.avi                  -rw--      82944 Mon Oct 14 1996 1:38 AM
        /// Cookies                    drw--          0 Fri Nov 13 1998 9:42 PM
        /// 2 items in 5ms
        /// 
///
/// a wildcard expression /// SmbException /// /// An array of SmbFile objects representing file /// and directories, workgroups, servers, or shares depending on the context /// of the resource URL /// /// public virtual SmbFile[] ListFiles(string wildcard) { return ListFiles(wildcard, AttrDirectory | AttrHidden | AttrSystem, null, null ); } /// List the contents of this SMB resource. /// /// List the contents of this SMB resource. The list returned will be /// identical to the list returned by the parameterless listFiles() /// method minus files filtered by the specified filename filter. /// /// a filter to exclude files from the results /// An array of SmbFile objects /// SmbException /// public virtual SmbFile[] ListFiles(ISmbFilenameFilter filter) { return ListFiles("*", AttrDirectory | AttrHidden | AttrSystem, filter, null); } /// List the contents of this SMB resource. /// /// List the contents of this SMB resource. The list returned will be /// identical to the list returned by the parameterless listFiles() /// method minus filenames filtered by the specified filter. /// /// a file filter to exclude files from the results /// An array of SmbFile objects /// public virtual SmbFile[] ListFiles(ISmbFileFilter filter) { return ListFiles("*", AttrDirectory | AttrHidden | AttrSystem, null, filter); } /// internal virtual string[] List(string wildcard, int searchAttributes, ISmbFilenameFilter fnf, ISmbFileFilter ff) { List list = new List(); DoEnum(list, false, wildcard, searchAttributes, fnf, ff); return Collections.ToArray(list); //Collections.ToArray(list); } /// internal virtual SmbFile[] ListFiles(string wildcard, int searchAttributes , ISmbFilenameFilter fnf, ISmbFileFilter ff) { List list = new List(); DoEnum(list, true, wildcard, searchAttributes, fnf, ff); return Collections.ToArray(list); //Collections.ToArray(list); } /// internal virtual void DoEnum(List list, bool files, string wildcard, int searchAttributes , ISmbFilenameFilter fnf, ISmbFileFilter ff) { if (ff != null && ff is DosFileFilter) { DosFileFilter dff = (DosFileFilter)ff; if (dff.Wildcard != null) { wildcard = dff.Wildcard; } searchAttributes = dff.Attributes; } try { int hostlen = Url.GetHost() != null ? Url.GetHost().Length : 0; if (hostlen == 0 || GetType() == TypeWorkgroup) { DoNetServerEnum(list, files, wildcard, searchAttributes, fnf, ff); } else { if (_share == null) { DoShareEnum(list, files, wildcard, searchAttributes, fnf, ff); } else { DoFindFirstNext(list, files, wildcard, searchAttributes, fnf, ff); } } } catch (UnknownHostException uhe) { throw new SmbException(Url.ToString(), uhe); } catch (UriFormatException mue) { throw new SmbException(Url.ToString(), mue); } } private void RemoveCurrentAddress() { if (AddressIndex >= 1) { UniAddress[] aux = new UniAddress[Addresses.Length - 1]; Array.Copy(Addresses, 1, aux, 0, Addresses.Length - 1); Addresses = aux; AddressIndex--; } } /// /// /// internal virtual void DoShareEnum(List list, bool files, string wildcard, int searchAttributes, ISmbFilenameFilter fnf, ISmbFileFilter ff) { string p = Url.AbsolutePath; IOException last = null; IFileEntry[] entries; UniAddress addr; IFileEntry e; Hashtable map; if (p.LastIndexOf('/') != (p.Length - 1)) { throw new SmbException(Url + " directory must end with '/'"); } if (GetType() != TypeServer) { throw new SmbException("The requested list operations is invalid: " + Url); } map = new Hashtable(); if (_enableDfs && Dfs.IsTrustedDomain(GetServer(), Auth)) { try { entries = DoDfsRootEnum(); for (int ei = 0; ei < entries.Length; ei++) { e = entries[ei]; if (map.ContainsKey(e) == false) { map.Put(e, e); } } } catch (IOException ioe) { if (Log.Level >= 4) { Runtime.PrintStackTrace(ioe, Log); } } } addr = GetFirstAddress(); while (addr != null) { try { last = null; DoConnect(); try { entries = DoMsrpcShareEnum(); } catch (IOException ioe) { if (Log.Level >= 3) { Runtime.PrintStackTrace(ioe, Log); } entries = DoNetShareEnum(); } for (int ei = 0; ei < entries.Length; ei++) { e = entries[ei]; if (map.ContainsKey(e) == false) { map.Put(e, e); } } break; } catch (IOException ioe) { if (Log.Level >= 3) { Runtime.PrintStackTrace(ioe, Log); } last = ioe; if (!(ioe is SmbAuthException)) { RemoveCurrentAddress(); addr = GetNextAddress(); } else { break; } } } if (last != null && map.Count == 0) { if (last is SmbException == false) { throw new SmbException(Url.ToString(), last); } throw (SmbException)last; } //Iterator iter = map.Keys.Iterator(); //while (iter.HasNext()) foreach (var item in map.Keys) { e = (IFileEntry)item; string name = e.GetName(); if (fnf != null && fnf.Accept(this, name) == false) { continue; } if (name.Length > 0) { // if !files we don't need to create SmbFiles here SmbFile f = new SmbFile(this, name, e.GetType(), AttrReadonly | AttrDirectory, 0L, 0L, 0L); if (ff != null && ff.Accept(f) == false) { continue; } if (files) { list.Add(f); } else { list.Add(name); } } } } /// internal virtual IFileEntry[] DoDfsRootEnum() { MsrpcDfsRootEnum rpc; DcerpcHandle handle = null; IFileEntry[] entries; handle = DcerpcHandle.GetHandle("ncacn_np:" + GetAddress().GetHostAddress() + "[\\PIPE\\netdfs]" , Auth); try { rpc = new MsrpcDfsRootEnum(GetServer()); handle.Sendrecv(rpc); if (rpc.Retval != 0) { throw new SmbException(rpc.Retval, true); } return rpc.GetEntries(); } finally { try { handle.Close(); } catch (IOException ioe) { if (Log.Level >= 4) { Runtime.PrintStackTrace(ioe, Log); } } } } /// internal virtual IFileEntry[] DoMsrpcShareEnum() { MsrpcShareEnum rpc; DcerpcHandle handle; rpc = new MsrpcShareEnum(Url.GetHost()); handle = DcerpcHandle.GetHandle("ncacn_np:" + GetAddress().GetHostAddress() + "[\\PIPE\\srvsvc]" , Auth); try { handle.Sendrecv(rpc); if (rpc.Retval != 0) { throw new SmbException(rpc.Retval, true); } return rpc.GetEntries(); } finally { try { handle.Close(); } catch (IOException ioe) { if (Log.Level >= 4) { Runtime.PrintStackTrace(ioe, Log); } } } } /// internal virtual IFileEntry[] DoNetShareEnum() { SmbComTransaction req = new NetShareEnum(); SmbComTransactionResponse resp = new NetShareEnumResponse(); Send(req, resp); if (resp.Status != WinError.ErrorSuccess) { throw new SmbException(resp.Status, true); } return resp.Results; } /// /// /// internal virtual void DoNetServerEnum(List list, bool files, string wildcard , int searchAttributes, ISmbFilenameFilter fnf, ISmbFileFilter ff) { int listType = Url.GetHost().Length == 0 ? 0 : GetType(); SmbComTransaction req; SmbComTransactionResponse resp; if (listType == 0) { Connect0(); req = new NetServerEnum2(Tree.Session.transport.Server.OemDomainName, NetServerEnum2 .SvTypeDomainEnum); resp = new NetServerEnum2Response(); } else { if (listType == TypeWorkgroup) { req = new NetServerEnum2(Url.GetHost(), NetServerEnum2.SvTypeAll); resp = new NetServerEnum2Response(); } else { throw new SmbException("The requested list operations is invalid: " + Url); } } bool more; do { int n; Send(req, resp); if (resp.Status != WinError.ErrorSuccess && resp.Status != WinError.ErrorMoreData) { throw new SmbException(resp.Status, true); } more = resp.Status == WinError.ErrorMoreData; n = more ? resp.NumEntries - 1 : resp.NumEntries; for (int i = 0; i < n; i++) { IFileEntry e = resp.Results[i]; string name = e.GetName(); if (fnf != null && fnf.Accept(this, name) == false) { continue; } if (name.Length > 0) { // if !files we don't need to create SmbFiles here SmbFile f = new SmbFile(this, name, e.GetType(), AttrReadonly | AttrDirectory, 0L, 0L, 0L); if (ff != null && ff.Accept(f) == false) { continue; } if (files) { list.Add(f); } else { list.Add(name); } } } if (GetType() != TypeWorkgroup) { break; } req.SubCommand = unchecked(SmbComTransaction.NetServerEnum3); req.Reset(0, ((NetServerEnum2Response)resp).LastName); resp.Reset(); } while (more); } /// /// /// internal virtual void DoFindFirstNext(List list, bool files, string wildcard , int searchAttributes, ISmbFilenameFilter fnf, ISmbFileFilter ff) { SmbComTransaction req; Trans2FindFirst2Response resp; int sid; string path = GetUncPath0(); string p = Url.AbsolutePath; if (p.LastIndexOf('/') != (p.Length - 1)) { throw new SmbException(Url + " directory must end with '/'"); } req = new Trans2FindFirst2(path, wildcard, searchAttributes); resp = new Trans2FindFirst2Response(); if (Log.Level >= 3) { Log.WriteLine("doFindFirstNext: " + req.Path); } Send(req, resp); sid = resp.Sid; req = new Trans2FindNext2(sid, resp.ResumeKey, resp.LastName); resp.SubCommand = SmbComTransaction.Trans2FindNext2; for (; ; ) { for (int i = 0; i < resp.NumEntries; i++) { IFileEntry e = resp.Results[i]; string name = e.GetName(); if (name.Length < 3) { int h = name.GetHashCode(); if (h == HashDot || h == HashDotDot) { if (name.Equals(".") || name.Equals("..")) { continue; } } } if (fnf != null && fnf.Accept(this, name) == false) { continue; } if (name.Length > 0) { SmbFile f = new SmbFile(this, name, TypeFilesystem, e.GetAttributes (), e.CreateTime(), e.LastModified(), e.Length()); if (ff != null && ff.Accept(f) == false) { continue; } if (files) { list.Add(f); } else { list.Add(name); } } } if (resp.IsEndOfSearch || resp.NumEntries == 0) { break; } req.Reset(resp.ResumeKey, resp.LastName); resp.Reset(); Send(req, resp); } try { Send(new SmbComFindClose2(sid), Blank_resp()); } catch (SmbException se) { if (Log.Level >= 4) { Runtime.PrintStackTrace(se, Log); } } } /// /// Changes the name of the file this SmbFile represents to the name /// designated by the SmbFile argument. /// /// /// Changes the name of the file this SmbFile represents to the name /// designated by the SmbFile argument. ///

/// Remember: SmbFiles are immutible and therefore /// the path associated with this SmbFile object will not /// change). To access the renamed file it is necessary to construct a /// new SmbFile. /// /// An SmbFile that represents the new pathname /// If the dest argument is null /// /// public virtual void RenameTo(SmbFile dest) { if (GetUncPath0().Length == 1 || dest.GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } ResolveDfs(null); dest.ResolveDfs(null); if (!Tree.Equals(dest.Tree)) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } if (Log.Level >= 3) { Log.WriteLine("renameTo: " + Unc + " -> " + dest.Unc); } _attrExpiration = _sizeExpiration = 0; dest._attrExpiration = 0; Send(new SmbComRename(Unc, dest.Unc), Blank_resp()); } internal class WriterThread : Thread { internal byte[] B; internal int N; internal long Off; internal bool Ready; internal SmbFile Dest; internal SmbException E; internal bool UseNtSmbs; internal SmbComWriteAndX Reqx; internal SmbComWrite Req; internal ServerMessageBlock Resp; /// public WriterThread(SmbFile enclosing) : base("JCIFS-WriterThread") { this._enclosing = enclosing; UseNtSmbs = this._enclosing.Tree.Session.transport.HasCapability(SmbConstants.CapNtSmbs); if (UseNtSmbs) { Reqx = new SmbComWriteAndX(); Resp = new SmbComWriteAndXResponse(); } else { Req = new SmbComWrite(); Resp = new SmbComWriteResponse(); } Ready = false; } internal virtual void Write(byte[] b, int n, SmbFile dest, long off) { lock (this) { this.B = b; this.N = n; this.Dest = dest; this.Off = off; Ready = false; Runtime.Notify(this); } } public override void Run() { lock (this) { try { for (; ; ) { Runtime.Notify(this); Ready = true; while (Ready) { Runtime.Wait(this); } if (N == -1) { return; } if (UseNtSmbs) { Reqx.SetParam(Dest.Fid, Off, N, B, 0, N); Dest.Send(Reqx, Resp); } else { Req.SetParam(Dest.Fid, Off, N, B, 0, N); Dest.Send(Req, Resp); } } } catch (SmbException e) { this.E = e; } catch (Exception x) { E = new SmbException("WriterThread", x); } Runtime.Notify(this); } } private readonly SmbFile _enclosing; } /// internal virtual void CopyTo0(SmbFile dest, byte[][] b, int bsize, WriterThread w, SmbComReadAndX req, SmbComReadAndXResponse resp) { int i; if (_attrExpiration < Runtime.CurrentTimeMillis()) { _attributes = AttrReadonly | AttrDirectory; _createTime = 0L; _lastModified = 0L; _isExists = false; IInfo info = QueryPath(GetUncPath0(), Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); _attributes = info.GetAttributes(); _createTime = info.GetCreateTime(); _lastModified = info.GetLastWriteTime(); _isExists = true; _attrExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; } if (IsDirectory()) { SmbFile[] files; SmbFile ndest; string path = dest.GetUncPath0(); if (path.Length > 1) { try { dest.Mkdir(); dest.SetPathInformation(_attributes, _createTime, _lastModified); } catch (SmbException se) { if (se.GetNtStatus() != NtStatus.NtStatusAccessDenied && se.GetNtStatus() != NtStatus .NtStatusObjectNameCollision) { throw; } } } files = ListFiles("*", AttrDirectory | AttrHidden | AttrSystem, null, null); try { for (i = 0; i < files.Length; i++) { ndest = new SmbFile(dest, files[i].GetName(), files[i].Type, files[i]._attributes, files[i]._createTime, files[i]._lastModified, files[i]._size); files[i].CopyTo0(ndest, b, bsize, w, req, resp); } } catch (UnknownHostException uhe) { throw new SmbException(Url.ToString(), uhe); } catch (UriFormatException mue) { throw new SmbException(Url.ToString(), mue); } } else { long off; try { Open(ORdonly, 0, AttrNormal, 0); try { dest.Open(OCreat | OWronly | OTrunc, SmbConstants.FileWriteData | SmbConstants.FileWriteAttributes, _attributes, 0); } catch (SmbAuthException sae) { if ((dest._attributes & AttrReadonly) != 0) { dest.SetPathInformation(dest._attributes & ~AttrReadonly, 0L, 0L); dest.Open(OCreat | OWronly | OTrunc, SmbConstants.FileWriteData | SmbConstants.FileWriteAttributes, _attributes, 0); } else { throw; } } i = 0; off = 0L; for (; ; ) { req.SetParam(Fid, off, bsize); resp.SetParam(b[i], 0); Send(req, resp); lock (w) { if (w.E != null) { throw w.E; } while (!w.Ready) { try { Runtime.Wait(w); } catch (Exception ie) { throw new SmbException(dest.Url.ToString(), ie); } } if (w.E != null) { throw w.E; } if (resp.DataLength <= 0) { break; } w.Write(b[i], resp.DataLength, dest, off); } i = i == 1 ? 0 : 1; off += resp.DataLength; } dest.Send(new Trans2SetFileInformation(dest.Fid, _attributes, _createTime, _lastModified ), new Trans2SetFileInformationResponse()); dest.Close(0L); } catch (SmbException se) { if (IgnoreCopyToException == false) { throw new SmbException("Failed to copy file from [" + ToString() + "] to [" + dest + "]", se); } if (Log.Level > 1) { Runtime.PrintStackTrace(se, Log); } } finally { Close(); } } } ///

/// This method will copy the file or directory represented by this /// SmbFile and it's sub-contents to the location specified by the /// dest parameter. /// /// /// This method will copy the file or directory represented by this /// SmbFile and it's sub-contents to the location specified by the /// dest parameter. This file and the destination file do not /// need to be on the same host. This operation does not copy extended /// file attibutes such as ACLs but it does copy regular attributes as /// well as create and last write times. This method is almost twice as /// efficient as manually copying as it employs an additional write /// thread to read and write data concurrently. ///

/// It is not possible (nor meaningful) to copy entire workgroups or /// servers. /// /// the destination file or directory /// SmbException /// public virtual void CopyTo(SmbFile dest) { SmbComReadAndX req; SmbComReadAndXResponse resp; WriterThread w; int bsize; byte[][] b; if (_share == null || dest._share == null) { throw new SmbException("Invalid operation for workgroups or servers"); } req = new SmbComReadAndX(); resp = new SmbComReadAndXResponse(); Connect0(); dest.Connect0(); ResolveDfs(null); try { if (GetAddress().Equals(dest.GetAddress()) && _canon.RegionMatches(true, 0, dest._canon , 0, Math.Min(_canon.Length, dest._canon.Length))) { throw new SmbException("Source and destination paths overlap."); } } catch (UnknownHostException) { } w = new WriterThread(this); w.SetDaemon(true); w.Start(); SmbTransport t1 = Tree.Session.transport; SmbTransport t2 = dest.Tree.Session.transport; if (t1.SndBufSize < t2.SndBufSize) { t2.SndBufSize = t1.SndBufSize; } else { t1.SndBufSize = t2.SndBufSize; } bsize = Math.Min(t1.RcvBufSize - 70, t1.SndBufSize - 70); b = new[] { new byte[bsize], new byte[bsize] }; try { CopyTo0(dest, b, bsize, w, req, resp); } finally { w.Write(null, -1, null, 0); } } ///

/// This method will delete the file or directory specified by this /// SmbFile. /// /// /// This method will delete the file or directory specified by this /// SmbFile. If the target is a directory, the contents of /// the directory will be deleted as well. If a file within the directory or /// it's sub-directories is marked read-only, the read-only status will /// be removed and the file will be deleted. /// /// SmbException /// public virtual void Delete() { Exists(); GetUncPath0(); Delete(Unc); } /// internal virtual void Delete(string fileName) { if (GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } if (Runtime.CurrentTimeMillis() > _attrExpiration) { _attributes = AttrReadonly | AttrDirectory; _createTime = 0L; _lastModified = 0L; _isExists = false; IInfo info = QueryPath(GetUncPath0(), Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); _attributes = info.GetAttributes(); _createTime = info.GetCreateTime(); _lastModified = info.GetLastWriteTime(); _attrExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; _isExists = true; } if ((_attributes & AttrReadonly) != 0) { SetReadWrite(); } if (Log.Level >= 3) { Log.WriteLine("delete: " + fileName); } if ((_attributes & AttrDirectory) != 0) { try { SmbFile[] l = ListFiles("*", AttrDirectory | AttrHidden | AttrSystem, null, null ); for (int i = 0; i < l.Length; i++) { l[i].Delete(); } } catch (SmbException se) { if (se.GetNtStatus() != NtStatus.NtStatusNoSuchFile) { throw; } } Send(new SmbComDeleteDirectory(fileName), Blank_resp()); } else { Send(new SmbComDelete(fileName), Blank_resp()); } _attrExpiration = _sizeExpiration = 0; } /// Returns the length of this SmbFile in bytes. /// /// Returns the length of this SmbFile in bytes. If this object /// is a TYPE_SHARE the total capacity of the disk shared in /// bytes is returned. If this object is a directory or a type other than /// TYPE_SHARE, 0L is returned. /// /// /// The length of the file in bytes or 0 if this /// SmbFile is not a file. /// /// SmbException /// public virtual long Length() { if (_sizeExpiration > Runtime.CurrentTimeMillis()) { return _size; } if (GetType() == TypeShare) { Trans2QueryFsInformationResponse response; int level = Trans2QueryFsInformationResponse.SMB_INFO_ALLOCATION; response = new Trans2QueryFsInformationResponse(level); Send(new Trans2QueryFsInformation(level), response); _size = response.Info.GetCapacity(); } else { if (GetUncPath0().Length > 1 && Type != TypeNamedPipe) { IInfo info = QueryPath(GetUncPath0(), Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO ); _size = info.GetSize(); } else { _size = 0L; } } _sizeExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; return _size; } /// /// This method returns the free disk space in bytes of the drive this share /// represents or the drive on which the directory or file resides. /// /// /// This method returns the free disk space in bytes of the drive this share /// represents or the drive on which the directory or file resides. Objects /// other than TYPE_SHARE or TYPE_FILESYSTEM will result /// in 0L being returned. /// /// /// the free disk space in bytes of the drive on which this file or /// directory resides /// /// public virtual long GetDiskFreeSpace() { if (GetType() == TypeShare || Type == TypeFilesystem) { int level = Trans2QueryFsInformationResponse.SmbFsFullSizeInformation; try { return QueryFsInformation(level); } catch (SmbException ex) { switch (ex.GetNtStatus()) { case NtStatus.NtStatusInvalidInfoClass: case NtStatus.NtStatusUnsuccessful: { // NetApp Filer // SMB_FS_FULL_SIZE_INFORMATION not supported by the server. level = Trans2QueryFsInformationResponse.SMB_INFO_ALLOCATION; return QueryFsInformation(level); } } throw; } } return 0L; } /// private long QueryFsInformation(int level) { Trans2QueryFsInformationResponse response; response = new Trans2QueryFsInformationResponse(level); Send(new Trans2QueryFsInformation(level), response); if (Type == TypeShare) { _size = response.Info.GetCapacity(); _sizeExpiration = Runtime.CurrentTimeMillis() + AttrExpirationPeriod; } return response.Info.GetFree(); } /// /// Creates a directory with the path specified by this /// SmbFile. /// /// /// Creates a directory with the path specified by this /// SmbFile. For this method to be successful, the target /// must not already exist. This method will fail when /// used with smb://, smb://workgroup/, /// smb://server/, or smb://server/share/ URLs /// because workgroups, servers, and shares cannot be dynamically created /// (although in the future it may be possible to create shares). /// /// SmbException /// public virtual void Mkdir() { string path = GetUncPath0(); if (path.Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } if (Log.Level >= 3) { Log.WriteLine("mkdir: " + path); } Send(new SmbComCreateDirectory(path), Blank_resp()); _attrExpiration = _sizeExpiration = 0; } /// /// Creates a directory with the path specified by this SmbFile /// and any parent directories that do not exist. /// /// /// Creates a directory with the path specified by this SmbFile /// and any parent directories that do not exist. This method will fail /// when used with smb://, smb://workgroup/, /// smb://server/, or smb://server/share/ URLs /// because workgroups, servers, and shares cannot be dynamically created /// (although in the future it may be possible to create shares). /// /// SmbException /// public virtual void Mkdirs() { SmbFile parent; try { parent = new SmbFile(GetParent(), Auth); } catch (IOException) { return; } if (parent.Exists() == false) { parent.Mkdirs(); } Mkdir(); } /// Create a new file but fail if it already exists. /// /// Create a new file but fail if it already exists. The check for /// existance of the file and it's creation are an atomic operation with /// respect to other filesystem activities. /// /// public virtual void CreateNewFile() { if (GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } Close(Open0(ORdwr | OCreat | OExcl, 0, AttrNormal, 0), 0L); } /// internal virtual void SetPathInformation(int attrs, long ctime, long mtime) { int f; int dir; Exists(); dir = _attributes & AttrDirectory; f = Open0(ORdonly, SmbConstants.FileWriteAttributes, dir, dir != 0 ? 0x0001 : 0x0040); Send(new Trans2SetFileInformation(f, attrs | dir, ctime, mtime), new Trans2SetFileInformationResponse ()); Close(f, 0L); _attrExpiration = 0; } /// Set the create time of the file. /// /// Set the create time of the file. The time is specified as milliseconds /// from Jan 1, 1970 which is the same as that which is returned by the /// createTime() method. ///

/// This method does not apply to workgroups, servers, or shares. /// /// the create time as milliseconds since Jan 1, 1970 /// public virtual void SetCreateTime(long time) { if (GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } SetPathInformation(0, time, 0L); } ///

Set the last modified time of the file. /// /// Set the last modified time of the file. The time is specified as milliseconds /// from Jan 1, 1970 which is the same as that which is returned by the /// lastModified(), getLastModified(), and getDate() methods. ///

/// This method does not apply to workgroups, servers, or shares. /// /// the last modified time as milliseconds since Jan 1, 1970 /// public virtual void SetLastModified(long time) { if (GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } SetPathInformation(0, 0L, time); } ///

Return the attributes of this file. /// /// Return the attributes of this file. Attributes are represented as a /// bitset that must be masked with ATTR_* constants to determine /// if they are set or unset. The value returned is suitable for use with /// the setAttributes() method. /// /// the ATTR_* attributes associated with this file /// SmbException /// public virtual int GetAttributes() { if (GetUncPath0().Length == 1) { return 0; } Exists(); return _attributes & AttrGetMask; } /// Set the attributes of this file. /// /// Set the attributes of this file. Attributes are composed into a /// bitset by bitwise ORing the ATTR_* constants. Setting the /// value returned by getAttributes will result in both files /// having the same attributes. /// /// SmbException /// public virtual void SetAttributes(int attrs) { if (GetUncPath0().Length == 1) { throw new SmbException("Invalid operation for workgroups, servers, or shares"); } SetPathInformation(attrs & AttrSetMask, 0L, 0L); } /// Make this file read-only. /// /// Make this file read-only. This is shorthand for setAttributes( /// getAttributes() | ATTR_READ_ONLY ). /// /// SmbException /// public virtual void SetReadOnly() { SetAttributes(GetAttributes() | AttrReadonly); } /// Turn off the read-only attribute of this file. /// /// Turn off the read-only attribute of this file. This is shorthand for /// setAttributes( getAttributes() & ~ATTR_READONLY ). /// /// SmbException /// public virtual void SetReadWrite() { SetAttributes(GetAttributes() & ~AttrReadonly); } /// /// Computes a hashCode for this file based on the URL string and IP /// address if the server. /// /// /// Computes a hashCode for this file based on the URL string and IP /// address if the server. The hashing function uses the hashcode of the /// server address, the canonical representation of the URL, and does not /// compare authentication information. In essance, two /// SmbFile objects that refer to /// the same file should generate the same hashcode provided it is possible /// to make such a determination. /// /// A hashcode for this abstract file /// SmbException public override int GetHashCode() { int hash; try { hash = GetAddress().GetHashCode(); } catch (UnknownHostException) { hash = GetServer().ToUpper().GetHashCode(); } GetUncPath0(); return hash + _canon.ToUpper().GetHashCode(); } protected internal virtual bool PathNamesPossiblyEqual(string path1, string path2 ) { int p1; int p2; int l1; int l2; // if unsure return this method returns true p1 = path1.LastIndexOf('/'); p2 = path2.LastIndexOf('/'); l1 = path1.Length - p1; l2 = path2.Length - p2; // anything with dots voids comparison if (l1 > 1 && path1[p1 + 1] == '.') { return true; } if (l2 > 1 && path2[p2 + 1] == '.') { return true; } return l1 == l2 && path1.RegionMatches(true, p1, path2, p2, l1); } /// Tests to see if two SmbFile objects are equal. /// /// Tests to see if two SmbFile objects are equal. Two /// SmbFile objects are equal when they reference the same SMB /// resource. More specifically, two SmbFile objects are /// equals if their server IP addresses are equal and the canonicalized /// representation of their URLs, minus authentication parameters, are /// case insensitivly and lexographically equal. ///

/// For example, assuming the server angus resolves to the /// 192.168.1.15 IP address, the below URLs would result in /// SmbFiles that are equal. ///

        /// smb://192.168.1.15/share/DIR/foo.txt
        /// smb://angus/share/data/../dir/foo.txt
        /// 
///
/// Another SmbFile object to compare for equality /// /// true if the two objects refer to the same SMB resource /// and false otherwise /// /// SmbException public override bool Equals(object obj) { if (obj is SmbFile) { SmbFile f = (SmbFile)obj; bool ret; if (this == f) { return true; } if (PathNamesPossiblyEqual(Url.AbsolutePath, f.Url.AbsolutePath)) { GetUncPath0(); f.GetUncPath0(); if (Runtime.EqualsIgnoreCase(_canon, f._canon)) { try { ret = GetAddress().Equals(f.GetAddress()); } catch (UnknownHostException) { ret = Runtime.EqualsIgnoreCase(GetServer(), f.GetServer()); } return ret; } } } return false; } /// Returns the string representation of this SmbFile object. /// /// Returns the string representation of this SmbFile object. This will /// be the same as the URL used to construct this SmbFile. /// This method will return the same value /// as getPath. /// /// The original URL representation of this SMB resource /// SmbException public override string ToString() { return Url.ToString(); } /// This URLConnection method just returns the result of length(). /// This URLConnection method just returns the result of length(). /// the length of this file or 0 if it refers to a directory public int GetContentLength() { try { return (int)(Length() & unchecked(0xFFFFFFFFL)); } catch (SmbException) { } return 0; } /// This URLConnection method just returns the result of lastModified. /// /// This URLConnection method just returns the result of lastModified. /// /// the last modified data as milliseconds since Jan 1, 1970 public long GetDate() { try { return LastModified(); } catch (SmbException) { } return 0L; } /// This URLConnection method just returns the result of lastModified. /// /// This URLConnection method just returns the result of lastModified. /// /// the last modified data as milliseconds since Jan 1, 1970 public long GetLastModified() { try { return LastModified(); } catch (SmbException) { } return 0L; } /// This URLConnection method just returns a new SmbFileInputStream created with this file. /// /// This URLConnection method just returns a new SmbFileInputStream created with this file. /// /// thrown by SmbFileInputStream constructor /// public InputStream GetInputStream() { return new SmbFileInputStream(this); } /// This URLConnection method just returns a new SmbFileOutputStream created with this file. /// /// This URLConnection method just returns a new SmbFileOutputStream created with this file. /// /// thrown by SmbFileOutputStream constructor /// public OutputStream GetOutputStream() { return new SmbFileOutputStream(this); } /// private void ProcessAces(Ace[] aces, bool resolveSids) { string server = GetServerWithDfs(); int ai; if (resolveSids) { Sid[] sids = new Sid[aces.Length]; string[] names = null; for (ai = 0; ai < aces.Length; ai++) { sids[ai] = aces[ai].Sid; } for (int off = 0; off < sids.Length; off += 64) { int len = sids.Length - off; if (len > 64) { len = 64; } Sid.ResolveSids(server, Auth, sids, off, len); } } else { for (ai = 0; ai < aces.Length; ai++) { aces[ai].Sid.OriginServer = server; aces[ai].Sid.OriginAuth = Auth; } } } /// /// Return an array of Access Control Entry (ACE) objects representing /// the security descriptor associated with this file or directory. /// /// /// Return an array of Access Control Entry (ACE) objects representing /// the security descriptor associated with this file or directory. /// If no DACL is present, null is returned. If the DACL is empty, an array with 0 elements is returned. /// /// /// Attempt to resolve the SIDs within each ACE form /// their numeric representation to their corresponding account names. /// /// public virtual Ace[] GetSecurity(bool resolveSids) { int f; Ace[] aces; f = Open0(ORdonly, SmbConstants.ReadControl, 0, IsDirectory() ? 1 : 0); NtTransQuerySecurityDesc request = new NtTransQuerySecurityDesc(f, 0x04); NtTransQuerySecurityDescResponse response = new NtTransQuerySecurityDescResponse( ); try { Send(request, response); } finally { Close(f, 0L); } aces = response.SecurityDescriptor.Aces; if (aces != null) { ProcessAces(aces, resolveSids); } return aces; } /// /// Return an array of Access Control Entry (ACE) objects representing /// the share permissions on the share exporting this file or directory. /// /// /// Return an array of Access Control Entry (ACE) objects representing /// the share permissions on the share exporting this file or directory. /// If no DACL is present, null is returned. If the DACL is empty, an array with 0 elements is returned. ///

/// Note that this is different from calling getSecurity on a /// share. There are actually two different ACLs for shares - the ACL on /// the share and the ACL on the folder being shared. /// Go to Computer Management /// > System Tools > Shared Folders > Shares and /// look at the Properties for a share. You will see two tabs - one /// for "Share Permissions" and another for "Security". These correspond to /// the ACLs returned by getShareSecurity and getSecurity /// respectively. /// /// /// Attempt to resolve the SIDs within each ACE form /// their numeric representation to their corresponding account names. /// /// public virtual Ace[] GetShareSecurity(bool resolveSids) { string p = Url.AbsolutePath; MsrpcShareGetInfo rpc; DcerpcHandle handle; Ace[] aces; ResolveDfs(null); string server = GetServerWithDfs(); rpc = new MsrpcShareGetInfo(server, Tree.Share); handle = DcerpcHandle.GetHandle("ncacn_np:" + server + "[\\PIPE\\srvsvc]", Auth); try { handle.Sendrecv(rpc); if (rpc.Retval != 0) { throw new SmbException(rpc.Retval, true); } aces = rpc.GetSecurity(); if (aces != null) { ProcessAces(aces, resolveSids); } } finally { try { handle.Close(); } catch (IOException ioe) { if (Log.Level >= 1) { Runtime.PrintStackTrace(ioe, Log); } } } return aces; } ///

/// Return an array of Access Control Entry (ACE) objects representing /// the security descriptor associated with this file or directory. /// /// /// Return an array of Access Control Entry (ACE) objects representing /// the security descriptor associated with this file or directory. ///

/// Initially, the SIDs within each ACE will not be resolved however when /// getType(), getDomainName(), getAccountName(), /// or toString() is called, the names will attempt to be /// resolved. If the names cannot be resolved (e.g. due to temporary /// network failure), the said methods will return default values (usually /// S-X-Y-Z strings of fragments of). ///

/// Alternatively getSecurity(true) may be used to resolve all /// SIDs together and detect network failures. /// /// public virtual Ace[] GetSecurity() { return GetSecurity(false); } } }