+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
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.
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"
--- /dev/null
+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 );
+ }
+}
--- /dev/null
+/* 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] ));
+ }
+}
*/
import jcifs.smb.SmbFile;
+import jcifs.smb.SmbException;
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();
}
}
}
--- /dev/null
+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" ));
+ }
+}
+
// 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
// 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" );
// 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
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
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
// 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
// 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() );
}
}
}
public static void main( String argv[] ) throws Exception {
+ System.in.read();
+
Class.forName( "jcifs.Config" );
URL url = new URL( argv[0] );
--- /dev/null
+/* 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();
+ }
+}
+
--- /dev/null
+/* 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() );
+ }
+}
+
* 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;
SmbFile file = new SmbFile( argv[0] );
+ file.list();
long t1 = System.currentTimeMillis();
String[] files = file.list();
long t2 = System.currentTimeMillis() - t1;
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();
}
}
}
--- /dev/null
+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" );
+ }
+}
*/
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 );
}
}
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 );
}
}
*/
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 {
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();
+ }
}
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+import java.util.Date;
import jcifs.smb.*;
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] )));
}
public class ThreadedSmbCrawler {
+ static long time;
+
class DirEntry {
SmbFile dir;
int depth;
DirEntry e;
synchronized( dirList ) {
+time = System.currentTimeMillis();
while( dirList.isEmpty() ) {
dirList.wait( 500 );
}
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" );
}
}
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++ ) {
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>
--- /dev/null
+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();
+ }
+}
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;
}
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 );
}
}
* 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 {
* 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)
*/
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;
}
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() );
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 ) {
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++ ) {
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 );
}
}
}
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;
}
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 ) {
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();
}
-
}
NbtAddress addrEntry;
NameQueryResponse() {
- recordName = new Name( null, 0, null );
+ recordName = new Name();
}
int writeBodyWireFormat( byte[] dst, int dstIndex ) {
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;
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
*/
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() ) {
} 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 );
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() {
}
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 ));
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 ) {
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 );
}
}
}
- 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 {
request.isBroadcast = true;
}
- int n = retryCount;
+ n = retryCount;
while( n-- > 0 ) {
try {
send( request, response, retryTimeout );
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 ) {
}
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 );
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;
}
}
* 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}.
*
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
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;
}
}
+ 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;
}
}
- 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() );
}
/**
+ * 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".
*
public static NbtAddress getByName( String host )
throws UnknownHostException {
- return getByName( host, 0, null );
+ return getByName( host, 0x00, null );
}
/**
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;
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';
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 );
}
}
*/
- public static NbtAddress[] getAllByAddress( String host ) throws UnknownHostException {
+ public static NbtAddress[] getAllByAddress( String host )
+ throws UnknownHostException {
return getAllByAddress( getByName( host, 0x00, null ));
}
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();
+ }
+}
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 )) {
}
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 ) {
NodeStatusResponse( NbtAddress queryAddress ) {
this.queryAddress = queryAddress;
- recordName = new Name( null, 0, null );
+ recordName = new Name();
macAddress = new byte[6];
}
addressArray = new NbtAddress[numberOfNames];
String n;
- int type;
+ int hexCode;
String scope = queryAddress.hostName.scope;
boolean groupName;
int ownerNodeType;
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;
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,
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;
}
n = readBytesWireFormat( buffer, bufferIndex );
}
- if( n != byteCount ) {
- Log.println( Log.WARNINGS, "smb andx packet format warning", "byteCount=" +
- byteCount + " but readBytesWireFormat returned " + n );
- }
bufferIndex += byteCount;
}
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() {
--- /dev/null
+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;
+ }
+ }
+ }
+ }
+}
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();
}
}
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" ) + "]" );
}
}
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;
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;
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] );
}
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;
--- /dev/null
+package jcifs.smb;
+
+public class SmbAuthException extends SmbException {
+
+ public SmbAuthException( int code ) {
+ super( code );
+ }
+}
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 ) {
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;
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;
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() {
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;
pad1 = pad1 == 0 ? 0 : PADDING_SIZE - pad1;
dataOffset += pad1;
- totalDataCount = writeDataWireFormat( buf, bufDataOffset );
+ totalDataCount = writeDataWireFormat( txn_buf, bufDataOffset );
dataCount = Math.min( totalDataCount, available );
} else {
dst[dstIndex++] = (byte)0x00; // Pad
}
- System.arraycopy( buf, bufParameterOffset, dst, dstIndex, parameterCount );
+ System.arraycopy( txn_buf, bufParameterOffset, dst, dstIndex, parameterCount );
dstIndex += parameterCount;
}
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;
}
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;
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() {
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;
}
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;
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];
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,
super.toString() +
",disconnectTid=" + disconnectTid +
",passwordLength=" + passwordLength +
- ",password=" + Log.getHexString(
- password, passwordLength, 0 ) +
+ ",password=" + Log.getHexString( password, passwordLength, 0 ) +
",path=" + path +
",service=" + service + "]" );
return result;
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;
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;
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;
+ }
}
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;
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 {
}
}
- 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
* 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() );
}
/**
* 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 );
}
* 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;
}
* Close Request / Response
*/
- tree.send( new SmbComClose( fid ), new SmbComBlankResponse() );
+ send( new SmbComClose( fid ), new SmbComBlankResponse() );
}
*/
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 );
}
/**
*/
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://";
}
/**
*/
public String getPath() {
- return url.toString();
+ return url;
}
/**
*/
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();
}
/**
*/
public String getShare() {
- return url.share;
+ return share;
}
/**
*/
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.
*
*/
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;
}
/**
* <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;
}
/**
* @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?
}
/**
* 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;
* @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;
}
/**
* @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;
}
/**
* @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;
}
* 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;
}
/**
* @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;
}
/**
* 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 );
}
/**
* <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() );
}
/**
* @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;
}
* <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() );
}
/**
*/
public URL toURL() throws MalformedURLException {
- return new URL( url.toString() );
+ return new URL( getCanonicalPath() );
}
/**
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();
}
}
}
*/
public String toString() {
- return url.toString();
+ return url;
}
-
}
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.
*
* @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 ));
}
*
* @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 );
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 );
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 ) {
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.
*
* @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 );
}
*
* @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 );
}
*
* @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 );
}
*
* @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;
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;
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;
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;
}
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;
}
transport.send( request, response );
}
synchronized void sessionSetup( ServerMessageBlock andx,
- ServerMessageBlock andxResponse )
- throws IOException {
+ ServerMessageBlock andxResponse ) throws SmbException {
+ SmbComSessionSetupAndXResponse response = null;
if( sessionSetup ) {
return;
* 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;
}
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;
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;
Vector sessions;
boolean negotiated, useUnicode;
- NbtAddress address;
+ UniAddress address;
int port, rcv_buf_size, snd_buf_size;
int negotiatedDialectIndex;
int vcNumber = 1;
}
class ServerProperties {
+ String tconHostName;
+
byte flags;
int flags2;
int maxMpxCount;
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(); ) {
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;
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();
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();
}
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();
negotiated = false;
thread = null;
responseTable.clear();
+ BufferCache.releaseBuffer( rcv_buf );
+ BufferCache.releaseBuffer( snd_buf );
}
}
public void run() {
}
}
void send( ServerMessageBlock request,
- ServerMessageBlock response ) throws IOException {
+ ServerMessageBlock response ) throws SmbException {
Integer mid = null;
negotiate();
}
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 );
}
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 ));
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();
} 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;
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;
",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 ) {
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 );
/*
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;
}
}
-//
-// 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 + "]";
}
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 )) {
}
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;
}
}
}
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
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
* 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 );
}
}
- 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();
}
}
}
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();
- }
}
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;
}
/**
if( connected ) {
return;
}
- file = new SmbFile( url.getCanonicalPath() );
+ f.exists();
}
/**
public int getContentLength() {
try {
- connect();
- return (int)file.length();
- } catch( IOException ioe ) {
+ return (int)f.length();
+ } catch( SmbException se ) {
}
return 0;
}
*/
public long getDate() {
- return getLastModified();
+ try {
+ return f.lastModified();
+ } catch( SmbException se ) {
+ }
+ return 0L;
}
/**
public long getLastModified() {
try {
- connect();
- return file.lastModified();
- } catch( IOException ioe ) {
+ return f.lastModified();
+ } catch( SmbException se ) {
}
return 0L;
}
*/
public InputStream getInputStream() throws IOException {
- connect();
- return new SmbFileInputStream( file );
+ return new SmbFileInputStream( f );
}
/**
*/
public String toString() {
- return new String( "SmbURLConnection[url=" + url.toString() + "]" );
+ return new String( "SmbURLConnection[url=" + f.toString() + "]" );
}
}
TransactNamedPipeOutputStream( SmbNamedPipe pipe ) throws IOException {
this.pipe = pipe;
- path = pipe.path.toUpperCase();
+ path = pipe.uncPath;
}
public void close() throws IOException {
--- /dev/null
+package jcifs.util;
+
+public interface AuthHandler {
+
+ public boolean authenticate( AuthInfo auth );
+}
--- /dev/null
+package jcifs.util;
+
+public class AuthInfo {
+
+ public String target;
+ public String domain;
+ public String username;
+ public String password;
+ public Exception exception;
+}
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