All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jcifs.smb.SmbTreeConnection Maven / Gradle / Ivy

/*
 * © 2017 AgNO3 Gmbh & Co. KG
 * 
 * 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
 */
package jcifs.smb;


import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jcifs.CIFSContext;
import jcifs.CIFSException;
import jcifs.Configuration;
import jcifs.DfsReferralData;
import jcifs.RuntimeCIFSException;
import jcifs.SmbConstants;
import jcifs.SmbResourceLocator;
import jcifs.SmbTreeHandle;
import jcifs.internal.CommonServerMessageBlockRequest;
import jcifs.internal.CommonServerMessageBlockResponse;
import jcifs.internal.RequestWithPath;
import jcifs.internal.dfs.DfsReferralDataInternal;
import jcifs.internal.smb1.com.SmbComClose;
import jcifs.internal.smb1.com.SmbComFindClose2;
import jcifs.internal.smb1.trans.nt.NtTransQuerySecurityDesc;
import jcifs.util.transport.TransportException;


/**
 * This class encapsulates the logic for switching tree connections
 * 
 * Switching trees can occur either when the tree has been disconnected by failure or idle-timeout - as well as on
 * DFS referrals.
 * 
 * @author mbechler
 *
 */
class SmbTreeConnection {

    private static final Logger log = LoggerFactory.getLogger(SmbTreeConnection.class);

    private final CIFSContext ctx;
    private final SmbTreeConnection delegate;
    private SmbTreeImpl tree;
    private volatile boolean treeAcquired;
    private volatile boolean delegateAcquired;

    private SmbTransportInternal exclusiveTransport;
    private boolean nonPooled;

    private final AtomicLong usageCount = new AtomicLong();

    private static final Random RAND = new Random();


    protected SmbTreeConnection ( CIFSContext ctx ) {
        this.ctx = ctx;
        this.delegate = null;
    }


    protected SmbTreeConnection ( SmbTreeConnection treeConnection ) {
        this.ctx = treeConnection.ctx;
        this.delegate = treeConnection;
    }


    static SmbTreeConnection create ( CIFSContext c ) {
        if ( c.getConfig().isTraceResourceUsage() ) {
            return new SmbTreeConnectionTrace(c);
        }
        return new SmbTreeConnection(c);
    }


    static SmbTreeConnection create ( SmbTreeConnection c ) {
        if ( c.ctx.getConfig().isTraceResourceUsage() ) {
            return new SmbTreeConnectionTrace(c);
        }
        return new SmbTreeConnection(c);
    }


    /**
     * @return the active configuration
     */
    public Configuration getConfig () {
        return this.ctx.getConfig();
    }


    private synchronized SmbTreeImpl getTree () {
        SmbTreeImpl t = this.tree;
        if ( t != null ) {
            return t.acquire(false);
        }
        else if ( this.delegate != null ) {
            this.tree = this.delegate.getTree();
            return this.tree;
        }
        return t;
    }


    /**
     * @return
     */
    private synchronized SmbTreeImpl getTreeInternal () {
        SmbTreeImpl t = this.tree;
        if ( t != null ) {
            return t;
        }
        if ( this.delegate != null ) {
            return this.delegate.getTreeInternal();
        }
        return null;
    }


    /**
     * @param t
     */
    private synchronized void switchTree ( SmbTreeImpl t ) {
        try ( SmbTreeImpl old = getTree() ) {
            if ( old == t ) {
                return;
            }
            boolean wasAcquired = this.treeAcquired;
            log.debug("Switching tree");
            if ( t != null ) {
                log.debug("Acquired tree on switch " + t);
                t.acquire();
                this.treeAcquired = true;
            }
            else {
                this.treeAcquired = false;
            }

            this.tree = t;
            if ( old != null ) {
                if ( wasAcquired ) {
                    // release
                    old.release(true);
                }
            }
            if ( this.delegate != null && this.delegateAcquired ) {
                log.debug("Releasing delegate");
                this.delegateAcquired = false;
                this.delegate.release();
            }
        }
    }


    /**
     * @return tree connection with increased usage count
     */
    public SmbTreeConnection acquire () {
        long usage = this.usageCount.incrementAndGet();
        if ( log.isTraceEnabled() ) {
            log.trace("Acquire tree connection " + usage + " " + this);
        }

        if ( usage == 1 ) {
            synchronized ( this ) {
                try ( SmbTreeImpl t = getTree() ) {
                    if ( t != null ) {
                        if ( !this.treeAcquired ) {
                            if ( log.isDebugEnabled() ) {
                                log.debug("Acquire tree on first usage " + t);
                            }
                            t.acquire();
                            this.treeAcquired = true;
                        }
                    }
                }
                if ( this.delegate != null && !this.delegateAcquired ) {
                    log.debug("Acquire delegate on first usage");
                    this.delegate.acquire();
                    this.delegateAcquired = true;
                }
            }
        }

        return this;

    }


    /**
     * 
     */
    public void release () {
        long usage = this.usageCount.decrementAndGet();
        if ( log.isTraceEnabled() ) {
            log.trace("Release tree connection " + usage + " " + this);
        }

        if ( usage == 0 ) {
            synchronized ( this ) {
                try ( SmbTreeImpl t = getTree() ) {
                    if ( this.treeAcquired && t != null ) {
                        if ( log.isDebugEnabled() ) {
                            log.debug("Tree connection no longer in use, release tree " + t);
                        }
                        this.treeAcquired = false;
                        t.release();
                    }
                }
                if ( this.delegate != null && this.delegateAcquired ) {
                    this.delegateAcquired = false;
                    this.delegate.release();
                }
            }

            SmbTransportInternal et = this.exclusiveTransport;
            if ( et != null ) {
                synchronized ( this ) {
                    try {
                        log.debug("Disconnecting exclusive transport");
                        this.exclusiveTransport = null;
                        this.tree = null;
                        this.treeAcquired = false;
                        et.close();
                        et.disconnect(false, false);
                    }
                    catch ( Exception e ) {
                        log.error("Failed to close exclusive transport", e);
                    }
                }
            }
        }
        else if ( usage < 0 ) {
            log.error("Usage count dropped below zero " + this);
            throw new RuntimeCIFSException("Usage count dropped below zero");
        }
    }


    protected void checkRelease () {
        if ( isConnected() && this.usageCount.get() != 0 ) {
            log.warn("Tree connection was not properly released " + this);
        }
    }


    synchronized void disconnect ( boolean inError ) {
        try ( SmbSessionImpl session = getSession() ) {
            if ( session == null ) {
                return;
            }
            try ( SmbTransportImpl transport = session.getTransport() ) {
                synchronized ( transport ) {
                    SmbTreeImpl t = getTreeInternal();
                    if ( t != null ) {
                        try {
                            t.treeDisconnect(inError, true);
                        }
                        finally {
                            this.tree = null;
                            this.treeAcquired = false;
                        }
                    }
                    else {
                        this.delegate.disconnect(inError);
                    }
                }
            }
        }
    }


     T send ( SmbResourceLocatorImpl loc, CommonServerMessageBlockRequest request, T response,
            RequestParam... params ) throws CIFSException {
        return send(loc, request, response, params.length == 0 ? EnumSet.noneOf(RequestParam.class) : EnumSet.copyOf(Arrays.asList(params)));
    }


     T send ( SmbResourceLocatorImpl loc, CommonServerMessageBlockRequest request, T response,
            Set params ) throws CIFSException {
        CIFSException last = null;
        RequestWithPath rpath = ( request instanceof RequestWithPath ) ? (RequestWithPath) request : null;
        String savedPath = rpath != null ? rpath.getPath() : null;
        String savedFullPath = rpath != null ? rpath.getFullUNCPath() : null;

        String fullPath = "\\" + loc.getServer() + "\\" + loc.getShare() + loc.getUNCPath();
        int maxRetries = this.ctx.getConfig().getMaxRequestRetries();
        for ( int retries = 1; retries <= maxRetries; retries++ ) {

            if ( rpath != null ) {
                rpath.setFullUNCPath(null, null, fullPath);
            }

            try {
                return send0(loc, request, response, params);
            }
            catch ( SmbException smbe ) {
                // Retrying only makes sense if the invalid parameter is an tree id. If we have a stale file descriptor
                // retrying make no sense, as it will never become available again.
                if ( params.contains(RequestParam.NO_RETRY)
                        || ( ! ( smbe.getCause() instanceof TransportException ) ) && smbe.getNtStatus() != NtStatus.NT_STATUS_INVALID_PARAMETER ) {
                    log.debug("Not retrying", smbe);
                    throw smbe;
                }
                log.debug("send", smbe);
                last = smbe;
            }
            catch ( CIFSException e ) {
                log.debug("send", e);
                last = e;
            }
            // If we get here, we got the 'The Parameter is incorrect' error or a transport exception
            // Disconnect and try again from scratch.

            if ( log.isDebugEnabled() ) {
                log.debug(String.format("Retrying (%d/%d) request %s", retries, maxRetries, request));
            }

            // should we disconnect the transport here? otherwise we make an additional attempt to detect that if the
            // server closed the connection as a result
            log.debug("Disconnecting tree on send retry", last);
            disconnect(true);

            if ( retries >= maxRetries ) {
                break;
            }

            try {
                if ( retries != 1 ) {
                    // backoff, but don't delay the first attempt as there are various reasons that can be fixed
                    // immediately
                    Thread.sleep(500 + RAND.nextInt(1000));
                }
            }
            catch ( InterruptedException e ) {
                log.debug("interrupted sleep in send", e);
            }

            if ( request != null ) {
                log.debug("Restting request");
                request.reset();
            }
            if ( rpath != null ) {
                // resolveDfs() and tree.send() modify the request packet.
                // I want to restore it before retrying. request.reset()
                // restores almost everything that was modified, except the path.
                rpath.setPath(savedPath);
                rpath.setFullUNCPath(rpath.getDomain(), rpath.getServer(), savedFullPath);
            }
            if ( response != null ) {
                response.reset();
            }

            try ( SmbTreeHandle th = connectWrapException(loc) ) {
                log.debug("Have new tree connection for retry");
            }
            catch ( SmbException e ) {
                log.debug("Failed to connect tree on retry", e);
                last = e;
            }
        }

        if ( last != null ) {
            log.debug("All attempts have failed, last exception", last);
            throw last;
        }
        throw new SmbException("All attempts failed, but no exception");
    }


    private  T send0 ( SmbResourceLocatorImpl loc, CommonServerMessageBlockRequest request, T response,
            Set params ) throws CIFSException, DfsReferral {
        for ( int limit = 10; limit > 0; limit-- ) {
            if ( request instanceof RequestWithPath ) {
                ensureDFSResolved(loc, (RequestWithPath) request);
            }
            try ( SmbTreeImpl t = getTree() ) {
                if ( t == null ) {
                    throw new CIFSException("Failed to get tree connection");
                } ;
                return t.send(request, response, params);
            }
            catch ( DfsReferral dre ) {
                if ( dre.getData().unwrap(DfsReferralDataInternal.class).isResolveHashes() ) {
                    throw dre;
                }
                request.reset();
                log.trace("send0", dre);
            }
        }

        throw new CIFSException("Loop in DFS referrals");
    }


    /**
     * @param loc
     * @return tree handle
     * @throws SmbException
     */
    public SmbTreeHandleImpl connectWrapException ( SmbResourceLocatorImpl loc ) throws SmbException {
        try {
            return connect(loc);
        }
        catch ( UnknownHostException uhe ) {
            throw new SmbException("Failed to connect to server", uhe);
        }
        catch ( SmbException se ) {
            throw se;
        }
        catch ( IOException ioe ) {
            throw new SmbException("Failed to connect to server", ioe);
        }
    }


    /**
     * @param loc
     * @return tree handle
     * @throws IOException
     */
    public synchronized SmbTreeHandleImpl connect ( SmbResourceLocatorImpl loc ) throws IOException {
        try ( SmbSessionImpl session = getSession() ) {
            if ( isConnected() ) {
                try ( SmbTransportImpl transport = session.getTransport() ) {
                    if ( transport.isDisconnected() || transport.getRemoteHostName() == null ) {
                        /*
                         * Tree/session thinks it is connected but transport disconnected
                         * under it, reset tree to reflect the truth.
                         */
                        log.debug("Disconnecting failed tree and session");
                        disconnect(true);
                    }
                }
            }

            if ( isConnected() ) {
                log.trace("Already connected");
                return new SmbTreeHandleImpl(loc, this);
            }

            return connectHost(loc, loc.getServerWithDfs());
        }

    }


    /**
     * @return whether we have a valid tree connection
     */
    @SuppressWarnings ( "resource" )
    public synchronized boolean isConnected () {
        SmbTreeImpl t = getTreeInternal();
        return t != null && t.isConnected();
    }


    /**
     * 
     * @param loc
     * @param host
     * @return tree handle
     * @throws IOException
     */
    public synchronized SmbTreeHandleImpl connectHost ( SmbResourceLocatorImpl loc, String host ) throws IOException {
        return connectHost(loc, host, null);
    }


    /**
     * 
     * @param loc
     * @param host
     * @param referral
     * @return tree handle
     * @throws IOException
     */
    public synchronized SmbTreeHandleImpl connectHost ( SmbResourceLocatorImpl loc, String host, DfsReferralData referral ) throws IOException {
        String targetDomain = null;
        try ( SmbTreeImpl t = getTree() ) {
            if ( t != null ) {
                if ( log.isDebugEnabled() ) {
                    log.debug("Tree is " + t);
                }

                if ( Objects.equals(loc.getShare(), t.getShare()) ) {
                    try ( SmbSessionImpl session = t.getSession() ) {
                        targetDomain = session.getTargetDomain();
                        if ( !session.isFailed() ) {
                            try ( SmbTransportImpl trans = session.getTransport();
                                  SmbTreeImpl ct = connectTree(loc, host, t.getShare(), trans, t, null) ) {
                                switchTree(ct);
                                return new SmbTreeHandleImpl(loc, this);
                            }
                        }
                        log.debug("Session no longer valid");
                    }
                }
            }
        }

        String hostName = loc.getServerWithDfs();
        String path = ( loc.getType() == SmbConstants.TYPE_SHARE || loc.getUNCPath() == null || "\\".equals(loc.getUNCPath()) ) ? null
                : loc.getUNCPath();
        String share = loc.getShare();

        DfsReferralData start = referral != null ? referral : this.ctx.getDfs().resolve(this.ctx, hostName, loc.getShare(), path);
        DfsReferralData dr = start;
        IOException last = null;
        do {
            if ( dr != null ) {
                targetDomain = dr.getDomain();
                host = dr.getServer().toLowerCase(Locale.ROOT);
                share = dr.getShare();
            }

            try {

                if ( this.nonPooled ) {
                    if ( log.isDebugEnabled() ) {
                        log.debug("Using exclusive transport for " + this);
                    }
                    this.exclusiveTransport = this.ctx.getTransportPool()
                            .getSmbTransport(this.ctx, host, loc.getPort(), true, loc.shouldForceSigning()).unwrap(SmbTransportInternal.class);
                    SmbTransportInternal trans = this.exclusiveTransport;
                    try ( SmbSessionInternal smbSession = trans.getSmbSession(this.ctx, host, targetDomain).unwrap(SmbSessionInternal.class);
                          SmbTreeImpl uct = smbSession.getSmbTree(share, null).unwrap(SmbTreeImpl.class);
                          SmbTreeImpl ct = connectTree(loc, host, share, trans, uct, dr) ) {

                        if ( dr != null ) {
                            ct.setTreeReferral(dr);
                            if ( dr != start ) {
                                dr.unwrap(DfsReferralDataInternal.class).replaceCache();
                            }
                        }
                        switchTree(ct);
                        return new SmbTreeHandleImpl(loc, this);
                    }
                }

                try ( SmbTransportInternal trans = this.ctx.getTransportPool()
                        .getSmbTransport(this.ctx, host, loc.getPort(), false, loc.shouldForceSigning()).unwrap(SmbTransportInternal.class);
                      SmbSessionInternal smbSession = trans.getSmbSession(this.ctx, host, targetDomain).unwrap(SmbSessionInternal.class);
                      SmbTreeImpl uct = smbSession.getSmbTree(share, null).unwrap(SmbTreeImpl.class);
                      SmbTreeImpl ct = connectTree(loc, host, share, trans, uct, dr) ) {
                    if ( dr != null ) {
                        ct.setTreeReferral(dr);
                        if ( dr != start ) {
                            dr.unwrap(DfsReferralDataInternal.class).replaceCache();
                        }
                    }
                    switchTree(ct);
                    return new SmbTreeHandleImpl(loc, this);
                }
            }
            catch ( IOException e ) {
                last = e;
                log.debug("Referral failed, trying next", e);
            }

            if ( dr != null ) {
                dr = dr.next();
            }
        }
        while ( dr != start );
        throw last;
    }


    /**
     * @param loc
     * @param addr
     * @param trans
     * @param t
     * @throws CIFSException
     */
    private SmbTreeImpl connectTree ( SmbResourceLocatorImpl loc, String addr, String share, SmbTransportInternal trans, SmbTreeImpl t,
            DfsReferralData referral ) throws CIFSException {
        if ( log.isDebugEnabled() && trans.isSigningOptional() && !loc.isIPC() && !this.ctx.getConfig().isSigningEnforced() ) {
            log.debug("Signatures for file enabled but not required " + this);
        }

        if ( referral != null ) {
            t.markDomainDfs();
        }

        try {
            if ( log.isTraceEnabled() ) {
                log.trace("doConnect: " + addr);
            }
            t.treeConnect(null, null);
            return t.acquire();
        }
        catch ( SmbAuthException sae ) {
            log.debug("Authentication failed", sae);
            return retryAuthentication(loc, share, trans, t, referral, sae);
        }
    }


    private SmbTreeImpl retryAuthentication ( SmbResourceLocatorImpl loc, String share, SmbTransportInternal trans, SmbTreeImpl t,
            DfsReferralData referral, SmbAuthException sae ) throws SmbAuthException, CIFSException {
        try ( SmbSessionImpl treesess = t.getSession() ) {
            if ( treesess.getCredentials().isAnonymous() || treesess.getCredentials().isGuest() ) {
                // refresh anonymous session or fallback to anonymous from guest login
                try ( SmbSessionInternal s = trans
                        .getSmbSession(this.ctx.withAnonymousCredentials(), treesess.getTargetHost(), treesess.getTargetDomain())
                        .unwrap(SmbSessionInternal.class);
                      SmbTreeImpl tr = s.getSmbTree(share, null).unwrap(SmbTreeImpl.class) ) {
                    tr.treeConnect(null, null);
                    log.debug("Anonymous retry succeeded");
                    return tr.acquire();
                }
                catch ( Exception e ) {
                    log.debug("Retry also failed", e);
                    throw sae;
                }
            }
            else if ( this.ctx.renewCredentials(loc.getURL().toString(), sae) ) {
                log.debug("Trying to renew credentials after auth error");
                try ( SmbSessionInternal s = trans.getSmbSession(this.ctx, treesess.getTargetHost(), treesess.getTargetDomain())
                        .unwrap(SmbSessionInternal.class);
                      SmbTreeImpl tr = s.getSmbTree(share, null).unwrap(SmbTreeImpl.class) ) {
                    if ( referral != null ) {
                        tr.markDomainDfs();
                    }
                    tr.treeConnect(null, null);
                    return tr.acquire();
                }
            }
            else {
                throw sae;
            }
        }
    }


    SmbResourceLocator ensureDFSResolved ( SmbResourceLocatorImpl loc ) throws CIFSException {
        return ensureDFSResolved(loc, null);
    }


    SmbResourceLocator ensureDFSResolved ( SmbResourceLocatorImpl loc, RequestWithPath request ) throws CIFSException {
        if ( request instanceof SmbComClose )
            return loc;

        for ( int retries = 0; retries < 1 + this.ctx.getConfig().getMaxRequestRetries(); retries++ ) {
            try {
                return resolveDfs0(loc, request);
            }
            catch ( SmbException smbe ) {
                // The connection may have been dropped?
                if ( smbe.getNtStatus() != NtStatus.NT_STATUS_NOT_FOUND && ! ( smbe.getCause() instanceof TransportException ) ) {
                    throw smbe;
                }
                log.debug("resolveDfs", smbe);
            }
            // If we get here, we apparently have a bad connection.
            // Disconnect and try again.
            if ( log.isDebugEnabled() ) {
                log.debug("Retrying (" + retries + ") resolveDfs: " + request);
            }
            log.debug("Disconnecting tree on DFS retry");
            disconnect(true);
            try {
                Thread.sleep(500 + RAND.nextInt(5000));
            }
            catch ( InterruptedException e ) {
                log.debug("resolveDfs", e);
            }

            try ( SmbTreeHandle th = connectWrapException(loc) ) {}
        }

        return loc;
    }


    private SmbResourceLocator resolveDfs0 ( SmbResourceLocatorImpl loc, RequestWithPath request ) throws CIFSException {
        try ( SmbTreeHandleImpl th = connectWrapException(loc);
              SmbSessionImpl session = th.getSession();
              SmbTransportImpl transport = session.getTransport();
              SmbTreeImpl t = getTree() ) {
            transport.ensureConnected();

            String rpath = request != null ? request.getPath() : loc.getUNCPath();
            String rfullpath = request != null ? request.getFullUNCPath() : ( '\\' + loc.getServer() + '\\' + loc.getShare() + loc.getUNCPath() );
            if ( t.isInDomainDfs() || !t.isPossiblyDfs() ) {
                if ( t.isInDomainDfs() ) {
                    // need to adjust request path
                    DfsReferralData dr = t.getTreeReferral();
                    if ( dr != null ) {
                        if ( log.isDebugEnabled() ) {
                            log.debug(String.format("Need to adjust request path %s (full: %s) -> %s", rpath, rfullpath, dr));
                        }
                        String dunc = loc.handleDFSReferral(dr, rpath);
                        if ( request != null ) {
                            request.setPath(dunc);
                        }
                        return loc;
                    }

                    // fallthrough to normal handling
                    log.debug("No tree referral but in DFS");
                }
                else {
                    log.trace("Not in DFS");
                    return loc;
                }
            }

            if ( request != null ) {
                request.setFullUNCPath(session.getTargetDomain(), session.getTargetHost(), rfullpath);
            }

            // for standalone DFS we could be checking for a referral here, too
            DfsReferralData dr = this.ctx.getDfs().resolve(this.ctx, loc.getServer(), loc.getShare(), loc.getUNCPath());
            if ( dr != null ) {
                if ( log.isDebugEnabled() ) {
                    log.debug("Resolved " + rfullpath + " -> " + dr);
                }

                String dunc = loc.handleDFSReferral(dr, rpath);
                if ( request != null ) {
                    request.setPath(dunc);
                }

                if ( !t.getShare().equals(dr.getShare()) ) {
                    // this should only happen for standalone roots or if the DC/domain root lookup failed
                    IOException last;
                    DfsReferralData start = dr;
                    do {
                        if ( log.isDebugEnabled() ) {
                            log.debug("Need to switch tree for " + dr);
                        }
                        try ( SmbTreeHandleImpl nt = connectHost(loc, session.getTargetHost(), dr) ) {
                            log.debug("Switched tree");
                            return loc;
                        }
                        catch ( IOException e ) {
                            log.debug("Failed to connect tree", e);
                            last = e;
                        }
                        dr = dr.next();
                    }
                    while ( dr != start );
                    throw new CIFSException("All referral tree connections failed", last);
                }

                return loc;
            }
            else if ( t.isInDomainDfs() && ! ( request instanceof NtTransQuerySecurityDesc ) && ! ( request instanceof SmbComClose )
                    && ! ( request instanceof SmbComFindClose2 ) ) {
                if ( log.isDebugEnabled() ) {
                    log.debug("No referral available for  " + rfullpath);
                }
                throw new CIFSException("No referral but in domain DFS " + rfullpath);
            }
            else {
                log.trace("Not in DFS");
                return loc;
            }
        }
    }


    /**
     * Use a exclusive connection for this tree
     * 
     * If an exclusive connection is used the caller must make sure that the tree handle is kept alive,
     * otherwise the connection will be disconnected once the usage drops to zero.
     * 
     * @param np
     *            whether to use an exclusive connection
     */
    void setNonPooled ( boolean np ) {
        this.nonPooled = np;
    }


    /**
     * @return the currently connected tid
     */
    @SuppressWarnings ( "resource" )
    public long getTreeId () {
        SmbTreeImpl t = getTreeInternal();
        if ( t == null ) {
            return -1;
        }
        return t.getTreeNum();
    }


    /**
     * 
     * Only call this method while holding a tree handle
     * 
     * @return session that this file has been loaded through
     */
    @SuppressWarnings ( "resource" )
    public SmbSessionImpl getSession () {
        SmbTreeImpl t = getTreeInternal();
        if ( t != null ) {
            return t.getSession();
        }
        return null;
    }


    /**
     * 
     * Only call this method while holding a tree handle
     * 
     * @param cap
     * @return whether the capability is available
     * @throws SmbException
     */
    public boolean hasCapability ( int cap ) throws SmbException {
        try ( SmbSessionImpl s = getSession() ) {
            if ( s != null ) {
                try ( SmbTransportImpl transport = s.getTransport() ) {
                    return transport.hasCapability(cap);
                }
            }
            throw new SmbException("Not connected");
        }
    }


    /**
     * Only call this method while holding a tree handle
     * 
     * @return the connected tree type
     */
    public int getTreeType () {
        try ( SmbTreeImpl t = getTree() ) {
            return t.getTreeType();
        }
    }


    /**
     * 
     * Only call this method while holding a tree handle
     * 
     * @return the share we are connected to
     */
    public String getConnectedShare () {
        try ( SmbTreeImpl t = getTree() ) {
            return t.getShare();
        }
    }


    /**
     * 
     * Only call this method while holding a tree handle
     * 
     * @param other
     * @return whether the connection refers to the same tree
     */
    public boolean isSame ( SmbTreeConnection other ) {
        try ( SmbTreeImpl t1 = getTree();
              SmbTreeImpl t2 = other.getTree() ) {
            return t1 == t2;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy