mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-16 17:55:15 +00:00
Added support for link nodes in the repo filesystem driver.
Includes a patch to update existing link node file extensions from .lnk to .url, as CIFS requires .url files to generate the file:// links. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4947 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
parent
01fb4eac8a
commit
60ba6773c5
@ -123,3 +123,8 @@ patch.wcmFolders.webprojects.result.exists=The Web Projects folder already exist
|
||||
patch.wcmFolders.webprojects.result.created=The Web Projects folder was successfully created: {0}
|
||||
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
|
||||
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
|
||||
|
||||
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
|
||||
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
|
||||
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
|
||||
patch.linkNodeExtension.rewritten=Name ''{0}'' rewritten to ''{1}''
|
||||
|
@ -61,6 +61,7 @@
|
||||
<property name="permissionService"><ref bean="permissionService"/></property>
|
||||
<property name="authenticationComponent"><ref bean="authenticationComponent"/></property>
|
||||
<property name="authenticationService"><ref bean="authenticationService"/></property>
|
||||
<property name="fileFolderService"><ref bean="FileFolderService" /></property>
|
||||
<property name="serviceRegistry"><ref bean="ServiceRegistry"/></property>
|
||||
<property name="stateReaper"><ref bean="fileStateReaper"/></property>
|
||||
</bean>
|
||||
|
@ -586,4 +586,19 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.LinkNodeFileExtension" class="org.alfresco.repo.admin.patch.impl.LinkNodeFileExtensionPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.LinkNodeFileExtension</value></property>
|
||||
<property name="description"><value>patch.invalidNameEnding.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>33</value></property>
|
||||
<property name="targetSchema"><value>34</value></property>
|
||||
<!-- helper beans -->
|
||||
<property name="sessionFactory">
|
||||
<ref bean="sessionFactory" />
|
||||
</property>
|
||||
<property name="nodeDaoService">
|
||||
<ref bean="nodeDaoService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@ -19,4 +19,4 @@ version.build=@build-number@
|
||||
|
||||
# Schema number
|
||||
|
||||
version.schema=33
|
||||
version.schema=34
|
||||
|
@ -334,6 +334,16 @@ public abstract class AlfrescoContext extends DiskDeviceContext
|
||||
*/
|
||||
protected abstract IOControlHandler createIOHandler( DiskInterface filesysDriver);
|
||||
|
||||
/**
|
||||
* Set the I/O control handler
|
||||
*
|
||||
* @param ioctlHandler IOControlHandler
|
||||
*/
|
||||
protected void setIOHandler( IOControlHandler ioctlHandler)
|
||||
{
|
||||
m_ioHandler = ioctlHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the filesystem context
|
||||
*/
|
||||
|
@ -29,7 +29,6 @@ import java.util.StringTokenizer;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.filesys.server.filesys.FileAttribute;
|
||||
import org.alfresco.filesys.server.filesys.FileExistsException;
|
||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||
import org.alfresco.filesys.server.filesys.FileName;
|
||||
import org.alfresco.filesys.util.WildCard;
|
||||
import org.alfresco.model.ContentModel;
|
||||
@ -175,14 +174,12 @@ public class CifsHelper
|
||||
* @return Returns the existing node reference
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public FileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
|
||||
public ContentFileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
|
||||
{
|
||||
// get the node being referenced
|
||||
NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
|
||||
|
||||
FileInfo fileInfo = getFileInformation(nodeRef);
|
||||
|
||||
return fileInfo;
|
||||
return getFileInformation(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,13 +193,14 @@ public class CifsHelper
|
||||
* @return Returns the file information pertinent to the node
|
||||
* @throws FileNotFoundException if the path refers to a non-existent file
|
||||
*/
|
||||
public FileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
|
||||
public ContentFileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
|
||||
{
|
||||
// get the file info
|
||||
org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
|
||||
|
||||
// retrieve required properties and create file info
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
ContentFileInfo fileInfo = new ContentFileInfo();
|
||||
fileInfo.setNodeRef(nodeRef);
|
||||
|
||||
// unset all attribute flags
|
||||
int fileAttributes = 0;
|
||||
@ -251,6 +249,11 @@ public class CifsHelper
|
||||
|
||||
fileInfo.setFileAttributes( attr);
|
||||
}
|
||||
|
||||
// Check if it is a link node
|
||||
|
||||
if ( fileFolderInfo.isLink())
|
||||
fileInfo.setLinkNodeRef( fileFolderInfo.getLinkNodeRef());
|
||||
}
|
||||
|
||||
// created
|
||||
|
@ -55,6 +55,10 @@ public class ContentContext extends AlfrescoContext
|
||||
m_rootPath = rootPath;
|
||||
|
||||
m_rootNodeRef = rootNodeRef;
|
||||
|
||||
// Create the I/O control handler
|
||||
|
||||
setIOHandler( createIOHandler( null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,6 @@ import javax.transaction.UserTransaction;
|
||||
import org.alfresco.config.ConfigElement;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
|
||||
import org.alfresco.filesys.avm.AVMNetworkFile;
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.core.DeviceContext;
|
||||
import org.alfresco.filesys.server.core.DeviceContextException;
|
||||
@ -56,6 +55,7 @@ import org.alfresco.filesys.util.WildCard;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.lock.NodeLockedException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
@ -101,6 +101,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
private SearchService searchService;
|
||||
private ContentService contentService;
|
||||
private PermissionService permissionService;
|
||||
private FileFolderService fileFolderService;
|
||||
|
||||
private AuthenticationComponent authComponent;
|
||||
private AuthenticationService authService;
|
||||
@ -254,6 +255,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file folder server
|
||||
*
|
||||
* @param fileService FileFolderService
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileService)
|
||||
{
|
||||
fileFolderService = fileService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and validate the parameter string and create a device context object for this instance
|
||||
* of the shared device. The same DeviceInterface implementation may be used for multiple
|
||||
@ -466,6 +477,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
context.enableStateTable( true, getStateReaper());
|
||||
|
||||
// Initialize the I/O control handler
|
||||
|
||||
if ( context.hasIOHandler())
|
||||
context.getIOHandler().initialize( this, context);
|
||||
|
||||
// Return the context for this shared filesystem
|
||||
|
||||
return context;
|
||||
@ -1200,9 +1216,53 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
}
|
||||
}
|
||||
|
||||
// Create the network file
|
||||
// Check if the node is a link node
|
||||
|
||||
NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
|
||||
NodeRef linkRef = (NodeRef) nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION);
|
||||
NetworkFile netFile = null;
|
||||
|
||||
if ( linkRef == null)
|
||||
{
|
||||
// Create the network file
|
||||
|
||||
netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the target node to a path, convert to URL format
|
||||
|
||||
String path = getPathForNode( tree, linkRef);
|
||||
path = path.replace( FileName.DOS_SEPERATOR, '/');
|
||||
|
||||
// Build the URL file data
|
||||
|
||||
StringBuilder urlStr = new StringBuilder();
|
||||
|
||||
urlStr.append("[InternetShortcut]\r\n");
|
||||
urlStr.append("URL=file://");
|
||||
urlStr.append( sess.getServer().getServerName());
|
||||
urlStr.append("/");
|
||||
urlStr.append( tree.getSharedDevice().getName());
|
||||
urlStr.append( path);
|
||||
urlStr.append("\r\n");
|
||||
|
||||
// Create the in memory pseudo file for the URL link
|
||||
|
||||
byte[] urlData = urlStr.toString().getBytes();
|
||||
|
||||
// Get the file information for the link node
|
||||
|
||||
FileInfo fInfo = cifsHelper.getFileInformation( nodeRef);
|
||||
|
||||
// Set the file size to the actual data length
|
||||
|
||||
fInfo.setFileSize( urlData.length);
|
||||
|
||||
// Create the network file using the in-memory file data
|
||||
|
||||
netFile = new LinkMemoryNetworkFile( fInfo.getFileName(), urlData, fInfo, nodeRef);
|
||||
netFile.setFullName( params.getPath());
|
||||
}
|
||||
|
||||
// Generate a file id for the file
|
||||
|
||||
@ -1619,12 +1679,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
|
||||
if (file.hasDeleteOnClose())
|
||||
{
|
||||
// Check if the file is a content file
|
||||
// Check if the file is a noderef based file
|
||||
|
||||
if ( file instanceof ContentNetworkFile)
|
||||
if ( file instanceof NodeRefNetworkFile)
|
||||
{
|
||||
ContentNetworkFile contentNetFile = (ContentNetworkFile) file;
|
||||
NodeRef nodeRef = contentNetFile.getNodeRef();
|
||||
NodeRefNetworkFile nodeNetFile = (NodeRefNetworkFile) file;
|
||||
NodeRef nodeRef = nodeNetFile.getNodeRef();
|
||||
|
||||
// We don't know how long the network file has had the reference, so check for existence
|
||||
|
||||
@ -1776,14 +1836,22 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
ContentContext ctx = (ContentContext) tree.getContext();
|
||||
|
||||
// Get the file/folder to move
|
||||
|
||||
NodeRef nodeToMoveRef = getNodeForPath(tree, oldName);
|
||||
|
||||
// Check if the node is a link node
|
||||
|
||||
if ( nodeToMoveRef != null && nodeService.getProperty(nodeToMoveRef, ContentModel.PROP_LINK_DESTINATION) != null)
|
||||
throw new AccessDeniedException("Cannot rename link nodes");
|
||||
|
||||
// Get the new target folder - it must be a folder
|
||||
|
||||
String[] splitPaths = FileName.splitPath(newName);
|
||||
NodeRef targetFolderRef = getNodeForPath(tree, splitPaths[0]);
|
||||
String name = splitPaths[1]; // the new file or folder name
|
||||
String name = splitPaths[1];
|
||||
|
||||
// Update the state table
|
||||
|
||||
boolean relinked = false;
|
||||
if ( ctx.hasStateTable())
|
||||
{
|
||||
@ -2195,6 +2263,44 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
||||
return cifsHelper.getNodeRef(ctx.getRootNode(), path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a node into a share relative path
|
||||
*
|
||||
* @param tree TreeConnection
|
||||
* @param nodeRef NodeRef
|
||||
* @return String
|
||||
* @exception FileNotFoundException
|
||||
*/
|
||||
public String getPathForNode( TreeConnection tree, NodeRef nodeRef)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
// Convert the target node to a path
|
||||
|
||||
ContentContext ctx = (ContentContext) tree.getContext();
|
||||
List<org.alfresco.service.cmr.model.FileInfo> linkPaths = null;
|
||||
|
||||
try {
|
||||
linkPaths = fileFolderService.getNamePath( ctx.getRootNode(), nodeRef);
|
||||
}
|
||||
catch ( org.alfresco.service.cmr.model.FileNotFoundException ex)
|
||||
{
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
// Build the share relative path to the node
|
||||
|
||||
StringBuilder pathStr = new StringBuilder();
|
||||
|
||||
for ( org.alfresco.service.cmr.model.FileInfo fInfo : linkPaths) {
|
||||
pathStr.append( FileName.DOS_SEPERATOR);
|
||||
pathStr.append( fInfo.getName());
|
||||
}
|
||||
|
||||
// Return the share relative path
|
||||
|
||||
return pathStr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file state for the specified path
|
||||
*
|
||||
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.smb.server.repo;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Content Disk Driver File Info Class
|
||||
*
|
||||
* <p>Adds fields for the file/folder NodeRef, and linked NodeRef for a link node.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class ContentFileInfo extends FileInfo {
|
||||
|
||||
// Version id
|
||||
|
||||
private static final long serialVersionUID = 2518699645372408663L;
|
||||
|
||||
// File/folder node
|
||||
|
||||
private NodeRef m_nodeRef;
|
||||
|
||||
// Linked node
|
||||
|
||||
private NodeRef m_linkRef;
|
||||
|
||||
/**
|
||||
* Return the file/folder node
|
||||
*
|
||||
* @return NodeRef
|
||||
*/
|
||||
public final NodeRef getNodeRef()
|
||||
{
|
||||
return m_nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a link node
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean isLinkNode()
|
||||
{
|
||||
return m_linkRef != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the link node, or null if this is not a link
|
||||
*
|
||||
* @return NodeRef
|
||||
*/
|
||||
public final NodeRef getLinkNodeRef()
|
||||
{
|
||||
return m_linkRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node for this file/folder
|
||||
*
|
||||
* @param node NodeRef
|
||||
*/
|
||||
public final void setNodeRef(NodeRef node)
|
||||
{
|
||||
m_nodeRef = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the link node
|
||||
*
|
||||
* @param link NodeRef
|
||||
*/
|
||||
public final void setLinkNodeRef(NodeRef link)
|
||||
{
|
||||
m_linkRef = link;
|
||||
}
|
||||
}
|
@ -175,6 +175,20 @@ public class ContentIOControlHandler implements IOControlHandler
|
||||
int devType = NTIOCtl.getDeviceType(ctrlCode);
|
||||
int ioFunc = NTIOCtl.getFunctionCode(ctrlCode);
|
||||
|
||||
// Check for I/O controls that require a success status
|
||||
|
||||
if ( devType == NTIOCtl.DeviceFileSystem)
|
||||
{
|
||||
// I/O control requests that require a success status
|
||||
//
|
||||
// Create or get object id
|
||||
|
||||
if ( ioFunc == NTIOCtl.FsCtlCreateOrGetObjectId)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the I/O control looks like a custom I/O control request
|
||||
|
||||
if ( devType != NTIOCtl.DeviceFileSystem || dataBuf == null)
|
||||
throw new IOControlNotImplementedException();
|
||||
|
||||
|
@ -50,14 +50,13 @@ import org.apache.commons.logging.LogFactory;
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class ContentNetworkFile extends NetworkFile
|
||||
public class ContentNetworkFile extends NodeRefNetworkFile
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(ContentNetworkFile.class);
|
||||
|
||||
private TransactionService transactionService;
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
private NodeRef nodeRef;
|
||||
|
||||
// File channel to file content
|
||||
|
||||
@ -175,12 +174,11 @@ public class ContentNetworkFile extends NetworkFile
|
||||
NodeRef nodeRef,
|
||||
String name)
|
||||
{
|
||||
super(name);
|
||||
super(name, nodeRef);
|
||||
setFullName(name);
|
||||
this.transactionService = transactionService;
|
||||
this.nodeService = nodeService;
|
||||
this.contentService = contentService;
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,7 +191,7 @@ public class ContentNetworkFile extends NetworkFile
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append( "[");
|
||||
str.append( nodeRef.getId());
|
||||
str.append( getNodeRef().getId());
|
||||
str.append( ",channel=");
|
||||
str.append( channel);
|
||||
if ( channel != null)
|
||||
@ -205,14 +203,6 @@ public class ContentNetworkFile extends NetworkFile
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the node reference representing this file
|
||||
*/
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if the channel should be writable
|
||||
*
|
||||
@ -304,7 +294,7 @@ public class ContentNetworkFile extends NetworkFile
|
||||
{
|
||||
// Get a writeable channel to the content
|
||||
|
||||
content = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, false);
|
||||
content = contentService.getWriter( getNodeRef(), ContentModel.PROP_CONTENT, false);
|
||||
|
||||
// Indicate that we have a writable channel to the file
|
||||
|
||||
@ -318,14 +308,14 @@ public class ContentNetworkFile extends NetworkFile
|
||||
{
|
||||
// Get a read-only channel to the content
|
||||
|
||||
content = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
||||
content = contentService.getReader( getNodeRef(), ContentModel.PROP_CONTENT);
|
||||
|
||||
// Ensure that the content we are going to read is valid
|
||||
|
||||
content = FileContentReader.getSafeContentReader(
|
||||
(ContentReader) content,
|
||||
I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT),
|
||||
nodeRef, content);
|
||||
getNodeRef(), content);
|
||||
|
||||
// Indicate that we only have a read-only channel to the data
|
||||
|
||||
@ -372,7 +362,7 @@ public class ContentNetworkFile extends NetworkFile
|
||||
// Update node properties
|
||||
|
||||
ContentData contentData = content.getContentData();
|
||||
nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, contentData);
|
||||
nodeService.setProperty( getNodeRef(), ContentModel.PROP_CONTENT, contentData);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ package org.alfresco.filesys.smb.server.repo;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.FileAttribute;
|
||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||
import org.alfresco.filesys.server.filesys.FileName;
|
||||
import org.alfresco.filesys.server.filesys.SearchContext;
|
||||
@ -37,8 +38,18 @@ import org.apache.commons.logging.LogFactory;
|
||||
*/
|
||||
public class ContentSearchContext extends SearchContext
|
||||
{
|
||||
// Debug logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ContentSearchContext.class);
|
||||
|
||||
// Constants
|
||||
//
|
||||
// Link file size, actual size will be set if/when the link is opened
|
||||
|
||||
public final static int LinkFileSize = 512;
|
||||
|
||||
// List of nodes returned from the folder search
|
||||
|
||||
private CifsHelper cifsHelper;
|
||||
private List<NodeRef> results;
|
||||
private int index = -1;
|
||||
@ -193,7 +204,7 @@ public class ContentSearchContext extends SearchContext
|
||||
{
|
||||
// Get the file information and copy across to the callers file info
|
||||
|
||||
FileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "");
|
||||
ContentFileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "");
|
||||
info.copyFrom(nextInfo);
|
||||
|
||||
// Generate a file id for the current file
|
||||
@ -203,6 +214,20 @@ public class ContentSearchContext extends SearchContext
|
||||
|
||||
info.setFileId( pathStr.toString().hashCode());
|
||||
|
||||
// Check if this is a link node
|
||||
|
||||
if ( nextInfo.isLinkNode())
|
||||
{
|
||||
// Set a dummy file size for the link data that will be generated if/when the file is opened
|
||||
|
||||
info.setFileSize( LinkFileSize);
|
||||
|
||||
// Make the link read-only
|
||||
|
||||
if ( info.isReadOnly() == false)
|
||||
info.setFileAttributes( info.getFileAttributes() + FileAttribute.ReadOnly);
|
||||
}
|
||||
|
||||
// Indicate that the file information is valid
|
||||
|
||||
return true;
|
||||
|
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
|
||||
package org.alfresco.filesys.smb.server.repo;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||
import org.alfresco.filesys.smb.SeekType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Link Node In Memory Network File Class
|
||||
*
|
||||
* <p>In memory network file implementation that uses a memory buffer for the file data.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class LinkMemoryNetworkFile extends NodeRefNetworkFile
|
||||
{
|
||||
// Current file position
|
||||
|
||||
private long m_filePos;
|
||||
|
||||
// File data
|
||||
|
||||
private byte[] m_data;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param name String
|
||||
* @param localPath String
|
||||
* @param finfo FileInfo
|
||||
* @param nodeRef NodeRef
|
||||
*/
|
||||
public LinkMemoryNetworkFile(String name, byte[] data, FileInfo finfo, NodeRef nodeRef)
|
||||
{
|
||||
super( name, nodeRef);
|
||||
|
||||
// Set the file data
|
||||
|
||||
m_data = data;
|
||||
if ( m_data == null)
|
||||
m_data = new byte[0];
|
||||
|
||||
// Set the file size
|
||||
|
||||
setFileSize( m_data.length);
|
||||
|
||||
// Set the creation and modification date/times
|
||||
|
||||
setModifyDate( finfo.getModifyDateTime());
|
||||
setCreationDate( finfo.getCreationDateTime());
|
||||
|
||||
// Set the file id and relative path
|
||||
|
||||
if ( finfo.getPath() != null)
|
||||
{
|
||||
setFileId( finfo.getPath().hashCode());
|
||||
setFullName( finfo.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the network file.
|
||||
*/
|
||||
public void closeFile() throws java.io.IOException
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current file position.
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public long currentPosition()
|
||||
{
|
||||
return m_filePos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the file.
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
public void flushFile() throws IOException
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the end of file has been reached.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isEndOfFile() throws java.io.IOException
|
||||
{
|
||||
// Check if we reached end of file
|
||||
|
||||
if ( m_filePos == m_data.length)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the file.
|
||||
*
|
||||
* @param createFlag boolean
|
||||
* @exception IOException
|
||||
*/
|
||||
public void openFile(boolean createFlag) throws java.io.IOException
|
||||
{
|
||||
// Indicate that the file is open
|
||||
|
||||
setClosed(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from the file.
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param len int
|
||||
* @param pos int
|
||||
* @param fileOff long
|
||||
* @return Length of data read.
|
||||
* @exception IOException
|
||||
*/
|
||||
public int readFile(byte[] buf, int len, int pos, long fileOff) throws java.io.IOException
|
||||
{
|
||||
// Check if the read is within the file data range
|
||||
|
||||
long fileLen = (long) m_data.length;
|
||||
|
||||
if ( fileOff >= fileLen)
|
||||
return 0;
|
||||
|
||||
// Calculate the actual read length
|
||||
|
||||
if (( fileOff + len) > fileLen)
|
||||
len = (int) ( fileLen - fileOff);
|
||||
|
||||
// Copy the data to the user buffer
|
||||
|
||||
System.arraycopy( m_data, (int) fileOff, buf, pos, len);
|
||||
|
||||
// Update the current file position
|
||||
|
||||
m_filePos = fileOff + len;
|
||||
|
||||
// Return the actual length of data read
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to the specified file position.
|
||||
*
|
||||
* @param pos long
|
||||
* @param typ int
|
||||
* @return long
|
||||
* @exception IOException
|
||||
*/
|
||||
public long seekFile(long pos, int typ) throws IOException
|
||||
{
|
||||
// Seek to the required file position
|
||||
|
||||
switch (typ)
|
||||
{
|
||||
// From start of file
|
||||
|
||||
case SeekType.StartOfFile:
|
||||
if (currentPosition() != pos)
|
||||
m_filePos = pos;
|
||||
break;
|
||||
|
||||
// From current position
|
||||
|
||||
case SeekType.CurrentPos:
|
||||
m_filePos += pos;
|
||||
break;
|
||||
|
||||
// From end of file
|
||||
|
||||
case SeekType.EndOfFile:
|
||||
m_filePos += pos;
|
||||
if ( m_filePos < 0)
|
||||
m_filePos = 0L;
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the new file position
|
||||
|
||||
return currentPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the file
|
||||
*
|
||||
* @param siz long
|
||||
* @exception IOException
|
||||
*/
|
||||
public void truncateFile(long siz) throws IOException
|
||||
{
|
||||
// Allow the truncate, do not alter the pseduo file data
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a block of data to the file.
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param len int
|
||||
* @exception IOException
|
||||
*/
|
||||
public void writeFile(byte[] buf, int len, int pos) throws java.io.IOException
|
||||
{
|
||||
// Allow the write, just do not do anything
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a block of data to the file.
|
||||
*
|
||||
* @param buf byte[]
|
||||
* @param len int
|
||||
* @param pos int
|
||||
* @param offset long
|
||||
* @exception IOException
|
||||
*/
|
||||
public void writeFile(byte[] buf, int len, int pos, long offset) throws java.io.IOException
|
||||
{
|
||||
// Allow the write, just do not do anything
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.smb.server.repo;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.NetworkFile;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* NodeRef Based Network File Class
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public abstract class NodeRefNetworkFile extends NetworkFile {
|
||||
|
||||
// Associated node ref
|
||||
|
||||
protected NodeRef m_nodeRef;
|
||||
|
||||
/**
|
||||
* Create a network file object with the specified file/directory name.
|
||||
*
|
||||
* @param name File name string.
|
||||
*/
|
||||
public NodeRefNetworkFile(String name)
|
||||
{
|
||||
super( name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a network file object with the specified file/directory name.
|
||||
*
|
||||
* @param name File name string.
|
||||
* @param node NodeRef
|
||||
*/
|
||||
public NodeRefNetworkFile(String name, NodeRef node)
|
||||
{
|
||||
super( name);
|
||||
|
||||
m_nodeRef = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node ref
|
||||
*
|
||||
* @return NodeRef
|
||||
*/
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return m_nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the node ref
|
||||
*
|
||||
* @param nodeRef NodeRef
|
||||
*/
|
||||
public void setNodeRef( NodeRef nodeRef)
|
||||
{
|
||||
m_nodeRef = nodeRef;
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.domain.hibernate.NodeImpl;
|
||||
import org.alfresco.repo.node.db.NodeDaoService;
|
||||
import org.alfresco.service.cmr.admin.PatchException;
|
||||
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||
|
||||
/**
|
||||
* Checks that all names do not end with ' ' or '.'
|
||||
*
|
||||
* @author David Caruana
|
||||
*/
|
||||
public class LinkNodeFileExtensionPatch extends AbstractPatch
|
||||
{
|
||||
private static final String MSG_SUCCESS = "patch.linkNodeExtension.result";
|
||||
private static final String MSG_REWRITTEN = "patch.linkNodeExtension.rewritten";
|
||||
private static final String ERR_UNABLE_TO_FIX = "patch.linkNodeExtension.err.unable_to_fix";
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
private NodeDaoService nodeDaoService;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
*/
|
||||
public LinkNodeFileExtensionPatch()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session factory
|
||||
*
|
||||
* @param sessionFactory SessionFactory
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory)
|
||||
{
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeDaoService The service that generates the CRC values
|
||||
*/
|
||||
public void setNodeDaoService(NodeDaoService nodeDaoService)
|
||||
{
|
||||
this.nodeDaoService = nodeDaoService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(sessionFactory, "sessionFactory");
|
||||
checkPropertyNotNull(nodeDaoService, "nodeDaoService");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
// Initialise the helper
|
||||
|
||||
HibernateHelper helper = new HibernateHelper();
|
||||
helper.setSessionFactory(sessionFactory);
|
||||
|
||||
try
|
||||
{
|
||||
// Fix the link node file names
|
||||
|
||||
return helper.fixNames();
|
||||
}
|
||||
finally
|
||||
{
|
||||
helper.closeWriter();
|
||||
}
|
||||
}
|
||||
|
||||
private class HibernateHelper extends HibernateDaoSupport
|
||||
{
|
||||
private File logFile;
|
||||
private FileChannel channel;
|
||||
|
||||
private HibernateHelper() throws IOException
|
||||
{
|
||||
// Open a log file
|
||||
|
||||
logFile = new File("./LinkNodeExtensionPatch.log");
|
||||
RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw");
|
||||
channel = outputFile.getChannel();
|
||||
|
||||
// Append to the end of the file
|
||||
|
||||
channel.position(channel.size());
|
||||
|
||||
writeLine("").writeLine("");
|
||||
writeLine("LinkNodeExtensionPatch executing on " + new Date());
|
||||
}
|
||||
|
||||
private HibernateHelper write(Object obj) throws IOException
|
||||
{
|
||||
channel.write(ByteBuffer.wrap(obj.toString().getBytes()));
|
||||
return this;
|
||||
}
|
||||
private HibernateHelper writeLine(Object obj) throws IOException
|
||||
{
|
||||
write(obj);
|
||||
write("\n");
|
||||
return this;
|
||||
}
|
||||
private void closeWriter()
|
||||
{
|
||||
try { channel.close(); } catch (Throwable e) {}
|
||||
}
|
||||
|
||||
public String fixNames() throws Exception
|
||||
{
|
||||
// Get the list of nodes to be updated
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
List<NodeImpl> nodes = getInvalidNames();
|
||||
|
||||
int updated = 0;
|
||||
for (NodeImpl node : nodes)
|
||||
{
|
||||
// Check that the node is a link node
|
||||
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
|
||||
if ( nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION) != null)
|
||||
{
|
||||
// Get the current file name
|
||||
|
||||
String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
||||
if (name != null && name.length() >= 4 && name.endsWith(".lnk"))
|
||||
{
|
||||
// Update the name string, replace '.lnk' with '.url'
|
||||
|
||||
String updatedName = name.substring(0, name.length() - 4) + ".url";
|
||||
|
||||
int idx = 0;
|
||||
boolean applied = false;
|
||||
while (!applied)
|
||||
{
|
||||
try
|
||||
{
|
||||
nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, updatedName);
|
||||
applied = true;
|
||||
}
|
||||
catch(DuplicateChildNodeNameException e)
|
||||
{
|
||||
idx++;
|
||||
if (idx > 10)
|
||||
{
|
||||
writeLine(I18NUtil.getMessage(ERR_UNABLE_TO_FIX, name, updatedName));
|
||||
throw new PatchException(ERR_UNABLE_TO_FIX, logFile);
|
||||
}
|
||||
updatedName += "_" + idx;
|
||||
}
|
||||
}
|
||||
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, name ,updatedName));
|
||||
updated++;
|
||||
getSession().flush();
|
||||
getSession().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile);
|
||||
return msg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<NodeImpl> getInvalidNames()
|
||||
{
|
||||
HibernateCallback callback = new HibernateCallback()
|
||||
{
|
||||
public Object doInHibernate(Session session)
|
||||
{
|
||||
Query query = session
|
||||
.createQuery(
|
||||
"select node from org.alfresco.repo.domain.hibernate.NodeImpl as node " +
|
||||
"join node.properties prop where " +
|
||||
" prop.stringValue like '%.lnk' ");
|
||||
return query.list();
|
||||
}
|
||||
};
|
||||
List<NodeImpl> results = (List<NodeImpl>) getHibernateTemplate().execute(callback);
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -68,7 +68,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
"./*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_ALL =
|
||||
@ -77,6 +78,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
"+(" +
|
||||
"TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " +
|
||||
"TYPE:\"" + ContentModel.TYPE_FOLDER + "\" " +
|
||||
"TYPE:\"" + ContentModel.TYPE_LINK + "\" " +
|
||||
")";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
@ -96,7 +98,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
".//*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||
|
||||
/** empty parameters */
|
||||
private static final QueryParameterDefinition[] PARAMS_ANY_NAME = new QueryParameterDefinition[1];
|
||||
@ -246,7 +249,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT))
|
||||
else if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT) ||
|
||||
dictionaryService.isSubClass(typeQName, ContentModel.TYPE_LINK))
|
||||
{
|
||||
// it is a regular file
|
||||
return false;
|
||||
|
@ -35,7 +35,9 @@ import org.alfresco.service.namespace.QName;
|
||||
public class FileInfoImpl implements FileInfo
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private NodeRef linkNodeRef;
|
||||
private boolean isFolder;
|
||||
private boolean isLink;
|
||||
private Map<QName, Serializable> properties;
|
||||
|
||||
/**
|
||||
@ -46,6 +48,14 @@ public class FileInfoImpl implements FileInfo
|
||||
this.nodeRef = nodeRef;
|
||||
this.isFolder = isFolder;
|
||||
this.properties = properties;
|
||||
|
||||
// Check if this is a link node
|
||||
|
||||
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
|
||||
{
|
||||
isLink = true;
|
||||
linkNodeRef = (NodeRef) properties.get( ContentModel.PROP_LINK_DESTINATION);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,8 +65,15 @@ public class FileInfoImpl implements FileInfo
|
||||
sb.append("FileInfo")
|
||||
.append("[name=").append(getName())
|
||||
.append(", isFolder=").append(isFolder)
|
||||
.append(", nodeRef=").append(nodeRef)
|
||||
.append("]");
|
||||
.append(", nodeRef=").append(nodeRef);
|
||||
|
||||
if ( isLink())
|
||||
{
|
||||
sb.append(", linkref=");
|
||||
sb.append(linkNodeRef);
|
||||
}
|
||||
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -70,6 +87,16 @@ public class FileInfoImpl implements FileInfo
|
||||
return isFolder;
|
||||
}
|
||||
|
||||
public boolean isLink()
|
||||
{
|
||||
return isLink;
|
||||
}
|
||||
|
||||
public NodeRef getLinkNodeRef()
|
||||
{
|
||||
return linkNodeRef;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return (String) properties.get(ContentModel.PROP_NAME);
|
||||
|
@ -43,6 +43,16 @@ public interface FileInfo
|
||||
*/
|
||||
public boolean isFolder();
|
||||
|
||||
/**
|
||||
* @return true if this instance represents a link to a node
|
||||
*/
|
||||
public boolean isLink();
|
||||
|
||||
/**
|
||||
* @return Return the reference to the node that this node is linked to
|
||||
*/
|
||||
public NodeRef getLinkNodeRef();
|
||||
|
||||
/**
|
||||
* @return Returns the name of the file or folder within the parent folder
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user