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:
Gary Spencer
2007-01-29 10:46:01 +00:00
parent 01fb4eac8a
commit 60ba6773c5
18 changed files with 892 additions and 40 deletions

View File

@@ -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

View File

@@ -55,6 +55,10 @@ public class ContentContext extends AlfrescoContext
m_rootPath = rootPath;
m_rootNodeRef = rootNodeRef;
// Create the I/O control handler
setIOHandler( createIOHandler( null));
}
/**

View File

@@ -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;
@@ -253,6 +254,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
@@ -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
*

View File

@@ -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;
}
}

View File

@@ -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();
@@ -260,7 +274,7 @@ public class ContentIOControlHandler implements IOControlHandler
retBuffer = procRunAction(sess, tree, dataBuf, folderNode, netFile);
break;
// Unknown I/O control code
default:

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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;
}
}