Merge 3.2 to HEAD:

17443: Port fix for cannot delete file via CIFS that has a thumbnail associated with it. ETHREEOH-3143 and ETHREEOH-3115.
          Port fix for CIFS/Kerberos/SPNEGO logon problem with Win2008/Win7 client. ETHREEOH-3225.
   17444: Update svn:mergeinfo (Record-only)
   17512: Fix for no sites in AVM folder via CIFS/FTP when Kerberos auth enabled. ETHREEOH-3080.
   17849: Re-use open files for the same session/process id. Port of ETWOTWO-1250.
   17853: Rewrite the rename file logic to handle MS Office file rename patterns. Port of ETHREEOH-1951.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18269 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gary Spencer
2010-01-25 13:18:15 +00:00
parent 999609e17c
commit 9436fbb567
5 changed files with 427 additions and 265 deletions

View File

@@ -845,7 +845,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
boolean loggedOn = false; boolean loggedOn = false;
if ( useRawNTLMSSP() || isNTLMSSP == true || sess.hasSetupObject( client.getProcessId()) || setupObj != null) if ( respBlob != null || sess.hasSetupObject( client.getProcessId()) || setupObj != null)
{ {
// NTLMSSP has two stages, if there is a stored setup object then indicate more processing // NTLMSSP has two stages, if there is a stored setup object then indicate more processing
// required // required

View File

@@ -2434,7 +2434,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
webProjName = props.get( SandboxConstants.PROP_WEBSITE_NAME).getStringValue(); webProjName = props.get( SandboxConstants.PROP_WEBSITE_NAME).getStringValue();
// Get the user name from teh store name // Get the user name from the store name
userName = storeName.substring( webProjName.length() + 2); userName = storeName.substring( webProjName.length() + 2);
} }
@@ -2874,28 +2874,45 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
{ {
// Check if the pseudo folder is a web project folder or sandbox within a web project // Check if the pseudo folder is a web project folder or sandbox within a web project
String curUserName = m_authComponent.getCurrentUserName();
if ( pseudoFolder instanceof WebProjectStorePseudoFile) if ( pseudoFolder instanceof WebProjectStorePseudoFile)
{ {
// Check the users role within the web project // Check the users role within the web project
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) pseudoFolder; WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) pseudoFolder;
int role = webFolder.getUserRole( cInfo.getUserName()); int role = webFolder.getUserRole( curUserName);
if ( role == WebProjectStorePseudoFile.RoleNone) if ( role == WebProjectStorePseudoFile.RoleNone)
{ {
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("User " + curUserName + " has no access to web project, " + webFolder.getFileName());
// User does not have access to this web project // User does not have access to this web project
throw new AccessDeniedException("User " + cInfo.getUserName() + " has no access to web project, " + webFolder.getFileName()); throw new AccessDeniedException("User " + curUserName + " has no access to web project, " + webFolder.getFileName());
} }
else if ( avmCtx.allowAdminStagingWrites() && cInfo.isAdministrator()) else if ( avmCtx.allowAdminStagingWrites() && cInfo.isAdministrator())
{ {
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("User " + curUserName + " granted write access to web project, " + webFolder.getFileName());
// Allow admin write access // Allow admin write access
avmPath.setReadOnlyAccess( false); avmPath.setReadOnlyAccess( false);
} }
else else
{ {
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("User " + curUserName + " granted read-only access to web project, " + webFolder.getFileName());
// Only allow read-only access to the staging area // Only allow read-only access to the staging area
avmPath.setReadOnlyAccess( true); avmPath.setReadOnlyAccess( true);
@@ -2914,20 +2931,20 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) rootState.getPseudoFileList().findFile( storeFolder.getWebProject(), false); WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) rootState.getPseudoFileList().findFile( storeFolder.getWebProject(), false);
int role = webFolder.getUserRole( cInfo.getUserName()); int role = webFolder.getUserRole( curUserName);
if ( role == WebProjectStorePseudoFile.RoleNone) if ( role == WebProjectStorePseudoFile.RoleNone)
{ {
// User does not have access to this web project // User does not have access to this web project
throw new AccessDeniedException("User " + cInfo.getUserName() + " has no access to web project, " + webFolder.getFileName() + "/" + storeFolder.getFileName()); throw new AccessDeniedException("User " + curUserName + " has no access to web project, " + webFolder.getFileName() + "/" + storeFolder.getFileName());
} }
else if ( role == WebProjectStorePseudoFile.RolePublisher && else if ( role == WebProjectStorePseudoFile.RolePublisher &&
storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName()) == false) storeFolder.getUserName().equalsIgnoreCase( curUserName) == false)
{ {
// User does not have access to this web project // User does not have access to this web project
throw new AccessDeniedException("User " + cInfo.getUserName() + " has no access to web project, " + webFolder.getFileName() + "/" + storeFolder.getFileName()); throw new AccessDeniedException("User " + curUserName + " has no access to web project, " + webFolder.getFileName() + "/" + storeFolder.getFileName());
} }
} }
} }
@@ -2971,12 +2988,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
// Check for the admin user, no need to filter the list // Check for the admin user, no need to filter the list
PseudoFileList fullList = fstate.getPseudoFileList(); PseudoFileList fullList = fstate.getPseudoFileList();
if ( cInfo.getUserName().equalsIgnoreCase( m_authComponent.getSystemUserName())) if ( cInfo.isAdministrator())
return fullList; return fullList;
// Create a filtered list of store pseudo folders that the user has access to // Create a filtered list of store pseudo folders that the user has access to
PseudoFileList filterList = new PseudoFileList(); PseudoFileList filterList = new PseudoFileList();
String userName = m_authComponent.getCurrentUserName();
for ( int i = 0; i < fullList.numberOfFiles(); i++) for ( int i = 0; i < fullList.numberOfFiles(); i++)
{ {
@@ -2992,7 +3010,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) pseudoFolder; WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) pseudoFolder;
if ( avmCtx.showStagingStores() && webFolder.getUserRole( cInfo.getUserName()) != WebProjectStorePseudoFile.RoleNone) if ( avmCtx.showStagingStores() && webFolder.getUserRole( userName) != WebProjectStorePseudoFile.RoleNone)
{ {
// User has access to this store // User has access to this store
@@ -3015,7 +3033,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) fullList.findFile( storeFolder.getWebProject(), false); WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) fullList.findFile( storeFolder.getWebProject(), false);
if ( webFolder != null) { if ( webFolder != null) {
int role = webFolder.getUserRole( cInfo.getUserName()); int role = webFolder.getUserRole( userName);
if ( role == WebProjectStorePseudoFile.RoleContentManager && avmCtx.showStoreType( storeFolder.isStoreType())) if ( role == WebProjectStorePseudoFile.RoleContentManager && avmCtx.showStoreType( storeFolder.isStoreType()))
{ {
@@ -3027,7 +3045,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
{ {
// Allow access if the user owns the current folder // Allow access if the user owns the current folder
if ( storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName())) if ( storeFolder.getUserName().equalsIgnoreCase( userName))
filterList.addFile( storeFolder); filterList.addFile( storeFolder);
} }
} }

View File

@@ -79,7 +79,9 @@ import org.alfresco.service.cmr.lock.NodeLockedException;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -842,6 +844,14 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( fstate.hasModifyDateTime()) if ( fstate.hasModifyDateTime())
finfo.setModifyDateTime(fstate.getModifyDateTime()); finfo.setModifyDateTime(fstate.getModifyDateTime());
} }
else {
// Create a file state for the file/folder
fstate = ctx.getStateTable().findFileState( path, finfo.isDirectory(), true);
fstate.setNodeRef( nodeRef);
}
} }
// Return the file information // Return the file information
@@ -1581,8 +1591,57 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( linkRef == null) if ( linkRef == null)
{ {
// Create the network file // Check if the file is already opened by this client/process
if ( tree.openFileCount() > 1) {
// Search the open file table for this session/virtual circuit
int idx = 0;
while ( idx < tree.getFileTableLength() && netFile == null) {
// Get the current file from the open file table
NetworkFile curFile = tree.findFile( idx);
if ( curFile != null && curFile instanceof ContentNetworkFile) {
// Check if the file is the same path and process id
ContentNetworkFile contentFile = (ContentNetworkFile) curFile;
if ( contentFile.getProcessId() == params.getProcessId() &&
contentFile.getFullName().equalsIgnoreCase( params.getFullPath())) {
// Check that the access mode is the same
if (( params.isReadWriteAccess() && contentFile.getGrantedAccess() == NetworkFile.READWRITE) ||
( params.isReadOnlyAccess() && contentFile.getGrantedAccess() == NetworkFile.READONLY)) {
// Found a match, re-use the open file
netFile = contentFile;
// Increment the file open count, last file close will actually close the file/stream
contentFile.incrementOpenCount();
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Re-use existing file open Path " + params.getPath() + ", PID=" + params.getProcessId());
}
}
}
// Update the file table index
idx++;
}
}
// Create the network file, if we could not match an existing file open
if ( netFile == null)
netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params); netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params);
} }
else else
@@ -1780,6 +1839,10 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
netFile.setGrantedAccess(NetworkFile.READWRITE); netFile.setGrantedAccess(NetworkFile.READWRITE);
// Set the owner process id for this open file
netFile.setProcessId( params.getProcessId());
// Truncate the file so that the content stream is created // Truncate the file so that the content stream is created
netFile.truncateFile( 0L); netFile.truncateFile( 0L);
@@ -2121,6 +2184,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
ContentContext ctx = (ContentContext) tree.getContext(); ContentContext ctx = (ContentContext) tree.getContext();
if ( file instanceof ContentNetworkFile) {
// Decrement the file open count
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.decrementOpenCount() > 0) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Deferred file close, path=" + file.getFullName() + ", openCount=" + contentFile.getOpenCount());
// Defer the file close to the last reference
return;
}
}
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
{ {
FileState fstate = ctx.getStateTable().findFileState(file.getFullName()); FileState fstate = ctx.getStateTable().findFileState(file.getFullName());
@@ -2169,6 +2251,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
{ {
try try
{ {
boolean isVersionable = nodeService.hasAspect( nodeRef, ContentModel.ASPECT_VERSIONABLE);
try try
{ {
// Delete the file // Delete the file
@@ -2185,6 +2269,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
{ {
if ( isVersionable == true) {
// Get, or create, the file state // Get, or create, the file state
FileState fState = ctx.getStateTable().findFileState(file.getFullName(), false, true); FileState fState = ctx.getStateTable().findFileState(file.getFullName(), false, true);
@@ -2198,6 +2284,13 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
fState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout); fState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
fState.setNodeRef(nodeRef); fState.setNodeRef(nodeRef);
} }
else {
// Remove the file state
ctx.getStateTable().removeFileState( file.getFullName());
}
}
} }
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{ {
@@ -2257,15 +2350,35 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
NodeRef nodeRef = getNodeForPath(tree, name); NodeRef nodeRef = getNodeForPath(tree, name);
if (fileFolderService.exists(nodeRef)) if (fileFolderService.exists(nodeRef))
{ {
// Check if the node is versionable
boolean isVersionable = nodeService.hasAspect( nodeRef, ContentModel.ASPECT_VERSIONABLE);
fileFolderService.delete(nodeRef); fileFolderService.delete(nodeRef);
// Remove the file state // Remove the file state
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
{ {
// Check if the node is versionable, cache the node details for a short while
if ( isVersionable == true) {
// Make sure the file state is cached for a short while, a new file may be renamed to the same name
// in which case we can connect the file to the previous version history
FileState delState = ctx.getStateTable().findFileState( name, false, true);
delState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout);
delState.setFileStatus(FileStateStatus.DeleteOnClose);
delState.setNodeRef( nodeRef);
}
else {
// Remove the file state // Remove the file state
ctx.getStateTable().removeFileState(name); ctx.getStateTable().removeFileState( name);
}
// Update, or create, a parent folder file state // Update, or create, a parent folder file state
@@ -2344,6 +2457,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
ContentContext ctx = (ContentContext) tree.getContext(); ContentContext ctx = (ContentContext) tree.getContext();
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Rename oldName=" + oldName + ", newName=" + newName);
try try
{ {
// Get the file/folder to move // Get the file/folder to move
@@ -2369,67 +2487,81 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if ( splitPaths[0].equalsIgnoreCase( oldPaths[0])) if ( splitPaths[0].equalsIgnoreCase( oldPaths[0]))
sameFolder = true; sameFolder = true;
// Update the state table // Get the file state for the old file, if available
boolean relinked = false; FileState oldState = ctx.getStateTable().findFileState( oldName);
if ( ctx.hasStateTable())
// Check if we are renaming a folder, or the rename is to a different folder
boolean isFolder = cifsHelper.isDirectory( nodeToMoveRef);
if ( isFolder == true || sameFolder == false) {
// Update the old file state
if ( oldState != null)
{ {
// Check if the file rename can be relinked to a previous version // Update the file state index to use the new name
if ( !cifsHelper.isDirectory(nodeToMoveRef) ) ctx.getStateTable().renameFileState(newName, oldState);
{ }
// Check if there is a renamed or delete on close file state for the new file name
FileState renState = ctx.getStateTable().removeFileState(newName); // Rename or move the file/folder
if ( renState != null) if ( sameFolder == true)
{ cifsHelper.rename(nodeToMoveRef, name);
// Check if there is a renamed state for the new file else
cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
if ( renState.getFileStatus() == FileStateStatus.Renamed)
{
// Check if the renamed node still exists
if ( nodeService.exists( renState.getNodeRef()))
{
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Found rename state, relinking, " + renState); logger.debug(" Renamed " + (isFolder ? "folder" : "file") + " using " + (sameFolder ? "rename" : "move"));
// Relink the new version of the file data to the previously renamed node so that it
// picks up version history and other settings.
cifsHelper.relinkNode( renState.getNodeRef(), nodeToMoveRef, targetFolderRef, name);
relinked = true;
// Link the node ref for the associated rename state
if ( renState.hasRenameState())
renState.getRenameState().setNodeRef(nodeToMoveRef);
// Get, or create, a file state for the new file path
FileState fstate = ctx.getStateTable().findFileState(newName, false, true);
fstate.setNodeRef(renState.getNodeRef());
fstate.setFileStatus(FileStateStatus.FileExists);
} }
else {
// Remove the file state for the old file name // Rename a file within the same folder
//
// Check if the target file already exists
ctx.getStateTable().removeFileState(oldName); int newExists = fileExists( sess, tree, newName);
FileState newState = ctx.getStateTable().findFileState( newName, false, true);
NodeRef targetNodeRef = null;
boolean isFromVersionable = nodeService.hasAspect( nodeToMoveRef, ContentModel.ASPECT_VERSIONABLE);
if ( newExists == FileStatus.FileExists) {
// Use the existing file as the target node
targetNodeRef = getNodeForPath( tree, newName);
} }
else if ( renState.getFileStatus() == FileStateStatus.DeleteOnClose) else {
{
// Check if the target has a renamed or delete-on-close state
if ( newState.getFileStatus() == FileStateStatus.Renamed) {
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Found delete on close state, restore and relink, " + renState); logger.debug(" Using renamed node, " + newState);
// Use the renamed node as the target
targetNodeRef = newState.getNodeRef();
}
else if ( newState.getFileStatus() == FileStateStatus.DeleteOnClose) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Restoring delete-on-close node, " + newState);
// Restore the deleted node so we can relink the new version to the old history/properties // Restore the deleted node so we can relink the new version to the old history/properties
NodeRef archivedNode = getNodeArchiveService().getArchivedNode( renState.getNodeRef()); NodeRef archivedNode = getNodeArchiveService().getArchivedNode( newState.getNodeRef());
// DEBUG // DEBUG
@@ -2440,192 +2572,110 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
{ {
// Restore the node // Restore the node
NodeRef restoredNode = getNodeService().restoreNode( archivedNode, null, null, null); targetNodeRef = getNodeService().restoreNode( archivedNode, null, null, null);
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Restored node " + restoredNode); logger.debug(" Restored node " + targetNodeRef);
}
}
if ( restoredNode != null) // Check if the node being renamed is versionable
{
// Get the properties for the old and new nodes
org.alfresco.service.cmr.model.FileInfo restoredFileInfo = fileFolderService.getFileInfo(restoredNode); else if ( isFromVersionable == true) {
org.alfresco.service.cmr.model.FileInfo fileToMoveInfo = fileFolderService.getFileInfo(nodeToMoveRef);
// Swap the content between the temp and restored file // Create a new node for the target
ContentData oldContentData = restoredFileInfo.getContentData(); targetNodeRef = cifsHelper.createNode(ctx.getRootNode(), newName, true);
ContentData newContentData = fileToMoveInfo.getContentData();
nodeService.setProperty(restoredNode, ContentModel.PROP_CONTENT, newContentData);
nodeService.setProperty(nodeToMoveRef, ContentModel.PROP_CONTENT, oldContentData);
relinked = true;
// Delete the node that was being renamed
nodeService.deleteNode(nodeToMoveRef);
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Swapped content to restored node, delete " + oldName + ", nodeRef=" + nodeToMoveRef); logger.debug(" Created new node for " + newName);
// Link the node ref for the associated rename state
if ( renState.hasRenameState())
renState.getRenameState().setNodeRef(nodeToMoveRef);
//Fix for ETHREEOH-1951
//Set delete on close state for a short period to avoid loosing of version history
//if "always create a backup copy" option is enabled in MS Word.
FileState oldState = ctx.getStateTable().findFileState(oldName, false, true);
oldState.setNodeRef(nodeToMoveRef);
oldState.setFileStatus(FileStateStatus.DeleteOnClose);
oldState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
// Get, or create, a file state for the new file path
FileState fstate = ctx.getStateTable().findFileState(newName, false, true);
fstate.setNodeRef(restoredNode);
fstate.setFileStatus(FileStateStatus.FileExists);
}
}
}
}
}
else
{
// Get the file state for the folder, if available
FileState fstate = ctx.getStateTable().findFileState(oldName);
if ( fstate != null)
{
// Update the file state index to use the new name
ctx.getStateTable().renameFileState(newName, fstate);
}
}
}
// Move the file/folder, if not relinked to previous version history
if (!relinked)
{
// Move or rename the file/folder
if ( sameFolder == true)
{
// Check if the new file name is a temporary file name // Check if the new file name is a temporary file name
String newNameNorm = newName.toLowerCase(); String newNameNorm = newName.toLowerCase();
boolean isTempFile = false;
if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp") || newNameNorm.endsWith(".wbk")) { if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp")) {
// Add the temporary aspect, also prevents versioning // Add the temporary aspect, also prevents versioning
nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null); nodeService.addAspect(targetNodeRef, ContentModel.ASPECT_TEMPORARY, null);
// Indicate that the new file is a temporary file
isTempFile = true;
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Added Temporary aspect to renamed file " + newName); logger.debug(" Added Temporary aspect to renamed file " + newName);
} }
}
}
// If the original or target nodes are not versionable then just use a standard rename of the node
if ( isFromVersionable == false &&
( targetNodeRef == null || nodeService.hasAspect( targetNodeRef, ContentModel.ASPECT_VERSIONABLE) == false)) {
// Rename the file/folder // Rename the file/folder
cifsHelper.rename(nodeToMoveRef, name); cifsHelper.rename(nodeToMoveRef, name);
// Check if the temporary aspect should be removed from the renamed file // Remove the file state for the old file name
String oldNameNorm = oldName.toLowerCase(); ctx.getStateTable().renameFileState(newName, oldState);
if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp") || oldNameNorm.endsWith(".wbk"))) {
// Remove the temporary aspect
nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY);
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Removed Temporary aspect from renamed file " + newName); logger.debug(" User standard rename for " + name + "(versionable=" + isFromVersionable + ", targetNodeRef=" + targetNodeRef + ")");
} }
else {
// Make sure we have a valid target node
if ( targetNodeRef == null) {
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Renamed file: from=" + oldName + " to=" + newName); logger.debug(" No target node for rename");
}
else
{
// Move the file/folder
cifsHelper.move(nodeToMoveRef, targetFolderRef, name); // Throw an error
// DEBUG throw new AccessDeniedException( "No target node for file rename");
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Moved file: from=" + oldName + " to=" + newName);
} }
// Check if we renamed a file, if so then cache the rename details for a short period // Copy content data from the old file to the new file
// in case another file renamed to the old name. MS Word uses renames to move a new
// version of a document into place so we need to reconnect the version history.
if ( !cifsHelper.isDirectory(nodeToMoveRef) && sameFolder == true) copyContentData( sess, tree, nodeToMoveRef, targetNodeRef);
{
// Get or create a new file state for the old file path
FileState fstate = ctx.getStateTable().findFileState(oldName, false, true); // Mark the new file as existing
// Make sure the file state is cached for a short while, the file may not be open so the newState.setFileStatus( FileStatus.FileExists);
newState.setNodeRef( targetNodeRef);
// Delete the old file
nodeService.deleteNode( nodeToMoveRef);
// Make sure the old file state is cached for a short while, the file may not be open so the
// file state could be expired // file state could be expired
fstate.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout); oldState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout);
// Indicate that this is a renamed file state, set the node ref of the file that was renamed // Indicate that this is a deleted file state, set the node ref of the file that was renamed
fstate.setFileStatus(FileStateStatus.Renamed); oldState.setFileStatus(FileStateStatus.DeleteOnClose);
fstate.setNodeRef(nodeToMoveRef); oldState.setNodeRef(nodeToMoveRef);
// Get, or create, a file state for the new file path
FileState newState = ctx.getStateTable().findFileState(newName, false, true);
newState.setNodeRef(nodeToMoveRef);
newState.setFileStatus(FileStateStatus.FileExists);
// Link the renamed state to the new state
fstate.setRenameState(newState);
// DEBUG // DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) if ( logger.isDebugEnabled() && ctx.hasDebug( AlfrescoContext.DBG_RENAME))
{ logger.debug(" Cached delete state for " + oldName);
logger.debug("Cached rename state for " + oldName + ", state=" + fstate);
logger.debug(" new name " + newName + ", state=" + newState);
} }
} }
} }
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Moved node: from=" + oldName + " to=" + newName);
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{ {
// Debug // Debug
@@ -2721,15 +2771,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
throw new AccessDeniedException("Node locked, cannot mark for delete"); throw new AccessDeniedException("Node locked, cannot mark for delete");
} }
// Check if a folder is being marked for delete
// Get the node for the folder // Get the node for the folder
if (fileFolderService.exists(nodeRef)) if (fileFolderService.exists(nodeRef))
{ {
// Check if it is a folder that is being deleted, make sure it is empty
boolean isFolder = true;
if ( fstate != null)
isFolder = fstate.isDirectory();
else {
ContentFileInfo cInfo = cifsHelper.getFileInformation( nodeRef);
if ( cInfo != null && cInfo.isDirectory() == false)
isFolder = false;
}
// Check if the folder is empty // Check if the folder is empty
if ( cifsHelper.isFolderEmpty( nodeRef) == false) if ( isFolder == true && cifsHelper.isFolderEmpty( nodeRef) == false)
throw new DirectoryNotEmptyException( name); throw new DirectoryNotEmptyException( name);
} }
@@ -3134,4 +3194,32 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
ContentContext ctx = (ContentContext) tree.getContext(); ContentContext ctx = (ContentContext) tree.getContext();
return ctx.getDisableOplocks() ? false : true; return ctx.getDisableOplocks() ? false : true;
} }
/**
* Copy content data from file to file
*
* @param sess SrvSession
* @param tree TreeConnection
* @param fromNode NodeRef
* @param toNode NodeRef
* @exception IOException
*/
private void copyContentData( SrvSession sess, TreeConnection tree, NodeRef fromNode, NodeRef toNode)
throws IOException {
try {
// Open the input and output files
ContentReader fromReader = contentService.getReader( fromNode, ContentModel.PROP_CONTENT);
ContentWriter toWriter = contentService.getWriter( toNode, ContentModel.PROP_CONTENT, true);
// Copy the content
toWriter.putContent( fromReader);
}
catch ( Exception ex) {
throw new IOException("Failed to copy content");
}
}
} }

View File

@@ -38,6 +38,16 @@ public abstract class NodeRefNetworkFile extends AlfrescoNetworkFile {
protected NodeRef m_nodeRef; protected NodeRef m_nodeRef;
// Process id of the owner
protected int m_pid;
// Reference count of file opens
//
// The same file stream may be re-used if the same process/client opens it multiple times
private int m_openCount = 1;
/** /**
* Create a network file object with the specified file/directory name. * Create a network file object with the specified file/directory name.
* *
@@ -80,4 +90,49 @@ public abstract class NodeRefNetworkFile extends AlfrescoNetworkFile {
{ {
m_nodeRef = nodeRef; m_nodeRef = nodeRef;
} }
/**
* Return the process id of the owner
*
* @return int
*/
public final int getProcessId() {
return m_pid;
}
/**
* Set the owner process id
*
* @param pid int
*/
public final void setProcessId(int pid) {
m_pid = pid;
}
/**
* Increment the file open count
*
* @return int
*/
public synchronized final int incrementOpenCount() {
return ++m_openCount;
}
/**
* Decrement the file open count
*
* @return int
*/
public synchronized final int decrementOpenCount() {
return --m_openCount;
}
/**
* Return the open file count
*
* @return int
*/
public final int getOpenCount() {
return m_openCount;
}
} }

View File

@@ -56,6 +56,7 @@ public class FileState
public final static long NoTimeout = -1L; public final static long NoTimeout = -1L;
public final static long DefTimeout = 2 * 60000L; // 2 minutes public final static long DefTimeout = 2 * 60000L; // 2 minutes
public final static long RenameTimeout = 1 * 60000L; // 1 minute public final static long RenameTimeout = 1 * 60000L; // 1 minute
public final static long DeleteTimeout = 15000L; // 15 seconds
// File status // File status