[jcifs] '/' required at the end of directories

Allen, Michael B (RSCH) Michael_B_Allen at ml.com
Mon Jan 20 11:05:46 EST 2003

> -----Original Message-----
> From:	Christopher R. Hertel [SMTP:crh at ubiqx.mn.org]
> > >
> > > > > The solution is semantic, not syntactic, I'm afraid.  You'd have
> > > > > to contact the server and ask it "what is this thing".  If it's
> > > > > a directory, then add the slash.
> > > >
> > > > Which means we would have to actually connect to the server and query
> > > > the resource just to parse it. Ha. No.
> > >
> > > We do that anyway, in other areas.  We contact servers to discover the
> > > semantic differences between an NBT name and a DNS name.  We contact
> > > servers to discover NBT vs. naked TCP (port 445) transport.  We do
> > > that a lot already.  That's a problem with SMB.
> > >
> > > In this case, however, I strongly suspect that the semantic differences
> > > between a directory and a file won't matter *until after* the server is
> > > contacted anyway.  Something like:
> > >
> > >   smb://server/share/something
> > >
> > > can probably remain ambiguous until you've talked to the server about
> > > it.
> > >
> > No because it must be known when you create the java.net.URL object
> > which is in the SmbFile constructor. We can get away with querying the
> > server vs. workgroup distinction. I was going to rip that out but I
> > thought users were going to need to do it anyway so we might as well do
> > it for them. And it doesn't happen all that frequently. But when you're
> > manipulating a big list of URLs and most of them are files you cannot go
> > off onto the network and query each to determine if it's really a
> > directory. That would be slower than evolution.
> I'm not too good at the "it can't be done" scenario, but I do find it easier
> to be demanding when I'm not the one writing the code.  :)
> Still, I don't like it.  What about a named pipe?  You can't distinguish
> that from a directory or file path until you connect either.
	Well as long as you don't try to compose a new URL from a context URL and
	a relative path then you'll never have a problem. And in the case of a named
	pipe you would never need to do that so it doesn't matter if you use a trailing '/':

	  u1 = new URL( "smb://server/IPC$/PIPE/foo" );
	  u2 = new URL( u1, "?" );

	You can also get away with not have the trailing slash for a directory but as
	soon as you try to compose a derived URL object you'll have a problem.
	Because it's known that listFiles will do this we deliberately throw an
	Exception to clue people in:

	Exception in thread "main" jcifs.smb.SmbException: smb://miallen2/pub directory must end with '/'
	        at jcifs.smb.SmbFile.listFiles(SmbFile.java:1256)
	        at jcifs.smb.SmbFile.listFiles(SmbFile.java:1222)
	        at ListFiles.main(ListFiles.java:31)

> You said above that the java.net.URL object needs to know ahead of time what
> type of object something is before it accesses that object.  That's
> a big chicken-and-egg problem, and I'd go so far as to call it a bug in
> the design of java.net.URL.  I probably need a much better understanding
> of that class before I complain, but...
	RFC 2396 section 5.2. Resolving Relative References to Absolute Form: 
	   6) If this step is reached, then we are resolving a relative-path
	      reference.  The relative path needs to be merged with the base
	      URI's path.  Although there are many ways to do this, we will
	      describe a simple method using a separate string buffer.

	      a) All but the last segment of the base URI's path component is
	         copied to the buffer.  In other words, any characters after the
	         last (right-most) slash character, if any, are excluded.

> The distinction is moot for the HTTP protocol, since the web server will
> send HTML or some other mime-type back in any case.  That is, if you enter
> "http://server/directory" you will most likely get back an HTML document
> that is the listing of the directory contents.
	Notice if you send an HTTP request like:

	GET /foo HTTP/1.1

	and foo turns out to be a directory you will get:

	HTTP/1.1 301 Moved Permanently
	Location: http://server.com/foo/

> > Just a reminder, because it already got chopped above, the problem is
> > internal to the java.net.URL when you create a new URL from a context
> > URL object and a relative path like:
> > 
> >   smb://server/share/dir/ + file.txt => smb://server/share/dir/file.txt
> >   smb://server/share/dir + file.txt => smb://server/share/file.txt
> > 
> > See how the 'dir' got chopped. I believe this is correct URL behavior
> > BTW.
> The 'dir' got replaced.  Yes, I agree that the above is probably proper
> manipulation of relative URLs.  Note, however, that the above is purely
> syntactical.  No semantics are applied.
> > With jCIFS this is done for each SmbFile returned in SmbFile.listFiles()
> > for example.
> If I say I want to list "smb://server/share/dir" (no final '/') then a
> connection must be made to the server to query "/share/dir".  You can't
> can't list it as a file or list the files within it as a directory until
> you've connected to it.
	But then it's too late. You created the URL object well before the point that you
	try to actually use it. You cannot create it and then say oops it's actually a
	directory. They are immutable so you cannot just replace it with a new URL

> If I understand, java.net.URL is requiring that you know those semantics
> *before* you make the connection.  I wonder how this is handled for FTP...
	With the Java URL you will get exactly the same behavior. There must be a
	trailing slash.

> Hmmm... here's another question for you.  You said:
> > With jCIFS this is done for each SmbFile returned in SmbFile.listFiles()
> > for example.
> ...but what if the directory contains subdirectories?  I imagine that when
> you list the contents of the directory you will get back information on the
> type of each object within the directory.  That would be necessary for a
> graphical front-end, for example, that would allow you to browse the share.
	Since the TRANS2_FIND_FIRST2/NEXT2 operation returns the attributes
	necessary to determine if each item is a file or directory trailing slashes are
	automatically appended for directories. Also the SmbFile.getName() method
	will return a name with an appended slash if the object is a directory.

More information about the jcifs mailing list