From 5462b9c9bb0a37f35ac906dbca8017315a806b17 Mon Sep 17 00:00:00 2001 From: Gary Spencer Date: Tue, 24 Jun 2008 14:30:56 +0000 Subject: [PATCH] CIFS multi-threading changes, SLNG-11. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9553 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../filesys/ServerConfigurationBean.java | 307 +++++++++++++++++- .../filesys/alfresco/AlfrescoContext.java | 2 +- .../filesys/alfresco/AlfrescoDiskDriver.java | 34 +- .../cifs/EnterpriseCifsAuthenticator.java | 81 +++-- .../auth/cifs/PassthruCifsAuthenticator.java | 61 ++-- .../auth/nfs/AlfrescoRpcAuthenticator.java | 2 +- .../org/alfresco/filesys/repo/CifsHelper.java | 17 + .../filesys/repo/ContentDiskDriver.java | 38 ++- .../filesys/repo/ContentNetworkFile.java | 5 + .../filesys/state/FileStateTable.java | 7 + 10 files changed, 469 insertions(+), 85 deletions(-) diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java index 4403ee35ba..817172c15b 100644 --- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.java @@ -61,6 +61,7 @@ import org.alfresco.jlan.server.auth.acl.InvalidACLTypeException; import org.alfresco.jlan.server.auth.passthru.DomainMapping; import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; +import org.alfresco.jlan.server.config.CoreServerConfigSection; import org.alfresco.jlan.server.config.GlobalConfigSection; import org.alfresco.jlan.server.config.InvalidConfigurationException; import org.alfresco.jlan.server.config.SecurityConfigSection; @@ -70,8 +71,10 @@ import org.alfresco.jlan.server.core.ShareType; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskSharedDevice; import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; +import org.alfresco.jlan.server.thread.ThreadRequestPool; import org.alfresco.jlan.smb.server.CIFSConfigSection; import org.alfresco.jlan.util.IPAddress; +import org.alfresco.jlan.util.MemorySize; import org.alfresco.jlan.util.Platform; import org.alfresco.jlan.util.StringList; import org.alfresco.jlan.util.X64; @@ -106,6 +109,8 @@ import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import net.sf.acegisecurity.AuthenticationManager; @@ -128,6 +133,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl private static final String ConfigNFS = "NFS Server"; private static final String ConfigFilesystems = "Filesystems"; private static final String ConfigSecurity = "Filesystem Security"; + private static final String ConfigCoreServer = "Server Core"; // Server configuration bean name @@ -139,7 +145,7 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl private static final String m_sessDbgStr[] = { "NETBIOS", "STATE", "RXDATA", "TXDATA", "DUMPDATA", "NEGOTIATE", "TREE", "SEARCH", "INFO", "FILE", "FILEIO", "TRANSACT", "ECHO", "ERROR", "IPC", "LOCK", "PKTTYPE", "DCERPC", "STATECACHE", "TIMING", "NOTIFY", - "STREAMS", "SOCKET" }; + "STREAMS", "SOCKET", "PKTPOOL", "PKTSTATS", "THREADPOOL", "BENCHMARK" }; // FTP server debug type strings @@ -163,6 +169,27 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl private static final String TokenLocalName = "${localname}"; + // Default thread pool size + + private static final int DefaultThreadPoolInit = 25; + private static final int DefaultThreadPoolMax = 50; + + // Default memory pool settings + + private static final int[] DefaultMemoryPoolBufSizes = { 256, 4096, 16384, 66000 }; + private static final int[] DefaultMemoryPoolInitAlloc = { 20, 20, 5, 5 }; + private static final int[] DefaultMemoryPoolMaxAlloc = { 100, 50, 50, 50 }; + + // Memory pool packet size limits + + private static final int MemoryPoolMinimumPacketSize = 256; + private static final int MemoryPoolMaximumPacketSize = 128 * (int) MemorySize.KILOBYTE; + + // Memory pool allocation limits + + private static final int MemoryPoolMinimumAllocation = 5; + private static final int MemoryPoolMaximumAllocation = 500; + // Authentication manager private AuthenticationManager m_authenticationManager; @@ -411,7 +438,8 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl */ public void init() { - // check that all required properties have been set + // Check that all required properties have been set + if (m_authenticationManager == null) { throw new AlfrescoRuntimeException("Property 'authenticationManager' not set"); @@ -480,15 +508,20 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl try { + // Process the core server configuration + + config = m_configService.getConfig(ConfigCoreServer, configCtx); + processCoreServerConfig( config); + // Process the security configuration config = m_configService.getConfig(ConfigSecurity, configCtx); - processSecurityConfig(config); + processSecurityConfig( config); // Process the filesystems configuration config = m_configService.getConfig(ConfigFilesystems, configCtx); - processFilesystemsConfig(config); + processFilesystemsConfig( config); // Indicate that the filesystems were initialized @@ -1509,7 +1542,6 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl while (token.hasMoreTokens()) { - // Get the current debug flag token String dbg = token.nextToken().trim(); @@ -1534,6 +1566,20 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl cifsConfig.setSessionDebugFlags(sessDbg); } + + // Check if NIO based socket code should be disabled + + if ( config.getConfigElement( "disableNIO") != null) { + + // Disable NIO based code + + cifsConfig.setDisableNIOCode( true); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("NIO based code disabled for CIFS server"); + } } catch ( InvalidConfigurationException ex) { @@ -2387,6 +2433,257 @@ public class ServerConfigurationBean extends ServerConfiguration implements Appl } } + /** + * Process the core server configuration + * + * @param config Config + * @exception InvalidConfigurationException + */ + private final void processCoreServerConfig(Config config) + throws InvalidConfigurationException + { + // Create the core server configuration section + + CoreServerConfigSection coreConfig = new CoreServerConfigSection(this); + + // Check if the server core element has been specified + + if ( config == null) { + + // Configure a default memory pool + + coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + + // Configure a default thread pool size + + coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax); + return; + } + + // Check if the thread pool size has been specified + + ConfigElement elem = config.getConfigElement("threadPool"); + if ( elem != null) { + + // Get the initial thread pool size + + String initSizeStr = elem.getAttribute("init"); + if ( initSizeStr == null || initSizeStr.length() == 0) + throw new InvalidConfigurationException("Thread pool initial size not specified"); + + // Validate the initial thread pool size + + int initSize = 0; + + try { + initSize = Integer.parseInt( initSizeStr); + } + catch (NumberFormatException ex) { + throw new InvalidConfigurationException("Invalid thread pool size value, " + initSizeStr); + } + + // Range check the thread pool size + + if ( initSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size below minimum allowed size"); + + if ( initSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size above maximum allowed size"); + + // Get the maximum thread pool size + + String maxSizeStr = elem.getAttribute("max"); + int maxSize = initSize; + + if ( maxSizeStr.length() > 0) { + + // Validate the maximum thread pool size + + try { + maxSize = Integer.parseInt( maxSizeStr); + } + catch (NumberFormatException ex) { + throw new InvalidConfigurationException(" Invalid thread pool maximum size value, " + maxSizeStr); + } + + // Range check the maximum thread pool size + + if ( maxSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size"); + + if ( maxSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size"); + + if ( maxSize < initSize) + throw new InvalidConfigurationException("Initial size is larger than maxmimum size"); + } + else if ( maxSizeStr != null) + throw new InvalidConfigurationException("Thread pool maximum size not specified"); + + // Configure the thread pool + + coreConfig.setThreadPool( initSize, maxSize); + } + else { + + // Configure a default thread pool size + + coreConfig.setThreadPool( DefaultThreadPoolInit, DefaultThreadPoolMax); + } + + // Check if thread pool debug output is enabled + + if ( config.getConfigElement( "threadPoolDebug") != null) + coreConfig.getThreadPool().setDebug( true); + + // Check if the memory pool configuration has been specified + + elem = config.getConfigElement( "memoryPool"); + if ( elem != null) { + + // Check if the packet sizes/allocations have been specified + + ConfigElement pktElem = elem.getChild( "packetSizes"); + if ( pktElem != null) { + + // Calculate the array size for the packet size/allocation arrays + + int elemCnt = pktElem.getChildCount(); + + // Create the packet size, initial allocation and maximum allocation arrays + + int[] pktSizes = new int[elemCnt]; + int[] initSizes = new int[elemCnt]; + int[] maxSizes = new int[elemCnt]; + + int elemIdx = 0; + + // Process the packet size elements + + List pktSizeList = pktElem.getChildren(); + for ( int i = 0; i < pktSizeList.size(); i++) { + + // Get the current element + + ConfigElement curChild = pktSizeList.get( i); + if ( curChild.getName().equals( "packet")) { + + // Get the packet size + + int pktSize = -1; + int initAlloc = -1; + int maxAlloc = -1; + + String pktSizeStr = curChild.getAttribute("size"); + if ( pktSizeStr == null || pktSizeStr.length() == 0) + throw new InvalidConfigurationException("Memory pool packet size not specified"); + + // Parse the packet size + + try { + pktSize = MemorySize.getByteValueInt( pktSizeStr); + } + catch ( NumberFormatException ex) { + throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " + pktSizeStr); + } + + // Make sure the packet sizes have been specified in ascending order + + if ( elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize) + throw new InvalidConfigurationException("Invalid packet size specified, less than/equal to previous packet size"); + + // Get the initial allocation for the current packet size + + String initSizeStr = curChild.getAttribute("init"); + if ( initSizeStr == null || initSizeStr.length() == 0) + throw new InvalidConfigurationException("Memory pool initial allocation not specified"); + + // Parse the initial allocation + + try { + initAlloc = Integer.parseInt( initSizeStr); + } + catch (NumberFormatException ex) { + throw new InvalidConfigurationException("Invalid initial allocation, " + initSizeStr); + } + + // Range check the initial allocation + + if ( initAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " + MemoryPoolMinimumAllocation); + + if ( initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " + MemoryPoolMaximumAllocation); + + // Get the maximum allocation for the current packet size + + String maxSizeStr = curChild.getAttribute("max"); + if ( maxSizeStr == null || maxSizeStr.length() == 0) + throw new InvalidConfigurationException("Memory pool maximum allocation not specified"); + + // Parse the maximum allocation + + try { + maxAlloc = Integer.parseInt( maxSizeStr); + } + catch (NumberFormatException ex) { + throw new InvalidConfigurationException("Invalid maximum allocation, " + maxSizeStr); + } + + // Range check the maximum allocation + + if ( maxAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " + MemoryPoolMinimumAllocation); + + if ( initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " + MemoryPoolMaximumAllocation); + + // Set the current packet size elements + + pktSizes[elemIdx] = pktSize; + initSizes[elemIdx] = initAlloc; + maxSizes[elemIdx] = maxAlloc; + + elemIdx++; + } + } + + // Check if all elements were used in the packet size/allocation arrays + + if ( elemIdx < pktSizes.length) { + + // Re-allocate the packet size/allocation arrays + + int[] newPktSizes = new int[elemIdx]; + int[] newInitSizes = new int[elemIdx]; + int[] newMaxSizes = new int[elemIdx]; + + // Copy the values to the shorter arrays + + System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx); + System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx); + System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx); + + // Move the new arrays into place + + pktSizes = newPktSizes; + initSizes = newInitSizes; + maxSizes = newMaxSizes; + } + + // Configure the memory pool + + coreConfig.setMemoryPool( pktSizes, initSizes, maxSizes); + } + } + else { + + // Configure a default memory pool + + coreConfig.setMemoryPool( DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + } + } + /** * Process an access control sub-section and return the access control list * diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java index ce894910e6..c60208f906 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java @@ -95,7 +95,7 @@ public abstract class AlfrescoContext extends DiskDeviceContext { return FileSystem.TypeNTFS; } - + /** * Determine if the file state table is enabled * diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java index cf046dae31..d4b5fb14ea 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java @@ -54,6 +54,10 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst // Logging private static final Log logger = LogFactory.getLog(AlfrescoDiskDriver.class); + + // Transaction logging + + private static final Log txLogger = LogFactory.getLog( "org.alfresco.fileserver.transaction"); // Service registry for desktop actions @@ -180,9 +184,9 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst * End an active transaction * * @param sess SrvSession - * @param tx ThreadLocal + * @param tx Object */ - public void endTransaction(SrvSession sess, ThreadLocal tx) { + public void endTransaction(SrvSession sess, Object tx) { // Check that the transaction object is valid @@ -191,7 +195,7 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst // Get the filesystem transaction - FilesysTransaction filesysTx = (FilesysTransaction) tx.get(); + FilesysTransaction filesysTx = (FilesysTransaction) tx; // Check if there is an active transaction @@ -205,7 +209,9 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst { // Commit or rollback the transaction - if ( ftx.getStatus() == Status.STATUS_MARKED_ROLLBACK) + if ( ftx.getStatus() == Status.STATUS_MARKED_ROLLBACK || + ftx.getStatus() == Status.STATUS_ROLLEDBACK || + ftx.getStatus() == Status.STATUS_ROLLING_BACK) { // Transaction is marked for rollback @@ -218,7 +224,7 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst } else { - // Commit the transaction + // Commit the transaction ftx.commit(); @@ -230,19 +236,17 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst } catch ( Exception ex) { - throw new AlfrescoRuntimeException("Failed to end transaction", ex); + if ( logger.isDebugEnabled()) + logger.debug("Failed to end transaction, " + ex.getMessage()); +// throw new AlfrescoRuntimeException("Failed to end transaction", ex); } finally { // Clear the current transaction - filesysTx.clearTransaction(); + sess.clearTransaction(); } } - - // Clear the active transaction interface, leave the transaction object as we will reuse it - - sess.setTransaction( null); } /** @@ -272,7 +276,7 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst if ( filesysTx.hasTransaction()) { - // Get the active transaction + // Get the active transaction UserTransaction tx = filesysTx.getTransaction(); @@ -311,7 +315,7 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst { // Clear the active transaction - filesysTx.clearTransaction(); + sess.clearTransaction(); } } } @@ -322,7 +326,9 @@ public class AlfrescoDiskDriver implements IOCtlInterface, TransactionalFilesyst { try { - UserTransaction userTrans = m_transactionService.getUserTransaction(readOnly); + // Create a new transaction + + UserTransaction userTrans = m_transactionService.getUserTransaction(readOnly); userTrans.begin(); // Store the transaction diff --git a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java index fbe26428c3..0370446f1c 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/EnterpriseCifsAuthenticator.java @@ -46,6 +46,7 @@ import javax.transaction.UserTransaction; import org.alfresco.config.ConfigElement; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoClientInfo; +import org.alfresco.jlan.debug.Debug; import org.alfresco.jlan.server.auth.AuthenticatorException; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.auth.NTLanManAuthContext; @@ -64,6 +65,7 @@ import org.alfresco.jlan.server.auth.spnego.OID; import org.alfresco.jlan.server.auth.spnego.SPNEGO; import org.alfresco.jlan.server.config.InvalidConfigurationException; import org.alfresco.jlan.server.config.ServerConfiguration; +import org.alfresco.jlan.server.core.NoPooledMemoryException; import org.alfresco.jlan.smb.Capability; import org.alfresco.jlan.smb.SMBStatus; import org.alfresco.jlan.smb.dcerpc.UUID; @@ -502,10 +504,9 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement * * @param sess SMBSrvSession * @param reqPkt SMBSrvPacket - * @param respPkt SMBSrvPacket * @exception SMBSrvException */ - public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt) + public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt) throws SMBSrvException { // Check that the received packet looks like a valid NT session setup andX request @@ -528,7 +529,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement // Process the hashed password session setup - doHashedPasswordLogon( sess, reqPkt, respPkt); + doHashedPasswordLogon( sess, reqPkt); } catch ( Exception ex) { @@ -766,6 +767,10 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement int respLen = respBlob != null ? respBlob.length : 0; + // Use the original packet for the response + + SMBSrvPacket respPkt = reqPkt; + // Check if there is/was a session setup object stored in the session, this indicates a multi-stage session // setup so set the status code accordingly @@ -787,12 +792,41 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement loggedOn = true; } - respPkt.setParameterCount(4); - respPkt.setParameter(0, 0xFF); // No chained response - respPkt.setParameter(1, 0); // Offset to chained response - - respPkt.setParameter(2, 0); // Action - respPkt.setParameter(3, respLen); + // Set the parameter count then check if the security blob will fit into the current + // packet buffer + + respPkt.setParameterCount(4); + int reqLen = respLen + 100; // allow for strings + + if ( reqLen > respPkt.getAvailableLength()) { + + try { + + // Allocate a new buffer for the response + + respPkt = sess.getPacketPool().allocatePacket(respPkt.getByteOffset() + reqLen, reqPkt); + } + catch (NoPooledMemoryException ex) { + + // DEBUG + + if ( Debug.EnableDbg && hasDebug()) + Debug.println("Authenticator failed to allocate packet from pool, reqSiz=" + + (respPkt.getByteOffset() + respLen)); + + // Return a server error to the client + + throw new SMBSrvException(SMBStatus.NTInvalidParameter, SMBStatus.SRVNoBuffers, SMBStatus.ErrSrv); + } + } + + // Fill in the rest of the packet header + + respPkt.setParameter(0, 0xFF); // No chained response + respPkt.setParameter(1, 0); // Offset to chained response + + respPkt.setParameter(2, 0); // Action + respPkt.setParameter(3, respLen); } else { @@ -1970,10 +2004,9 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement * * @param sess SMBSrvSession * @param reqPkt SMBSrvPacket - * @param respPkt SMBSrvPacket * @exception SMBSrvException */ - private final void doHashedPasswordLogon( SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt) + private final void doHashedPasswordLogon( SMBSrvSession sess, SMBSrvPacket reqPkt) throws SMBSrvException { // Check that the received packet looks like a valid NT session setup andX request @@ -2159,30 +2192,30 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement // Build the session setup response SMB - respPkt.setParameterCount(3); - respPkt.setParameter(0, 0); // No chained response - respPkt.setParameter(1, 0); // Offset to chained response - respPkt.setParameter(2, isGuest ? 1 : 0); - respPkt.setByteCount(0); + reqPkt.setParameterCount(3); + reqPkt.setParameter(0, 0); // No chained response + reqPkt.setParameter(1, 0); // Offset to chained response + reqPkt.setParameter(2, isGuest ? 1 : 0); + reqPkt.setByteCount(0); - respPkt.setTreeId(0); - respPkt.setUserId(uid); + reqPkt.setTreeId(0); + reqPkt.setUserId(uid); // Set the various flags - int flags = respPkt.getFlags(); + int flags = reqPkt.getFlags(); flags &= ~SMBSrvPacket.FLG_CASELESS; - respPkt.setFlags(flags); + reqPkt.setFlags(flags); int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES; if (isUni) flags2 += SMBSrvPacket.FLG2_UNICODE; - respPkt.setFlags2(flags2); + reqPkt.setFlags2(flags2); // Pack the OS, dialect and domain name strings. - int pos = respPkt.getByteOffset(); - buf = respPkt.getBuffer(); + int pos = reqPkt.getByteOffset(); + buf = reqPkt.getBuffer(); if (isUni) pos = DataPacker.wordAlign(pos); @@ -2191,6 +2224,6 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement pos = DataPacker.putString("Alfresco CIFS Server " + sess.getServer().isVersion(), buf, pos, true, isUni); pos = DataPacker.putString(getCIFSConfig().getDomainName(), buf, pos, true, isUni); - respPkt.setByteCount(pos - respPkt.getByteOffset()); + reqPkt.setByteCount(pos - reqPkt.getByteOffset()); } } diff --git a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java index e047630b84..dbb796bf20 100644 --- a/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/cifs/PassthruCifsAuthenticator.java @@ -501,10 +501,9 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements * * @param sess SMBSrvSession * @param reqPkt SMBSrvPacket - * @param respPkt SMBSrvPacket * @exception SMBSrvException */ - public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt, SMBSrvPacket respPkt) + public void processSessionSetup(SMBSrvSession sess, SMBSrvPacket reqPkt) throws SMBSrvException { // Check that the received packet looks like a valid NT session setup andX request @@ -518,7 +517,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements { // Process the standard password session setup - super.processSessionSetup( sess, reqPkt, respPkt); + super.processSessionSetup( sess, reqPkt); return; } @@ -684,43 +683,43 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // required if ( sess.hasSetupObject( client.getProcessId())) - respPkt.setLongErrorCode( SMBStatus.NTMoreProcessingRequired); + reqPkt.setLongErrorCode( SMBStatus.NTMoreProcessingRequired); else { - respPkt.setLongErrorCode( SMBStatus.NTSuccess); + reqPkt.setLongErrorCode( SMBStatus.NTSuccess); // Indicate that the user is logged on loggedOn = true; } - respPkt.setParameterCount(4); - respPkt.setParameter(0, 0xFF); // No chained response - respPkt.setParameter(1, 0); // Offset to chained response + reqPkt.setParameterCount(4); + reqPkt.setParameter(0, 0xFF); // No chained response + reqPkt.setParameter(1, 0); // Offset to chained response - respPkt.setParameter(2, 0); // Action - respPkt.setParameter(3, respLen); + reqPkt.setParameter(2, 0); // Action + reqPkt.setParameter(3, respLen); } else { // Build a completed session setup response - respPkt.setLongErrorCode( SMBStatus.NTSuccess); + reqPkt.setLongErrorCode( SMBStatus.NTSuccess); // Build the session setup response SMB - respPkt.setParameterCount(12); - respPkt.setParameter(0, 0xFF); // No chained response - respPkt.setParameter(1, 0); // Offset to chained response + reqPkt.setParameterCount(12); + reqPkt.setParameter(0, 0xFF); // No chained response + reqPkt.setParameter(1, 0); // Offset to chained response - respPkt.setParameter(2, SMBSrvSession.DefaultBufferSize); - respPkt.setParameter(3, SMBSrvSession.NTMaxMultiplexed); - respPkt.setParameter(4, 0); // virtual circuit number - respPkt.setParameterLong(5, 0); // session key - respPkt.setParameter(7, respLen); + reqPkt.setParameter(2, SMBSrvSession.DefaultBufferSize); + reqPkt.setParameter(3, SMBSrvSession.NTMaxMultiplexed); + reqPkt.setParameter(4, 0); // virtual circuit number + reqPkt.setParameterLong(5, 0); // session key + reqPkt.setParameter(7, respLen); // security blob length - respPkt.setParameterLong(8, 0); // reserved - respPkt.setParameterLong(10, getServerCapabilities()); + reqPkt.setParameterLong(8, 0); // reserved + reqPkt.setParameterLong(10, getServerCapabilities()); // Indicate that the user is logged on @@ -763,27 +762,27 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements // Common session setup response - respPkt.setCommand( reqPkt.getCommand()); - respPkt.setByteCount(0); + reqPkt.setCommand( reqPkt.getCommand()); + reqPkt.setByteCount(0); - respPkt.setTreeId( 0); - respPkt.setUserId( uid); + reqPkt.setTreeId( 0); + reqPkt.setUserId( uid); // Set the various flags - int flags = respPkt.getFlags(); + int flags = reqPkt.getFlags(); flags &= ~SMBSrvPacket.FLG_CASELESS; - respPkt.setFlags(flags); + reqPkt.setFlags(flags); int flags2 = SMBSrvPacket.FLG2_LONGFILENAMES + SMBSrvPacket.FLG2_EXTENDEDSECURITY + SMBSrvPacket.FLG2_LONGERRORCODE; if ( isUni) flags2 += SMBSrvPacket.FLG2_UNICODE; - respPkt.setFlags2( flags2); + reqPkt.setFlags2( flags2); // Pack the security blob - int pos = respPkt.getByteOffset(); - buf = respPkt.getBuffer(); + int pos = reqPkt.getByteOffset(); + buf = reqPkt.getBuffer(); if ( respBlob != null) { @@ -800,7 +799,7 @@ public class PassthruCifsAuthenticator extends CifsAuthenticatorBase implements pos = DataPacker.putString("Alfresco CIFS Server " + sess.getServer().isVersion(), buf, pos, true, isUni); pos = DataPacker.putString(getCIFSConfig().getDomainName(), buf, pos, true, isUni); - respPkt.setByteCount(pos - respPkt.getByteOffset()); + reqPkt.setByteCount(pos - reqPkt.getByteOffset()); } /** diff --git a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java index 178bb1cabd..8b0da1ce8f 100644 --- a/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java +++ b/source/java/org/alfresco/filesys/auth/nfs/AlfrescoRpcAuthenticator.java @@ -94,8 +94,8 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator { int nameLen = rpc.unpackInt(); rpc.skipBytes(nameLen); - int gid = rpc.unpackInt(); int uid = rpc.unpackInt(); + int gid = rpc.unpackInt(); // DEBUG diff --git a/source/java/org/alfresco/filesys/repo/CifsHelper.java b/source/java/org/alfresco/filesys/repo/CifsHelper.java index 63536b13ea..8ed44a7d52 100644 --- a/source/java/org/alfresco/filesys/repo/CifsHelper.java +++ b/source/java/org/alfresco/filesys/repo/CifsHelper.java @@ -41,6 +41,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.MimetypeService; @@ -675,4 +676,20 @@ public class CifsHelper return fname; } + + /** + * Check if the folder node is empty + * + * @param folderNode NodeRef + * @return boolean + */ + public boolean isFolderEmpty( NodeRef folderNode) { + + // Check if the node has any child files/folders + + List files = fileFolderService.listFiles( folderNode); + if ( files == null || files.size() == 0) + return true; + return false; + } } diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index 28e64abc6c..7c183abda9 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java @@ -43,6 +43,7 @@ import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContextException; import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.jlan.server.filesys.AccessMode; +import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileAttribute; import org.alfresco.jlan.server.filesys.FileInfo; @@ -1462,7 +1463,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( ctx.hasStateTable()) { - FileState fstate = ctx.getStateTable().findFileState(path, false, true); + FileState fstate = ctx.getStateTable().findFileState(params.getPath(), false, true); if ( fstate != null) { // Indicate that the file is open @@ -1577,7 +1578,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( ctx.hasStateTable()) { - FileState fstate = ctx.getStateTable().findFileState(path, true, true); + FileState fstate = ctx.getStateTable().findFileState( params.getPath(), true, true); if ( fstate != null) { // Indicate that the file is open @@ -1647,17 +1648,28 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa try { - // get the node + // Get the node for the folder + NodeRef nodeRef = cifsHelper.getNodeRef(deviceRootNodeRef, dir); if (nodeService.exists(nodeRef)) { - nodeService.deleteNode(nodeRef); - - // Remove the file state - - if ( ctx.hasStateTable()) - ctx.getStateTable().removeFileState(dir); + // Check if the folder is empty + + if ( cifsHelper.isFolderEmpty( nodeRef) == true) { + + // Delete the folder node + + nodeService.deleteNode(nodeRef); + + // Remove the file state + + if ( ctx.hasStateTable()) + ctx.getStateTable().removeFileState(dir); + } + else + throw new DirectoryNotEmptyException( dir); } + // done if (logger.isDebugEnabled()) { @@ -1768,6 +1780,14 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( ctx.hasStateTable()) ctx.getStateTable().removeFileState(file.getFullName()); + + // Commit the current transaction + +// sess.endTransaction(); +// beginReadTransaction( sess); + + if ( nodeService.exists( nodeRef)) + System.out.println("Node still exists - " + file.getFullName()); } catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) { diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java index e18ec78be7..53f6487e22 100644 --- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java +++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java @@ -435,6 +435,10 @@ public class ContentNetworkFile extends NodeRefNetworkFile modified = true; + // Set the new file size + + setFileSize( size); + // DEBUG if (logger.isDebugEnabled()) @@ -465,6 +469,7 @@ public class ContentNetworkFile extends NodeRefNetworkFile // Set modification flag modified = true; + incrementWriteCount(); // Update the current file size diff --git a/source/java/org/alfresco/filesys/state/FileStateTable.java b/source/java/org/alfresco/filesys/state/FileStateTable.java index e0b98086fa..958a4c8b3a 100644 --- a/source/java/org/alfresco/filesys/state/FileStateTable.java +++ b/source/java/org/alfresco/filesys/state/FileStateTable.java @@ -159,6 +159,13 @@ public class FileStateTable state.setExpiryTime(System.currentTimeMillis() + getCacheTimer()); m_stateTable.put(state.getPath(), state); + + // DEBUG + + if ( logger.isDebugEnabled() && state.getPath().length() > 0 && state.getPath().indexOf("\\") == -1) { + logger.debug("*** File state path is not relative - " + state.getPath() + " ***"); + Thread.dumpStack(); + } } // Return the file state