mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -845,7 +845,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticatorBase implement
|
||||
|
||||
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
|
||||
// required
|
||||
|
@@ -2434,7 +2434,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
String curUserName = m_authComponent.getCurrentUserName();
|
||||
|
||||
if ( pseudoFolder instanceof WebProjectStorePseudoFile)
|
||||
{
|
||||
// Check the users role within the web project
|
||||
|
||||
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) pseudoFolder;
|
||||
|
||||
int role = webFolder.getUserRole( cInfo.getUserName());
|
||||
int role = webFolder.getUserRole( curUserName);
|
||||
|
||||
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
|
||||
|
||||
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())
|
||||
{
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("User " + curUserName + " granted write access to web project, " + webFolder.getFileName());
|
||||
|
||||
// Allow admin write access
|
||||
|
||||
avmPath.setReadOnlyAccess( false);
|
||||
}
|
||||
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
|
||||
|
||||
avmPath.setReadOnlyAccess( true);
|
||||
@@ -2914,20 +2931,20 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
|
||||
|
||||
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) rootState.getPseudoFileList().findFile( storeFolder.getWebProject(), false);
|
||||
|
||||
int role = webFolder.getUserRole( cInfo.getUserName());
|
||||
int role = webFolder.getUserRole( curUserName);
|
||||
|
||||
if ( role == WebProjectStorePseudoFile.RoleNone)
|
||||
{
|
||||
// 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 &&
|
||||
storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName()) == false)
|
||||
storeFolder.getUserName().equalsIgnoreCase( curUserName) == false)
|
||||
{
|
||||
// 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
|
||||
|
||||
PseudoFileList fullList = fstate.getPseudoFileList();
|
||||
if ( cInfo.getUserName().equalsIgnoreCase( m_authComponent.getSystemUserName()))
|
||||
if ( cInfo.isAdministrator())
|
||||
return fullList;
|
||||
|
||||
// Create a filtered list of store pseudo folders that the user has access to
|
||||
|
||||
PseudoFileList filterList = new PseudoFileList();
|
||||
String userName = m_authComponent.getCurrentUserName();
|
||||
|
||||
for ( int i = 0; i < fullList.numberOfFiles(); i++)
|
||||
{
|
||||
@@ -2992,7 +3010,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
|
||||
|
||||
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
|
||||
|
||||
@@ -3015,7 +3033,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
|
||||
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) fullList.findFile( storeFolder.getWebProject(), false);
|
||||
|
||||
if ( webFolder != null) {
|
||||
int role = webFolder.getUserRole( cInfo.getUserName());
|
||||
int role = webFolder.getUserRole( userName);
|
||||
|
||||
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
|
||||
|
||||
if ( storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName()))
|
||||
if ( storeFolder.getUserName().equalsIgnoreCase( userName))
|
||||
filterList.addFile( storeFolder);
|
||||
}
|
||||
}
|
||||
|
@@ -79,7 +79,9 @@ import org.alfresco.service.cmr.lock.NodeLockedException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
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.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@@ -842,6 +844,14 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
if ( fstate.hasModifyDateTime())
|
||||
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
|
||||
@@ -1581,8 +1591,57 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
@@ -1780,6 +1839,10 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
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
|
||||
|
||||
netFile.truncateFile( 0L);
|
||||
@@ -2121,6 +2184,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
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())
|
||||
{
|
||||
FileState fstate = ctx.getStateTable().findFileState(file.getFullName());
|
||||
@@ -2169,6 +2251,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean isVersionable = nodeService.hasAspect( nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
|
||||
try
|
||||
{
|
||||
// Delete the file
|
||||
@@ -2185,6 +2269,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
if ( ctx.hasStateTable())
|
||||
{
|
||||
if ( isVersionable == true) {
|
||||
|
||||
// Get, or create, the file state
|
||||
|
||||
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.setNodeRef(nodeRef);
|
||||
}
|
||||
else {
|
||||
|
||||
// Remove the file state
|
||||
|
||||
ctx.getStateTable().removeFileState( file.getFullName());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
|
||||
{
|
||||
@@ -2257,15 +2350,35 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
NodeRef nodeRef = getNodeForPath(tree, name);
|
||||
if (fileFolderService.exists(nodeRef))
|
||||
{
|
||||
// Check if the node is versionable
|
||||
|
||||
boolean isVersionable = nodeService.hasAspect( nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
|
||||
fileFolderService.delete(nodeRef);
|
||||
|
||||
// Remove the file state
|
||||
|
||||
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
|
||||
|
||||
ctx.getStateTable().removeFileState( name);
|
||||
}
|
||||
|
||||
// Update, or create, a parent folder file state
|
||||
|
||||
@@ -2344,6 +2457,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
ContentContext ctx = (ContentContext) tree.getContext();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
logger.debug("Rename oldName=" + oldName + ", newName=" + newName);
|
||||
|
||||
try
|
||||
{
|
||||
// Get the file/folder to move
|
||||
@@ -2369,67 +2487,81 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
if ( splitPaths[0].equalsIgnoreCase( oldPaths[0]))
|
||||
sameFolder = true;
|
||||
|
||||
// Update the state table
|
||||
// Get the file state for the old file, if available
|
||||
|
||||
boolean relinked = false;
|
||||
if ( ctx.hasStateTable())
|
||||
FileState oldState = ctx.getStateTable().findFileState( oldName);
|
||||
|
||||
// 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) )
|
||||
{
|
||||
// Check if there is a renamed or delete on close file state for the new file name
|
||||
ctx.getStateTable().renameFileState(newName, oldState);
|
||||
}
|
||||
|
||||
FileState renState = ctx.getStateTable().removeFileState(newName);
|
||||
// Rename or move the file/folder
|
||||
|
||||
if ( renState != null)
|
||||
{
|
||||
// Check if there is a renamed state for the new file
|
||||
if ( sameFolder == true)
|
||||
cifsHelper.rename(nodeToMoveRef, name);
|
||||
else
|
||||
cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
|
||||
|
||||
if ( renState.getFileStatus() == FileStateStatus.Renamed)
|
||||
{
|
||||
// Check if the renamed node still exists
|
||||
|
||||
if ( nodeService.exists( renState.getNodeRef()))
|
||||
{
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
logger.debug(" Found rename state, relinking, " + renState);
|
||||
|
||||
// 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);
|
||||
logger.debug(" Renamed " + (isFolder ? "folder" : "file") + " using " + (sameFolder ? "rename" : "move"));
|
||||
}
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
NodeRef archivedNode = getNodeArchiveService().getArchivedNode( renState.getNodeRef());
|
||||
NodeRef archivedNode = getNodeArchiveService().getArchivedNode( newState.getNodeRef());
|
||||
|
||||
// DEBUG
|
||||
|
||||
@@ -2440,192 +2572,110 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
{
|
||||
// Restore the node
|
||||
|
||||
NodeRef restoredNode = getNodeService().restoreNode( archivedNode, null, null, null);
|
||||
targetNodeRef = getNodeService().restoreNode( archivedNode, null, null, null);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
logger.debug(" Restored node " + restoredNode);
|
||||
logger.debug(" Restored node " + targetNodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
if ( restoredNode != null)
|
||||
{
|
||||
// Get the properties for the old and new nodes
|
||||
// Check if the node being renamed is versionable
|
||||
|
||||
org.alfresco.service.cmr.model.FileInfo restoredFileInfo = fileFolderService.getFileInfo(restoredNode);
|
||||
org.alfresco.service.cmr.model.FileInfo fileToMoveInfo = fileFolderService.getFileInfo(nodeToMoveRef);
|
||||
else if ( isFromVersionable == true) {
|
||||
|
||||
// Swap the content between the temp and restored file
|
||||
// Create a new node for the target
|
||||
|
||||
ContentData oldContentData = restoredFileInfo.getContentData();
|
||||
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);
|
||||
targetNodeRef = cifsHelper.createNode(ctx.getRootNode(), newName, true);
|
||||
|
||||
// DEBUG
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null);
|
||||
|
||||
// Indicate that the new file is a temporary file
|
||||
|
||||
isTempFile = true;
|
||||
nodeService.addAspect(targetNodeRef, ContentModel.ASPECT_TEMPORARY, null);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
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
|
||||
|
||||
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();
|
||||
|
||||
if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp") || oldNameNorm.endsWith(".wbk"))) {
|
||||
|
||||
// Remove the temporary aspect
|
||||
|
||||
nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY);
|
||||
ctx.getStateTable().renameFileState(newName, oldState);
|
||||
|
||||
// DEBUG
|
||||
|
||||
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
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
logger.debug("Renamed file: from=" + oldName + " to=" + newName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move the file/folder
|
||||
logger.debug(" No target node for rename");
|
||||
|
||||
cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
|
||||
// Throw an error
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
|
||||
logger.debug("Moved file: from=" + oldName + " to=" + newName);
|
||||
throw new AccessDeniedException( "No target node for file rename");
|
||||
}
|
||||
|
||||
// Check if we renamed a file, if so then cache the rename details for a short period
|
||||
// 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.
|
||||
// Copy content data from the old file to the new file
|
||||
|
||||
if ( !cifsHelper.isDirectory(nodeToMoveRef) && sameFolder == true)
|
||||
{
|
||||
// Get or create a new file state for the old file path
|
||||
copyContentData( sess, tree, nodeToMoveRef, targetNodeRef);
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
fstate.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);
|
||||
oldState.setFileStatus(FileStateStatus.DeleteOnClose);
|
||||
oldState.setNodeRef(nodeToMoveRef);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled() && ctx.hasDebug( AlfrescoContext.DBG_RENAME))
|
||||
{
|
||||
logger.debug("Cached rename state for " + oldName + ", state=" + fstate);
|
||||
logger.debug(" new name " + newName + ", state=" + newState);
|
||||
logger.debug(" Cached delete state for " + oldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Debug
|
||||
@@ -2721,15 +2771,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
throw new AccessDeniedException("Node locked, cannot mark for delete");
|
||||
}
|
||||
|
||||
// Check if a folder is being marked for delete
|
||||
|
||||
// Get the node for the folder
|
||||
|
||||
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
|
||||
|
||||
if ( cifsHelper.isFolderEmpty( nodeRef) == false)
|
||||
if ( isFolder == true && cifsHelper.isFolderEmpty( nodeRef) == false)
|
||||
throw new DirectoryNotEmptyException( name);
|
||||
}
|
||||
|
||||
@@ -3134,4 +3194,32 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
ContentContext ctx = (ContentContext) tree.getContext();
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,6 +38,16 @@ public abstract class NodeRefNetworkFile extends AlfrescoNetworkFile {
|
||||
|
||||
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.
|
||||
*
|
||||
@@ -80,4 +90,49 @@ public abstract class NodeRefNetworkFile extends AlfrescoNetworkFile {
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ public class FileState
|
||||
public final static long NoTimeout = -1L;
|
||||
public final static long DefTimeout = 2 * 60000L; // 2 minutes
|
||||
public final static long RenameTimeout = 1 * 60000L; // 1 minute
|
||||
public final static long DeleteTimeout = 15000L; // 15 seconds
|
||||
|
||||
// File status
|
||||
|
||||
|
Reference in New Issue
Block a user