jcifs-0.5.2 from tgz
authorFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 13:59:53 +0000 (15:59 +0200)
committerFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 13:59:53 +0000 (15:59 +0200)
jcifs-0.5.2 from tgz

 There have been significant changes under the hood. The primitives such as packet encoding/decoding and transport have proven very sturdy however
 the top level glue and logic driving the client really needed an overhaul in hindsight. The client is much smarter now whereas previously jCIFS
 was quite chatty and used some messages abusively (NodeStatusRequest). Some other cleanups that took into account allocation of buffers and large
 numbers of objects have resulted in measureable performance improvements. All of this should be transparent to the user however my confidence in
 the stabilty of 0.5.1 no longer applies. It will take some time to confirm everything works as advertised. I am confident however that any bugs
 will only require minor adjustments to fix. Of course the name resolution bug that triggered this crusade has been fixed.

 There are some API changes. Most methods of SmbFile throw the now public SmbException. Natrually, this will require changes to existing code. For
 example, if your code was:

 if( r.delete() ) {
   System.out.println( "delete successfull" );
 } else {
   System.out.println( "error!" );
 }

 you might replace this with:

 try {
   f.delete();
   System.out.println( "delete successfull" );
 } catch( SmbException se ) {
   System.out.println( "error: " + se.getMessage() );
 }

 There are quite a few different messages that can be provoked such as:

 The file is being used by another process
 The device is not ready
 All pipe instances are busy
 ...

 not all of which have text messages (and which ones do have messages are in only English at the moment). You can test and make dicisions based on the
 errorClass and errorCode of an SmbException. All SmbExceptions are thrown through these methods unless an object implementing the AuthHandler
 interface has been called with the static SmbFile.setAuthHanler method. If an AuthHandler has been specified the following authentication related
 SmbExceptions:

 Access denied
 Bad password
 The client does not have the necessary access rights for the requested function
 The user account has expired
 The user is not allowed to access this server from this client
 The user is not permitted to access the server at this time
 The password of the user has expired

 will not be thrown by SmbFile methods but rather passed in the AuthInfo object to the AuthHandler's authenticate() method along with the username,
 password,
 domain, and target URL if one of these SmbExceptions occurs. See http://lists.samba.org/pipermail/jcifs/2001-October/001553.html for a related
 discussion. I
 believe this is a powerfull feature in itself. This provides for sophisticated error handling and consistent error messages (the messages are the
 same as those reported by Windows clients). There is also an oppurunity to introduce a ResourceBundle of text messages here. I beleive it will work
 quite well and in practice I do not believe code will be cluttered with try/catch.

 The NbtAddress class was designed to handle NetBIOS name queries similarly to the common InetAddress class. Unfortunately a lapse in judgment
 integrated DNS
 queries into this class in jcifs-0.5 (thus the name service bug). The solution is to remove this DNS code and provide a wrapper class that handles
 both DNS queries as well as NetBIOS queries mainly delegating the work to InetAddress and NbtAddress. This class is UniAddress. Here is how each of
 these classes should be used:

 o InetAddress - Lookup a DNS name
 o NbtAddress - Lookup a NetBIOS name or perform NetBIOS specific
     queries (NodeStatus with getAllByAddress)
 o UniAddress - Don't know or care what type of name it is, try to
     find the name with both DNS and NetBIOS queries if necessary. Query
     behavior is governed by the jcifs.resolveOrder property.

 So generally the UniAddress class should be used if you wish to interface
 with name services directly (normally not necessary when working with
 the jcifs.smb package).

56 files changed:
README.txt
build.xml
examples/AuthDialog.java [new file with mode: 0644]
examples/CrawlerBench.java [new file with mode: 0644]
examples/Delete.java
examples/Dns.java [new file with mode: 0644]
examples/FileOps.java
examples/GetURL.java
examples/IsDir.java [new file with mode: 0644]
examples/Length.java [new file with mode: 0644]
examples/List.java
examples/Mkdir.java
examples/ProcTest.java [new file with mode: 0644]
examples/Query.java
examples/RenameTo.java
examples/SmbShell.java
examples/TestSmbFile.java
examples/ThreadedSmbCrawler.java
examples/TortureTest5.java
src/jcifs/Config.java
src/jcifs/UniAddress.java [new file with mode: 0644]
src/jcifs/netbios/Lmhosts.java
src/jcifs/netbios/Log.java
src/jcifs/netbios/Name.java
src/jcifs/netbios/NameQueryResponse.java
src/jcifs/netbios/NameServiceClient.java
src/jcifs/netbios/NbtAddress.java
src/jcifs/netbios/NbtSocket.java
src/jcifs/netbios/NodeStatusRequest.java
src/jcifs/netbios/NodeStatusResponse.java
src/jcifs/netbios/SessionRequestPacket.java
src/jcifs/smb/AndXServerMessageBlock.java
src/jcifs/smb/BufferCache.java [new file with mode: 0644]
src/jcifs/smb/Handler.java
src/jcifs/smb/NetServerEnum2.java
src/jcifs/smb/NetServerEnum2Response.java
src/jcifs/smb/NetShareEnumResponse.java
src/jcifs/smb/ServerMessageBlock.java
src/jcifs/smb/SmbAuthException.java [new file with mode: 0644]
src/jcifs/smb/SmbComNTCreateAndX.java
src/jcifs/smb/SmbComTransaction.java
src/jcifs/smb/SmbComTransactionResponse.java
src/jcifs/smb/SmbComTreeConnectAndX.java
src/jcifs/smb/SmbException.java
src/jcifs/smb/SmbFile.java
src/jcifs/smb/SmbFileInputStream.java
src/jcifs/smb/SmbFileOutputStream.java
src/jcifs/smb/SmbSession.java
src/jcifs/smb/SmbTransport.java
src/jcifs/smb/SmbTree.java
src/jcifs/smb/SmbURL.java
src/jcifs/smb/SmbURLConnection.java
src/jcifs/smb/TransactNamedPipeOutputStream.java
src/jcifs/util/AuthHandler.java [new file with mode: 0644]
src/jcifs/util/AuthInfo.java [new file with mode: 0644]
src/jcifs/util/Config.java

index ea26918..21ea297 100644 (file)
@@ -1,3 +1,54 @@
+There have been significant changes under the hood. The primitives such as packet encoding/decoding and transport have proven very sturdy however the top level glue and logic driving the client really needed an overhaul in hindsight. The client is much smarter now whereas previously jCIFS was quite chatty and used some messages abusively (NodeStatusRequest). Some other cleanups that took into account allocation of buffers and large numbers of objects have resulted in measureable performance improvements. All of this should be transparent to the user however my confidence in the stabilty of 0.5.1 no longer applies. It will take some time to confirm everything works as advertised. I am confident however that any bugs will only require minor adjustments to fix. Of course the name resolution bug that triggered this crusade has been fixed.
+
+There are some API changes. Most methods of SmbFile throw the now public SmbException. Natrually, this will require changes to existing code. For example, if your code was:
+
+if( r.delete() ) {
+  System.out.println( "delete successfull" );
+} else {
+  System.out.println( "error!" );
+}
+
+you might replace this with:
+
+try {
+  f.delete();
+  System.out.println( "delete successfull" );
+} catch( SmbException se ) {
+  System.out.println( "error: " + se.getMessage() );
+}
+
+There are quite a few different messages that can be provoked such as:
+
+The file is being used by another process
+The device is not ready
+All pipe instances are busy
+...
+
+not all of which have text messages (and which ones do have messages are in only English at the moment). You can test and make dicisions based on the errorClass and errorCode of an SmbException. All SmbExceptions are thrown through these methods unless an object implementing the AuthHandler interface has been called with the static SmbFile.setAuthHanler method. If an AuthHandler has been specified the following authentication related SmbExceptions:
+
+Access denied
+Bad password
+The client does not have the necessary access rights for the requested function
+The user account has expired
+The user is not allowed to access this server from this client
+The user is not permitted to access the server at this time
+The password of the user has expired
+
+will not be thrown by SmbFile methods but rather passed in the AuthInfo object to the AuthHandler's authenticate() method along with the username, password, domain, and target URL if one of these SmbExceptions occurs. See http://lists.samba.org/pipermail/jcifs/2001-October/001553.html for a related discussion. I believe this is a powerfull feature in itself. This provides for sophisticated error handling and consistent error messages (the messages are the same as those reported by Windows clients). There is also an oppurunity to introduce a ResourceBundle of text messages here. I beleive it will work quite well and in practice I do not believe code will be cluttered with try/catch.
+
+The NbtAddress class was designed to handle NetBIOS name queries similarly to the common InetAddress class. Unfortunately a lapse in judgment integrated DNS queries into this class in jcifs-0.5 (thus the name service bug). The solution is to remove this DNS code and provide a wrapper class that handles both DNS queries as well as NetBIOS queries mainly delegating the work to InetAddress and NbtAddress. This class is UniAddress. Here is how each of these classes should be used:
+
+o InetAddress - Lookup a DNS name
+o NbtAddress - Lookup a NetBIOS name or perform NetBIOS specific
+    queries (NodeStatus with getAllByAddress)
+o UniAddress - Don't know or care what type of name it is, try to
+    find the name with both DNS and NetBIOS queries if necessary. Query
+    behavior is governed by the jcifs.resolveOrder property.
+
+So generally the UniAddress class should be used if you wish to interface
+with name services directly (normally not necessary when working with
+the jcifs.smb package).
+
 Mon Aug 27 00:29:02 EDT 2001
 
 jcifs-0.5.1
@@ -5,7 +56,7 @@ jcifs-0.5.1
 Chris did some great testing at the CIFS Conference Interoperability
 Lab and found three minor bugs. They are described in detail here:
 
-http://lists.samba.org/pipermail/jcifs/2001-August/001428.html
+http://lists.samba.org/pipermail/jcifs/2001-August/001428
 
 These packages will now work with Java 1.1 as well as Java 2.
 
index 038b4f6..8561843 100644 (file)
--- a/build.xml
+++ b/build.xml
                                destdir="build"
                                includes="jcifs/util/*.java"
                                debug="on"/>
-               <javac srcdir="src"
-                               destdir="build"
-                               includes="jcifs/Config.java"
-                               debug="on"/>
        </target>
        <target name="netbios" depends="util">
                <mkdir dir="build"/>
                <delete dir="build"/>
        </target>
        <target name="jar" depends="smb">
-               <jar jarfile="jcifs-0.5.1.jar" basedir="build"/>
+               <jar jarfile="jcifs-0.5.2.jar" basedir="build"/>
        </target>
 
        <target name="tgz">
-               <copy todir="dist_tmp/jcifs_0.5.1">
+               <copy todir="dist_tmp/jcifs_0.5.2">
                        <fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
                </copy>
-               <tar tarfile="jcifs-0.5.1.tar" basedir="dist_tmp"/>
-               <gzip src="jcifs-0.5.1.tar" zipfile="jcifs-0.5.1.tgz"/>
-               <delete file="jcifs-0.5.1.tar"/>
+               <tar tarfile="jcifs-0.5.2.tar" basedir="dist_tmp"/>
+               <gzip src="jcifs-0.5.2.tar" zipfile="jcifs-0.5.2.tgz"/>
+               <delete file="jcifs-0.5.2.tar"/>
                <delete dir="dist_tmp"/>
        </target>
        <target name="zip">
-               <copy todir="dist_tmp/jcifs_0.5.1">
+               <copy todir="dist_tmp/jcifs_0.5.2">
                        <fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
                </copy>
                <fixcrlf srcdir="dist_tmp" cr="add" tab="remove" tablength="4" excludes="**/*.jar,**/*.exe"/>
-               <zip zipfile="jcifs-0.5.1.zip" basedir="dist_tmp"/>
+               <zip zipfile="jcifs-0.5.2.zip" basedir="dist_tmp"/>
                <delete dir="dist_tmp"/>
        </target>
 
        <target name="javadoc">
                <delete dir="docs/api"/>
                <mkdir dir="docs/api"/>
-               <javadoc sourcefiles="jcifs/netbios/NbtAddress,jcifs/smb/SmbFile,jcifs/smb/SmbNamedPipe,jcifs/smb/SmbFileInputStream,jcifs/smb/SmbFileOutputStream,jcifs/smb/SmbURLConnection,jcifs/util/Config,jcifs/util/PropertiesTree,jcifs/util/Log"
+               <javadoc sourcefiles="jcifs/netbios/NbtAddress,jcifs/smb/SmbFile,jcifs/smb/SmbException,jcifs/util/AuthHandler,jcifs/util/AuthInfo,jcifs/smb/SmbNamedPipe,jcifs/smb/SmbFileInputStream,jcifs/smb/SmbFileOutputStream,jcifs/smb/SmbURLConnection,jcifs/UniAddress,jcifs/Config,jcifs/util/PropertiesTree,jcifs/util/Log"
                                sourcepath="src"
                                destdir="docs/api"
                                overview="docs/overview.html"
diff --git a/examples/AuthDialog.java b/examples/AuthDialog.java
new file mode 100644 (file)
index 0000000..0587cff
--- /dev/null
@@ -0,0 +1,64 @@
+import java.awt.*;
+import java.awt.event.*;
+
+public class AuthDialog extends Dialog implements ActionListener {
+
+       Panel labels, fields, top, middle, buttons;
+       TextField username, password;
+       Button ok, cancel;
+
+       public AuthDialog() {
+               super( new Frame(), "Authentication", true );
+               setSize( 200, 165 );
+               setLocation( 400, 300 );
+
+               top = new Panel();
+               middle = new Panel();
+               labels = new Panel( new GridLayout( 2, 1 ));
+               fields = new Panel( new GridLayout( 2, 1 ));
+               buttons = new Panel( new GridLayout( 1, 2 ));
+
+               username = new TextField( 15 );
+               password = new TextField( 15 );
+
+               fields.add( username );
+               fields.add( password );
+
+               labels.add( new Label( "Username:" ));
+               labels.add( new Label( "Password:" ));
+
+               middle.add( labels, BorderLayout.WEST );
+               middle.add( fields, BorderLayout.CENTER );
+
+               top.add( new TextArea( "The client does not have the necessary access rights for the requested function", 3, 30, TextArea.SCROLLBARS_NONE ), BorderLayout.CENTER );
+               top.add( middle, BorderLayout.SOUTH );
+
+               ok = new Button( "Ok" );
+               cancel = new Button( "Cancel" );
+               password.setEchoChar( '*' );
+               ok.addActionListener( this );
+               cancel.addActionListener( this );
+               buttons.add( ok );
+               buttons.add( cancel );
+
+               add( top, BorderLayout.CENTER );
+               add( buttons, BorderLayout.SOUTH );
+
+               addWindowListener( new CloseWindow() );
+       }
+
+       public void actionPerformed( ActionEvent ae ) {
+               setVisible( false );
+       }
+
+       class CloseWindow extends WindowAdapter {
+               public void windowClosing( WindowEvent e ) {
+                       setVisible( false );
+               }
+       }
+
+       public static void main( String[] argv ) {
+               AuthDialog authDialog = new AuthDialog();
+               authDialog.setVisible( true );
+       }
+}
diff --git a/examples/CrawlerBench.java b/examples/CrawlerBench.java
new file mode 100644 (file)
index 0000000..12e60bb
--- /dev/null
@@ -0,0 +1,116 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import jcifs.smb.SmbFile;
+import jcifs.util.Log;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.net.MalformedURLException;
+import java.io.*;
+
+public class CrawlerBench {
+
+       static long time;
+
+       class DirEntry {
+               SmbFile dir;
+               int depth;
+
+               DirEntry( SmbFile dir, int depth ) {
+                       this.dir = dir;
+                       this.depth = depth;
+               }
+       }
+
+       class SmbCrawlerThread extends Thread {
+
+               StringBuffer sb = new StringBuffer();
+
+               SmbCrawlerThread() {
+               }
+
+               public void run() {
+                       try {
+                               Thread.sleep( 5000 );
+                       } catch( Exception e ) {
+                       }
+                       while( true ) {
+                               try {
+                                       DirEntry e;
+
+                                       synchronized( dirList ) {
+                                               while( dirList.isEmpty() ) {
+                                                       dirList.wait( 500 );
+                                               }
+                                               e = (DirEntry)dirList.remove( 0 );
+                                       }
+
+                                       if( e.depth == 0 ) {
+                                               continue;
+                                       }
+
+                                       String[] l = e.dir.list();
+
+                                       int n = maxDepth - e.depth;
+
+                                       for(int i = 0; l != null && i < l.length; i++ ) {
+                                               try {
+                                                       sb.setLength( 0 );
+                                                       for( int k = 0; k < n; k++ ) {
+                               //                              sb.append( "    " );
+                                                       }
+                                                       SmbFile d = new SmbFile( e.dir, l[i] );
+                                       //              System.out.println( sb.append( d ));
+                                                       if( d.isDirectory() ) {
+                                                               synchronized( dirList ) {
+                                                                       dirList.add( new DirEntry( d, e.depth - 1 ));
+                                                                       dirList.notify();
+                                                               }
+                                                       }
+                                               } catch( IOException ioe ) {
+                                               }
+                                       }
+                               } catch( Exception x ) {
+                               }
+                       }
+               }
+       }
+
+       LinkedList dirList;
+       int maxDepth;
+
+       CrawlerBench( String dir, int maxDepth, int numThreads ) throws Exception {
+               this.maxDepth = maxDepth;
+               dirList = new LinkedList();
+               dirList.add( new DirEntry( new SmbFile( dir ), maxDepth ));
+               for( int i = 0; i < numThreads; i++ ) {
+                       (new SmbCrawlerThread()).start();
+               }
+       }
+
+       public static void main(String[] argv) throws Exception {
+               if( argv.length < 3 ) {
+                       System.out.println( "usage: CrawlerBench dir depth numThreads" );
+                       return;
+               }
+               System.out.print( "Hit Enter when ready." );
+               System.in.read();
+
+               new CrawlerBench( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] ));
+       }
+}
index be09979..8aea63e 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 import jcifs.smb.SmbFile;
+import jcifs.smb.SmbException;
 
 public class Delete {
 
@@ -25,10 +26,15 @@ public class Delete {
                long t0 = System.currentTimeMillis();
 
                SmbFile f = new SmbFile( argv[0] );
-               if( f.delete() ) {
-                       System.out.println( f.getCanonicalPath() + " deleted " + ( System.currentTimeMillis() - t0 ) + "ms" );
-               } else {
-                       System.out.println( f.getCanonicalPath() + " deleted failed" );
+               try {
+                       if( f.delete() ) {
+                               System.out.println( f.getCanonicalPath() + " deleted " + ( System.currentTimeMillis() - t0 ) + "ms" );
+                       } else {
+                               System.out.println( "Could not find " + f.getCanonicalPath() );
+                       }
+               } catch( SmbException se ) {
+                       System.out.println( se.getMessage() );
+                       se.printStackTrace();
                }
        }
 }
diff --git a/examples/Dns.java b/examples/Dns.java
new file mode 100644 (file)
index 0000000..2a5209f
--- /dev/null
@@ -0,0 +1,10 @@
+import jcifs.netbios.NbtAddress;
+import java.net.*;
+
+public class Dns {
+
+       public static void main( String argv[] ) throws Exception {
+               DatagramSocket s = new DatagramSocket( 0, InetAddress.getByName( "255.255.255.255" ));
+       }
+}
+
index 2b717ee..bb64368 100644 (file)
@@ -67,11 +67,12 @@ public class FileOps {
 
        // delete - Delete the directory if it exists
 
-               if( d.delete() ) {
-                       System.out.println( "okay - delete " + d + " successfull" );
-               } else {
-                       System.out.println( "okay - delete " + d + " failed" );
+               try {
+                       d.delete();
+               } catch( SmbException se ) {
+                       System.out.println( "okay - delete " + d + " failed: " + se.getMessage() );
                }
+               System.out.println( "okay - delete " + d + " successfull" );
 
        // exists - Test the directory that should not exist
 
@@ -84,14 +85,10 @@ public class FileOps {
 
        // mkdir - Create the directory
 
-               if( d.mkdir() ) {
-                       System.out.println( "okay - mkdir " + d + " successfull" );
-               } else {
-                       System.out.println( "fail - mkdir " + d + " failed" );
-                       System.exit( 1 );
-               }
+               d.mkdir();
+               System.out.println( "okay - mkdir " + d + " successfull" );
 
-       // exist - Test the directory with should exist now
+       // exist - Test the directory which should exist now
 
                if( d.exists() ) {
                        System.out.println( "okay - " + d + " exists" );
@@ -102,11 +99,12 @@ public class FileOps {
 
        // mkdir - Try to create a directory even though it already exists
 
-               if( d.mkdir() ) {
+               try {
+                       d.mkdir();
                        System.out.println( "fail - mkdir " + d + " successfull" );
                        System.exit( 1 );
-               } else {
-                       System.out.println( "okay - mkdir " + d + " failed" );
+               } catch( SmbException se ) {
+                       System.out.println( "okay - mkdir " + d + " failed: " + se.getMessage() );
                }
 
        // Create a file to test against
@@ -118,9 +116,9 @@ public class FileOps {
                o.write( "The Common Internet File System (CIFS) is the de-facto file sharing protocol on the Microsoft Windows platform. It is the underlying networking protocol used when accessing shares with Windows Explorer, the Network Neighborhood, via a Map Network Drive...  dialog, the C:\\> net use * \\\\server\\share commands, or smbclient on UNIX, smbfs on Linux, and elsewhere.\r\n".getBytes() );
                o.close();
        } catch( IOException ioe ) {
-               System.out.println( "fail - could not create file " + d + "/aboutcifs.txt");
+               System.out.println( "fail - could not create file " + d + "/foo.txt: " + ioe.getMessage() );
        }
-       System.out.println( "okay - created file " + d + "/aboutcifs.txt" );
+       System.out.println( "okay - created file " + d + "/foo.txt" );
 
        // canRead - Test to see if the new file can be read
 
@@ -160,21 +158,24 @@ public class FileOps {
                        w.close();
                        System.out.println( "fail - successfully opened " + f + " for writing even though it should be marked read-only ... continuing on" );
                } catch( IOException ioe ) {
-                       System.out.println( "okay - correctly failed to open " + f + " for writing" );
+                       System.out.println( "okay - correctly failed to open " + f + " for writing: " + ioe.getMessage() );
                }
 
        // renameTo - rename the file to bar.txt
 
                SmbFile b = new SmbFile( d, "bar.txt" );
 
-               if( f.renameTo(b) ) {
+               try {
+                       f.renameTo( b );
                        System.out.println( "okay - renameTo " + f + " to " + b + " successfull even with read-only" );
-                       if( b.renameTo(f) == false ) {
+                       try {
+                               b.renameTo(f);
+                       } catch( SmbException se ) {
                                System.out.println( "fail - but failed to rename file back to original!" );
-                               System.exit( 1 );
+                               throw se;
                        }
-               } else {
-                       System.out.println( "fail - renameTo " + f + " should have been successfull even though the file is marked read-only" );
+               } catch( SmbException se ) {
+                       System.out.println( "fail - renameTo " + f + " should have been successfull even though the file is marked read-only: " + se.getMessage() );
                }
 
        // ASK USER TO FLIP ON HIDDEN FLAG
@@ -240,10 +241,11 @@ public class FileOps {
 
        // delete - See if we can delete the file even though it's read-only
 
-               if( f.delete() ) {
+               try {
+                       f.delete();
                        System.out.println( "fail - delete " + f + " should not have been successfull because it is read-only" );
-               } else {
-                       System.out.println( "okay - delete " + f + " failed because it is read-only" );
+               } catch( SmbException se ) {
+                       System.out.println( "okay - delete " + f + " failed because it is read-only: " + se.getMessage() );
                }
 
        // Flip off both read-only and hidden
@@ -263,26 +265,29 @@ public class FileOps {
 
        // Must delete any left over directory from a previous run
 
-               if( r.delete() ) {
+               try {
+                       r.delete();
                        System.out.println( "okay - delete " + r + " successfull" );
-               } else {
-                       System.out.println( "okay - delete " + r + " probably wasn't there" );
+               } catch( SmbException se ) {
+                       System.out.println( "okay - delete " + r + " probably wasn't there: " + se.getMessage() );
                }
 
        // renameTo - Rename the whole directory to JcifsDeleteMe
 
-               if( d.renameTo( r )) {
+               try {
+                       d.renameTo( r );
                        System.out.println( "okay - renameTo " + d + " successfull even though it is a directory" );
-               } else {
-                       System.out.println( "fail - renameTo " + d + " failed" );
+               } catch( SmbException se ) {
+                       System.out.println( "fail - renameTo " + d + " failed: " + se.getMessage() );
                }
 
        // delete - Now delete the whole workspace
 
-               if( r.delete() ) {
+               try {
+                       r.delete();
                        System.out.println( "okay - delete " + d + " successfull" );
-               } else {
-                       System.out.println( "fail - delete " + d + " failed" );
+               } catch( SmbException se ) {
+                       System.out.println( "fail - delete " + d + " failed: " + se.getMessage() );
                }
        }
 }
index 1298554..0ba6317 100644 (file)
@@ -23,6 +23,8 @@ public class GetURL {
 
        public static void main( String argv[] ) throws Exception {
 
+               System.in.read();
+
                Class.forName( "jcifs.Config" );
 
                URL url = new URL( argv[0] );
diff --git a/examples/IsDir.java b/examples/IsDir.java
new file mode 100644 (file)
index 0000000..273a4e9
--- /dev/null
@@ -0,0 +1,28 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import jcifs.util.Log;
+import jcifs.smb.SmbFile;
+
+public class IsDir {
+
+       public static void main( String argv[] ) throws Exception {
+               (new SmbFile( argv[0] )).isDirectory();
+       }
+}
+
diff --git a/examples/Length.java b/examples/Length.java
new file mode 100644 (file)
index 0000000..152a8b6
--- /dev/null
@@ -0,0 +1,29 @@
+/* examples for the jcifs smb client library in Java
+ * Copyright (C) 2001  "Michael B. Allen" <mballen@erols.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import jcifs.smb.SmbFile;
+
+public class Length {
+
+       public static void main( String argv[] ) throws Exception {
+
+               SmbFile f = new SmbFile( argv[0] );
+               System.out.println( argv[0] + "'s length is " + f.length() );
+       }
+}
+
index 33eb841..fe4ab54 100644 (file)
@@ -16,6 +16,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+import jcifs.netbios.NbtAddress;
 import jcifs.smb.SmbFile;
 import jcifs.util.Log;
 import java.util.Date;
@@ -26,6 +27,7 @@ public class List {
 
                SmbFile file = new SmbFile( argv[0] );
 
+               file.list();
                long t1 = System.currentTimeMillis();
                String[] files = file.list();
                long t2 = System.currentTimeMillis() - t1;
index b9e3f42..310a2fa 100644 (file)
@@ -21,13 +21,11 @@ import jcifs.smb.SmbFile;
 
 public class Mkdir {
 
-       public static void main( String argv[] ) throws Exception {
-
-               SmbFile f = new SmbFile( argv[0] );
-               if( f.mkdir() ) {
-                       System.out.println( f.getCanonicalPath() + " created" );
-               } else {
-                       System.out.println( "mkdir failed: " + f.getCanonicalPath() );
+       public static void main( String argv[] ) {
+               try {
+                       (new SmbFile( argv[0] )).mkdir();
+               } catch( Exception e ) {
+                       e.printStackTrace();
                }
        }
 }
diff --git a/examples/ProcTest.java b/examples/ProcTest.java
new file mode 100644 (file)
index 0000000..a8b9758
--- /dev/null
@@ -0,0 +1,17 @@
+import java.io.*;
+
+public class ProcTest {
+
+       public static void main( String[] argv ) throws Exception {
+               BufferedReader br = new BufferedReader( new InputStreamReader( System.in ));
+               String pid = br.readLine();
+
+               FileInputStream fis = new FileInputStream( "/proc/" + pid + "/status" );
+
+               int ch;
+               while(( ch = fis.read() ) != -1 ) {
+                       System.out.print( (char)ch );
+               }
+               System.out.println( "done" );
+       }
+}
index 17b7ac0..8910ce8 100644 (file)
  */
 
 import jcifs.netbios.NbtAddress;
+import jcifs.UniAddress;
+import java.net.InetAddress;
 
 public class Query {
 
        public static void main( String argv[] ) throws Exception {
-               System.out.println( NbtAddress.getByName( argv[0], 0x1b, "" ));
+               UniAddress ua;
+               String cn;
+
+               ua = UniAddress.getByName( argv[0] );
+
+               cn = ua.firstCalledName();
+               do {
+                       System.out.println( "calledName=" + cn );
+               } while(( cn = ua.nextCalledName() ) != null );
        }
 }
index 6d196c3..91ffd3c 100644 (file)
@@ -24,11 +24,7 @@ public class RenameTo {
 
                SmbFile from = new SmbFile( argv[0] );
                SmbFile to = new SmbFile( argv[1] );
-               if( from.renameTo( to )) {
-                       System.out.println( from.getCanonicalPath() + " renamed to " + to.getCanonicalPath() );
-               } else {
-                       System.out.println( "Failed to rename " + from.getCanonicalPath() + " to " + to.getCanonicalPath() );
-               }
+               from.renameTo( to );
        }
 }
 
index 3793f0c..ddcdf25 100644 (file)
  */
 
 import jcifs.smb.*;
+import jcifs.util.AuthHandler;
+import jcifs.util.AuthInfo;
 import java.net.UnknownHostException;
 import java.net.MalformedURLException;
 
-public class SmbShell {
+public class SmbShell implements AuthHandler {
 
     public static String readLine() throws Exception {
         int c;
         StringBuffer sb = new StringBuffer();
         while(( c = System.in.read() ) != '\n' ) {
+                       if( c == -1 ) return "";
             sb.append( (char)c );
         }
         return sb.toString().trim();
     }
 
-    public static void main( String[] argv ) throws Exception {
+       public boolean authenticate( AuthInfo authInfo ) {
+               System.out.println( authInfo.exception.getMessage() + " on " + authInfo.target + " as " + authInfo.domain + "\\" + authInfo.username );
+               System.out.print( "    user: " );
+               int i;
+               try {
+                       String user = readLine();
+                       if((i = user.indexOf( '\\' )) != -1 ) {
+                               authInfo.domain = user.substring( 0, i );
+                               authInfo.username = user.substring( i + 1 );
+                       } else {
+                               authInfo.username = user;
+                       }
+                       System.out.print( "password: " );
+                       authInfo.password = readLine();
+                       if( authInfo.password.length() > 0 ) {
+                               return true;
+                       }
+               } catch( Exception e ) {
+               }
+               return false;
+       }
+
+       void run() throws Exception {
         int c;
         String cmd, prompt;
                SmbFile conn, tmp;
 
+               SmbFile.setAuthHandler( this );
+
                conn = new SmbFile( "smb://" );
         while( true ) {
                        try {
@@ -98,13 +125,17 @@ public class SmbShell {
                        System.out.println( "  pwd" );
                        System.out.println( "  quit" );
                    }
-                       } catch( UnknownHostException uhe ) {
-                               uhe.printStackTrace();
                        } catch( MalformedURLException mue ) {
                                mue.printStackTrace();
                                conn = null;
+                       } catch( Exception e ) {
+                               e.printStackTrace();
                        }
         }
                System.exit( 0 );
     }
+    public static void main( String[] argv ) throws Exception {
+               SmbShell smbsh = new SmbShell();
+               smbsh.run();
+       }
 }
index 22eaa28..e2a86cd 100644 (file)
@@ -16,6 +16,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+import java.util.Date;
 import jcifs.smb.*;
 
 public class TestSmbFile {
@@ -27,15 +28,20 @@ public class TestSmbFile {
                } else {
                        f = new SmbFile( argv[0], argv[1] );
                }
-               System.out.println( "toString()=" + f.toString());
-               System.out.println( "getCanonicalPath()=" + f.getCanonicalPath());
-               System.out.println( "getName()=" + f.getName());
-               System.out.println( "getParent()=" + f.getParent());
-               System.out.println( "getPath()=" + f.getPath());
-               System.out.println( "getServer()=" + f.getServer());
-               System.out.println( "getShare()=" + f.getShare());
-               System.out.println( "isWorkgroup()=" + f.isWorkgroup());
-               System.out.println( "toURL().toString()=" + f.toURL().toString());
+               System.out.println( "toString()         : " + f.toString());
+               System.out.println( "getCanonicalPath() : " + f.getCanonicalPath());
+               System.out.println( "getName()          : " + f.getName());
+               System.out.println( "getParent()        : " + f.getParent());
+               System.out.println( "getPath()          : " + f.getPath());
+               System.out.println( "getServer()        : " + f.getServer());
+               System.out.println( "getShare()         : " + f.getShare());
+               System.out.println( "exists()           : " + f.exists());
+               System.out.println( "isDirectory()      : " + f.isDirectory());
+               System.out.println( "isFile()           : " + f.isFile());
+               System.out.println( "length()           : " + f.length());
+               System.out.println( "lastModified()     : " + (new Date( f.lastModified() )));
+               System.out.println( "isWorkgroup()      : " + f.isWorkgroup());
+//             System.out.println( "toURL().toString() : " + f.toURL().toString());
                if( argv.length > 2 ) {
                        System.out.println( "equals( " + argv[1] + " )=" + f.equals( new SmbFile( argv[1] )));
                }
index ce775b2..9f4ec76 100644 (file)
@@ -25,6 +25,8 @@ import java.io.IOException;
 
 public class ThreadedSmbCrawler {
 
+       static long time;
+
        class DirEntry {
                SmbFile dir;
                int depth;
@@ -48,6 +50,7 @@ public class ThreadedSmbCrawler {
                                        DirEntry e;
 
                                        synchronized( dirList ) {
+time = System.currentTimeMillis();
                                                while( dirList.isEmpty() ) {
                                                        dirList.wait( 500 );
                                                }
@@ -105,6 +108,9 @@ public class ThreadedSmbCrawler {
                        return;
                }
                Log.setMask( Log.CRITICAL_EXCEPTIONS );
+long start = System.currentTimeMillis();
                new ThreadedSmbCrawler( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] ));
+System.in.read();
+System.out.println( "time=" + (time - start) + "ms" );
        }
 }
index efe80ed..b204d14 100644 (file)
@@ -38,7 +38,7 @@ public class TortureTest5 extends Thread {
        public static void main( String[] argv ) throws Exception {
        //      jcifs.util.Log.setMask( jcifs.util.Log.EXCEPTIONS | jcifs.util.Log.HEX_DUMPS );
        //      jcifs.util.Config.setProperty( "retryCount", "1" );
-               jcifs.util.Config.setProperty( "soTimeout", "1000" );
+       //      jcifs.util.Config.setProperty( "soTimeout", "1000" );
 
                Thread[] threads = new Thread[30];
                for( int i = 0; i < argv.length; i++ ) {
index cfbf626..c47f68d 100644 (file)
@@ -28,7 +28,7 @@ import java.io.IOException;
 import java.net.InetAddress;
 
 /**
- * This class extends the {@link jcifs.util.Config} class to simply add
+ * This class enhances the {@link jcifs.util.Config} class to simply add
  * additional configuration information specific to the jcifs smb library.
  * <p>
  * See also <a href="../../overview-summary.html#scp">Setting JCIFS Properties</a>
diff --git a/src/jcifs/UniAddress.java b/src/jcifs/UniAddress.java
new file mode 100644 (file)
index 0000000..81e8873
--- /dev/null
@@ -0,0 +1,292 @@
+package jcifs;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.io.IOException;
+import java.util.StringTokenizer;
+import jcifs.util.Log;
+import jcifs.netbios.NbtAddress;
+import jcifs.netbios.Lmhosts;
+
+/**
+ * This class is a wrapper for both {@link jcifs.netbios.NbtAddress} and
+ * {@link java.net.InetAddress}. This frees the NetBIOS implementation
+ * from trying to handle DNS and abstacts the NetBIOS protocol from the smb
+ * package. This is a prerequisite of NetBIOS-less transport; a precedent
+ * set by Microsoft's latest servers.
+ */
+
+public class UniAddress {
+
+       static final int RESOLVER_WINS    = 0;
+       static final int RESOLVER_BCAST   = 1;
+       static final int RESOLVER_DNS     = 2;
+       static final int RESOLVER_LMHOSTS = 3;
+
+       static int[] resolveOrder;
+       static InetAddress nbns, baddr;
+
+       static class QueryThread extends Thread {
+
+               Object lock;
+               String host, scope;
+               int type;
+               NbtAddress ans = null;
+               InetAddress svr;
+               UnknownHostException uhe;
+
+               QueryThread( Object lock, String host, int type,
+                                                                                       String scope, InetAddress svr ) {
+                       this.lock = lock;
+                       this.host = host;
+                       this.type = type;
+                       this.scope = scope;
+                       this.svr = svr;
+               }
+               public void run() {
+                       try {
+                               ans = NbtAddress.getByName( host, type, scope, svr );
+                       } catch( UnknownHostException uhe ) {
+                               this.uhe = uhe;
+                       }
+                       synchronized( lock ) {
+                               lock.notify();
+                       }
+               }
+       }
+
+       static {
+               String ro = Config.getProperty( "jcifs.resolveOrder" );
+               nbns = Config.getInetAddress( "jcifs.netbios.wins", null );
+
+               try {
+                       baddr = Config.getInetAddress( "jcifs.netbios.baddr",
+                                                               InetAddress.getByName( "255.255.255.255" ));
+               } catch( UnknownHostException uhe ) {
+               }
+
+               if( ro == null || ro.length() == 0 ) {
+
+                       /* No resolveOrder has been specified, use the
+                        * default which is LMHOSTS,WINS,BCAST,DNS or just
+                        * LMHOSTS,BCAST,DNS if jcifs.netbios.wins has not
+                        * been specified.
+                        */
+
+                       if( nbns == null ) {
+                               resolveOrder = new int[3];
+                               resolveOrder[0] = RESOLVER_LMHOSTS;
+                               resolveOrder[1] = RESOLVER_BCAST;
+                               resolveOrder[2] = RESOLVER_DNS;
+                       } else {
+                               resolveOrder = new int[4];
+                               resolveOrder[0] = RESOLVER_LMHOSTS;
+                               resolveOrder[1] = RESOLVER_WINS;
+                               resolveOrder[2] = RESOLVER_BCAST;
+                               resolveOrder[3] = RESOLVER_DNS;
+                       }
+               } else {
+                       int[] tmp = new int[4];
+                       StringTokenizer st = new StringTokenizer( ro, "," );
+                       int i = 0;
+                       while( st.hasMoreTokens() ) {
+                               String s = st.nextToken().trim();
+                               if( s.equalsIgnoreCase( "LMHOSTS" )) {
+                                       tmp[i++] = RESOLVER_LMHOSTS;
+                               } else if( s.equalsIgnoreCase( "WINS" )) {
+                                       if( nbns == null ) {
+                                               Log.println( Log.WARNINGS, "netbios name service warning",
+                                                               " resolveOrder specifies WINS however the " +
+                                                               "jcifs.netbios.wins property has not been set" );
+                                               continue;
+                                       }
+                                       tmp[i++] = RESOLVER_WINS;
+                               } else if( s.equalsIgnoreCase( "BCAST" )) {
+                                       tmp[i++] = RESOLVER_BCAST;
+                               } else if( s.equalsIgnoreCase( "DNS" )) {
+                                       tmp[i++] = RESOLVER_DNS;
+                               } else {
+                                       Log.println( Log.WARNINGS, "netbios name service warning",
+                                                               "unknown resolver method: " + s );
+                               }
+                       }
+                       resolveOrder = new int[i];
+                       System.arraycopy( tmp, 0, resolveOrder, 0, i );
+               }
+       }
+
+       static NbtAddress lookupServerOrWorkgroup( String name, InetAddress svr )
+                                                                                                       throws UnknownHostException {
+               Object lock = new Object();
+               QueryThread q1d = new QueryThread( lock, name, 0x1d, null, svr );
+               QueryThread q20 = new QueryThread( lock, name, 0x20, null, svr );
+               q1d.setDaemon( true );
+               q20.setDaemon( true );
+               try {
+                       synchronized( lock ) {
+                               q1d.start();
+                               q20.start();
+
+                               int i = 2;
+                               while( i-- > 0 && q1d.ans == null && q20.ans == null ) {
+                                       lock.wait();
+                               }
+                       }
+               } catch( InterruptedException ie ) {
+                       throw new UnknownHostException( name );
+               }
+               if( q1d.ans != null ) {
+// why was this: return NbtAddress.getByName( q1d.ans.getHostAddress(), 0x1d, null );
+                       return q1d.ans;
+               } else if( q20.ans != null ) {
+                       return q20.ans;
+               } else {
+                       throw q1d.uhe;
+               }
+       }
+       public static UniAddress getByName( String hostname )
+                                                                               throws UnknownHostException {
+               return getByName( hostname, false );
+       }
+
+       static boolean isDotQuadIP( String hostname ) {
+               if( Character.isDigit( hostname.charAt( 0 ))) {
+                       int i, len, dots;
+                       char[] data;
+
+                       i = dots = 0;                    /* quick IP address validation */
+                       len = hostname.length();
+                       data = hostname.toCharArray();
+                       while( i < len && Character.isDigit( data[i++] )) {
+                               if( i == len && dots == 3 ) {
+                                       // probably an IP address
+                                       return true;
+                               }
+                               if( data[i] == '.' ) {
+                                       dots++;
+                                       i++;
+                               }
+                       }
+               }
+
+               return false;
+       }
+
+       public static UniAddress getByName( String hostname,
+                                                                               boolean possibleNTDomainOrWorkgroup )
+                                                                               throws UnknownHostException {
+               Object addr;
+               int i;
+
+               if( hostname == null || hostname.length() == 0 ) {
+                       throw new UnknownHostException();
+               }
+
+               if( isDotQuadIP( hostname )) {
+                       return new UniAddress( NbtAddress.getByName( hostname ));
+               }
+
+               for( i = 0; i < resolveOrder.length; i++ ) {
+                       try {
+                               switch( resolveOrder[i] ) {
+                                       case RESOLVER_LMHOSTS:
+                                               if(( addr = Lmhosts.getByName( hostname )) == null ) {
+                                                       continue;
+                                               }
+                                               break;
+                                       case RESOLVER_WINS:
+                                               if( hostname == NbtAddress.MASTER_BROWSER_NAME ||
+                                                                                                       hostname.length() > 15 ) {
+                                                                                                       // invalid netbios name
+                                                       continue;
+                                               }
+                                               addr = NbtAddress.getByName( hostname, 0x20, null, nbns );
+                                               break;
+                                       case RESOLVER_BCAST:
+                                               if( hostname.length() > 15 ) {
+                                                       // invalid netbios name
+                                                       continue;
+                                               }
+                                               if( possibleNTDomainOrWorkgroup ) {
+                                                       addr = lookupServerOrWorkgroup( hostname, baddr );
+                                               } else {
+                                                       addr = NbtAddress.getByName( hostname, 0x20, null, baddr );
+                                               }
+                                               break;
+                                       case RESOLVER_DNS:
+                                               addr = InetAddress.getByName( hostname );
+                                               break;
+                                       default:
+                                               throw new UnknownHostException();
+                               }
+                               return new UniAddress( addr ); // Success
+                       } catch( IOException ioe ) {
+                               // Failure
+                       }
+               }
+               throw new UnknownHostException( hostname );
+       }
+
+       Object addr;
+       String calledName;
+
+       UniAddress( Object addr ) {
+               this.addr = addr;
+       }
+
+       public boolean equals( Object obj ) {
+               return obj instanceof UniAddress && addr.equals( ((UniAddress)obj).addr );
+       }
+
+/* Guess next called name to try for session establishment. These
+ * methods are used by the smb package.
+ */
+       public String firstCalledName() {
+               if( addr instanceof NbtAddress ) {
+                       return ((NbtAddress)addr).firstCalledName();
+               } else {
+                       calledName = ((InetAddress)addr).getHostName();
+                       if( isDotQuadIP( calledName )) {
+                               calledName = NbtAddress.SMBSERVER_NAME;
+                       } else {
+                               int i = calledName.indexOf( '.' );
+                               if( i > 1 && i < 15 ) {
+                                       calledName = calledName.substring( 0, i ).toUpperCase();
+                               } else if( calledName.length() > 15 ) {
+                                       calledName = NbtAddress.SMBSERVER_NAME;
+                               } else {
+                                       calledName = calledName.toUpperCase();
+                               }
+                       }
+               }
+
+               return calledName;
+    }
+       public String nextCalledName() {
+               if( addr instanceof NbtAddress ) {
+                       return ((NbtAddress)addr).nextCalledName();
+               } else if( calledName != NbtAddress.SMBSERVER_NAME ) {
+                       calledName = NbtAddress.SMBSERVER_NAME;
+                       return calledName;
+               }
+               return null;
+       }
+       public Object getAddress() {
+               return addr;
+       }
+       public String getHostName() {
+               if( addr instanceof NbtAddress ) {
+                       return ((NbtAddress)addr).getHostName();
+               }
+               return ((InetAddress)addr).getHostName();
+       }
+       public String getHostAddress() {
+               if( addr instanceof NbtAddress ) {
+                       return ((NbtAddress)addr).getHostAddress();
+               }
+               return ((InetAddress)addr).getHostAddress();
+       }
+    public String toString() {
+        return addr.toString();
+       }
+}
index 4fe8af4..6e11029 100644 (file)
@@ -30,13 +30,24 @@ import java.io.IOException;
 import java.util.Hashtable;
 import java.net.UnknownHostException;
 
-class Lmhosts {
+public class Lmhosts {
 
        static String filename = Config.getProperty( "jcifs.netbios.lmhosts" );
        static Hashtable tab = new Hashtable();
        static long lastModified = 1L;
        static int alt;
 
+       /**
+        * This is really just for {@link jcifs.UniAddress}. It does
+        * not throw an {@link java.net.UnknownHostException} because this
+        * is queried frequently and exceptions would be rather costly to
+        * throw on a regular basis here.
+        */
+
+       public synchronized static NbtAddress getByName( String host ) {
+               return getByName( new Name( host, 0x20, null ));
+       }
+
        synchronized static NbtAddress getByName( Name name ) {
                NbtAddress result = null;
 
@@ -130,7 +141,9 @@ class Lmhosts {
                                }
 
                                name = new Name( line.substring( i, j ), 0x20, null );
-                               addr = new NbtAddress( name, ip, false, NbtAddress.B_NODE );
+                               addr = new NbtAddress( name, ip, false, NbtAddress.B_NODE,
+                                                                       false, false, true, true,
+                                                                       NbtAddress.unknownMacAddress );
                                tab.put( name, addr );
                        }
                }
index b881cc1..12e07fe 100644 (file)
@@ -34,10 +34,7 @@ import java.util.Enumeration;
  * See the {@link jcifs.util.Log} parent class for details about this
  * logging style.
  *
- * @version   0.1, 00/03/13
- * @author    Michael B. Allen
  * @see       jcifs.util.Log
- * @since     jcifs-0.1
  */
 
 public class Log extends jcifs.util.Log {
@@ -53,12 +50,6 @@ public class Log extends jcifs.util.Log {
  * This mask produces limited netbios name service packet information. See
  * <a href="http://www.cis.ohio-state.edu/rfc/rfc1002.txt">RFC 1002</a>
  * for a detailed description of packet contents and their meaning.
- * <p><blockquote><pre>
- *  Mar 13 09:17:04 - name service packet
- *   angus.mimosa.com/192.168.1.152:137 [62]
- *   28887  Positive Name Query Response
- *   authoritative answer,unicast,recursion desired,recursion available
- * </pre></blockquote>
  *
  * @see jcifs.util.Log#setMask(int mask)
  */
@@ -81,7 +72,7 @@ public class Log extends jcifs.util.Log {
     public static final int RESERVED8                   = 0x00000080;
 
        static void printPacketData( String desc, SessionServicePacket ssp ) {
-               try {
+               try { // why do I have try/catch here?
                        if(( SESSION_SERVICE_PACKET_DATA & mask ) == 0 ) {
                                return;
                        }
@@ -108,7 +99,7 @@ public class Log extends jcifs.util.Log {
         NbtAddress.CacheEntry ce;
         for( Enumeration e = addressCache.elements(); e.hasMoreElements(); ) {
             ce = (NbtAddress.CacheEntry)e.nextElement();
-            sb.append( ' ' ).append( ce.hostName );
+                       sb.append( ' ' ).append( ce.hostName );
                        sb.append( ' ' ).append( ce.address ).append( NL );
         }
         out.println( desc, sb.toString() );
index 697149f..449a732 100644 (file)
@@ -48,16 +48,21 @@ class Name {
        static String defaultScope = Config.getProperty( "jcifs.netbios.scope" );
 
     String name, scope;
-    int type;
-
-    Name( String name, int type, String scope ) {
-               this.name = name;
-               this.type = type;
-               if( scope != null ) {
-                       this.scope = scope;
-               } else {
-                       this.scope = defaultScope;
+    int hexCode;
+       int srcHashCode; /* srcHashCode must be set by name resolution
+                                         * routines before entry into addressCache
+                                         */
+
+       Name() {
+       }
+    Name( String name, int hexCode, String scope ) {
+           if( name.length() > 15 ) {
+                       name = name.substring( 0, 15 );
                }
+               this.name = name.toUpperCase();
+               this.hexCode = hexCode;
+               this.scope = scope != null && scope.length() > 0 ? scope : defaultScope;
+               this.srcHashCode = 0;
     }
 
        int writeWireFormat( byte[] dst, int dstIndex ) {
@@ -65,9 +70,6 @@ class Name {
         dst[dstIndex] = 0x20;
 
         // write name
-           name = ( name.length() > 15 ) ?
-                                                       name.substring( 0, 15 ).toUpperCase() :
-                                                       name.toUpperCase();
         byte tmp[] = name.getBytes();
         int i;
         for( i = 0; i < tmp.length; i++ ) {
@@ -78,8 +80,8 @@ class Name {
             dst[dstIndex + ( 2 * i + 1 )] = (byte)0x43;
             dst[dstIndex + ( 2 * i + 2 )] = (byte)0x41;
         }
-        dst[dstIndex + TYPE_OFFSET] = (byte)((( type & 0xF0 ) >> 4 ) + 0x41 );
-        dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( type & 0x0F ) + 0x41 );
+        dst[dstIndex + TYPE_OFFSET] = (byte)((( hexCode & 0xF0 ) >> 4 ) + 0x41 );
+        dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( hexCode & 0x0F ) + 0x41 );
                return SCOPE_OFFSET + writeScopeWireFormat( dst, dstIndex + SCOPE_OFFSET );
        }
 
@@ -95,12 +97,12 @@ class Name {
             }
         }
         name = new String( tmp, 0, length );
-        type = (( src[srcIndex + TYPE_OFFSET] & 0xFF ) - 0x41 ) << 4;
-        type |= (( src[srcIndex + TYPE_OFFSET + 1] & 0xFF ) - 0x41 ) & 0x0F;
+        hexCode = (( src[srcIndex + TYPE_OFFSET] & 0xFF ) - 0x41 ) << 4;
+        hexCode |= (( src[srcIndex + TYPE_OFFSET + 1] & 0xFF ) - 0x41 ) & 0x0F;
                return SCOPE_OFFSET + readScopeWireFormat( src, srcIndex + SCOPE_OFFSET );
     }
        int writeScopeWireFormat( byte[] dst, int dstIndex ) {
-               if( scope == null || scope.length() == 0 ) {
+               if( scope == null ) {
                        dst[dstIndex] = (byte)0x00;
                        return 1;
                }
@@ -131,54 +133,52 @@ class Name {
        int readScopeWireFormat( byte[] src, int srcIndex ) {
                int start = srcIndex;
                int n;
+               StringBuffer sb;
 
                if(( n = src[srcIndex++] & 0xFF ) == 0 ) {
                        scope = null;
                        return 1;
                }
 
-               StringBuffer sb = new StringBuffer( new String( src, srcIndex, n ));
+               sb = new StringBuffer( new String( src, srcIndex, n ));
                srcIndex += n;
                while(( n = src[srcIndex++] & 0xFF ) != 0 ) {
                        sb.append( '.' ).append( new String( src, srcIndex, n ));
                        srcIndex += n;
                }
+               scope = sb.toString();
+
                return srcIndex - start;
        }
 
     public int hashCode() {
-               int result = name.toUpperCase().hashCode();
-               result += 65599 * type;
+               int result;
+
+               result = name.hashCode();
+               result += 65599 * hexCode;
+               result += 65599 * srcHashCode; /* hashCode is different depending
+                                                                               * on where it came from
+                                                                               */
                if( scope != null && scope.length() != 0 ) {
                        result += scope.hashCode();
                }
         return result;
     }
     public boolean equals( Object obj ) {
+               Name n;
+
         if( !( obj instanceof Name )) {
             return false;
         }
-        Name n = (Name)obj;
-        name = ( name.length() > 15 ) ?
-                                               name.substring( 0, 15 ).toUpperCase() :
-                                               name.toUpperCase();
-        n.name = ( n.name.length() > 15 ) ?
-                                               n.name.substring( 0, 15 ).toUpperCase() :
-                                               n.name.toUpperCase();
-               if(( scope == null || scope.length() == 0 ) &&
-                               ( n.scope == null || n.scope.length() == 0 )) {
-                       return name.equals( n.name ) && type == n.type;
+        n = (Name)obj;
+               if( scope == null && n.scope == null ) {
+                       return name.equals( n.name ) && hexCode == n.hexCode;
                }
-               return name.equals( n.name ) && type == n.type && scope.equals( n.scope );
+               return name.equals( n.name ) && hexCode == n.hexCode && scope.equals( n.scope );
     }
-       String getName() {
-        return ( name.length() > 15 ) ?
-                                               name.substring( 0, 15 ).toUpperCase() :
-                                               name.toUpperCase();
-       }
     public String toString() {
                StringBuffer sb = new StringBuffer();
-               String n = getName();
+               String n = name;
 
         // fix MSBROWSE name
         if( n.charAt( 0 ) == 0x01 ) {
@@ -189,12 +189,11 @@ class Name {
             n = new String( b );
         }
 
-        sb.append( n ).append( "<" ).append( toHexChars( type )).append( ">" );
-        if( scope != null && scope.length() != 0 ) {
+        sb.append( n ).append( "<" ).append( toHexChars( hexCode )).append( ">" );
+        if( scope != null ) {
             sb.append( "." ).append( scope );
         }
         return sb.toString();
     }
-
 }
 
index dd67797..1027e5f 100644 (file)
@@ -23,7 +23,7 @@ class NameQueryResponse extends NameServicePacket {
        NbtAddress addrEntry;
 
        NameQueryResponse() {
-               recordName = new Name( null, 0, null );
+               recordName = new Name();
        }
 
        int writeBodyWireFormat( byte[] dst, int dstIndex ) {
index 327fe02..c5a4acc 100644 (file)
@@ -37,12 +37,10 @@ class NameServiceClient implements Runnable {
        static final int DEFAULT_RETRY_COUNT = 2;
        static final int DEFAULT_RETRY_TIMEOUT = 3000;
 
-       static final int RESOLVER_WINS    = 0;
-       static final int RESOLVER_BCAST   = 1;
-       static final int RESOLVER_DNS     = 2;
-       static final int RESOLVER_LMHOSTS = 3;
+       static final int RESOLVER_LMHOSTS = 1;
+       static final int RESOLVER_BCAST   = 2;
+       static final int RESOLVER_WINS    = 3;
 
-       NbtAddress localhost;
     InetAddress laddr, baddr, nbns;
     int port, soTimeout, retryCount, retryTimeout, closeTimeout;
     int snd_buf_size, rcv_buf_size;
@@ -66,29 +64,24 @@ class NameServiceClient implements Runnable {
                try {
                        baddr = Config.getInetAddress( "jcifs.netbios.baddr",
                                                InetAddress.getByName( "255.255.255.255" ));
-
-                       InetAddress inet = laddr;
-                       if( inet == null ) {
-                               inet = InetAddress.getLocalHost();
-                       }
-                       String name = Config.getProperty( "jcifs.netbios.hostname", null );
-                       if( name == null || name.length() == 0 ) {
-                               byte[] addr = inet.getAddress();
-                               name = "JCIFS" +
-                                               ( addr[2] & 0xFF ) + "_" +
-                                               ( addr[3] & 0xFF ) + "_" +
-                                               Name.toHexChars( (int)( Math.random() * (double)0xFF ));
-                       }
-                       localhost = NbtAddress.getByName( inet.getHostAddress(),
-                                               0x00, Config.getProperty( "jcifs.netbios.scope", null ));
-                       localhost.hostName.name = name;
-                       NbtAddress.cacheAddress( localhost.hostName, localhost, NbtAddress.FOREVER );
                } catch( UnknownHostException uhe ) {
                }
 
                nbns = Config.getInetAddress( "jcifs.netbios.wins", null );
+        soTimeout = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
+               retryCount = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT );
+               retryTimeout = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT);
+        rcv_buf_size = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
+        snd_buf_size = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE );
+        rcv_buf = new byte[rcv_buf_size];
+        snd_buf = new byte[snd_buf_size];
+        in  = new DatagramPacket( rcv_buf, rcv_buf_size );
+        out = new DatagramPacket( snd_buf, snd_buf_size, baddr, NAME_SERVICE_UDP_PORT );
+               responseTable = new Hashtable();
+               nextNameTrnId = 0;
+               socketLock = new Object();
 
-               String ro = Config.getProperty( "jcifs.netbios.resolveOrder" );
+               String ro = Config.getProperty( "jcifs.resolveOrder" );
                if( ro == null || ro.length() == 0 ) {
 
                        /* No resolveOrder has been specified, use the
@@ -98,19 +91,17 @@ class NameServiceClient implements Runnable {
                         */
 
                        if( nbns == null ) {
-                               resolveOrder = new int[3];
+                               resolveOrder = new int[2];
                                resolveOrder[0] = RESOLVER_LMHOSTS;
                                resolveOrder[1] = RESOLVER_BCAST;
-                               resolveOrder[2] = RESOLVER_DNS;
                        } else {
-                               resolveOrder = new int[4];
+                               resolveOrder = new int[3];
                                resolveOrder[0] = RESOLVER_LMHOSTS;
                                resolveOrder[1] = RESOLVER_WINS;
                                resolveOrder[2] = RESOLVER_BCAST;
-                               resolveOrder[3] = RESOLVER_DNS;
                        }
                } else {
-                       int[] tmp = new int[4];
+                       int[] tmp = new int[3];
                        StringTokenizer st = new StringTokenizer( ro, "," );
                        int i = 0;
                        while( st.hasMoreTokens() ) {
@@ -128,7 +119,7 @@ class NameServiceClient implements Runnable {
                                } else if( s.equalsIgnoreCase( "BCAST" )) {
                                        tmp[i++] = RESOLVER_BCAST;
                                } else if( s.equalsIgnoreCase( "DNS" )) {
-                                       tmp[i++] = RESOLVER_DNS;
+                                       i++; // skip
                                } else {
                                        Log.println( Log.WARNINGS, "netbios name service warning",
                                                                "unknown resolver method: " + s );
@@ -137,19 +128,6 @@ class NameServiceClient implements Runnable {
                        resolveOrder = new int[i];
                        System.arraycopy( tmp, 0, resolveOrder, 0, i );
                }
-
-        soTimeout = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
-               retryCount = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT );
-               retryTimeout = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT);
-        rcv_buf_size = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
-        snd_buf_size = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE );
-        rcv_buf = new byte[rcv_buf_size];
-        snd_buf = new byte[snd_buf_size];
-        in  = new DatagramPacket( rcv_buf, rcv_buf_size );
-        out = new DatagramPacket( snd_buf, snd_buf_size, baddr, NAME_SERVICE_UDP_PORT );
-               responseTable = new Hashtable();
-               nextNameTrnId = 0;
-               socketLock = new Object();
     }
 
        int getNextNameTrnId() {
@@ -206,7 +184,7 @@ class NameServiceClient implements Runnable {
                }
 
                        Log.println( Log.DEBUGGING, "nbt name service debugging",
-                                                                                                       " new data read from socket" );
+                                                                                               " new data read from socket" );
 
                        nameTrnId = NameServicePacket.readNameTrnId( rcv_buf, 0 );
                        response = (NameServicePacket)responseTable.get( new Integer( nameTrnId ));
@@ -219,14 +197,14 @@ class NameServiceClient implements Runnable {
 
                                Log.printPacketData( "nbt name service packet receviced", response );
                                Log.printHexDump( "datagram packet received from: " +
-                                               in.getAddress().toString(), rcv_buf, 0, in.getLength() );
+                                               in.getAddress().getHostAddress(), rcv_buf, 0, in.getLength() );
 
                                response.notify();
                        }
         }
     }
-    void send( NameServicePacket request,
-                                       NameServicePacket response, int timeout ) throws IOException {
+    void send( NameServicePacket request, NameServicePacket response,
+                                                                                       int timeout ) throws IOException {
                Integer nid = null;
 
                synchronized( response ) {
@@ -245,7 +223,7 @@ class NameServiceClient implements Runnable {
 
                                        Log.printPacketData( "nbt name service packet sent", request );
                                        Log.printHexDump( "datagram packet sent to: " +
-                                                               out.getAddress().toString(), snd_buf, 0, out.getLength() );
+                                                               out.getAddress().getHostAddress(), snd_buf, 0, out.getLength() );
                                }
 
                                response.wait( timeout );
@@ -256,25 +234,56 @@ class NameServiceClient implements Runnable {
                        }
                }
     }
-       NbtAddress getByName( Name name ) throws UnknownHostException {
+
+       NbtAddress getByName( Name name, InetAddress addr )
+                                                                                       throws UnknownHostException {
+               int n;
                NameQueryRequest request = new NameQueryRequest( name );
                NameQueryResponse response = new NameQueryResponse();
 
+               if( addr != null ) { /* UniAddress calls always use this
+                                                         * because it specifies addr
+                                                         */
+                       request.addr = addr; /* if addr ends with 255 flag it bcast */
+                       request.isBroadcast = (addr.getAddress()[3] == (byte)0xFF);
+
+                       n = retryCount;
+                       do {
+                               try {
+                                       send( request, response, retryTimeout );
+                               } catch( IOException ioe ) {
+                                       Log.printStackTrace( "nbt name service send:", ioe );
+                                       throw new UnknownHostException( ioe.getMessage() );
+                               }
+                               if( response.received && response.resultCode == 0 ) {
+                                       response.addrEntry.hostName.srcHashCode = addr.hashCode();
+                                       return response.addrEntry;
+                               }
+                       } while( --n > 0 && request.isBroadcast );
+
+                       throw new UnknownHostException( name.name );
+               }
+
+               /* If a target address to query was not specified explicitly
+                * with the addr parameter we fall into this resolveOrder routine.
+                */
+
                for( int i = 0; i < resolveOrder.length; i++ ) {
                        try {
                                switch( resolveOrder[i] ) {
                                        case RESOLVER_LMHOSTS:
                                                NbtAddress ans = Lmhosts.getByName( name );
                                                if( ans != null ) {
+                                                       ans.hostName.srcHashCode = 0; // just has to be different
+                                                                                                                 // from other methods
                                                        return ans;
                                                }
                                                break;
                                        case RESOLVER_WINS:
                                        case RESOLVER_BCAST:
                                                if( resolveOrder[i] == RESOLVER_WINS &&
-                                                               nbns != null &&
                                                                name.name != NbtAddress.MASTER_BROWSER_NAME &&
-                                                               name.type != 0x1d ) {
+                                                               name.hexCode != 0x1d ) {
                                                        request.addr = nbns;
                                                        request.isBroadcast = false;
                                                } else {
@@ -282,7 +291,7 @@ class NameServiceClient implements Runnable {
                                                        request.isBroadcast = true;
                                                }
 
-                                               int n = retryCount;
+                                               n = retryCount;
                                                while( n-- > 0 ) {
                                                        try {
                                                                send( request, response, retryTimeout );
@@ -291,17 +300,22 @@ class NameServiceClient implements Runnable {
                                                                throw new UnknownHostException( ioe.getMessage() );
                                                        }
                                                        if( response.received && response.resultCode == 0 ) {
+
+/* Before we return, in anticipation of this address being cached we must
+ * augment the addresses name's hashCode to distinguish those resolved by
+ * Lmhosts, WINS, or BCAST. Otherwise a failed query from say WINS would
+ * get pulled out of the cache for a BCAST on the same name.
+ */
+                                                               response.addrEntry.hostName.srcHashCode =
+                                                                                                               request.addr.hashCode();
                                                                return response.addrEntry;
+                                                       } else if( resolveOrder[i] == RESOLVER_WINS ) {
+                                                               /* If WINS reports negative, no point in retry
+                                                                */
+                                                               break;
                                                        }
                                                }
                                                break;
-                                       case RESOLVER_DNS:
-                                               if( name.type == 0x20 || name.type == 0x00 ) {
-                                                       InetAddress addr = InetAddress.getByName( name.name );
-                                                       return new NbtAddress( new Name( NbtAddress.ALL_HOSTS_NAME,
-                                                                               name.type, name.scope ), addr.hashCode(), false,
-                                                                               NbtAddress.B_NODE );
-                                               }
                                }
                        } catch( IOException ioe ) {
                        }
@@ -309,10 +323,16 @@ class NameServiceClient implements Runnable {
                throw new UnknownHostException( name.name );
        }
        NbtAddress[] getNodeStatus( NbtAddress addr ) throws UnknownHostException {
-               NodeStatusRequest request = new NodeStatusRequest( addr.hostName );
-               NodeStatusResponse response = new NodeStatusResponse( addr );
+               int n, srcHashCode;
+               NodeStatusRequest request;
+               NodeStatusResponse response;
+
+               response = new NodeStatusResponse( addr );
+               request = new NodeStatusRequest(
+                                                       new Name( NbtAddress.ANY_HOSTS_NAME, 0x00, null));
                request.addr = addr.getInetAddress();
-               int n = retryCount;
+
+               n = retryCount;
                while( n-- > 0 ) {
                        try {
                                send( request, response, retryTimeout );
@@ -321,6 +341,24 @@ class NameServiceClient implements Runnable {
                                throw new UnknownHostException( ioe.getMessage() );
                        }
                        if( response.received && response.resultCode == 0 ) {
+
+               /* For name queries resolved by different sources (e.g. WINS,
+                * BCAST, Node Status) we need to augment the hashcode generated
+                * for the addresses hostname or failed lookups for one type will
+                * be cached and cause other types to fail even though they may
+                * not be the authority for the name. For example, if a WINS lookup
+                * for FOO fails and caches unknownAddress for FOO, a subsequent
+                * lookup for FOO using BCAST should not fail because of that
+                * name cached from WINS.
+                *
+                * So, here we apply the source addresses hashCode to each name to
+                * make them specific to who resolved the name.
+                */
+
+                               srcHashCode = request.addr.hashCode();
+                               for( int i = 0; i < response.addressArray.length; i++ ) {
+                                       response.addressArray[i].hostName.srcHashCode = srcHashCode;
+                               }
                                return response.addressArray;
                        }
                }
index 04f0eb2..aa7df31 100644 (file)
@@ -31,7 +31,7 @@ import jcifs.Config;
  * name resolution and session services are handled internally by the smb package.
  * 
  * <p> Applications can use the methods <code>getLocalHost</code>,
- * <code>getAllByName</code>, and
+ * <code>getByName</code>, and
  * <code>getAllByAddress</code> to create a new NbtAddress instance. This
  * class is symmetric with {@link java.net.InetAddress}.
  *
@@ -77,63 +77,28 @@ import jcifs.Config;
 
 public final class NbtAddress {
 
-    Name hostName;
-    int address, nodeType;
-    boolean groupName,
-               isBeingDeleted,
-       isInConflict,
-       isActive,
-       isPermanent,
-       isDataFromNodeStatus;
-    byte[] macAddress;
-
-    private static final byte[] MASTER_BROWSER_BYTES = {
+    static final byte[] MASTER_BROWSER_BYTES = {
         (byte)0x01, (byte)0x02, (byte)0x5F, (byte)0x5F, (byte)0x4D, (byte)0x53,
         (byte)0x42, (byte)0x52, (byte)0x4F, (byte)0x57, (byte)0x53, (byte)0x45,
         (byte)0x5F, (byte)0x5F, (byte)0x02
     };
-    private static final byte[] SMBSERVER_BYTES = {
+    static final byte[] SMBSERVER_BYTES = {
                (byte)0x2a, (byte)0x53, (byte)0x4d, (byte)0x42, (byte)0x53, (byte)0x45,
                (byte)0x52, (byte)0x56, (byte)0x45, (byte)0x52, (byte)0x20, (byte)0x20,
                (byte)0x20, (byte)0x20, (byte)0x20
     };
-    private static final byte[] ALL_HOSTS_BYTES = {
+    static final byte[] ALL_HOSTS_BYTES = {
         (byte)0x2A, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
         (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
         (byte)0x00, (byte)0x00, (byte)0x00
     };
 
-    // Node Types
-
-/** 
- * A B node only broadcasts name queries. This is the default if a
- * nameserver such as WINS or Samba is not specified.
- */ 
-
-    public static final int B_NODE = 0;
-
-/**
- * A Point-to-Point node, or P node, unicasts queries to a nameserver
- * only. Natrually the <code>jcifs.netbios.nameserver</code> property must
- * be set.
- */
-
-    public static final int P_NODE = 1;
-
-/** 
- * Try Broadcast queries first, then try to resolve the name using the
- * nameserver.
- */
-
-    public static final int M_NODE = 2;
-
-/** 
- * A Hybrid node tries to resolve a name using the nameserver first. If that fails use the
- * broadcast address. This is the default if a nameserver is provided. This
- * is the behavior of Microsoft Windows machines.
+/*
+ * This is a special name that means all hosts. If you wish to find all hosts
+ * on a network querying a workgroup group name is the preferred method.
  */ 
 
-    public static final int H_NODE = 3;
+    static final String ANY_HOSTS_NAME = new String( ALL_HOSTS_BYTES );
 
 /** 
  * This is a special name for querying the master browser that serves the
@@ -143,248 +108,53 @@ public final class NbtAddress {
     public static final String MASTER_BROWSER_NAME = new String( MASTER_BROWSER_BYTES );
 
 /**
- * A special generic name specified when connecting to a host for which a name is not known. Not all servers respond to this name.
+ * A special generic name specified when connecting to a host for which
+ * a name is not known. Not all servers respond to this name.
  */
 
     public static final String SMBSERVER_NAME = new String( SMBSERVER_BYTES );
 
 /** 
- * This is a special name that means all hosts. If you wish to find all hosts
- * on a network querying a workgroup group name is the preferred method.
+ * A B node only broadcasts name queries. This is the default if a
+ * nameserver such as WINS or Samba is not specified.
  */ 
 
-    static final String ALL_HOSTS_NAME = new String( ALL_HOSTS_BYTES );
-
-    NbtAddress( Name hostName, int address, boolean groupName, int nodeType ) {
-        this.hostName = hostName;
-        this.address = address;
-        this.groupName = groupName;
-        this.nodeType = nodeType;
-    }
-    NbtAddress( Name hostName,
-                int address,
-                boolean groupName,
-                int nodeType,
-                boolean isBeingDeleted,
-                boolean isInConflict,
-                boolean isActive,
-                boolean isPermanent,
-                byte[] macAddress ) {
-
-        this.hostName = hostName;
-        this.address = address;
-        this.groupName = groupName;
-        this.nodeType = nodeType;
-        this.isBeingDeleted = isBeingDeleted;
-        this.isInConflict = isInConflict;
-        this.isActive = isActive;
-        this.isPermanent = isPermanent;
-        this.macAddress = macAddress;
-        isDataFromNodeStatus = true;
-    }
+    public static final int B_NODE = 0;
 
 /**
- * Determines if the address is a group address. This is also
- * known as a workgroup name or group name.
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
+ * A Point-to-Point node, or P node, unicasts queries to a nameserver
+ * only. Natrually the <code>jcifs.netbios.nameserver</code> property must
+ * be set.
  */
 
-    public boolean isGroupAddress() throws UnknownHostException {
-        checkData();
-        return groupName;
-    }
-
-/** 
- * Checks the node type of this address.
- * @return {@link jcifs.netbios.NbtAddress#B_NODE}, {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE}, {@link jcifs.netbios.NbtAddress#H_NODE}
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
- */ 
-
-    public int getNodeType() throws UnknownHostException {
-        checkData();
-        return nodeType;
-    }
-
-/** 
- * Determines if this address in the process of being deleted.
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
- */ 
-
-    public boolean isBeingDeleted() throws UnknownHostException {
-        checkNodeStatusData();
-        return isBeingDeleted;
-    }
-
-/** 
- * Determines if this address in conflict with another address.
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
- */ 
-
-    public boolean isInConflict() throws UnknownHostException {
-        checkNodeStatusData();
-        return isInConflict;
-    }
-
-/** 
- * Determines if this address is active.
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
- */ 
-
-    public boolean isActive() throws UnknownHostException {
-        checkNodeStatusData();
-        return isActive;
-    }
-
-/** 
- * Determines if this address is set to be permanent.
- *
- * @throws UnknownHostException if the host cannot be resolved to find out.
- */ 
-
-    public boolean isPermanent() throws UnknownHostException {
-        checkNodeStatusData();
-        return isPermanent;
-    }
-
-/** 
- * Retrieves the MAC address of the remote network interface. Samba returns all zeros.
- *
- * @return the MAC address as an array of six bytes
- * @throws UnknownHostException if the host cannot be resolved to determine the MAC address.
- */ 
-
-    public byte[] getMacAddress() throws UnknownHostException {
-        checkNodeStatusData();
-        return macAddress;
-    }
-
-/** 
- * The hostname of this address. If the hostname is null the local machines
- * IP address is returned.
- *
- * @return the text representation of the hostname associated with this address
- */ 
-
-    public String getHostName() {
-        try {
-                       checkData();
-        } catch( UnknownHostException uhe ) {
-            return getHostAddress();
-        }
-        return hostName.getName();
-    }
-
-       // just for the above methods
-
-    void checkData() throws UnknownHostException {
-        if( hostName.name == ALL_HOSTS_NAME || hostName.name == null ) {
-               getAllByAddress( this );
-        }
-    }
-    void checkNodeStatusData() throws UnknownHostException {
-        if( isDataFromNodeStatus == false ) {
-               getAllByAddress( this );
-        }
-    }
-
-/** 
- * Returns the raw IP address of this NbtAddress. The result is in network
- * byte order: the highest order byte of the address is in getAddress()[0].
- *
- * @return a four byte array
- */ 
-
-    public byte[] getAddress() {    
-        byte[] addr = new byte[4];
-
-        addr[0] = (byte)(( address >>> 24 ) & 0xFF );
-        addr[1] = (byte)(( address >>> 16 ) & 0xFF );
-        addr[2] = (byte)(( address >>> 8 ) & 0xFF );
-        addr[3] = (byte)( address & 0xFF );
-        return addr;
-    }
-
-/** 
- * To convert this address to an <code>InetAddress</code>.
- *
- * @return the {@link java.net.InetAddress} representation of this address.
- */ 
-
-    public InetAddress getInetAddress() throws UnknownHostException {
-        return InetAddress.getByName( getHostAddress() );
-    }
+    public static final int P_NODE = 1;
 
 /** 
- * Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".
- */ 
-
-    public String getHostAddress() {    
-        return (( address >>> 24 ) & 0xFF ) + "." +
-            (( address >>> 16 ) & 0xFF ) + "." +
-            (( address >>> 8 ) & 0xFF ) + "." +
-            (( address >>> 0 ) & 0xFF );
-    }
-
-/**
- * Returned the hex code associated with this name(e.g. 0x20 is for the file service)
+ * Try Broadcast queries first, then try to resolve the name using the
+ * nameserver.
  */
 
-       public int getNameType() {
-               return hostName.type;
-       }
-
-/** 
- * Returns a hashcode for this IP address. The hashcode comes from the IP address
- * and is not generated from the string representation. So because NetBIOS nodes
- * can have many names, all names associated with an IP will have the same
- * hashcode.
- */ 
-
-    public int hashCode() {
-        return address;
-    }
-
-/** 
- * Determines if this address is equal two another. Only the IP Addresses
- * are compared. Similar to the {@link #hashCode} method, the comparison
- * is based on the integer IP address and not the string representation.
- */ 
-
-    public boolean equals( NbtAddress nbAddr ) {
-        return ( nbAddr != null ) && ( nbAddr.address == address );
-    }
-
-/** 
- * Returns the {@link java.lang.String} representaion of this address.
- */ 
-
-    public String toString() {
-        return hostName.toString() + "/" + getHostAddress();
-    }
+    public static final int M_NODE = 2;
 
 /** 
- * Retrieves the local host address.
- *
- * @throws UnknownHostException This is not likely as the IP returned by <code>InetAddress</code> should be available
+ * A Hybrid node tries to resolve a name using the nameserver first. If
+ * that fails use the broadcast address. This is the default if a nameserver
+ * is provided. This is the behavior of Microsoft Windows machines.
  */ 
 
-    public static NbtAddress getLocalHost() throws UnknownHostException {
-        return client.localhost;
-    }
+    public static final int H_NODE = 3;
 
        static final int DEFAULT_CACHE_POLICY = 30;
     static final int FOREVER = -1;
 
-    static int cachePolicy = Config.getInt( "jcifs.netbios.cachePolicy",
-                                                                                                       DEFAULT_CACHE_POLICY );
-    static Hashtable addressCache = new Hashtable();
+    static int cachePolicy;
+    static Hashtable addressCache;
+       static Name unknownName;
     static NbtAddress unknownAddress;
-    static NbtAddress[] unknown_array;
+       static byte[] unknownMacAddress = new byte[] {
+                                               (byte)0x00, (byte)0x00, (byte)0x00,
+                                               (byte)0x00, (byte)0x00, (byte)0x00
+                                       };
 
     static final class CacheEntry {
                Name hostName;
@@ -398,6 +168,72 @@ public final class NbtAddress {
         }
     }
 
+    static NameServiceClient client;
+       static NbtAddress localhost;
+
+    static {
+               InetAddress localInetAddress;
+               String localHostname;
+               Name localName;
+
+       addressCache = new Hashtable();
+       cachePolicy = Config.getInt( "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY );
+
+               /* Construct the shared static client object that will
+                * conduct all encoding and decoding of NetBIOS name service
+                * messages as well as socket IO in a synchronized fashon.
+                */
+
+               client = new NameServiceClient();
+
+               /* Create an address to represent failed lookups and cache forever.
+                */
+
+        unknownName = new Name( "0.0.0.0", 0x00, null );
+        unknownAddress = new NbtAddress( unknownName, 0, false, B_NODE );
+        addressCache.put( unknownName,
+                                               new CacheEntry( unknownName, unknownAddress, FOREVER ));
+
+               /* Determine the InetAddress of the local interface
+                * if one was not specified.
+                */
+               localInetAddress = client.laddr;
+               if( localInetAddress == null ) {
+                       try {
+                               localInetAddress = InetAddress.getLocalHost();
+                       } catch( UnknownHostException uhe ) {
+                       }
+               }
+
+               /* If a local hostname was not provided a name like
+                * JCIFS34_172_A6 will be dynamically generated for the
+                * client. This is primarily (exclusively?) used as a
+                * CallingName during session establishment.
+                */
+               localHostname = Config.getProperty( "jcifs.netbios.hostname", null );
+               if( localHostname == null || localHostname.length() == 0 ) {
+                       byte[] addr = localInetAddress.getAddress();
+                       localHostname = "JCIFS" +
+                                       ( addr[2] & 0xFF ) + "_" +
+                                       ( addr[3] & 0xFF ) + "_" +
+                                       Name.toHexChars( (int)( Math.random() * (double)0xFF ));
+               }
+
+               /* Create an NbtAddress for the local interface with
+                * the name deduced above possibly with scope applied and
+                * cache it forever.
+                */
+               localName = new Name( localHostname, 0x20,
+                                                       Config.getProperty( "jcifs.netbios.scope", null ));
+               localhost = new NbtAddress( localName,
+                                                                       localInetAddress.hashCode(),
+                                                                       false,
+                                                                       B_NODE,
+                                                                       false, false, true, false,
+                                                                       unknownMacAddress );
+               cacheAddress( localName, localhost, FOREVER );
+    }
+
     static void cacheAddress( Name hostName, NbtAddress addr ) {
         if( cachePolicy == 0 ) {
             return;
@@ -460,28 +296,24 @@ public final class NbtAddress {
         }
     }
 
-    static NameServiceClient client = new NameServiceClient();
-
-    static {
-        unknownAddress = new NbtAddress( new Name( "0.0.0.0", 0x00, "" ), 0, false, B_NODE );
-        unknown_array = new NbtAddress[1];
-        unknown_array[0] = unknownAddress;
-        addressCache.put( unknownAddress.hostName,
-                                               new CacheEntry( unknownAddress.hostName, unknownAddress, FOREVER ));
-    }
-
-    static NbtAddress doNameQuery( Name name ) throws UnknownHostException {
+    static NbtAddress doNameQuery( Name name, InetAddress svr )
+                                                                                                       throws UnknownHostException {
+        NbtAddress addr;
 
-        NbtAddress addr = getCachedAddress( name );
+               if( name.hexCode == 0x1d && svr == null ) {
+                       svr = client.baddr; // bit of a hack but saves a lookup
+               }
+               name.srcHashCode = svr != null ? svr.hashCode() : 0;
+               addr = getCachedAddress( name );
 
         if( addr == null ) {
             try {
-                addr = client.getByName( name );
+                addr = client.getByName( name, svr );
             } catch( UnknownHostException uhe ) {
-                addr = unknownAddress;
+                               addr = unknownAddress;
             } finally {
-                cacheAddress( name, addr );
-            }
+               cacheAddress( name, addr );
+                       }
         }
         if( addr == unknownAddress ) {
             throw new UnknownHostException( name.toString() );
@@ -490,6 +322,17 @@ public final class NbtAddress {
     }
 
 /** 
+ * Retrieves the local host address.
+ *
+ * @throws UnknownHostException This is not likely as the IP returned
+ *                    by <code>InetAddress</code> should be available
+ */ 
+
+    public static NbtAddress getLocalHost() throws UnknownHostException {
+        return localhost;
+    }
+
+/** 
  * Determines the address of a host given it's host name. The name can be a
  * machine name like "jcifs.samba.org" or an IP address like "192.168.1.15".
  *
@@ -499,7 +342,7 @@ public final class NbtAddress {
 
     public static NbtAddress getByName( String host )
                                         throws UnknownHostException {
-        return getByName( host, 0, null );
+        return getByName( host, 0x00, null );
     }
 
 /** 
@@ -523,11 +366,26 @@ public final class NbtAddress {
                                         String scope )
                                         throws UnknownHostException {
 
+               return getByName( host, type, scope, null );
+       }
+
+/* 
+ * The additional <code>svr</code> parameter specifies the address to
+ * query. This might be the address of a specific host, a name server,
+ * or a broadcast address.
+ */ 
+
+    public static NbtAddress getByName( String host,
+                                        int type,
+                                        String scope,
+                                                                               InetAddress svr )
+                                        throws UnknownHostException {
+
         if( host == null || host.length() == 0 ) {
             return getLocalHost();
         }
         if( !Character.isDigit( host.charAt(0) )) {
-            return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+            return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
         } else {
             int IP = 0x00;
             int hitDots = 0;
@@ -536,12 +394,12 @@ public final class NbtAddress {
             for( int i = 0; i < data.length; i++ ) {
                 char c = data[i];
                 if( c < 48 || c > 57 ) {
-                    return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                 }
                 int b = 0x00;
                 while( c != '.' ) {
                     if( c < 48 || c > 57 ) {
-                        return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                        return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                     }
                     b = b * 10 + c - '0';
 
@@ -551,16 +409,15 @@ public final class NbtAddress {
                     c = data[i];
                 }
                 if( b > 0xFF ) {
-                    return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                    return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
                 }
                 IP = ( IP << 8 ) + b;
                 hitDots++;
             }
             if( hitDots != 4 || host.endsWith( "." )) {
-                return (NbtAddress)doNameQuery( new Name( host, type, scope ));
+                return (NbtAddress)doNameQuery( new Name( host, type, scope ), svr );
             }
-            return new NbtAddress( new Name( ALL_HOSTS_NAME, type, scope ),
-                                                                                                       IP, false, B_NODE );
+            return new NbtAddress( unknownName, IP, false, B_NODE );
         }
     }
 
@@ -575,7 +432,8 @@ public final class NbtAddress {
  */
 
 
-    public static NbtAddress[] getAllByAddress( String host ) throws UnknownHostException {
+    public static NbtAddress[] getAllByAddress( String host )
+                                                                                               throws UnknownHostException {
         return getAllByAddress( getByName( host, 0x00, null ));
     }
 
@@ -621,12 +479,325 @@ public final class NbtAddress {
             return addrs;
         } catch( UnknownHostException uhe ) {
             throw new UnknownHostException( "no name with type 0x" +
-                                                       Name.toHexChars( addr.hostName.type ) +
+                                                       Name.toHexChars( addr.hostName.hexCode ) +
                                                        ((( addr.hostName.scope == null ) ||
                                                        ( addr.hostName.scope.length() == 0 )) ?
                                                        " with no scope" : " with scope " + addr.hostName.scope ) +
                                                        " for host " + addr.getHostAddress() );
         }
     }
-}
 
+    Name hostName;
+    int address, nodeType;
+    boolean groupName,
+               isBeingDeleted,
+       isInConflict,
+       isActive,
+       isPermanent,
+       isDataFromNodeStatus;
+    byte[] macAddress;
+       String calledName;
+
+    NbtAddress( Name hostName, int address, boolean groupName, int nodeType ) {
+        this.hostName = hostName;
+        this.address = address;
+        this.groupName = groupName;
+        this.nodeType = nodeType;
+       }
+
+    NbtAddress( Name hostName,
+                int address,
+                boolean groupName,
+                int nodeType,
+                boolean isBeingDeleted,
+                boolean isInConflict,
+                boolean isActive,
+                boolean isPermanent,
+                byte[] macAddress ) {
+
+/* The NodeStatusResponse.readNodeNameArray method may also set this
+ * information. These two places where node status data is populated should
+ * be consistent. Be carefull!
+ */
+        this.hostName = hostName;
+        this.address = address;
+        this.groupName = groupName;
+        this.nodeType = nodeType;
+        this.isBeingDeleted = isBeingDeleted;
+        this.isInConflict = isInConflict;
+        this.isActive = isActive;
+        this.isPermanent = isPermanent;
+        this.macAddress = macAddress;
+        isDataFromNodeStatus = true;
+    }
+
+/* Guess next called name to try for session establishment. These
+ * methods are used by the smb package.
+ */
+
+       public String firstCalledName() {
+
+               calledName = hostName.name;
+
+               if( Character.isDigit( calledName.charAt( 0 ))) {
+                       int i, len, dots;
+                       char[] data;
+
+                       i = dots = 0;                    /* quick IP address validation */
+                       len = calledName.length();
+                       data = calledName.toCharArray();
+                       while( i < len && Character.isDigit( data[i++] )) {
+                               if( i == len && dots == 3 ) {
+                                       // probably an IP address
+                                       calledName = SMBSERVER_NAME;
+                                       break;
+                               }
+                               if( data[i] == '.' ) {
+                                       dots++;
+                                       i++;
+                               }
+                       }
+               }
+
+               return calledName;
+    }
+       public String nextCalledName() {
+
+               if( calledName == hostName.name ) {
+                       calledName = SMBSERVER_NAME;
+               } else if( calledName == SMBSERVER_NAME ) {
+                       NbtAddress[] addrs;
+
+                       try {
+                               addrs = client.getNodeStatus( this );
+                               if( isDataFromNodeStatus ) {
+                                       /* 'this' has been updated and should now
+                                        * have a real NetBIOS name
+                                        */
+                                       calledName = null;
+                                       return hostName.name;
+                               }
+                       } catch( UnknownHostException uhe ) {
+                               calledName = null;
+                       }
+               } else {
+                       calledName = null;
+               }
+
+               return calledName;
+       }
+
+/* 
+ * There are three degrees of state that any NbtAddress can have.
+ * 
+ * 1) IP Address - If a dot-quad IP string is used with getByName (or used
+ * to create an NbtAddress internal to this netbios package), no query is
+ * sent on the wire and the only state this object has is it's IP address
+ * (but that's enough to connect to a host using *SMBSERVER for CallingName).
+ * 
+ * 2) IP Address, NetBIOS name, nodeType, groupName - If however a
+ * legal NetBIOS name string is used a name query request will retreive
+ * the IP, node type, and whether or not this NbtAddress represents a
+ * group name. This degree of state can be obtained with a Name Query
+ * Request or Node Status Request.
+ * 
+ * 3) All - The NbtAddress will be populated with all state such as mac
+ * address, isPermanent, isBeingDeleted, ...etc. This information can only
+ * be retrieved with the Node Status request.
+ * 
+ * The degree of state that an NbtAddress has is dependant on how it was
+ * created and what is required of it. The second degree of state is the
+ * most common. This is the state information that would be retrieved from
+ * WINS for example. Natrually it is not practical for every NbtAddress
+ * to be populated will all state requiring a Node Status on every host
+ * encountered. The below methods allow state to be populated when requested
+ * in a lazy fashon.
+ */ 
+
+    void checkData() throws UnknownHostException {
+        if( hostName == unknownName ) {
+               getAllByAddress( this );
+        }
+    }
+    void checkNodeStatusData() throws UnknownHostException {
+        if( isDataFromNodeStatus == false ) {
+               getAllByAddress( this );
+        }
+    }
+
+/**
+ * Determines if the address is a group address. This is also
+ * known as a workgroup name or group name.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */
+
+    public boolean isGroupAddress() throws UnknownHostException {
+        checkData();
+        return groupName;
+    }
+
+/** 
+ * Checks the node type of this address.
+ * @return {@link jcifs.netbios.NbtAddress#B_NODE},
+ * {@link jcifs.netbios.NbtAddress#P_NODE}, {@link jcifs.netbios.NbtAddress#M_NODE},
+ * {@link jcifs.netbios.NbtAddress#H_NODE}
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public int getNodeType() throws UnknownHostException {
+        checkData();
+        return nodeType;
+    }
+
+/** 
+ * Determines if this address in the process of being deleted.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isBeingDeleted() throws UnknownHostException {
+        checkNodeStatusData();
+        return isBeingDeleted;
+    }
+
+/** 
+ * Determines if this address in conflict with another address.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isInConflict() throws UnknownHostException {
+        checkNodeStatusData();
+        return isInConflict;
+    }
+
+/** 
+ * Determines if this address is active.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isActive() throws UnknownHostException {
+        checkNodeStatusData();
+        return isActive;
+    }
+
+/** 
+ * Determines if this address is set to be permanent.
+ *
+ * @throws UnknownHostException if the host cannot be resolved to find out.
+ */ 
+
+    public boolean isPermanent() throws UnknownHostException {
+        checkNodeStatusData();
+        return isPermanent;
+    }
+
+/** 
+ * Retrieves the MAC address of the remote network interface. Samba returns all zeros.
+ *
+ * @return the MAC address as an array of six bytes
+ * @throws UnknownHostException if the host cannot be resolved to
+ * determine the MAC address.
+ */ 
+
+    public byte[] getMacAddress() throws UnknownHostException {
+        checkNodeStatusData();
+        return macAddress;
+    }
+
+/** 
+ * The hostname of this address. If the hostname is null the local machines
+ * IP address is returned.
+ *
+ * @return the text representation of the hostname associated with this address
+ */ 
+
+    public String getHostName() {
+        try {
+                       checkData();
+        } catch( UnknownHostException uhe ) {
+            return getHostAddress();
+        }
+        return hostName.name;
+    }
+
+
+/** 
+ * Returns the raw IP address of this NbtAddress. The result is in network
+ * byte order: the highest order byte of the address is in getAddress()[0].
+ *
+ * @return a four byte array
+ */ 
+
+    public byte[] getAddress() {    
+        byte[] addr = new byte[4];
+
+        addr[0] = (byte)(( address >>> 24 ) & 0xFF );
+        addr[1] = (byte)(( address >>> 16 ) & 0xFF );
+        addr[2] = (byte)(( address >>> 8 ) & 0xFF );
+        addr[3] = (byte)( address & 0xFF );
+        return addr;
+    }
+
+/** 
+ * To convert this address to an <code>InetAddress</code>.
+ *
+ * @return the {@link java.net.InetAddress} representation of this address.
+ */ 
+
+    public InetAddress getInetAddress() throws UnknownHostException {
+        return InetAddress.getByName( getHostAddress() );
+    }
+
+/** 
+ * Returns this IP adress as a {@link java.lang.String} in the form "%d.%d.%d.%d".
+ */ 
+
+    public String getHostAddress() {    
+        return (( address >>> 24 ) & 0xFF ) + "." +
+            (( address >>> 16 ) & 0xFF ) + "." +
+            (( address >>> 8 ) & 0xFF ) + "." +
+            (( address >>> 0 ) & 0xFF );
+    }
+
+/**
+ * Returned the hex code associated with this name(e.g. 0x20 is for the file service)
+ */
+
+       public int getNameType() {
+               return hostName.hexCode;
+       }
+
+/** 
+ * Returns a hashcode for this IP address. The hashcode comes from the IP address
+ * and is not generated from the string representation. So because NetBIOS nodes
+ * can have many names, all names associated with an IP will have the same
+ * hashcode.
+ */ 
+
+    public int hashCode() {
+        return address;
+    }
+
+/** 
+ * Determines if this address is equal two another. Only the IP Addresses
+ * are compared. Similar to the {@link #hashCode} method, the comparison
+ * is based on the integer IP address and not the string representation.
+ */ 
+
+    public boolean equals( Object obj ) {
+        return ( obj != null ) && ( obj instanceof NbtAddress ) &&
+                                                                               ( ((NbtAddress)obj).address == address );
+    }
+
+/** 
+ * Returns the {@link java.lang.String} representaion of this address.
+ */ 
+
+    public String toString() {
+        return hostName.toString() + "/" + getHostAddress();
+    }
+}
index d468032..3258f97 100644 (file)
@@ -97,8 +97,7 @@ public class NbtSocket extends Socket {
                InputStream in = super.getInputStream();
                OutputStream out = super.getOutputStream();
 
-               address.checkData();
-               SessionServicePacket ssp0 = new SessionRequestPacket( calledName, NbtAddress.getLocalHost().hostName );
+               SessionServicePacket ssp0 = new SessionRequestPacket( calledName, NbtAddress.localhost.hostName );
                out.write( buffer, 0, ssp0.writeWireFormat( buffer, 0 ));
 
                switch( ssp0.readPacketType( in, buffer, 0 )) {
index d8ef2a6..841fe92 100644 (file)
@@ -26,10 +26,10 @@ class NodeStatusRequest extends NameServicePacket {
        }
 
        int writeBodyWireFormat( byte[] dst, int dstIndex ) {
-               int tmp = questionName.type;
-               questionName.type = 0x00; // type has to be 0x00 for node status
+               int tmp = questionName.hexCode;
+               questionName.hexCode = 0x00; // type has to be 0x00 for node status
                int result = writeQuestionSectionWireFormat( dst, dstIndex );
-               questionName.type = tmp;
+               questionName.hexCode = tmp;
                return result;
        }
        int readBodyWireFormat( byte[] src, int srcIndex ) {
index ee96932..c6efc2e 100644 (file)
@@ -37,7 +37,7 @@ class NodeStatusResponse extends NameServicePacket {
 
        NodeStatusResponse( NbtAddress queryAddress ) {
                this.queryAddress = queryAddress;
-               recordName = new Name( null, 0, null );
+               recordName = new Name();
         macAddress = new byte[6];
        }
 
@@ -70,7 +70,7 @@ class NodeStatusResponse extends NameServicePacket {
                addressArray = new NbtAddress[numberOfNames];
 
         String n;
-        int type;
+        int hexCode;
         String scope = queryAddress.hostName.scope;
         boolean groupName;
         int ownerNodeType;
@@ -84,18 +84,27 @@ class NodeStatusResponse extends NameServicePacket {
             for( j = srcIndex + 14; src[j] == 0x20; j-- )
                 ;
             n = new String( src, srcIndex, j - srcIndex + 1 );
-            type             =    src[srcIndex + 15] & 0xFF;
+            hexCode          =    src[srcIndex + 15] & 0xFF;
             groupName        = (( src[srcIndex + 16] & 0x80 ) == 0x80 ) ? true : false;
             ownerNodeType    =  ( src[srcIndex + 16] & 0x60 ) >> 5;
             isBeingDeleted   = (( src[srcIndex + 16] & 0x10 ) == 0x10 ) ? true : false;
             isInConflict     = (( src[srcIndex + 16] & 0x08 ) == 0x08 ) ? true : false;
             isActive         = (( src[srcIndex + 16] & 0x04 ) == 0x04 ) ? true : false;
             isPermanent      = (( src[srcIndex + 16] & 0x02 ) == 0x02 ) ? true : false;
-            if( !addrFound && queryAddress.hostName.type == type &&
-                    ( queryAddress.hostName.name == null ||
-                                       queryAddress.hostName.name.equals( NbtAddress.ALL_HOSTS_NAME ) ||
-                                       queryAddress.hostName.name.equalsIgnoreCase( n ))) {
-                queryAddress.hostName.name = n;
+
+/* The NbtAddress object used to query this node will be in the list
+ * returned by the Node Status. A new NbtAddress object should not be
+ * created for it because the original is potentially being actively
+ * referenced by other objects. We must populate the existing object's
+ * data explicitly (and carefully).
+ */
+            if( !addrFound && queryAddress.hostName.hexCode == hexCode &&
+                                       ( queryAddress.hostName == NbtAddress.unknownName ||
+                                       queryAddress.hostName.name.equals( n ))) {
+
+                               if( queryAddress.hostName == NbtAddress.unknownName ) {
+                       queryAddress.hostName = new Name( n, hexCode, scope );
+                               }
                 queryAddress.groupName = groupName;
                 queryAddress.nodeType = ownerNodeType;
                 queryAddress.isBeingDeleted = isBeingDeleted;
@@ -107,7 +116,7 @@ class NodeStatusResponse extends NameServicePacket {
                 addrFound = true;
                 addressArray[i] = queryAddress;
             } else {
-                addressArray[i] = new NbtAddress( new Name( n, type, scope ),
+                addressArray[i] = new NbtAddress( new Name( n, hexCode, scope ),
                                         queryAddress.address,
                                         groupName,
                                         ownerNodeType,
index e4ef8bb..2faed0e 100644 (file)
@@ -26,8 +26,8 @@ class SessionRequestPacket extends SessionServicePacket {
        Name calledName, callingName;
 
        SessionRequestPacket() {
-               calledName = new Name( null, 0, null );
-               callingName = new Name( null, 0, null );
+               calledName = new Name();
+               callingName = new Name();
        }
        SessionRequestPacket( Name calledName, Name callingName ) {
                type = SESSION_REQUEST;
index cf6c987..cc471ba 100644 (file)
@@ -255,10 +255,6 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock {
                                }
                                n = readBytesWireFormat( buffer, bufferIndex );
                        }
-                       if( n != byteCount ) {
-                               Log.println( Log.WARNINGS, "smb andx packet format warning", "byteCount=" +
-                                                               byteCount + " but readBytesWireFormat returned " + n );
-                       }
                        bufferIndex += byteCount;
                }
 
@@ -368,19 +364,13 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock {
                                        if( in.read( buffer, bufferIndex, andx.byteCount ) != andx.byteCount ) {
                                                throw new IOException( "unexpected EOF reading andx bytes" );
                                        }
-                                       int n;
-                                       if(( n = andx.readBytesWireFormat( buffer, bufferIndex )) != andx.byteCount ) {
-                                               Log.println( Log.WARNINGS, "smb andx packet format warning",
-                                                                       "byteCount=" + andx.byteCount +
-                                                                       " but readBytesWireFormat returned " + n );
-                                       }
+                                       andx.readBytesWireFormat( buffer, bufferIndex );
                                        bufferIndex += andx.byteCount;
                                }
                        }
                        andx.received = true;
                }
 
-
                return bufferIndex - start;
        }
        public String toString() {
diff --git a/src/jcifs/smb/BufferCache.java b/src/jcifs/smb/BufferCache.java
new file mode 100644 (file)
index 0000000..f07f331
--- /dev/null
@@ -0,0 +1,54 @@
+package jcifs.smb;
+
+import jcifs.Config;
+
+class BufferCache {
+
+       static final int MAX_BUFFERS = Config.getInt( "jcifs.smb.maxBuffers", 16 );
+
+       static Object[] cache = new Object[MAX_BUFFERS];
+       static int numBuffers = 0;
+       static int freeBuffers = 0;
+
+       static byte[] getBuffer() {
+               byte[] buf;
+
+               synchronized( cache ) {
+                       while( freeBuffers == 0 && numBuffers == MAX_BUFFERS ) {
+                               try {
+                                       cache.wait();
+                               } catch( InterruptedException ie ) {
+                                       return null;
+                               }
+                       }
+
+                       if( freeBuffers > 0 ) {
+                               for( int i = 0; i < MAX_BUFFERS; i++ ) {
+                                       if( cache[i] != null ) {
+                                               buf = (byte[])cache[i];
+                                               cache[i] = null;
+                                               freeBuffers--;
+                                               return buf;
+                                       }
+                               }
+                       }
+
+                       buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE];
+                       numBuffers++;
+               }
+
+               return buf;
+       }
+       static void releaseBuffer( byte[] buf ) {
+               synchronized( cache ) {
+                       for( int i = 0; i < MAX_BUFFERS; i++ ) {
+                               if( cache[i] == null ) {
+                                       cache[i] = buf;
+                                       freeBuffers++;
+                                       cache.notify();
+                                       return;
+                               }
+                       }
+               }
+       }
+}
index 1a5708b..c76a6b6 100644 (file)
@@ -25,20 +25,20 @@ import java.io.IOException;
 
 public class Handler extends URLStreamHandler {
 
-       SmbURL url;
+       SmbFile f;
 
        public URLConnection openConnection( URL u ) throws IOException {
-               return new SmbURLConnection( u, url );
+               return new SmbURLConnection( u, f );
        }
        protected void parseURL( URL u, String spec, int start, int limit ) {
                try {
-                       url = new SmbURL( spec, null, start, limit );
+                       f = new SmbFile( spec, null, start, limit );
                } catch( IOException ioe ) {
                        Log.printStackTrace( "smb URLStreamHandler exception", ioe );
                }
-               setURL( u, "smb", url.server, url.port, url.canonicalPath, null );
+               setURL( u, "smb", f.server, f.port, f.canonicalPath, null );
        }
        protected String toExternalForm( URL u ) {
-               return url.toString();
+               return f.toString();
        }
 }
index 8a722e1..81f3e8b 100644 (file)
@@ -74,6 +74,6 @@ class NetServerEnum2 extends SmbComTransaction {
                return 0;
        }
        public String toString() {
-               return new String( "NetServerEnum2[" + super.toString() + "]" );
+               return new String( "NetServerEnum2[" + super.toString() + ",name=" + name + ",serverTypes=" + (serverTypes == SV_TYPE_ALL ? "SV_TYPE_ALL" : "SV_TYPE_DOMAIN_ENUM" ) + "]" );
        }
 }
index 0fa9cea..c2d1903 100644 (file)
@@ -24,12 +24,6 @@ import java.io.IOException;
 
 class NetServerEnum2Response extends SmbComTransactionResponse {
 
-       // transaction response status
-       static final int NERR_Success                = 0;
-       static final int ERROR_MORE_DATA             = 234;
-       static final int NERR_ServerNotStarted       = 2114;
-       static final int NERR_BasicTransactConfig    = 2141;
-
        class ServerInfo1 {
                String name;
                int versionMajor;
index 0d0d022..3c80143 100644 (file)
@@ -24,14 +24,6 @@ import java.io.IOException;
 
 class NetShareEnumResponse extends SmbComTransactionResponse {
 
-       // transaction response status
-       static final int NERR_Success                = 0;
-       static final int ERROR_ACCESS_DENIED         = 5;
-       static final int ERROR_NETWORK_ACCESS_DENIED = 65;
-       static final int ERROR_MORE_DATA             = 234;
-       static final int NERR_ServerNotStarted       = 2114;
-       static final int NERR_BasicTransactConfig    = 2141;
-
        class ShareInfo1 {
                String netName;
                int type;
@@ -95,7 +87,7 @@ class NetShareEnumResponse extends SmbComTransactionResponse {
                        off = ( off & 0xFFFF ) - converter;
                        off = start + off;
                        results[i].remark = new String( buffer, off,
-                                                       readStringLength( buffer, off, 48 ));
+                                                       readStringLength( buffer, off, 128 ));
 Log.println( Log.DEBUGGING, "smb warning", results[i] );
                }
 
index 0fdac57..66d1faa 100644 (file)
@@ -311,7 +311,7 @@ abstract class ServerMessageBlock {
                int len = 0;
                while( src[srcIndex + len] != (byte)0x00 ) {
                        if( len++ > max ) {
-                               throw new RuntimeException( "zero termination not found" );
+                               throw new RuntimeException( "zero termination not found: " + this );
                        }
                }
                return len;
diff --git a/src/jcifs/smb/SmbAuthException.java b/src/jcifs/smb/SmbAuthException.java
new file mode 100644 (file)
index 0000000..0419498
--- /dev/null
@@ -0,0 +1,8 @@
+package jcifs.smb;
+
+public class SmbAuthException extends SmbException {
+
+       public SmbAuthException( int code ) {
+               super( code );
+       }
+}
index 5128f5d..99d9261 100644 (file)
@@ -122,7 +122,7 @@ class SmbComNTCreateAndX extends AndXServerMessageBlock {
                extFileAttributes = ATTR_NORMAL;
 
                // shareAccess
-               shareAccess = FILE_SHARE_READ;
+               shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
 
                // createDisposition
                if(( flags & SmbFile.O_TRUNC ) == SmbFile.O_TRUNC ) {
index d0f84f9..7127452 100644 (file)
@@ -44,7 +44,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
 
        static final int PADDING_SIZE = 2;
 
-       static final int DEFAULT_TRANSACTION_BUF_SIZE = 0xFFFF;
+       static final int TRANSACTION_BUF_SIZE = 0xFFFF;
 
        int totalParameterCount;
        int totalDataCount;
@@ -69,7 +69,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
        boolean isPrimary = true;
        int maxBufferSize; // set in SmbTransport.sendTransaction() before nextElement called
 
-       byte[] buf = new byte[DEFAULT_TRANSACTION_BUF_SIZE]; // yuck
+       byte[] txn_buf;
        int bufParameterOffset;
        int bufDataOffset;
 
@@ -77,7 +77,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
                maxParameterCount = 1024;
                // subtract 512 just to be safe
                maxDataCount = Config.getInt( "jcifs.smb.client.transaction_buf_size",
-                                                               SmbComTransactionResponse.DEFAULT_TRANSACTION_BUF_SIZE ) - 512;
+                                       SmbComTransaction.TRANSACTION_BUF_SIZE ) - 512;
        }
 
        public boolean hasMoreElements() {
@@ -95,7 +95,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
                        pad = pad == 0 ? 0 : PADDING_SIZE - pad;
                        parameterOffset += pad;
 
-                       totalParameterCount = writeParametersWireFormat( buf, bufParameterOffset );
+                       totalParameterCount = writeParametersWireFormat( txn_buf, bufParameterOffset );
                        bufDataOffset = totalParameterCount; // data comes right after data
 
                        int available = maxBufferSize - parameterOffset;
@@ -107,7 +107,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
                        pad1 = pad1 == 0 ? 0 : PADDING_SIZE - pad1;
                        dataOffset += pad1;
 
-                       totalDataCount = writeDataWireFormat( buf, bufDataOffset );
+                       totalDataCount = writeDataWireFormat( txn_buf, bufDataOffset );
 
                        dataCount = Math.min( totalDataCount, available );
                } else {
@@ -201,7 +201,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
                                dst[dstIndex++] = (byte)0x00;       // Pad
                        }
 
-                       System.arraycopy( buf, bufParameterOffset, dst, dstIndex, parameterCount );
+                       System.arraycopy( txn_buf, bufParameterOffset, dst, dstIndex, parameterCount );
                        dstIndex += parameterCount;
                }
 
@@ -210,7 +210,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
                        while( p-- > 0 ) {
                                dst[dstIndex++] = (byte)0x00;       // Pad1
                        }
-                       System.arraycopy( buf, bufDataOffset, dst, dstIndex, dataCount );
+                       System.arraycopy( txn_buf, bufDataOffset, dst, dstIndex, dataCount );
                        bufDataOffset += dataCount;
                        dstIndex += dataCount;
                }
index 0cfc779..fa0a8f9 100644 (file)
@@ -29,8 +29,6 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E
        static final int DISCONNECT_TID      = 0x01;
        static final int ONE_WAY_TRANSACTION = 0x02;
 
-       static final int DEFAULT_TRANSACTION_BUF_SIZE = 0xFFFF;
-
        int totalParameterCount;
        int totalDataCount;
        int parameterCount;
@@ -46,15 +44,12 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E
        boolean hasMore = true;
        boolean isPrimary = true;
 
-       int data_rcv_buf_size;
-       byte[] buf;
+       byte[] txn_buf;
        int bufParameterStart;
        int bufDataStart;
 
        SmbComTransactionResponse() {
-               data_rcv_buf_size = Config.getInt( "jcifs.smb.client.transaction_buf_size",
-                                                                                                               DEFAULT_TRANSACTION_BUF_SIZE );
-               buf = new byte[data_rcv_buf_size]; // OUCH !!
+               txn_buf = null;
        }
 
        public boolean hasMoreElements() {
@@ -109,13 +104,13 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E
 
                if( parameterCount > 0 ) {
                        bufferIndex += pad = parameterOffset - ( bufferIndex - headerStart );
-                       System.arraycopy( buffer, bufferIndex, buf,
+                       System.arraycopy( buffer, bufferIndex, txn_buf,
                                                        bufParameterStart + parameterDisplacement, parameterCount );
                        bufferIndex += parameterCount;
                }
                if( dataCount > 0 ) {
                        bufferIndex += pad1 = dataOffset - ( bufferIndex - headerStart );
-                       System.arraycopy( buffer, bufferIndex, buf,
+                       System.arraycopy( buffer, bufferIndex, txn_buf,
                                                        bufDataStart + dataDisplacement, dataCount );
                        bufferIndex += dataCount;
                }
@@ -127,8 +122,8 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E
                if(( parameterDisplacement + parameterCount ) == totalParameterCount &&
                                ( dataDisplacement + dataCount ) == totalDataCount ) {
                        hasMore = false;
-                       readParametersWireFormat( buf, bufParameterStart, totalParameterCount );
-                       readDataWireFormat( buf, bufDataStart, totalDataCount );
+                       readParametersWireFormat( txn_buf, bufParameterStart, totalParameterCount );
+                       readDataWireFormat( txn_buf, bufDataStart, totalDataCount );
                }
 
                return pad + parameterCount + pad1 + dataCount;
index 7363cb9..792c9fc 100644 (file)
@@ -97,6 +97,7 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock {
 
        int getBatchLimit( byte command ) {
                int c = (int)( command & 0xFF );
+               // why isn't this just return batchLimits[c]?
                switch( c ) {
                        case SMB_COM_CHECK_DIRECTORY:
                                return batchLimits[0];
@@ -123,7 +124,7 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock {
        int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
 
                if( session.transport.server.security == SECURITY_SHARE &&
-                                                                                                       session.password.length() != 0 ) {
+                                                                                               session.password.length() != 0 ) {
                        if( session.transport.server.encryptedPasswords ) {
                                // encrypted
                                password = SmbSession.getPreNTLMResponse( session.password,
@@ -181,8 +182,7 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock {
                        super.toString() +
                        ",disconnectTid=" + disconnectTid +
                        ",passwordLength=" + passwordLength +
-                       ",password=" + Log.getHexString(
-                                               password, passwordLength, 0 ) +
+                       ",password=" + Log.getHexString( password, passwordLength, 0 ) +
                        ",path=" + path +
                        ",service=" + service + "]" );
                return result;
index e9bfd06..6b73a99 100644 (file)
@@ -20,45 +20,135 @@ package jcifs.smb;
 
 import java.io.IOException;
 
-class SmbException extends IOException {
+/**
+ * Don't get to attached to these constants, we'll be switching to NT
+ * status codes sooner or later.
+ */
+
+public class SmbException extends IOException {
 
        // error classes
-       static final int SUCCESS = 0;
-       static final int ERRDOS  = 0x01;
-       static final int ERRSRV  = 0x02;
-       static final int ERRHRD  = 0x03;
-       static final int ERRCMD  = 0xFF;
+       public static final int SUCCESS = 0;
+       public static final int ERRDOS  = 0x01;
+       public static final int ERRSRV  = 0x02;
+       public static final int ERRHRD  = 0x03;
+       public static final int ERRCMD  = 0xFF;
+       public static final int ERRRAP  = 0x10;
+       public static final int ERRCLI  = 0x20;
 
        // dos error codes
-       static final int ERRbadfunc        = 1;
-       static final int ERRbadfile        = 2;
-       static final int ERRbadpath        = 3;
-       static final int ERRnoaccess   = 5;
-       static final int ERRbadfid     = 6;
-       static final int ERRbadshare   = 32;
-       static final int ERRbadnetname = 67;
-       static final int ERRbadparm        = 87;
-       static final int ERRfilexists  = 80;
-       static final int ERRbrokenpipe = 109;
-       static final int ERRinvname        = 123;
-       static final int ERRpipebusy   = 231;
-       static final int ERRnodata     = 232;
+/**
+ *  Invalid function
+ */
+       public static final int ERRbadfunc        = 1;
+/**
+ * File not found
+ */
+       public static final int ERRbadfile        = 2;
+/**
+ * Directory invalid
+ */
+       public static final int ERRbadpath        = 3;
+/**
+ * Access denied
+ */
+       public static final int ERRnoaccess   = 5;
+       public static final int ERRbadfid     = 6;
+/**
+ * Not enough storage is available to process this command
+ */
+       public static final int ERRnospace    = 8;
+/**
+ * The file is being used by another process
+ */
+       public static final int ERRbadshare   = 32;
+/**
+ * A duplicate name exists on the network
+ */
+       public static final int ERRdupname    = 52;
+/**
+ * The network name cannot be found
+ */
+       public static final int ERRbadnetname = 67;
+       public static final int ERRbadparm        = 87;
+/**
+ * Cannot create a file when that file alread exists
+ */
+       public static final int ERRfilexists  = 80;
+/**
+ * The pipe has been ended
+ */
+       public static final int ERRbrokenpipe = 109;
+/**
+ * Invalid name
+ */
+       public static final int ERRinvname        = 123;
+/**
+ * File exists
+ */
+       public static final int ERRexists     = 183;
+/**
+ * All pipe instances are busy
+ */
+       public static final int ERRpipebusy   = 231;
+/**
+ * The pipe is being closed
+ */
+       public static final int ERRnodata     = 232;
 
        // srv error codes
-       static final int ERRerror           = 1;
-       static final int ERRbadpw           = 2;
-       static final int ERRaccess          = 4;
-       static final int ERRinvnid          = 5;
-       static final int ERRinvnetname      = 6;
-       static final int ERRbaduid          = 91;
-       static final int ERRaccountExpired  = 2239;
-       static final int ERRbadClient       = 2240;
-       static final int ERRbadLogonTime    = 2241;
-       static final int ERRpasswordExpired = 2242;
+/**
+ * Non-specific error code
+ */
+       public static final int ERRerror           = 1;
+/**
+ * Bad password
+ */
+       public static final int ERRbadpw           = 2;
+/**
+ * The client does not have the necessary access rights for the requested function
+ */
+       public static final int ERRaccess          = 4;
+       public static final int ERRinvnid          = 5;
+       public static final int ERRinvnetname      = 6;
+       public static final int ERRbaduid          = 91;
+/**
+ * The user account has expired
+ */
+       public static final int ERRaccountExpired  = 2239;
+/**
+ * The user is not allowed to access this server from this client
+ */
+       public static final int ERRbadClient       = 2240;
+/**
+ * The user is not permitted to access the server at this time
+ */
+       public static final int ERRbadLogonTime    = 2241;
+/**
+ * The password of the user has expired
+ */
+       public static final int ERRpasswordExpired = 2242;
 
        // hrd error codes
-       static final int ERRnowrite  = 19;
-       static final int ERRnotready = 21;
+/**
+ * Attempt to write on write-protected media
+ */
+       public static final int ERRnowrite  = 19;
+/**
+ * The device is not ready
+ */
+       public static final int ERRnotready = 21;
+
+       // RAP transaction status codes
+       public static final int NERR_Success                = 0;
+       public static final int ERROR_MORE_DATA             = 234;
+       public static final int NERR_ServerNotStarted       = 2114;
+       public static final int NERR_BasicTransactConfig    = 2141;
+
+       // cli error codes (defined for jCIFS)
+       public static final int ERRserverTimeout = 5000;
+       public static final int ERRbadDialect    = 5001;
+       public static final int ERRioe           = 5002;
 
        int errorClass;
        int errorCode;
@@ -67,118 +157,148 @@ class SmbException extends IOException {
                String result = "";
                switch( errorClass ) {
                        case SUCCESS:
-                               result += "SUCCESS";
+                               result += "The operation completed successfully";
                                break;
                        case ERRDOS:
-                               result += "ERRDOS/";
                                switch( errorCode ) {
                                        case ERRbadfunc:
-                                               result += "ERRbadfunc: Invalid function";
+                                               result += "Invalid function";
                                                break;
                                        case ERRbadfile:
-                                               result += "ERRbadfile: File not found";
+                                               result += "File not found";
                                                break;
                                        case ERRbadpath:
-                                               result += "ERRbadpath: Directory invalid";
+                                               result += "Directory invalid";
                                                break;
                                        case ERRnoaccess:
-                                               result += "ERRnoaccess: Access denied";
+                                               result += "Access denied";
                                                break;
                                        case ERRbadparm:
-                                               result += "ERRbadparm: Invalid parameter";
+                                               result += "Invalid parameter";
                                                break;
                                        case ERRinvname:
-                                               result += "ERRinvname: Invalid name";
+                                               result += "Invalid name";
                                                break;
                                        case ERRfilexists:
-                                               result += "ERRfilexists: File exists";
+                                               result += "File exists";
                                                break;
                                        case ERRbadfid:
-                                               result += "ERRbadfid: Invalid file handle";
+                                               result += "Invalid file handle";
+                                               break;
+                                       case ERRnospace:
+                                               result += "Not enough storage is available to process this command";
                                                break;
                                        case ERRbadshare:
-                                               result += "ERRbadshare: The file is being used by another process";
+                                               result += "The file is being used by another process";
+                                               break;
+                                       case ERRdupname:
+                                               result += "A duplicate name exists on the network";
                                                break;
                                        case ERRnotready:
-                                               result += "ERRnotready: The device is not ready";
+                                               result += "The device is not ready";
                                                break;
                                        case ERRbadnetname:
-                                               result += "ERRbadnetname: The network name cannot be found.";
+                                               result += "The network name cannot be found";
+                                               break;
+                                       case ERRexists:
+                                               result += "Cannot create a file when that file alread exists";
                                                break;
                                        case ERRpipebusy:
-                                               result += "ERRpipebusy: All pipe instances are busy.";
+                                               result += "All pipe instances are busy";
                                                break;
                                        case ERRnodata:
-                                               result += "ERRnodata: The pipe is being closed.";
+                                               result += "The pipe is being closed";
                                                break;
                                        case ERRbrokenpipe:
-                                               result += "ERRbrokenpipe: The pipe has been ended.";
+                                               result += "The pipe has been ended";
                                                break;
                                        default:
-                                               result += "Ehh, one of the other ones. Please update " +
-                                                                               "getErrorString for errorCode=" + errorCode;
+                                               result += "No description available. Please update error string for errorCode=" + errorCode;
                                }
                                break;
                        case ERRSRV:
-                               result += "ERRSRV/";
                                switch( errorCode ) {
                                        case ERRerror:
-                                               result += "ERRerror: Non-specific error code";
+                                               result += "Non-specific error code";
                                                break;
                                        case ERRbadpw:
-                                               result += "ERRbadpw: Bad password";
+                                               result += "Bad password";
                                                break;
                                        case ERRinvnid:
-                                               result += "ERRinvnid: The Tid specified was invalid";
+                                               result += "The Tid specified was invalid";
                                                break;
                                        case ERRinvnetname:
-                                               result += "ERRinvnetname: Invalid network name in tree connect, " +
-                                                                                       "service not found";
+                                               result += "Invalid network name in tree connect, service not found";
                                                break;
                                        case ERRbaduid:
-                                               result += "ERRbaduid: The UID is not known as a valid user " +
-                                                                                       "identifier on this session";
+                                               result += "The UID is not known as a valid user identifier on this session";
                                                break;
                                        case ERRaccess:
-                                               result += "ERRaccess: The client does not have the necessary " +
-                                                                                       "access rights for the requested function";
+                                               result += "The client does not have the necessary access rights for the requested function";
                                                break;
                                        case ERRaccountExpired:
-                                               result += "ERRaccountExpired: The user account has expired";
+                                               result += "The user account has expired";
                                                break;
                                        case ERRbadClient:
-                                               result += "ERRbadClient: The user is not allowed to access " +
-                                                                                       "this server from this client";
+                                               result += "The user is not allowed to access this server from this client";
                                                break;
                                        case ERRbadLogonTime:
-                                               result += "ERRbadLogonTime: The user is not permitted to access " +
-                                                                                       "the server at this time";
+                                               result += "The user is not permitted to access the server at this time";
                                                break;
                                        case ERRpasswordExpired:
-                                               result += "ERRpasswordExpired: The password of the user has " +
-                                                                                       "expired. Please change your password.";
+                                               result += "The password of the user has expired";
                                                break;
                                        default:
-                                               result += "Ehh, one of the other ones. Please update " +
-                                                                                       "getErrorString for errorCode=" + errorCode;
+                                               result += "No description available [errorCode=" + errorCode + "]";
                                }
                                break;
                        case ERRHRD:
-                               result += "ERRHRD/";
                                switch( errorCode ) {
                                        case ERRnowrite:
-                                               result += "ERRnowrite: Attempt to write on write-protected media";
+                                               result += "Attempt to write on write-protected media";
                                                break;
                                        case ERRnotready:
-                                               result += "ERRnotready: The device is not ready";
+                                               result += "The device is not ready";
                                                break;
                                        default:
-                                               result += "Ehh, one of the other ones. Please update " +
-                                                               "getErrorString for errorCode=" + errorCode;
+                                               result += "No description available [errorCode=" + errorCode + "]";
                                }
                                break;
                        case ERRCMD:
-                               result += "ERRCMD: Command was not in the \"SMB\" format";
+                               result += "Command was not in the \"SMB\" format";
+                               break;
+                       case ERRRAP:
+                               // I don't think this should be here.
+                               // Should switch to NT status codes.
+                               switch( errorCode ) {
+                                       case NERR_Success:
+                                               result += "The operation completed successfully";
+                                               break;
+                                       case ERRnowrite:
+                                               NERR_ServerNotStarted:
+                                               result += "The Server service is not started";
+                                               break;
+                                       case NERR_BasicTransactConfig:
+                                               result += "The server is not configured for transactions";
+                                               break;
+                                       default:
+                                               result += "No description available [errorCode=" + errorCode + "]";
+                               }
+                               break;
+                       case ERRCLI:
+                               switch( errorCode ) {
+                                       case ERRserverTimeout:
+                                               result += "Timeout waiting for response from server.";
+                                               break;
+                                       case ERRbadDialect:
+                                               result += "Failed to negotiate dialect with server.";
+                                               break;
+                                       case ERRioe:
+                                               result += "An IO error occured.";
+                                               break;
+                                       default:
+                                               result += "No description available [errorCode=" + errorCode + "]";
+                               }
                                break;
                        default:
                                result += "unknown error class: " + errorClass;
@@ -192,11 +312,33 @@ class SmbException extends IOException {
                return getErrorString( code & 0xFF, ( code >> 16 ) & 0xFFFF );
        }
 
-       public SmbException() {
+       SmbException() {
        }
-       public SmbException( int code ) {
+       SmbException( int code ) {
                super( getErrorString( code & 0xFF, ( code >> 16 ) & 0xFFFF ));
                errorClass = code & 0xFF;
                errorCode = ( code >> 16 ) & 0xFFFF;
        }
+       SmbException( int errorClass, int errorCode ) {
+               super( getErrorString( errorClass, errorCode ));
+               this.errorClass = errorClass;
+               this.errorCode = errorCode;
+       }
+       SmbException( int errorClass, int errorCode, String message ) {
+               super( message );
+               this.errorClass = errorClass;
+               this.errorCode = errorCode;
+       }
+       SmbException( int code, String message ) {
+               super( message );
+               errorClass = code & 0xFF;
+               errorCode = ( code >> 16 ) & 0xFFFF;
+       }
+
+       public int getErrorClass() {
+               return errorClass;
+       }
+       public int getErrorCode() {
+               return errorCode;
+       }
 }
index a4dd454..b607bd9 100644 (file)
 
 package jcifs.smb;
 
+import jcifs.UniAddress;
+import jcifs.util.Config;
 import jcifs.netbios.NbtAddress;
+import jcifs.util.AuthHandler;
+import jcifs.util.AuthInfo;
 import java.net.MalformedURLException;
 import java.net.UnknownHostException;
 import java.net.URL;
@@ -269,6 +273,8 @@ public class SmbFile {
        static final int ATTR_DIRECTORY  = 0x10;
        static final int ATTR_ARCHIVE    = 0x20;
 
+       static final long ATTR_EXPIRATION_PERIOD = Config.getLong( "jcifs.smb.client.attrExpirationPeriod", 100 );
+
        static {
                // is this needed ??
                try {
@@ -278,14 +284,24 @@ public class SmbFile {
                }
        }
 
-       SmbURL url;
-       String path;
+       static AuthHandler authHandler = null;
+
+       public static void setAuthHandler( AuthHandler authHandler ) {
+               SmbFile.authHandler = authHandler;
+       }
+
+       AuthInfo authInfo = new AuthInfo();
+       String url, server, share, canonicalPath, uncPath, name;
+       int port;
+       boolean isWorkgroup, isExists;
+
        SmbTree tree;
-       int fid, tid, hash;
+       int fid, hash;
        int attributes = ATTR_READONLY | ATTR_DIRECTORY;
        long lastModified, size;
        boolean opened, isPipe;
-       NbtAddress address;
+       UniAddress address;
+       long attrExpiration = 0;
 
 /** 
  * Constructs an SmbFile representing a resource on an SMB network such as
@@ -300,8 +316,9 @@ public class SmbFile {
  *          the configured name resolution methods
  */
 
-       public SmbFile( String url ) throws MalformedURLException, UnknownHostException {
-               this( url, null );
+       public SmbFile( String url )
+                                               throws MalformedURLException, UnknownHostException {
+               this( url, null, 4, url.length() );
        }
 
 /**
@@ -320,8 +337,8 @@ public class SmbFile {
  *          the configured name resolution methods
  */
 
-       public SmbFile( SmbFile parent, String child ) throws MalformedURLException,
-                                                                                                                               UnknownHostException {
+       public SmbFile( SmbFile parent, String child )
+                                               throws MalformedURLException, UnknownHostException {
                this( parent.getCanonicalPath(), child );
        }
 
@@ -341,67 +358,124 @@ public class SmbFile {
  *          the configured name resolution methods
  */
 
-       public SmbFile( String parent, String child ) throws MalformedURLException,
-                                                                                                                               UnknownHostException {
-               String share = "IPC$";
-               String unc;
-               String username = "";
-               String password = "";
-               String domain = "";
-               SmbTransport trans;
-               SmbSession ssn;
-
-               url = new SmbURL( parent, child );
-
-               if( url.isWorkgroup ) {
-                       address = NbtAddress.getByName( url.server, 0x1d, null );
-                       // Cannot est. session using name WORKGROUP<1D> so convert to IP<20> to force rev. lookup
-                       address = NbtAddress.getByName( address.getHostAddress(), 0x20, null );
-               } else if( url.server != null && url.share != null ) {
-                       address = NbtAddress.getByName( url.server, 0x20, null );
-                       username = url.username;
-                       password = url.password;
-                       domain = url.domain;
-                       share = url.share;
-               } else if( url.server != null ) {
-                       address = NbtAddress.getByName( url.server, 0x20, null );
-                       username = url.username;
-                       password = url.password;
-                       domain = url.domain;
+       public SmbFile( String parent, String child )
+                                               throws MalformedURLException, UnknownHostException {
+               this( parent, child, 4, parent.length() );
+       }
+       SmbFile( String parent, String child, int start, int limit )
+                                               throws MalformedURLException, UnknownHostException {
+
+               SmbURL.parseSmbURL( this, parent, child, start, limit );
+
+               if( server == null ) {
+                       address = UniAddress.getByName( NbtAddress.getByName(
+                                               NbtAddress.MASTER_BROWSER_NAME,
+                                               0x01, null).getHostAddress() );
+               } else if( isWorkgroup ) {
+                       address = UniAddress.getByName( address.getHostAddress() );
                } else {
-                       address = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null );
-                       // Cannot est. session using name __MSBROWSE__<01> so convert to IP<20> to force rev. lookup
-                       address = NbtAddress.getByName( address.getHostAddress(), 0x20, null );
+                       address = UniAddress.getByName( server );
                }
 
-               trans = SmbTransport.getSmbTransport( address, url.port );
-               ssn = trans.getSmbSession( username, password, domain );
-               unc = new String( "\\\\" + address.getHostName() + "\\" + share ).toUpperCase();
-               tree = ssn.getSmbTree( unc, null );
-
-               if( url.canonicalPath == null ) {
-                       path = "\\";
+               if( canonicalPath == null ) {
+                       uncPath = "\\";
                } else {
-                       path = url.canonicalPath.replace( '/', '\\' );
+                       uncPath = canonicalPath.replace( '/', '\\' );
                }
-               opened = false;
        }
 
-       boolean isOpen() {
-               if( opened && tree.treeConnected && tid == tree.tid ) {
-                       return true;
+       void sendTransaction( SmbComTransaction request,
+                                       SmbComTransactionResponse response ) throws SmbException {
+               while( true ) {
+                       if( tree == null ) {
+                               SmbTransport trans = SmbTransport.getSmbTransport( address, port );
+                               SmbSession ssn = isWorkgroup ? trans.getSmbSession( "", "", "" ) :
+                                                                       trans.getSmbSession( authInfo.username,
+                                                                       authInfo.password, authInfo.domain );
+                               tree = share == null ? ssn.getSmbTree( "IPC$", null ) :
+                                                                       ssn.getSmbTree( share, null );
+                       }
+                       try {
+                               tree.sendTransaction( request, response );
+                               break;
+                       } catch( SmbAuthException sae ) {
+                               if( authHandler == null ) {
+                                       throw sae;
+                               }
+                               tree = null;
+                               authInfo.exception = sae;
+                               authInfo.target = url;
+                               if( authHandler.authenticate( authInfo ) == false ) {
+                                       throw sae;
+                               }
+                       }
                }
-               return false;
        }
-       void open( int flags ) throws IOException {
+       void send( ServerMessageBlock request,
+                                       ServerMessageBlock response ) throws SmbException {
+               while( true ) {
+                       if( tree == null ) {
+                               SmbTransport trans = SmbTransport.getSmbTransport( address, port );
+                               SmbSession ssn = isWorkgroup ? trans.getSmbSession( "", "", "" ) :
+                                                                       trans.getSmbSession( authInfo.username,
+                                                                       authInfo.password, authInfo.domain );
+                               tree = share == null ? ssn.getSmbTree( "IPC$", null ) :
+                                                                       ssn.getSmbTree( share, null );
+                       }
+                       try {
+                               tree.send( request, response );
+                               break;
+                       } catch( SmbAuthException sae ) {
+                               if( authHandler == null ) {
+                                       throw sae;
+                               }
+                               tree = null;
+                               authInfo.exception = sae;
+                               authInfo.target = url;
+                               if( authHandler.authenticate( authInfo ) == false ) {
+                                       throw sae;
+                               }
+                       }
+               }
+       }
+
+       boolean isOpen() {
+               return opened && tree.treeConnected;
+       }
+       void open( int flags ) throws SmbException {
+               SmbTransport trans;
+
                if( isOpen() ) {
                        return;
                }
-               fid = tree.open( path, flags );
-               tid = tree.tid;
+
+               Log.println( Log.WARNINGS, "smb open warning", " name=" + canonicalPath );
+
+               /*
+                * Open AndX Request / Response
+                */
+
+               /* To query server capabilities we must ensure the negotiation has talken place
+                */
+
+               trans = SmbTransport.getSmbTransport( address, port );
+               trans.negotiate();
+
+               if(( trans.negotiatedCapabilities &
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) ==
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
+                       SmbComNTCreateAndXResponse response = new SmbComNTCreateAndXResponse();
+                       send( new SmbComNTCreateAndX( uncPath, flags, null ), response );
+                       fid = response.fid;
+               } else {
+                       SmbComOpenAndXResponse response = new SmbComOpenAndXResponse();
+                       send( new SmbComOpenAndX( uncPath, flags, null ), response );
+                       fid = response.fid;
+               }
+
                opened = true;
        }
-       void close() throws IOException {
+       void close() throws SmbException {
                if( isOpen() == false ) {
                        return;
                }
@@ -414,7 +488,7 @@ public class SmbFile {
                 * Close Request / Response
                 */
 
-               tree.send( new SmbComClose( fid ), new SmbComBlankResponse() );
+               send( new SmbComClose( fid ), new SmbComBlankResponse() );
        }
 
 
@@ -431,15 +505,8 @@ public class SmbFile {
  */
 
        public String getName() {
-               String result;
-               int p;
-
-               if( url.server == null ) {
-                       return "smb://";
-               }
-               result = url.toString();
-               p = result.lastIndexOf( '/' );
-               return result.substring( p + 1 );
+               int p = url.lastIndexOf( '/' ) + 1;
+               return p == url.length() ? "smb://" : url.substring( p );
        }
 
 /**
@@ -453,15 +520,8 @@ public class SmbFile {
  */
 
        public String getParent() {
-               String result;
-               int p;
-
-               if( url.share == null ) {
-                       return "smb://";
-               }
-               result = url.toString();
-               p = result.lastIndexOf( '/' );
-               return result.substring( 0, p );
+               int p = url.lastIndexOf( '/' );
+               return p > 5 ? url.substring( 0, p ) : "smb://";
        }
 
 /**
@@ -473,7 +533,7 @@ public class SmbFile {
  */
 
        public String getPath() {
-               return url.toString();
+               return url;
        }
 
 /**
@@ -486,7 +546,30 @@ public class SmbFile {
  */
 
        public String getCanonicalPath() {
-               return url.getCanonicalPath();
+               StringBuffer sb = new StringBuffer( "smb://" );
+               if( server == null ) {
+                       return "smb://";
+               } else if( authInfo.username != null ) {
+                       if( authInfo.domain != null ) {
+                               sb.append( authInfo.domain ).append( ';' );
+                       }
+                       sb.append( authInfo.username );
+                       if( authInfo.password != null ) {
+                               sb.append( ':' ).append( authInfo.password );
+                       }
+                       sb.append( '@' );
+               }
+               sb.append( server );
+               if( port != 0 && port != 139 ) {
+                       sb.append( ":" ).append( port );
+               }
+               if( share != null ) {
+                       sb.append( '/' ).append( share );
+                       if( canonicalPath != null ) {
+                               sb.append( canonicalPath );
+                       }
+               }
+               return sb.toString();
        }
 
 /**
@@ -499,7 +582,7 @@ public class SmbFile {
  */
 
        public String getShare() {
-               return url.share;
+               return share;
        }
 
 /** 
@@ -513,11 +596,11 @@ public class SmbFile {
  */ 
 
        public String getServer() {
-               return url.server;
+               return server;
        }
 
 /**
- * Determines wheather or not this resource is a workgroup by querying
+ * Determines wheather or not this resource is an NT Domain/workgroup by querying
  * the NetBIOS name service. Only a URL of the form <code>smb://name</code>
  * has the capacity to be a workgroup.
  *
@@ -526,7 +609,54 @@ public class SmbFile {
  */
 
        public boolean isWorkgroup() {
-               return url.isWorkgroup;
+               return isWorkgroup;
+       }
+
+       Info queryPath( int infoLevel ) throws SmbException {
+               SmbTransport trans;
+               Info info;
+
+               Log.println( Log.WARNINGS, "smb query path warning",
+                                                       " querying path=" + uncPath );
+
+               /* normally we'd check the negotiatedCapabilities for CAP_NT_SMBS
+                * however I can't seem to get a good last modified time from
+                * SMB_COM_QUERY_INFORMATION so if NT_SMBs are requested
+                * by the server than in this case that's what it will get
+                * regardless of what jcifs.smb.client.useNTSmbs is set
+                * to(overrides negotiatedCapabilities).
+                */
+
+               /* make sure we're negotiated before we query capabilities
+                */
+               trans = SmbTransport.getSmbTransport( address, port );
+               trans.negotiate();
+               if(( trans.server.capabilities & ServerMessageBlock.CAP_NT_SMBS ) ==
+                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
+
+                       /*
+                        * Trans2 Query Path Information Request / Response
+                        */
+
+                       Trans2QueryPathInformationResponse response =
+                                               new Trans2QueryPathInformationResponse( infoLevel );
+                       sendTransaction( new Trans2QueryPathInformation( uncPath,
+                                               infoLevel ), response );
+                       info = response.info;
+               } else {
+
+                       /*
+                        * Query Information Request / Response
+                        */
+
+                       SmbComQueryInformationResponse response =
+                                               new SmbComQueryInformationResponse(
+                                               trans.server.serverTimeZone * 1000 * 60L );
+                       send( new SmbComQueryInformation( uncPath ), response );
+                       info = (Info)response;
+               }
+
+               return info;
        }
 
 /**
@@ -543,54 +673,62 @@ public class SmbFile {
  *         <code>false</code> otherwise
  */
 
-       public boolean exists() {
+       void updateAttributes() throws SmbException {
+               Info info;
+
+               if( attrExpiration > System.currentTimeMillis() ) {
+                       return;
+               }
+
                attributes = ATTR_READONLY | ATTR_DIRECTORY;
                lastModified = 0L;
+               info = queryPath( Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO );
+               attributes = info.getAttributes();
+               lastModified = info.getLastWriteTime();
+
+               attrExpiration = System.currentTimeMillis() + ATTR_EXPIRATION_PERIOD;
+       }
+       public boolean exists() throws SmbException {
+               if( attrExpiration > System.currentTimeMillis() ) {
+                       return isExists;
+               }
+
+               isExists = false;
+
                try {
-                       if( url.server == null ) {
-                       } else if( url.share == null ) {
-                               try {
-                                       if( url.isWorkgroup ) {
-                                               NbtAddress.getByName( url.server, 0x1d, null );
-                                       } else {
-                                               NbtAddress.getByName( url.server, 0x20, null );
-                                       }
-                               } catch( UnknownHostException uhe ) {
-                                       return false;
+                       if( server == null ) {
+                               isExists = true;
+                       } else if( share == null ) {
+                               if( isWorkgroup ) {
+                                       NbtAddress.getByName( server, 0x1d, null );
+                               } else {
+                                       UniAddress.getByName( server ).getHostName();
                                }
+                       } else if( canonicalPath == null ||
+                                                                               share.equalsIgnoreCase( "IPC$" )) {
+                               send( null, null ); // treeConnect is good enough
                        } else {
-                               if( url.share.equalsIgnoreCase( "IPC$" )) {
-                                       String[] shares = tree.netShareEnum();
-                                       for( int s = 0; s < shares.length; s++ ) {
-                                               if( shares[s].equalsIgnoreCase( "IPC$" )) {
-                                                       return true;
-                                               }
-                                       }
-                                       return false;
-                               }
-                               if( path.equals( "\\" )) {
-                                       String[] shares = tree.netShareEnum();
-                                       for( int s = 0; s < shares.length; s++ ) {
-                                               if( shares[s].equalsIgnoreCase( url.share )) {
-                                                       return true;
-                                               }
-                                       }
-                                       return false;
-                               }
+                               updateAttributes();
+                       }
 
-                               Info info = tree.queryPath( path,
-                                               Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO );
-                               if( info == null ) {
-                                       return false;
-                               }
-                               attributes = info.getAttributes();
-                               lastModified = info.getLastWriteTime();
+                       /* If any of the above fail, isExists will not be set true
+                        */
+
+                       isExists = true;
+
+               } catch( UnknownHostException uhe ) {
+                       isExists = false;
+               } catch( SmbException se ) {
+                       if( se.errorClass == SmbException.ERRDOS &&
+                                                       ( se.errorCode == SmbException.ERRbadfile ||
+                                                       se.errorCode == SmbException.ERRbadnetname )) {
+                               isExists = false;
+                       } else {
+                               throw se;
                        }
-                       return true;
-               } catch( Exception e ) {
-                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
                }
-               return false;
+
+               return isExists;
        }
 
 /**
@@ -601,8 +739,11 @@ public class SmbFile {
  * @return <code>true</code> if the file is read-only
  */
 
-       public boolean canRead() {
-               return exists();
+       public boolean canRead() throws SmbException {
+               if( isPipe ) { // try opening the pipe for writing?
+                       return true;
+               }
+               return exists(); // try opening and catch sharing violation?
        }
 
 /**
@@ -616,8 +757,8 @@ public class SmbFile {
  *          read-only
  */
 
-       public boolean canWrite() {
-               if( isPipe ) {
+       public boolean canWrite() throws SmbException {
+               if( isPipe ) { // try opening the pipe for writing?
                        return true;
                }
                return exists() && ( attributes & ATTR_READONLY ) == 0;
@@ -629,8 +770,12 @@ public class SmbFile {
  * @return <code>true</code> if this <code>SmbFile</code> is a directory
  */
 
-       public boolean isDirectory() {
-               return exists() && ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY;
+       public boolean isDirectory() throws SmbException {
+               if( canonicalPath == null ) {
+                       return true;
+               }
+               updateAttributes();
+               return ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY;
        }
 
 /**
@@ -639,8 +784,12 @@ public class SmbFile {
  * @return <code>true</code> if this <code>SmbFile</code> is not a directory
  */
 
-       public boolean isFile() {
-               return exists() && ( attributes & ATTR_DIRECTORY ) == 0;
+       public boolean isFile() throws SmbException {
+               if( canonicalPath == null ) {
+                       return false;
+               }
+               updateAttributes();
+               return ( attributes & ATTR_DIRECTORY ) == 0;
        }
 
 /**
@@ -649,16 +798,16 @@ public class SmbFile {
  * @return <code>true</code> if the <code>SmbFile</code> is marked as being hidden
  */
 
-       public boolean isHidden() {
-               if( url.share == null ) {
+       public boolean isHidden() throws SmbException {
+               if( share == null ) {
                        return false;
-               } else if( path.length() == 1 ) {
-                       if( url.share.endsWith( "$" )) {
+               } else if( canonicalPath == null ) {
+                       if( share.endsWith( "$" )) {
                                return true;
                        }
                        return false;
                }
-               exists();
+               updateAttributes();
                return ( attributes & ATTR_HIDDEN ) == ATTR_HIDDEN;
        }
 
@@ -673,9 +822,12 @@ public class SmbFile {
  *         1970 as a <code>long</code> value
  */
 
-       public long lastModified() {
-               exists();
-               return lastModified;
+       public long lastModified() throws SmbException {
+               if( canonicalPath != null ) {
+                       updateAttributes();
+                       return lastModified;
+               }
+               return 0L;
        }
 
 /**
@@ -692,29 +844,134 @@ public class SmbFile {
  * @return A <code>String</code> array of file and directories, workgroups, servers, or shares depending on the context of the resource URL
  */
 
-       public String[] list() {
-               try {
-                       if( url.server == null ) {
-                               try {
-                                       SmbTree.setLmbTree( this );
-                               } catch( IOException ioe ) {
-                                       Log.printStackTrace(
-                                                               "smb exception contacting local master browser", ioe );
-                                       return null;
+       public String[] list() throws SmbException {
+               if( server == null ) {
+                       // if share is null send/sendTransaction will tcon to IPC$
+                       SmbTransport trans = SmbTransport.getSmbTransport( address, port );
+                       trans.negotiate();
+
+                       NetServerEnum2Response response = new NetServerEnum2Response();
+                       sendTransaction( new NetServerEnum2( trans.server.oemDomainName,
+                                                                       NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response );
+
+                       if( response.status != SmbException.NERR_Success &&
+                                                               response.status != SmbException.ERROR_MORE_DATA ) {
+                               throw new SmbException( SmbException.ERRRAP,
+                                                               response.status, response.toString() );
+                       }
+
+                       String[] ret = new String[response.entriesReturned];
+                       for( int i = 0; i < response.entriesReturned; i++ ) {
+                               ret[i] = response.results[i].name;
+                       }
+                       return ret;
+               } else if( share == null ) {
+                       if( isWorkgroup ) {
+                               NetServerEnum2Response response = new NetServerEnum2Response();
+                               sendTransaction( new NetServerEnum2( server,
+                                                                               NetServerEnum2.SV_TYPE_ALL ), response );
+
+                               if( response.status != SmbException.NERR_Success &&
+                                               response.status != SmbException.ERROR_MORE_DATA ) {
+                                       throw new SmbException( SmbException.ERRRAP, response.status );
                                }
-                               return tree.domainEnum();
-                       } else if( url.share == null ) {
-                               if( url.isWorkgroup ) {
-                                       return tree.netServerEnum2( url.server );
-                               } else {
-                                       return tree.netShareEnum();
+
+                               String[] ret = new String[response.entriesReturned];
+                               for( int i = 0; i < response.entriesReturned; i++ ) {
+                                       ret[i] = response.results[i].name;
+                               }
+
+                               return ret;
+                       } else {
+                               NetShareEnumResponse response = new NetShareEnumResponse();
+                               sendTransaction( new NetShareEnum(), response );
+
+                               if( response.status != SmbException.NERR_Success &&
+                                                       response.status != SmbException.ERROR_MORE_DATA ) {
+                                       throw new SmbException( SmbException.ERRRAP, response.status );
+                               }
+
+                               String[] ret = new String[response.entriesReturned];
+                               for( int i = 0; i < response.entriesReturned; i++ ) {
+                                       ret[i] = response.results[i].netName;
+                               }
+
+                               return ret;
+                       }
+               } else {
+                       return list( uncPath );
+               }
+       }
+       String[] list( String dirPath ) throws SmbException {
+               int sid, count, i, j;
+               String[] results;
+               String filename;
+
+               Log.println( Log.WARNINGS, "smb find warning",
+                               " find with path=" + canonicalPath );
+
+               Trans2FindFirst2Response response = new Trans2FindFirst2Response();
+               sendTransaction( new Trans2FindFirst2( dirPath + "\\*" ), response );
+
+               sid = response.sid;
+               count = response.searchCount;
+               j = 0;
+
+               results = new String[Math.max( 16, count )];
+
+               int h1 = new String( "." ).hashCode();
+               int h2 = new String( ".." ).hashCode();
+               i = 0;
+               while( j < count ) {
+                       filename = response.results[i++].filename;
+                       if( filename.length() < 3 ) {
+                               int h = filename.hashCode();
+                               if( h == h1 || h == h2 ) {
+                                       count--;
+                                       continue;
                                }
                        }
-                       return tree.find( path );
-               } catch( Exception e ) {
-                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+                       results[j++] = filename;
+               }
+
+               /* only difference between first2 and next2
+                * responses is subCommand so let's recycle
+                */
+               response.subCommand = SmbComTransaction.TRANS2_FIND_NEXT2;
+
+               while( response.isEndOfSearch == false && response.searchCount > 0 ) {
+                       sendTransaction( new Trans2FindNext2( sid, response.resumeKey,
+                                                                                                       response.lastName ), response );
+                       count += response.searchCount;
+
+                       if( count > results.length ) {
+                               String[] tmp = results;
+                               results = new String[Math.max( results.length * 2, count )];
+                               System.arraycopy( tmp, 0, results, 0, j );
+                       }
+                       i = 0;
+                       while( j < count ) {
+                               filename = response.results[i++].filename;
+                               if( filename.length() < 3 ) {
+                                       int h = filename.hashCode();
+                                       if( h == h1 || h == h2 ) {
+                                               count--;
+                                               continue;
+                                       }
+                               }
+                               results[j++] = filename;
+                       }
+               }
+
+               send( new SmbComFindClose2( sid ), new SmbComBlankResponse() );
+
+               if( results.length != count ) {
+                       String[] tmp = results;
+                       results = new String[count];
+                       System.arraycopy( tmp, 0, results, 0, count );
                }
-               return null;
+
+               return results;
        }
 
 /**
@@ -730,24 +987,24 @@ public class SmbFile {
  *         If the <code>dest</code> argument is <code>null</code>
  */
 
-       public boolean renameTo( SmbFile dest ) {
-               try {
-                       if( dest.exists() ) {
-                               // otherwise we get Access Denied
-                               if(( dest.attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY ) {
-                                       Log.println( Log.WARNINGS, "SmbFile warning",
-                                               " cannot renameTo() a directory that exists: " + dest.getName() );
-                                       return false;
-                               }
-                               if( dest.delete() == false ) {
-                                       return false;
-                               }
-                       }
-                       return tree.rename( path, dest.path );
-               } catch( Exception e ) {
-                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
+       public void renameTo( SmbFile dest ) throws SmbException {
+               if( canonicalPath == null || dest.canonicalPath == null ) {
+                       throw new SmbException( SmbException.ERRDOS,
+                                                                       SmbException.ERRnoaccess );
                }
-               return false;
+
+               Log.println( Log.WARNINGS, "smb rename warning",
+                               " oldFileName=" + uncPath +
+                               ",newFileName=" + dest.uncPath );
+
+               attrExpiration = 0;
+
+               /*
+                * Rename Request / Response
+                */
+
+               SmbComBlankResponse response = new SmbComBlankResponse();
+               send( new SmbComRename( uncPath, dest.uncPath ), response );
        }
 
 /**
@@ -759,20 +1016,41 @@ public class SmbFile {
  *          <code>false</code> otherwise
  */
 
-       public boolean delete() {
-               if( path.length() > 1 ) {
-                       if( exists() ) {
-                               try {
-                                       return tree.delete( path, ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY );
-                               } catch( Exception e ) {
-                                       Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
-                               }
-                       }
-               } else {
-                       Log.println( Log.WARNINGS, "SmbFile warning",
-                                                       " cannot delete servers, workgroups, or shares" );
+       public void delete() throws SmbException {
+               delete( uncPath );
+       }
+       void delete( String fileName ) throws SmbException {
+               if( canonicalPath == null ) {
+                       throw new SmbException( SmbException.ERRDOS,
+                                                                       SmbException.ERRnoaccess );
+               }
+
+               attrExpiration = 0;
+
+               Log.println( Log.WARNINGS, "smb delete warning",
+                               " fileName=" + fileName );
+
+               /*
+                * Delete or Delete Directory Request / Response
+                */
+
+               ServerMessageBlock request = new SmbComDelete( fileName );
+               try {
+                       send( request, new SmbComBlankResponse() );
+                       return;
+               } catch( SmbException se ) {
                }
-               return false;
+
+               /* Recursively delete directory contents using post order DFS
+                */
+
+               String[] ls = list( fileName );
+               for( int i = 0; i < ls.length; i++ ) {
+                       delete( fileName + "\\" + ls[i] );
+               }
+
+               request = new SmbComDeleteDirectory( fileName );
+               send( request, new SmbComBlankResponse() );
        }
 
 /**
@@ -782,22 +1060,10 @@ public class SmbFile {
  * @return The length of the file in bytes
  */
 
-       public long length() {
-               Info info = null;
-               if( path.length() > 1 ) {
-                       try {
-                               int infoLevel =
-                                               Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO;
-                               info = tree.queryPath( path, infoLevel );
-                       } catch( Exception e ) {
-                               info = null;
-                               Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
-                       }
-                       if( info != null && ( info.getAttributes() & ATTR_DIRECTORY ) == 0 ) {
-                               // will do long a little later. not hard.
-                               size = info.getSize();
-                               return size;
-                       }
+       public long length() throws SmbException {
+               if( canonicalPath != null ) {
+                       Info info = queryPath( Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO );
+                       return info.getSize();
                }
                return 0L;
        }
@@ -814,18 +1080,20 @@ public class SmbFile {
  *          <code>false</code> otherwise
  */
 
-       public boolean mkdir() {
-               if( path.length() > 1 ) {
-                       try {
-                               return tree.createDirectory( path );
-                       } catch( Exception e ) {
-                               Log.printStackTrace( Log.NON_CRITICAL_EXCEPTIONS, "SmbFile exception", e );
-                       }
-               } else {
-                       Log.println( Log.WARNINGS, "SmbFile warning",
-                                               " cannot create servers, workgroups, or shares with mkdir" );
+       public void mkdir() throws SmbException {
+               if( canonicalPath == null ) {
+                       throw new SmbException( SmbException.ERRDOS,
+                                                                       SmbException.ERRnoaccess );
                }
-               return false;
+               Log.println( Log.WARNINGS, "smb create directory warning",
+                                                       " directoryName=" + uncPath );
+
+               /*
+                * Create Directory Request / Response
+                */
+
+               send( new SmbComCreateDirectory( uncPath ),
+                                                                       new SmbComBlankResponse() );
        }
 
 /**
@@ -838,7 +1106,7 @@ public class SmbFile {
  */
 
        public URL toURL() throws MalformedURLException {
-               return new URL( url.toString() );
+               return new URL( getCanonicalPath() );
        }
 
 /**
@@ -856,13 +1124,13 @@ public class SmbFile {
        public int hashCode() {
                if( hash == 0 ) {
                        hash = address.hashCode();
-                       if( url.port != 0 && url.port != 139 ) {
-                               hash += 65621 * url.port;
+                       if( port != 0 && port != 139 ) {
+                               hash += 65621 * port;
                        }
-                       if( url.share != null ) {
-                               hash += 65521 * url.share.toUpperCase().hashCode();
-                               if( url.canonicalPath != null ) {
-                                       hash += 65521 * url.canonicalPath.toUpperCase().hashCode();
+                       if( share != null ) {
+                               hash += 65521 * share.toUpperCase().hashCode();
+                               if( canonicalPath != null ) {
+                                       hash += 65521 * canonicalPath.toUpperCase().hashCode();
                                }
                        }
                }
@@ -904,7 +1172,6 @@ public class SmbFile {
  */
 
        public String toString() {
-               return url.toString();
+               return url;
        }
-
 }
index 7913b20..9a3faa5 100644 (file)
@@ -20,6 +20,8 @@ package jcifs.smb;
 
 import java.io.InputStream;
 import java.io.IOException;
+import java.net.UnknownHostException;
+import java.net.MalformedURLException;
 
 /**
  * This InputStream can read bytes from a file on an SMB file server.
@@ -39,10 +41,9 @@ public class SmbFileInputStream extends InputStream {
  *
  * @param url An smb URL string representing the file to read from
  * @return A new <code>InputStream</code> for the specified <code>SmbFile</code>
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileInputStream( String url ) throws IOException {
+       public SmbFileInputStream( String url ) throws SmbException, MalformedURLException, UnknownHostException {
                this( new SmbFile( url ));
        }
 
@@ -54,14 +55,13 @@ public class SmbFileInputStream extends InputStream {
  *
  * @param url An smb URL string representing the file to write to
  * @return A new <code>InputStream</code> for the specified <code>SmbFile</code>
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileInputStream( SmbFile file ) throws IOException {
+       public SmbFileInputStream( SmbFile file ) throws SmbException, MalformedURLException, UnknownHostException {
                this( file, SmbFile.O_RDONLY );
        }
 
-       SmbFileInputStream( SmbFile file, int openFlags ) throws IOException {
+       SmbFileInputStream( SmbFile file, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException {
                this.file = file;
                this.openFlags = openFlags;
                file.open( openFlags );
@@ -116,9 +116,7 @@ public class SmbFileInputStream extends InputStream {
                int start = fp;
 
                // ensure file is open
-               if( file.isOpen() == false ) {
-                       file.open( openFlags );
-               }
+               file.open( openFlags );
 
                Log.println( Log.WARNINGS, "smb read warning",
                                " fid=" + file.fid + ",off=" + off + ",len=" + len );
@@ -138,7 +136,7 @@ public class SmbFileInputStream extends InputStream {
                        r = len > readSize ? readSize : len;
 //System.out.println( "len=" + len + ",r=" + r + ",fp=" + fp );
                        try {
-                               file.tree.send( new SmbComReadAndX( file.fid, fp, r, null ), response );
+                               file.send( new SmbComReadAndX( file.fid, fp, r, null ), response );
                        } catch( SmbException se ) {
                                if( file.isPipe && se.errorClass == SmbException.ERRDOS &&
                                                                                        se.errorCode == SmbException.ERRbrokenpipe ) {
index f3ec600..2726835 100644 (file)
@@ -20,6 +20,8 @@ package jcifs.smb;
 
 import java.io.OutputStream;
 import java.io.IOException;
+import java.net.UnknownHostException;
+import java.net.MalformedURLException;
 
 /**
  * This <code>OutputStream</code> can write bytes to a file on an SMB file server.
@@ -40,10 +42,9 @@ public class SmbFileOutputStream extends OutputStream {
  *
  * @param url An smb URL string representing the file to write to
  * @return A new <code>OutputStream</code> for the specified file
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileOutputStream( String url ) throws IOException {
+       public SmbFileOutputStream( String url ) throws SmbException, MalformedURLException, UnknownHostException {
                this( url, false );
        }
 
@@ -55,10 +56,9 @@ public class SmbFileOutputStream extends OutputStream {
  *
  * @param url An <code>SmbFile</code> specifying the file to write to
  * @return A new <code>OutputStream</code> for the specified <code>SmbFile</code>
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileOutputStream( SmbFile file ) throws IOException {
+       public SmbFileOutputStream( SmbFile file ) throws SmbException, MalformedURLException, UnknownHostException {
                this( file, false );
        }
 
@@ -71,10 +71,9 @@ public class SmbFileOutputStream extends OutputStream {
  *
  * @param url An smb URL string representing the file to write to
  * @return A new <code>OutputStream</code> for the specified <code>url</code>
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileOutputStream( String url, boolean append ) throws IOException {
+       public SmbFileOutputStream( String url, boolean append ) throws SmbException, MalformedURLException, UnknownHostException {
                this( new SmbFile( url ), append );
        }
 
@@ -87,15 +86,14 @@ public class SmbFileOutputStream extends OutputStream {
  * 
  * @param url An <code>SmbFile</code> representing the file to write to
  * @return A new <code>OutputStream</code> for the specified <code>SmbFile</code>
- * @throws IOException if a network error occurs
  */
 
-       public SmbFileOutputStream( SmbFile file, boolean append ) throws IOException {
+       public SmbFileOutputStream( SmbFile file, boolean append ) throws SmbException, MalformedURLException, UnknownHostException {
                this( file, append, append ? SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_APPEND :
                                                                        SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC );
        }
 
-       SmbFileOutputStream( SmbFile file, boolean append, int openFlags ) throws IOException {
+       SmbFileOutputStream( SmbFile file, boolean append, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException {
                this.file = file;
                this.append = append;
                this.openFlags = openFlags;
@@ -166,7 +164,7 @@ public class SmbFileOutputStream extends OutputStream {
                int w;
                do {
                        w = len > writeSize ? writeSize : len;
-                       file.tree.send( new SmbComWriteAndX( file.fid, fp, len - w, b, off, w, null ),
+                       file.send( new SmbComWriteAndX( file.fid, fp, len - w, b, off, w, null ),
                                                                                                                new SmbComWriteAndXResponse() );
                        fp += w;
                        len -= w;
index 1923944..a015461 100644 (file)
 
 package jcifs.smb;
 
-import jcifs.netbios.NbtAddress;
 import jcifs.util.DES;
 import jcifs.util.MD4;
-import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.util.Hashtable;
 import java.util.Vector;
@@ -87,24 +85,18 @@ class SmbSession {
                this.password = password;
                this.domain = domain.toUpperCase();
                trees = new Vector();
-               sessionSetup = false;
-
-               if( password == null ) {
-                       passwordString = "null";
-               } else if( password.length() == 0 ) {
-                       passwordString = "";
-               }
+               passwordString = password == null ? "null" : "";
        }
 
-       synchronized SmbTree getSmbTree( String path, String service ) {
+       synchronized SmbTree getSmbTree( String share, String service ) {
                SmbTree t;
                for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
                        t = (SmbTree)e.nextElement();
-                       if( t.matches( path, service )) {
+                       if( t.matches( share, service )) {
                                return t;
                        }
                }
-               t = new SmbTree( this, path, service );
+               t = new SmbTree( this, share, service );
                trees.addElement( t );
                return t;
        }
@@ -114,14 +106,14 @@ class SmbSession {
                                this.domain.equals( domain.toUpperCase() );
        }
        void sendTransaction( SmbComTransaction request,
-                                                               SmbComTransactionResponse response ) throws IOException {
+                                                               SmbComTransactionResponse response ) throws SmbException {
                // transactions are not batchable
                sessionSetup( null, null );
                request.uid = uid;
                transport.sendTransaction( request, response );
        }
        void send( ServerMessageBlock request,
-                                                               ServerMessageBlock response ) throws IOException {
+                                                       ServerMessageBlock response ) throws SmbException {
                if( response != null ) {
                        response.received = false;
                }
@@ -133,8 +125,8 @@ class SmbSession {
                transport.send( request, response );
        }
        synchronized void sessionSetup( ServerMessageBlock andx,
-                                                               ServerMessageBlock andxResponse )
-                                                               throws IOException {
+                                                       ServerMessageBlock andxResponse ) throws SmbException {
+               SmbComSessionSetupAndXResponse response = null;
 
                if( sessionSetup ) {
                        return;
@@ -149,14 +141,13 @@ class SmbSession {
                 * Session Setup And X Request / Response
                 */
 
-               SmbComSessionSetupAndXResponse response =
-                                                               new SmbComSessionSetupAndXResponse( andxResponse );
+               response = new SmbComSessionSetupAndXResponse( andxResponse );
                transport.send( new SmbComSessionSetupAndX( this, andx ), response );
 
                uid = response.uid;
                sessionSetup = true;
        }
-       synchronized void logoff() throws IOException {
+       synchronized void logoff() throws SmbException {
                if( sessionSetup == false ) {
                        return;
                }
index a1dc22f..ed1d903 100644 (file)
@@ -21,6 +21,7 @@ package jcifs.smb;
 import jcifs.netbios.NbtSocket;
 import jcifs.netbios.NbtException;
 import jcifs.netbios.NbtAddress;
+import jcifs.UniAddress;
 import jcifs.Config;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -50,7 +51,7 @@ class SmbTransport implements Runnable {
 
        private byte[] rcv_buf, snd_buf;
 
-       private NbtSocket socket;
+       private NbtSocket socket; // should become UniSocket?
        private InputStream in;
        private OutputStream out;
        private int localPort, soTimeout, responseTimeout;
@@ -66,7 +67,7 @@ class SmbTransport implements Runnable {
        Vector sessions;
        boolean negotiated, useUnicode;
 
-       NbtAddress address;
+       UniAddress address;
        int port, rcv_buf_size, snd_buf_size;
 
        int negotiatedDialectIndex;
@@ -98,6 +99,8 @@ class SmbTransport implements Runnable {
                int vcNumber = 1;
        }
        class ServerProperties {
+               String tconHostName;
+
                byte flags;
                int flags2;
                int maxMpxCount;
@@ -123,12 +126,12 @@ class SmbTransport implements Runnable {
                byte[] encryptionKey;
        }
 
-       static synchronized SmbTransport getSmbTransport( NbtAddress address, int port ) {
+       static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
                return getSmbTransport( address, port,
                                                        Config.getInetAddress( "jcifs.smb.client.laddr", null ),
                                                        Config.getInt( "jcifs.smb.client.lport", 0 ));
        }
-       static synchronized SmbTransport getSmbTransport( NbtAddress address, int port,
+       static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
                                                                        InetAddress localAddr, int localPort ) {
                SmbTransport conn;
                for( Enumeration e = connections.elements(); e.hasMoreElements(); ) {
@@ -142,7 +145,7 @@ class SmbTransport implements Runnable {
                return conn;
        }
 
-       SmbTransport( NbtAddress address, int port, InetAddress localAddr, int localPort ) {
+       SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) {
                this.address = address;
                this.port = port;
                this.localAddr = localAddr;
@@ -162,8 +165,6 @@ class SmbTransport implements Runnable {
                                                                                                                        DEFAULT_RESPONSE_TIMEOUT );
                rcv_buf_size = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
                snd_buf_size = client.maxBufferSize;
-               rcv_buf = new byte[rcv_buf_size];
-               snd_buf = new byte[snd_buf_size];
                sessions = new Vector();
                responseTable = new Hashtable();
                outLock = new Object();
@@ -194,7 +195,7 @@ class SmbTransport implements Runnable {
                sessions.addElement( ssn );
                return ssn;
        }
-       boolean matches( NbtAddress address, int port, InetAddress localAddr, int localPort ) {
+       boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) {
                InetAddress defaultLocal = null;
                try {
                        defaultLocal = InetAddress.getLocalHost();
@@ -211,27 +212,59 @@ class SmbTransport implements Runnable {
        }
        void ensureOpen() throws IOException {
                if( socket == null ) {
-                       try {
-                               socket = new NbtSocket( address, port, localAddr, localPort );
-                       } catch( NbtException ne ) {
-                               if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
+                       Object obj;
+                       NbtAddress naddr;
+                       String calledName;
+
+                       /* Hack to convert InetAddress to NbtAddress until we properly
+                        * abstract NetBIOSless transport with some kind of "UniSocket".
+                        */
+                       obj = address.getAddress();
+                       if( obj instanceof NbtAddress ) {
+                               naddr = (NbtAddress)obj;
+                       } else {
+                               try {
+                                       naddr = NbtAddress.getByName( ((InetAddress)obj).getHostAddress() );
+                               } catch( UnknownHostException uhe ) {
+                                       naddr = null; // never happen
+                               }
+                       }
+
+                       calledName = address.firstCalledName();
+                       do {
+                               try {
+                                       socket = new NbtSocket( naddr, calledName, port, localAddr, localPort );
+                                       break;
+                               } catch( NbtException ne ) {
+                                       if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
                                                                ( ne.errorCode == NbtException.CALLED_NOT_PRESENT ||
                                                                ne.errorCode == NbtException.NOT_LISTENING_CALLED )) {
-                                       Log.println( Log.WARNINGS, "smb warning",
-                                                               " failed to establish netbios session: called name not " +
-                                                               "present or not listening for called name, trying " +
-                                                               "*SMBSERVER" );
-                                       socket = new NbtSocket( address, NbtAddress.SMBSERVER_NAME,
-                                                                                                               port, localAddr, localPort );
-                               } else {
-                                       throw ne;
+                                               Log.println( Log.WARNINGS, "smb warning", ne.getMessage() );
+                                       } else {
+                                               throw ne;
+                                       }
                                }
+                       } while(( calledName = address.nextCalledName()) != null );
+
+                       if( calledName == null ) {
+                               throw new IOException( "Failed to establish session with " + address );
                        }
+
+                       /* Save the calledName for using on SMB_COM_TREE_CONNECT
+                        */
+                       if( calledName == NbtAddress.SMBSERVER_NAME ) {
+                               server.tconHostName = address.getHostAddress();
+                       } else {
+                               server.tconHostName = calledName;
+                       }
+
                        if( Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false )) {
                                socket.setTcpNoDelay( true );
                        }
                        in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
                        out = socket.getOutputStream();
+                       rcv_buf = BufferCache.getBuffer();
+                       snd_buf = BufferCache.getBuffer();
                        thread = new Thread( this );
                        thread.setDaemon( true );
                        thread.start();
@@ -254,6 +287,8 @@ class SmbTransport implements Runnable {
                        negotiated = false;
                        thread = null;
                        responseTable.clear();
+                       BufferCache.releaseBuffer( rcv_buf );
+                       BufferCache.releaseBuffer( snd_buf );
                }
        }
        public void run() {
@@ -356,7 +391,7 @@ class SmbTransport implements Runnable {
                }
        }
        void send( ServerMessageBlock request,
-                                                       ServerMessageBlock response ) throws IOException {
+                                                       ServerMessageBlock response ) throws SmbException {
                Integer mid = null;
 
                negotiate();
@@ -380,6 +415,8 @@ class SmbTransport implements Runnable {
                                        }
                                        Log.printHexDump( "smb sent", snd_buf, 0, request.length );
                                }
+                       } catch( IOException ioe ) {
+                               throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() );
                        } finally {
                                releaseMid( request.mid );
                        }
@@ -415,42 +452,68 @@ class SmbTransport implements Runnable {
                                                                                                responseTimeout : response.responseTimeout );
                        }
                } catch( InterruptedException ie ) {
+               } catch( IOException ioe ) {
+                       throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() );
                } finally {
                        responseTable.remove( mid );
                        releaseMid( request.mid );
                }
 
                if( response.received == false ) {
-                       throw new IOException(
-                                                       "time out waiting for response from server: " + address );
+                       throw new SmbException( SmbException.ERRserverTimeout );
                }
-               if( response.errorCode != 0 ) {
-                       throw new SmbException( response.errorCode );
+               switch( response.errorCode & 0xFF ) {
+                       case SmbException.SUCCESS:
+                               break;
+                       case SmbException.ERRDOS:
+                               switch(( response.errorCode >> 16 ) & 0xFFFF ) {
+                                       case SmbException.ERRnoaccess:
+                                               throw new SmbAuthException( response.errorCode );
+                               }
+                               throw new SmbException( response.errorCode );
+                       case SmbException.ERRSRV:
+                               switch(( response.errorCode >> 16 ) & 0xFFFF ) {
+                                       case SmbException.ERRbadpw:
+                                       case SmbException.ERRaccess:
+                                       case SmbException.ERRaccountExpired:
+                                       case SmbException.ERRbadClient:
+                                       case SmbException.ERRbadLogonTime:
+                                       case SmbException.ERRpasswordExpired:
+                                               throw new SmbAuthException( response.errorCode );
+                               }
+                       default:
+                               throw new SmbException( response.errorCode );
                }
        }
        void sendTransaction( SmbComTransaction request,
-                                                       SmbComTransactionResponse response ) throws IOException {
+                                                       SmbComTransactionResponse response ) throws SmbException {
                Integer mid = null;
 
                negotiate();
 
-               try {
-                       request.flags2 = client.flags2;
-                       request.mid = aquireMid();
-                       mid = new Integer( request.mid );
-                       request.useUnicode = useUnicode;
-                       request.maxBufferSize = negotiatedMaxBufferSize;
-                       response.received = false;
-                       response.hasMore = true;
-                       response.isPrimary = true;
+               request.flags2 = client.flags2;
+               request.mid = aquireMid();
+               mid = new Integer( request.mid );
+               request.useUnicode = useUnicode;
+               request.maxBufferSize = negotiatedMaxBufferSize;
+               response.received = false;
+               response.hasMore = true;
+               response.isPrimary = true;
 
+               request.txn_buf = BufferCache.getBuffer();
+               response.txn_buf = BufferCache.getBuffer();
+
+               try {
                        request.nextElement();
                        if( request.hasMoreElements() ) {
                                // multi-part request
 
                                SmbComBlankResponse interimResponse = new SmbComBlankResponse();
+
                                synchronized( interimResponse ) {
+
                                        responseTable.put( mid, interimResponse );
+
                                        synchronized( outLock ) {
                                                ensureOpen();
                                                out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
@@ -459,13 +522,33 @@ class SmbTransport implements Runnable {
                                                Log.printMessageData( "smb sent", request );
                                                Log.printHexDump( "smb sent", snd_buf, 0, request.length );
                                        }
+
                                        interimResponse.wait( responseTimeout );
 
                                        if( interimResponse.received == false ) {
-                                               throw new IOException( "time out waiting for response from server" );
+                                               throw new SmbException( SmbException.ERRserverTimeout );
                                        }
-                                       if( interimResponse.errorCode != 0 ) {
-                                               throw new SmbException( interimResponse.errorCode );
+                                       switch( interimResponse.errorCode & 0xFF ) {
+                                               case SmbException.SUCCESS:
+                                                       break;
+                                               case SmbException.ERRDOS:
+                                                       switch(( interimResponse.errorCode >> 16 ) & 0xFFFF ) {
+                                                               case SmbException.ERRnoaccess:
+                                                                       throw new SmbAuthException( interimResponse.errorCode );
+                                                       }
+                                                       throw new SmbException( interimResponse.errorCode );
+                                               case SmbException.ERRSRV:
+                                                       switch(( interimResponse.errorCode >> 16 ) & 0xFFFF ) {
+                                                               case SmbException.ERRbadpw:
+                                                               case SmbException.ERRaccess:
+                                                               case SmbException.ERRaccountExpired:
+                                                               case SmbException.ERRbadClient:
+                                                               case SmbException.ERRbadLogonTime:
+                                                               case SmbException.ERRpasswordExpired:
+                                                                       throw new SmbAuthException( interimResponse.errorCode );
+                                                       }
+                                               default:
+                                                       throw new SmbException( interimResponse.errorCode );
                                        }
                                }
                                request.nextElement();
@@ -490,19 +573,43 @@ class SmbTransport implements Runnable {
                                } while( response.received && response.hasMoreElements() );
                        }
                } catch( InterruptedException ie ) {
+               } catch( IOException ioe ) {
+                       throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() );
                } finally {
                        responseTable.remove( mid );
                        releaseMid( request.mid );
+                       BufferCache.releaseBuffer( request.txn_buf );
+                       BufferCache.releaseBuffer( response.txn_buf );
                }
 
                if( response.received == false ) {
-                       throw new IOException( "time out waiting for response from server" );
+                       throw new SmbException( SmbException.ERRCLI,
+                                                                       SmbException.ERRserverTimeout );
                }
-               if( response.errorCode != 0 ) {
-                       throw new SmbException( response.errorCode );
+               switch( response.errorCode & 0xFF ) {
+                       case SmbException.SUCCESS:
+                               break;
+                       case SmbException.ERRDOS:
+                               switch(( response.errorCode >> 16 ) & 0xFFFF ) {
+                                       case SmbException.ERRnoaccess:
+                                               throw new SmbAuthException( response.errorCode );
+                               }
+                               throw new SmbException( response.errorCode );
+                       case SmbException.ERRSRV:
+                               switch(( response.errorCode >> 16 ) & 0xFFFF ) {
+                                       case SmbException.ERRbadpw:
+                                       case SmbException.ERRaccess:
+                                       case SmbException.ERRaccountExpired:
+                                       case SmbException.ERRbadClient:
+                                       case SmbException.ERRbadLogonTime:
+                                       case SmbException.ERRpasswordExpired:
+                                               throw new SmbAuthException( response.errorCode );
+                               }
+                       default:
+                               throw new SmbException( response.errorCode );
                }
        }
-       synchronized void negotiate() throws IOException {
+       synchronized void negotiate() throws SmbException {
 
                if( negotiated ) {
                        return;
@@ -525,7 +632,7 @@ class SmbTransport implements Runnable {
                send( new SmbComNegotiate(), response );
 
                if( response.dialectIndex > 10 ) {
-                       throw new IOException( "smb failed to negotiate dialect" );
+                       throw new SmbException( SmbException.ERRCLI, SmbException.ERRbadDialect );
                }
 
                server.securityMode        = response.securityMode;
@@ -571,11 +678,11 @@ class SmbTransport implements Runnable {
                        ",localPort=" + socket.getLocalPort() + "]";
        }
 
-       static int aquireMid() throws IOException {
+       static int aquireMid() throws SmbException {
                try {
                        return mpxCtrl.aquireMid();
                } catch( InterruptedException ie ) {
-                       throw new IOException( ie.getMessage() );
+                       throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ie.getMessage() );
                }
        }
        static void releaseMid( int mid ) {
index 980c250..e3b32a3 100644 (file)
 package jcifs.smb;
 
 import java.io.IOException;
+import jcifs.UniAddress;
 import jcifs.netbios.NbtAddress;
 import java.net.UnknownHostException;
 
 class SmbTree {
 
        int tid;
-       String path;
+       String share;
        String service = jcifs.Config.getProperty( "jcifs.smb.client.serviceType", "?????" );
        SmbSession session;
-       boolean treeConnected = false;
+       boolean treeConnected;
 
-       SmbTree( SmbSession session, String path, String service ) {
+       SmbTree( SmbSession session, String share, String service ) {
                this.session = session;
-               this.path = path;
+               this.share = share;
                if( service != null && service.startsWith( "??" ) == false ) {
                        this.service = service;
                }
        }
 
-       boolean matches( String path, String service ) {
-               return this.path.equals( path ) &&
+       boolean matches( String share, String service ) {
+               return this.share.equals( share ) &&
                                ( service == null || service.startsWith( "??" ) ||
                                this.service.equals( service ));
        }
        void sendTransaction( SmbComTransaction request,
-                                                               SmbComTransactionResponse response ) throws IOException {
+                                                       SmbComTransactionResponse response ) throws SmbException {
                // transactions are not batchable
                treeConnect( null, null );
                request.tid = tid;
                session.sendTransaction( request, response );
        }
        void send( ServerMessageBlock request,
-                                                               ServerMessageBlock response ) throws IOException {
+                                                       ServerMessageBlock response ) throws SmbException {
                if( response != null ) {
                        response.received = false;
                }
                treeConnect( request, response );
-               if( response != null && response.received ) {
+               if( request == null || (response != null && response.received )) {
                        return;
                }
                request.tid = tid;
                session.send( request, response );
        }
-       synchronized void treeConnect( ServerMessageBlock andx, ServerMessageBlock andxResponse )
-                                                               throws IOException {
+       synchronized void treeConnect( ServerMessageBlock andx,
+                                                       ServerMessageBlock andxResponse ) throws SmbException {
+               String unc;
 
                if( treeConnected ) {
                        return;
                }
 
+               /* The hostname to use in the path is only known for
+                * sure if the NetBIOS session has been successfully
+                * established.
+                */
+
+               session.transport.negotiate();
+
+               unc = "\\\\" + session.transport.server.tconHostName + "\\" + share;
+
                Log.println( Log.WARNINGS, "smb tree connect warning",
-                               " requesting tree connect with path=" + path +
+                               " requesting tree connect with unc=" + unc +
                                ",service=" + service );
 
                /*
@@ -80,7 +91,7 @@ class SmbTree {
                SmbComTreeConnectAndXResponse response =
                                                                        new SmbComTreeConnectAndXResponse( andxResponse );
                SmbComTreeConnectAndX request =
-                                                                       new SmbComTreeConnectAndX( session, path, service, andx );
+                                                                       new SmbComTreeConnectAndX( session, unc, service, andx );
                session.send( request, response );
 
                tid = response.tid;
@@ -100,402 +111,8 @@ class SmbTree {
                }
        }
 
-//
-// Not used at the moment.
-//
-//     boolean checkDirectory( String path ) throws IOException {
-//
-//             Log.println( Log.WARNINGS, "smb check directory warning",
-//                             " checking directory with path=" + path );
-//
-//             /*
-//              * Check Directory Request / Response
-//              */
-//
-//             try {
-//                     send( new SmbComCheckDirectory( path ), new SmbComBlankResponse() );
-//             } catch( SmbException se ) {
-//                     if( se.errorClass == SmbException.ERRDOS &&
-//                                                                     se.errorCode == SmbException.ERRbadpath ) {
-//                             return false;
-//                     } else {
-//                             throw se;
-//                     }
-//             }
-//             return true;
-//     }
-
-       Info queryPath( String path, int infoLevel ) throws IOException {
-
-               Log.println( Log.WARNINGS, "smb query path warning",
-                               " querying path=" + path );
-
-               /* To query server capabilities we must ensure the negotiation has talken place
-                */
-
-               synchronized( this ) {
-                       session.transport.negotiate();
-               }
-
-               /* normally we'd check the negotiatedCapabilities for CAP_NT_SMBS
-                * however I can't seem to get a good last modified time from
-                * SMB_COM_QUERY_INFORMATION so if NT_SMBs are requested
-                * by the server than in this case that's what it will get
-                * regardless of what jcifs.smb.client.useNTSmbs is set
-                * to(overrides negotiatedCapabilities).
-                */
-
-               Info result = null;
-               if(( session.transport.server.capabilities &
-                                                                       ServerMessageBlock.CAP_NT_SMBS ) ==
-                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
-                       /*
-                        * Trans2 Query Path Information Request / Response
-                        */
-
-                       Trans2QueryPathInformationResponse response =
-                                                                       new Trans2QueryPathInformationResponse( infoLevel );
-                       try {
-                               sendTransaction( new Trans2QueryPathInformation( path, infoLevel ), response );
-                       } catch( SmbException se ) {
-                               if( se.errorClass == SmbException.ERRDOS &&
-                                                                               se.errorCode == SmbException.ERRbadfile ) {
-                                       return null;
-                               } else {
-                                       throw se;
-                               }
-                       }
-                       result = response.info;
-               } else {
-
-                       /*
-                        * Query Information Request / Response
-                        */
-
-                       SmbComQueryInformationResponse response =
-                                               new SmbComQueryInformationResponse(
-                                               session.transport.server.serverTimeZone * 1000 * 60L );
-                       try {
-                               send( new SmbComQueryInformation( path ), response );
-                       } catch( SmbException se ) {
-                               if( se.errorClass == SmbException.ERRDOS &&
-                                                                               se.errorCode == SmbException.ERRbadfile ) {
-                                       return null;
-                               } else {
-                                       throw se;
-                               }
-                       }
-                       result = response;
-               }
-               return result;
-       }
-       String[] find( String path ) throws IOException {
-               int sid, count, i, j;
-               String[] results;
-               String filename;
-
-               synchronized( this ) {
-                       // Must ensure treeConnect has been issued to query the service type
-                       treeConnect( null, null );
-               }
-
-               if( service.equals( "A:" ) == false ) {
-                       // Cannot issue find on anything but a Disk Share
-                       return new String[0];
-               }
-
-               if( path.equals( "\\" )) {
-                       path = "\\*";
-               } else {
-                       path += "\\*";
-               }
-
-               Log.println( Log.WARNINGS, "smb find warning",
-                               " find with path=" + path );
-
-               Trans2FindFirst2Response response = new Trans2FindFirst2Response();
-               sendTransaction( new Trans2FindFirst2( path ), response );
-
-               sid = response.sid;
-               count = response.searchCount;
-               j = 0;
-
-               results = new String[Math.max( 10, count )];
-               /*
-                * using hashCode is much more efficient than
-                * filename.equals( "." ) || filename.equals( ".." )
-                */
-               int h1 = new String( "." ).hashCode();
-               int h2 = new String( ".." ).hashCode();
-               i = 0;
-               while( j < count ) {
-                       filename = response.results[i++].filename;
-                       if( filename.length() < 3 ) {
-                               int h = filename.hashCode();
-                               if( h == h1 || h == h2 ) {
-                                       count--;
-                                       continue;
-                               }
-                       }
-                       results[j++] = filename;
-               }
-
-               // only difference between first2 and next2 responses is subCommand so let's recycle
-               response.subCommand = SmbComTransaction.TRANS2_FIND_NEXT2;
-
-               while( response.isEndOfSearch == false && response.searchCount > 0 ) {
-                       sendTransaction( new Trans2FindNext2( sid, response.resumeKey,
-                                                                                                       response.lastName ), response );
-                       count += response.searchCount;
-
-                       if( count > results.length ) {
-                               String[] tmp = results;
-                               results = new String[Math.max( results.length * 2, count )];
-                               System.arraycopy( tmp, 0, results, 0, j );
-                       }
-                       i = 0;
-                       while( j < count ) {
-                               filename = response.results[i++].filename;
-                               if( filename.length() < 3 ) {
-                                       int h = filename.hashCode();
-                                       if( h == h1 || h == h2 ) {
-                                               count--;
-                                               continue;
-                                       }
-                               }
-                               results[j++] = filename;
-                       }
-               }
-
-               try {
-                       send( new SmbComFindClose2( sid ), new SmbComBlankResponse() );
-               } catch( SmbException se ) {
-                       Log.printStackTrace( "smb find close response exception", se );
-               }
-
-               if( results.length != count ) {
-                       String[] tmp = results;
-                       results = new String[count];
-                       System.arraycopy( tmp, 0, results, 0, count );
-               }
-
-               return results;
-       }
-       String[] netShareEnum() throws IOException {
-               String ipcPath = path.substring( 0, path.lastIndexOf( '\\' ) + 1 ) + "IPC$";
-               SmbTree t = session.getSmbTree( ipcPath, null );
-
-               NetShareEnumResponse response = new NetShareEnumResponse();
-               t.sendTransaction( new NetShareEnum(), response );
-
-               if( response.status != 0 &&
-                                                       response.status != NetShareEnumResponse.ERROR_MORE_DATA ) {
-                       throw new IOException( response.toString() );
-               }
-
-               String[] ret = new String[response.entriesReturned];
-               for( int i = 0; i < response.entriesReturned; i++ ) {
-                       ret[i] = response.results[i].netName;
-               }
-
-               return ret;
-       }
-       static void setLmbTree( SmbFile file ) throws IOException {
-               NbtAddress lmb = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null );
-               lmb = NbtAddress.getByName( lmb.getHostAddress() );
-               file.address = NbtAddress.getByName( lmb.getHostAddress(), 0x20, null );
-               SmbTransport trans = SmbTransport.getSmbTransport( file.address, 0 );
-               SmbSession ssn = trans.getSmbSession( "", "", "" );
-               String unc = new String( "\\\\" + file.address.getHostName() +
-                                                                                                                       "\\IPC$" ).toUpperCase();
-               file.tree = ssn.getSmbTree( unc, null );
-       }
-       String[] domainEnum() throws IOException {
-               String ipcPath = path.substring( 0, path.lastIndexOf( '\\' ) + 1 ) + "IPC$";
-               SmbTree t = session.getSmbTree( ipcPath, null );
-
-               synchronized( this ) {
-                       // to query oemDomainName megotiation must have occurred
-                       t.session.transport.negotiate();
-               }
-
-               NetServerEnum2Response response = new NetServerEnum2Response();
-               t.sendTransaction( new NetServerEnum2( t.session.transport.server.oemDomainName,
-                                                                       NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response );
-
-               if( response.status != NetServerEnum2Response.NERR_Success &&
-                               response.status != NetServerEnum2Response.ERROR_MORE_DATA ) {
-                       throw new IOException( response.toString() );
-               }
-
-               String[] ret = new String[response.entriesReturned];
-               for( int i = 0; i < response.entriesReturned; i++ ) {
-                       ret[i] = response.results[i].name;
-               }
-               return ret;
-       }
-       String[] netServerEnum2( String domain ) throws IOException {
-               NetServerEnum2Response response = new NetServerEnum2Response();
-               sendTransaction( new NetServerEnum2( domain, NetServerEnum2.SV_TYPE_ALL ), response );
-
-               if( response.status != NetServerEnum2Response.NERR_Success &&
-                               response.status != NetServerEnum2Response.ERROR_MORE_DATA ) {
-                       throw new IOException( response.toString() );
-               }
-
-               String[] ret = new String[response.entriesReturned];
-               for( int i = 0; i < response.entriesReturned; i++ ) {
-                       ret[i] = response.results[i].name;
-               }
-               return ret;
-       }
-       boolean rename( String oldFileName, String newFileName ) throws IOException {
-
-               Log.println( Log.WARNINGS, "smb rename warning",
-                               " oldFileName=" + oldFileName +
-                               ",newFileName=" + newFileName );
-
-               /*
-                * Rename Request / Response
-                */
-
-               SmbComBlankResponse response = new SmbComBlankResponse();
-               try {
-                       send( new SmbComRename( oldFileName, newFileName ), response );
-               } catch( SmbException se ) {
-                       if( se.errorClass == SmbException.ERRDOS &&
-                                                                       ( se.errorCode == SmbException.ERRbadpath ||
-                                                                       se.errorCode == SmbException.ERRbadfile )) {
-                               return false;
-                       } else {
-                               throw se;
-                       }
-               }
-               return true;
-       }
-
-//
-// Not used at the moment.
-//
-//     boolean copy( String sourceFileName, String targetFileName, int tid2 )
-//                                                                                                     throws IOException {
-//
-//             Log.println( Log.WARNINGS, "smb copy warning",
-//                             " sourceFileName=" + sourceFileName +
-//                             ",targetFileName=" + targetFileName );
-//
-//             /*
-//              * Copy Request / Response
-//              */
-//
-//             SmbComCopyResponse response = new SmbComCopyResponse();
-//             try {
-//                     send( new SmbComCopy( sourceFileName, targetFileName, tid2 ), response );
-//             } catch( SmbException se ) {
-//                     if( se.errorClass == SmbException.ERRDOS &&
-//                                                                     ( se.errorCode == SmbException.ERRbadpath ||
-//                                                                     se.errorCode == SmbException.ERRbadfile )) {
-//                             return false;
-//                     } else {
-//                             throw se;
-//                     }
-//             }
-//             return true;
-//     }
-
-       boolean delete( String fileName, boolean isDirectory ) throws IOException {
-
-               Log.println( Log.WARNINGS, "smb delete warning",
-                               " fileName=" + fileName );
-
-               /*
-                * Delete or Delete Directory Request / Response
-                */
-
-               ServerMessageBlock request;
-               if( isDirectory ) {
-
-                       /* Recursively delete directory contents using post order DFS
-                        */
-
-                       String[] list = find( fileName );
-                       for( int i = 0; i < list.length; i++ ) {
-                               String p = fileName + "\\" + list[i];
-                               int infoLevel = Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO;
-                               Info info = queryPath( p, infoLevel );
-                               boolean dir = ( info.getAttributes() & SmbFile.ATTR_DIRECTORY ) ==
-                                                                                                               SmbFile.ATTR_DIRECTORY;
-                               delete( p, dir );
-                       }
-
-                       request = new SmbComDeleteDirectory( fileName );
-               } else {
-                       request = new SmbComDelete( fileName );
-               }
-
-               try {
-                       send( request, new SmbComBlankResponse() );
-               } catch( SmbException se ) {
-                       if( se.errorClass == SmbException.ERRDOS &&
-                                                                       ( se.errorCode == SmbException.ERRbadpath ||
-                                                                       se.errorCode == SmbException.ERRbadfile )) {
-                               return false;
-                       } else {
-                               throw se;
-                       }
-               }
-               return true;
-       }
-       int open( String name, int flags ) throws IOException {
-
-               Log.println( Log.WARNINGS, "smb open warning", " name=" + name );
-
-               /*
-                * Open AndX Request / Response
-                */
-
-               /* To query server capabilities we must ensure the negotiation has talken place
-                */
-
-               synchronized( this ) {
-                       session.transport.negotiate();
-               }
-
-               if(( session.transport.negotiatedCapabilities &
-                                                                       ServerMessageBlock.CAP_NT_SMBS ) ==
-                                                                       ServerMessageBlock.CAP_NT_SMBS ) {
-                       SmbComNTCreateAndXResponse response = new SmbComNTCreateAndXResponse();
-                       send( new SmbComNTCreateAndX( name, flags, null ), response );
-                       return response.fid;
-               } else {
-                       SmbComOpenAndXResponse response = new SmbComOpenAndXResponse();
-                       send( new SmbComOpenAndX( name, flags, null ), response );
-                       return response.fid;
-               }
-       }
-       boolean createDirectory( String directoryName ) throws IOException {
-
-               Log.println( Log.WARNINGS, "smb create directory warning",
-                               " directoryName=" + directoryName );
-
-               /*
-                * Create Directory Request / Response
-                */
-
-               try {
-                       send( new SmbComCreateDirectory( directoryName ), new SmbComBlankResponse() );
-               } catch( SmbException se ) {
-                       if( se.errorClass == SmbException.ERRDOS &&
-                                                                       se.errorCode == SmbException.ERRnoaccess ) {
-                               return false;
-                       } else {
-                               throw se;
-                       }
-               }
-               return true;
-       }
        public String toString() {
-               return "SmbTree[path=" + path +
+               return "SmbTree[share=" + share +
                        ",service=" + service +
                        ",tid=" + tid + "]";
        }
index 647f4e1..04d0787 100644 (file)
 package jcifs.smb;
 
 import jcifs.netbios.NbtAddress;
-import java.io.IOException;
+import jcifs.UniAddress;
 import java.net.MalformedURLException;
 import java.net.UnknownHostException;
 import java.util.Vector;
 import java.util.Enumeration;
 
 final class SmbURL {
-       String url;
-       String domain;
-       String username;
-       String password;
-       String server;
-       int port;
-       String share;
-       String canonicalPath;
-       String path;
-       String file;
-       boolean isWorkgroup;
 
-       static class QueryThread extends Thread {
-
-               Object lock;
-               String host, scope;
-               int type;
-               NbtAddress ans = null;
-               UnknownHostException uhe;
-
-               QueryThread( Object lock, String host, int type, String scope ) {
-                       this.lock = lock;
-                       this.host = host;
-                       this.type = type;
-                       this.scope = scope;
-               }
-               public void run() {
-                       try {
-                               ans = NbtAddress.getByName( host, type, scope );
-                       } catch( UnknownHostException uhe ) {
-                               this.uhe = uhe;
-                       }
-                       synchronized( lock ) {
-                               lock.notify();
-                       }
-               }
-       }
-       static NbtAddress lookupServerOrWorkgroup( String name ) throws UnknownHostException {
-               Object lock = new Object();
-               QueryThread q1d = new QueryThread( lock, name, 0x1d, null );
-               QueryThread q20 = new QueryThread( lock, name, 0x20, null );
-               q1d.setDaemon( true );
-               q20.setDaemon( true );
-               try {
-                       synchronized( lock ) {
-                               q1d.start();
-                               q20.start();
-
-                               int i = 2;
-                               while( i-- > 0 && q1d.ans == null && q20.ans == null ) {
-                                       lock.wait();
-                               }
-                       }
-               } catch( InterruptedException ie ) {
-                       throw new UnknownHostException( name );
-               }
-               if( q1d.ans != null ) {
-                       return NbtAddress.getByName( q1d.ans.getHostAddress(), 0x1d, null );
-               } else if( q20.ans != null ) {
-                       return q20.ans;
-               } else {
-                       throw q1d.uhe;
-               }
+       static void parseSmbURL( SmbFile file, String url, String name )
+                                                               throws MalformedURLException, UnknownHostException {
+               parseSmbURL( file, url, name, 4, url.length() );
        }
-
-       /*
-        * smb://[[[ntdomain;]user[:password]@]server[:port][/share[/path]]]
-        *
-        * smb://hendrix/download/
-        * smb://nycdom;mike@angus/tmp/classes/Main.class
-        * smb://mike:sw@#ii@angus/tmp/classes
-        * smb://nycdom;mike:sw@#ii@hendrix/download/docs/index.html
-        */
-
-       SmbURL( String url ) throws MalformedURLException, UnknownHostException {
-               this( url, null, 4, url.length() );
-       }
-       SmbURL( String url, String name ) throws MalformedURLException, UnknownHostException {
-               this( url, name, 4, url.length() );
-       }
-       SmbURL( String url, String name, int start, int limit )
-                                                                               throws MalformedURLException, UnknownHostException {
+       static void parseSmbURL( SmbFile file, String url, String name,
+                                                               int start, int limit )
+                                                               throws MalformedURLException, UnknownHostException {
                int beg, end, c, at, srv, pat;
 
-               this.url = url;
-
                try {
                        if( name != null ) {
                                if( name.regionMatches( true, 0, "smb://", 0, 6 )) {
@@ -145,15 +69,15 @@ final class SmbURL {
                                }
                                if( beg == end && Character.isDigit( url.charAt( start + 2 )) == false ) {
                                        // Could be a workgroup. Need to query the network to find out.
-                                       NbtAddress ans = lookupServerOrWorkgroup( url.substring( 6, end ));
-                                       if( ans.getNameType() == 0x1d ) {
+                                       file.address = UniAddress.getByName( url.substring( 6, end ), true );
+                                       if( ((NbtAddress)file.address.getAddress()).getNameType() == 0x1d ) {
                                                if( name != null ) {
                                                        url = "smb://" + name;
                                                        name = null;
                                                        start = 4;
                                                        limit = url.length();
                                                } else {
-                                                       isWorkgroup = true;
+                                                       file.isWorkgroup = true;
                                                }
                                        }
                                }
@@ -184,17 +108,17 @@ final class SmbURL {
                                for( i = start; i < at; i++ ) {
                                        c = url.charAt( i );
                                        if( c == ';' ) {
-                                               domain = url.substring( start, i );
+                                               file.authInfo.domain = url.substring( start, i );
                                                u = i + 1;
                                        } else if( c == ':' ) {
-                                               password = url.substring( i + 1, at );
+                                               file.authInfo.password = url.substring( i + 1, at );
                                                break;
                                        }
                                }
-                               username = url.substring( u, i );
+                               file.authInfo.username = url.substring( u, i );
                        }
 
-                       server = url.substring( srv );
+                       file.server = url.substring( srv );
 
                        /* For the moment the server variable will
                         * contain everything that follows as well for
@@ -217,16 +141,20 @@ final class SmbURL {
                                        if( sha < srv ) {
                                                sha = limit;
                                        }
-                                       server = url.substring( srv, sha ) + name;
+                                       file.server = url.substring( srv, sha );
+                                       if( name.equals( "/" ) == false ) {
+                                               file.server += name;
+                                       }
                                } else {
-                                       if( server.length() == 0 || server.endsWith( "/" )) {
-                                               server += name;
+                                       if( file.server.length() == 0 || file.server.endsWith( "/" )) {
+                                               file.server += name;
                                        } else {
-                                               server = server + '/' + name;
+                                               file.server = file.server + '/' + name;
                                        }
                                }
                        }
-                       limit = server.length();
+                       file.url = url.substring( 0, srv ) + file.server;
+                       limit = file.server.length();
 
                        /* The path must preserve all that was provided in
                         * the primary url argument and possibly secondary
@@ -235,14 +163,12 @@ final class SmbURL {
                         * be equal.
                         */
 
-                       path = server;
-
                        Vector stk = new Vector();
                        String str;
                        for( int i = 0, s = 0; i <= limit; i++ ) {
-                               if( i == limit || server.charAt( i ) == '/' ) {
+                               if( i == limit || file.server.charAt( i ) == '/' ) {
                                        if( i > s ) {
-                                               str = server.substring( s, i );
+                                               str = file.server.substring( s, i );
                                                if( str.equals( ".." )) {
                                                        if( stk.isEmpty() == false ) {
                                                                stk.removeElementAt( stk.size() - 1 );
@@ -256,31 +182,28 @@ final class SmbURL {
                                }
                        }
 
-                       server = null;
+                       file.server = null;
                        if( stk.isEmpty() == false ) {
                                Enumeration e = stk.elements();
-                               server = (String)e.nextElement();
+                               file.server = (String)e.nextElement();
 
-                               int p = server.indexOf( ':' );
+                               int p = file.server.indexOf( ':' );
                                if( p > 0 ) {
-                                       port = Integer.parseInt( server.substring( p + 1 ));
-                                       server = server.substring( 0, p );
+                                       file.port = Integer.parseInt( file.server.substring( p + 1 ));
+                                       file.server = file.server.substring( 0, p );
                                }
 
-                               file = server;
                                if( e.hasMoreElements() ) {
                                        StringBuffer sb = new StringBuffer();
 
-                                       share = (String)e.nextElement();
-                                       file = share;
+                                       file.share = (String)e.nextElement();
 
                                        while( e.hasMoreElements() ) {
-                                               file = (String)e.nextElement();
-                                               sb.append( '/' ).append( file );
+                                               sb.append( '/' ).append( e.nextElement() );
                                        }
 
                                        if( sb.length() > 0 ) {
-                                               canonicalPath = sb.toString();
+                                               file.canonicalPath = sb.toString();
                                        }
                                }
                        }
@@ -290,57 +213,5 @@ final class SmbURL {
                        throw new MalformedURLException( url + ", " + name );
                }
        }
-
-       public boolean equals( Object obj ) {
-               return obj instanceof SmbURL && obj.hashCode() == hashCode();
-       }
-       public int hashCode() {
-               return toString().hashCode();
-       }
-       String getCanonicalPath() {
-               StringBuffer sb = new StringBuffer( "smb://" );
-               if( server == null ) {
-                       return "smb://";
-               } else if( username != null ) {
-                       if( domain != null ) {
-                               sb.append( domain ).append( ';' );
-                       }
-                       sb.append( username );
-                       if( password != null ) {
-                               sb.append( ':' ).append( password );
-                       }
-                       sb.append( '@' );
-               }
-               sb.append( server );
-               // should probably not put the netbios session service
-               // port in here like this :~(
-               if( port != 0 && port != 139 ) {
-                       sb.append( ":" ).append( port );
-               }
-               if( share != null ) {
-                       sb.append( '/' ).append( share );
-                       if( canonicalPath != null ) {
-                               sb.append( canonicalPath );
-                       }
-               }
-               return sb.toString();
-       }
-       public String toString() {
-               StringBuffer sb = new StringBuffer( "smb://" );
-               if( username != null ) {
-                       if( domain != null ) {
-                               sb.append( domain ).append( ';' );
-                       }
-                       sb.append( username );
-                       if( password != null ) {
-                               sb.append( ':' ).append( password );
-                       }
-                       sb.append( '@' );
-               }
-               if( server != null ) {
-                       sb.append( path );
-               }
-               return sb.toString();
-       }
 }
 
index 6a257db..42512cf 100644 (file)
@@ -56,12 +56,11 @@ import java.io.OutputStream;
 
 public class SmbURLConnection extends URLConnection {
 
-       SmbURL url;
-       SmbFile file;
+       SmbFile f;
 
-       SmbURLConnection( URL u, SmbURL url ) {
+       SmbURLConnection( URL u, SmbFile f ) {
                super( u );
-               this.url = url;
+               this.f = f;
        }
 
 /** 
@@ -73,7 +72,7 @@ public class SmbURLConnection extends URLConnection {
                if( connected ) {
                        return;
                }
-               file = new SmbFile( url.getCanonicalPath() );
+               f.exists();
        }
 
 /**
@@ -82,9 +81,8 @@ public class SmbURLConnection extends URLConnection {
 
        public int getContentLength() {
                try {
-                       connect();
-                       return (int)file.length();
-               } catch( IOException ioe ) {
+                       return (int)f.length();
+               } catch( SmbException se ) {
                }
                return 0;
        }
@@ -95,7 +93,11 @@ public class SmbURLConnection extends URLConnection {
  */
 
        public long getDate() {
-               return getLastModified();
+               try {
+                       return f.lastModified();
+               } catch( SmbException se ) {
+               }
+               return 0L;
        }
 
 /**
@@ -105,9 +107,8 @@ public class SmbURLConnection extends URLConnection {
 
        public long getLastModified() {
                try {
-                       connect();
-                       return file.lastModified();
-               } catch( IOException ioe ) {
+                       return f.lastModified();
+               } catch( SmbException se ) {
                }
                return 0L;
        }
@@ -118,8 +119,7 @@ public class SmbURLConnection extends URLConnection {
  */
 
        public InputStream getInputStream() throws IOException {
-               connect();
-               return new SmbFileInputStream( file );
+               return new SmbFileInputStream( f );
        }
 
 /**
@@ -127,6 +127,6 @@ public class SmbURLConnection extends URLConnection {
  */
 
        public String toString() {
-               return new String( "SmbURLConnection[url=" + url.toString() + "]" );
+               return new String( "SmbURLConnection[url=" + f.toString() + "]" );
        }
 }
index e5fdf6e..e4af4f4 100644 (file)
@@ -29,7 +29,7 @@ class TransactNamedPipeOutputStream extends OutputStream {
        
        TransactNamedPipeOutputStream( SmbNamedPipe pipe ) throws IOException {
                this.pipe = pipe;
-               path = pipe.path.toUpperCase();
+               path = pipe.uncPath;
        }
 
        public void close() throws IOException {
diff --git a/src/jcifs/util/AuthHandler.java b/src/jcifs/util/AuthHandler.java
new file mode 100644 (file)
index 0000000..3e72557
--- /dev/null
@@ -0,0 +1,6 @@
+package jcifs.util;
+
+public interface AuthHandler {
+
+       public boolean authenticate( AuthInfo auth );
+}
diff --git a/src/jcifs/util/AuthInfo.java b/src/jcifs/util/AuthInfo.java
new file mode 100644 (file)
index 0000000..c2e9f8b
--- /dev/null
@@ -0,0 +1,10 @@
+package jcifs.util;
+
+public class AuthInfo {
+
+       public String target;
+       public String domain;
+       public String username;
+       public String password;
+       public Exception exception;
+}
index 8c7d979..63e358f 100644 (file)
@@ -172,6 +172,24 @@ public class Config {
                return result;
        }
 
+       /**
+        * Retrieve a <code>long</code>. If the key does not exist or
+        * cannot be converted to a <code>long</code>, the provided default
+        * argument will be returned.
+        */
+
+       public static long getLong( String key, long def ) {
+               Object obj = get( key );
+               if( obj != null && obj instanceof String ) {
+                       try {
+                               def = Long.parseLong( (String)obj );
+                       } catch( NumberFormatException nfe ) {
+                               Log.printStackTrace( "configuration warning", nfe );
+                       }
+               }
+               return def;
+       }
+
        /** 
         * Retrieve an <code>InetAddress</code>. If the address is not
         * an IP address and cannot be resolved <code>null</code> will