[jcifs] SmbFile.getDiskFreeSpace bug

Thomas Krammer tkrammer at nxn-software.com
Thu Jan 27 20:47:51 GMT 2005


> The Windows Explorer is reporting the correct value. Windows XP is 
> using information level 1007 instead of information level 1 which 
> JCIFS uses. According the the Samba sources this is
>
> #define SMB_FS_FULL_SIZE_INFORMATION            1007
>
> It returns the following information (see trans2.c in the Samba sources):
>
> int64 Total allocation units
> int64 Caller available allocation units
> int64 Actual available allocation units
> int32 Sectors per allocation unit
> int32 Bytes per sector
>
> So it returns the block counts as 64 bit integers instead of 32 bit 
> integers.
>
> I extended getDiskFreeSpace() to use SMB_FS_FULL_SIZE_INFORMATION. If 
> the server returns a NT_STATUS_INVALID_INFO_CLASS error I fall back to 
> SMB_INFO_ALLOCATION. I don't know if there is a way to know if the 
> server supports a certain information level before making the call.
>
> I attached a patch with my extensions. I did some limited testing 
> against a Windows 2003 Server and it seems to work fine. I also asked 
> our customer to try out the patched JCIFS library. I will report back 
> as soon as I hear from them.
>
Of course it didn't work on their machine...

I just copied the int64 handling from 
Trans2QueryFSInformationResponse.readSmbQueryFSSizeInfoWireFormat(). 
That code doesn't work when actually more than 32 bit of the int64 are used.

I'm now using readInt8() and it works fine. I also fixed 
readSmbQueryFSSizeInfoWireFormat(). I attached the fixed version of the 
patch.


  Thomas

-------------- next part --------------
diff -Naur jcifs_1.1.7_org/src/jcifs/smb/SmbFile.java jcifs_1.1.7/src/jcifs/smb/SmbFile.java
--- jcifs_1.1.7_org/src/jcifs/smb/SmbFile.java	2005-01-16 18:55:22.000000000 +0100
+++ jcifs_1.1.7/src/jcifs/smb/SmbFile.java	2005-01-27 14:03:50.203000000 +0100
@@ -2183,21 +2183,35 @@
  */
     public long getDiskFreeSpace() throws SmbException {
         if( getType() == TYPE_SHARE || type == TYPE_FILESYSTEM ) {
-            Trans2QueryFSInformationResponse response;
-            int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION;
-
-            response = new Trans2QueryFSInformationResponse( level );
-            sendTransaction( new Trans2QueryFSInformation( level ), response );
-
-            if( type == TYPE_SHARE ) {
-                size = response.info.getCapacity();
-                sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod;
+            try {
+                return queryFSInformation(Trans2QueryFSInformationResponse.SMB_FS_FULL_SIZE_INFORMATION);
             }
-
-            return response.info.getFree();
+            catch(SmbException ex) {
+                if(ex.getNtStatus() == NtStatus.NT_STATUS_INVALID_INFO_CLASS) {
+                    // SMB_FS_FULL_SIZE_INFORMATION not supported by the server.
+                    return queryFSInformation(Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION);
+                }
+                
+                throw ex;
+            }
+            
         }
         return 0L;
     }
+    
+    private long queryFSInformation( int level ) throws SmbException {
+        Trans2QueryFSInformationResponse response;
+
+        response = new Trans2QueryFSInformationResponse( level );
+        sendTransaction( new Trans2QueryFSInformation( level ), response );
+
+        if( type == TYPE_SHARE ) {
+            size = response.info.getCapacity();
+            sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod;
+        }
+
+        return response.info.getFree();
+    }
 
 /**
  * Creates a directory with the path specified by this
diff -Naur jcifs_1.1.7_org/src/jcifs/smb/Trans2QueryFSInformationResponse.java jcifs_1.1.7/src/jcifs/smb/Trans2QueryFSInformationResponse.java
--- jcifs_1.1.7_org/src/jcifs/smb/Trans2QueryFSInformationResponse.java	2005-01-16 18:55:22.000000000 +0100
+++ jcifs_1.1.7/src/jcifs/smb/Trans2QueryFSInformationResponse.java	2005-01-27 21:09:10.453125000 +0100
@@ -25,6 +25,7 @@
     // information levels
     static final int SMB_INFO_ALLOCATION = 1;
     static final int SMB_QUERY_FS_SIZE_INFO = 0x103;
+    static final int SMB_FS_FULL_SIZE_INFORMATION = 1007;
 
     class SmbInfoAllocation implements AllocInfo {
         long alloc;                  // Also handles SmbQueryFSSizeInfo
@@ -77,6 +78,8 @@
                 return readSmbInfoAllocationWireFormat( buffer, bufferIndex );
             case SMB_QUERY_FS_SIZE_INFO:
                 return readSmbQueryFSSizeInfoWireFormat( buffer, bufferIndex );
+            case SMB_FS_FULL_SIZE_INFORMATION:
+                return readFsFullSizeInformationWireFormat( buffer, bufferIndex );
             default:
                 return 0;
         }
@@ -110,19 +113,42 @@
 
         SmbInfoAllocation info = new SmbInfoAllocation();
 
-        info.alloc = readInt4( buffer, bufferIndex );
-        bufferIndex += 4;
-        info.alloc |= readInt4( buffer, bufferIndex ) << 32L;
-        bufferIndex += 4;
+        info.alloc = readInt8( buffer, bufferIndex );
+        bufferIndex += 8;
 
-        info.free = readInt4( buffer, bufferIndex );
+        info.free = readInt8( buffer, bufferIndex );
+        bufferIndex += 8;
+
+        info.sectPerAlloc = readInt4( buffer, bufferIndex );
         bufferIndex += 4;
-        info.free |= readInt4( buffer, bufferIndex ) << 32L;
+
+        info.bytesPerSect = readInt4( buffer, bufferIndex );
         bufferIndex += 4;
 
+        this.info = info;
+
+        return bufferIndex - start;
+    }
+    int readFsFullSizeInformationWireFormat( byte[] buffer, int bufferIndex )
+    {
+        int start = bufferIndex;
+        
+        SmbInfoAllocation info = new SmbInfoAllocation();
+        
+        // Read total allocation units.
+        info.alloc = readInt8( buffer, bufferIndex );
+        bufferIndex += 8;
+        
+        // read caller available allocation units 
+        info.free = readInt8( buffer, bufferIndex );
+        bufferIndex += 8;
+
+        // skip actual free units
+        bufferIndex += 8;
+        
         info.sectPerAlloc = readInt4( buffer, bufferIndex );
         bufferIndex += 4;
-
+        
         info.bytesPerSect = readInt4( buffer, bufferIndex );
         bufferIndex += 4;
 
@@ -130,6 +156,7 @@
 
         return bufferIndex - start;
     }
+    
     public String toString() {
         return new String( "Trans2QueryFSInformationResponse[" +
             super.toString() + "]" );


More information about the jcifs mailing list