Updates to repo filesystem to add support for NFS, plus various updates/fixes to NFS.

Removed synchronization from content network file methods, synchronization is done in the protocol layer.
Compacted content network file debug output.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4810 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gary Spencer
2007-01-12 15:04:47 +00:00
parent f011e13683
commit 1b7cfc8303
9 changed files with 371 additions and 159 deletions

View File

@@ -529,7 +529,7 @@ public abstract class SrvSession
tx.rollback(); tx.rollback();
} }
} }
catch ( SystemException ex) catch ( Exception ex)
{ {
} }

View File

@@ -28,6 +28,7 @@ import org.alfresco.filesys.server.oncrpc.Rpc;
import org.alfresco.filesys.server.oncrpc.RpcAuthenticationException; import org.alfresco.filesys.server.oncrpc.RpcAuthenticationException;
import org.alfresco.filesys.server.oncrpc.RpcAuthenticator; import org.alfresco.filesys.server.oncrpc.RpcAuthenticator;
import org.alfresco.filesys.server.oncrpc.RpcPacket; import org.alfresco.filesys.server.oncrpc.RpcPacket;
import org.alfresco.filesys.server.oncrpc.nfs.NFS;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -91,6 +92,14 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator {
if ( logger.isDebugEnabled()) if ( logger.isDebugEnabled())
logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid); logger.debug( "RpcAuth: Type=Unix uid=" + uid + ", gid=" + gid);
// Check that there is a user name mapping for the uid/gid
Integer idKey = new Integer((gid << 16) + uid);
String userName = m_idMap.get( idKey);
if ( userName == null)
throw new RpcAuthenticationException( NFS.StsAccess);
// Check if the Unix authentication session table is valid // Check if the Unix authentication session table is valid
sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid); sessKey = new Long((((long) rpc.getClientAddress().hashCode()) << 32) + (gid << 16) + uid);
@@ -142,7 +151,8 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator {
* @param rpc RpcPacket * @param rpc RpcPacket
* @return ClientInfo * @return ClientInfo
*/ */
public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc) { public ClientInfo getRpcClientInformation(Object sessKey, RpcPacket rpc)
{
// Create a client information object to hold the client details // Create a client information object to hold the client details
@@ -240,7 +250,7 @@ public class AlfrescoRpcAuthenticator implements RpcAuthenticator {
// Check the account type and setup the authentication context // Check the account type and setup the authentication context
if ( client == null || client.isNullSession() || client.hasAuthenticationToken() == false) if ( client == null || client.isNullSession())
{ {
// Clear the authentication, null user should not be allowed to do any service calls // Clear the authentication, null user should not be allowed to do any service calls

View File

@@ -579,7 +579,6 @@ public class ServerConfiguration extends AbstractLifecycleBean
// Create the configuration context // Create the configuration context
ConfigLookupContext configCtx = new ConfigLookupContext(ConfigArea); ConfigLookupContext configCtx = new ConfigLookupContext(ConfigArea);
configCtx.setIncludeGlobalSection( false);
// Set the platform type // Set the platform type

View File

@@ -1778,8 +1778,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Get the disk interface from the disk driver // Get the disk interface from the disk driver
DiskInterface disk = (DiskInterface) conn.getSharedDevice() DiskInterface disk = (DiskInterface) conn.getSharedDevice().getInterface();
.getInterface();
// Get the pre-operation state for the parent directory // Get the pre-operation state for the parent directory
@@ -1846,8 +1845,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
if (finfo.isDirectory()) if (finfo.isDirectory())
packDirectoryHandle(shareId, finfo.getFileId(), rpc); packDirectoryHandle(shareId, finfo.getFileId(), rpc);
else else
packFileHandle(shareId, getFileIdForHandle(handle), packFileHandle(shareId, getFileIdForHandle(handle), finfo.getFileId(), rpc);
finfo.getFileId(), rpc);
// Pack the file attributes // Pack the file attributes
@@ -1856,19 +1854,17 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Add a cache entry for the path // Add a cache entry for the path
ShareDetails details = m_shareDetails.findDetails(shareId); ShareDetails details = m_shareDetails.findDetails(shareId);
details.getFileIdCache().addPath(finfo.getFileId(), details.getFileIdCache().addPath(finfo.getFileId(), filePath);
filePath);
// Add a cache entry for the network file // Add a cache entry for the network file
sess.getFileCache().addFile(netFile, conn); sess.getFileCache().addFile(netFile, conn, sess);
// Pack the wcc data structure for the directory // Pack the wcc data structure for the directory
packPreOpAttr(sess, preInfo, rpc); packPreOpAttr(sess, preInfo, rpc);
FileInfo postInfo = disk.getFileInformation(sess, conn, FileInfo postInfo = disk.getFileInformation(sess, conn, path);
path);
packPostOpAttr(sess, postInfo, shareId, rpc); packPostOpAttr(sess, postInfo, shareId, rpc);
// DEBUG // DEBUG
@@ -1879,8 +1875,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Notify change listeners that a new file has been created // Notify change listeners that a new file has been created
DiskDeviceContext diskCtx = (DiskDeviceContext) conn DiskDeviceContext diskCtx = (DiskDeviceContext) conn.getContext();
.getContext();
if (diskCtx.hasChangeHandler()) if (diskCtx.hasChangeHandler())
diskCtx.getChangeHandler().notifyFileChanged( NotifyChange.ActionAdded, filePath); diskCtx.getChangeHandler().notifyFileChanged( NotifyChange.ActionAdded, filePath);
@@ -2320,14 +2315,13 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Add a cache entry for the network file // Add a cache entry for the network file
sess.getFileCache().addFile(netFile, conn); sess.getFileCache().addFile(netFile, conn, sess);
// Pack the wcc data structure for the directory // Pack the wcc data structure for the directory
packPreOpAttr(sess, preInfo, rpc); packPreOpAttr(sess, preInfo, rpc);
FileInfo postInfo = disk.getFileInformation(sess, conn, FileInfo postInfo = disk.getFileInformation(sess, conn, path);
path);
packPostOpAttr(sess, postInfo, shareId, rpc); packPostOpAttr(sess, postInfo, shareId, rpc);
// DEBUG // DEBUG
@@ -3036,7 +3030,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Generate the search path // Generate the search path
String searchPath = generatePath(path, "*.*"); String searchPath = generatePath(path, "*");
// DEBUG // DEBUG
@@ -4611,8 +4605,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
* @exception StaleHandleException * @exception StaleHandleException
* If the file id cannot be converted to a path * If the file id cannot be converted to a path
*/ */
protected final NetworkFile getNetworkFileForHandle(NFSSrvSession sess, protected final NetworkFile getNetworkFileForHandle(NFSSrvSession sess, byte[] handle, TreeConnection conn, boolean readOnly)
byte[] handle, TreeConnection conn, boolean readOnly)
throws BadHandleException, StaleHandleException { throws BadHandleException, StaleHandleException {
// Check if the handle is a file handle // Check if the handle is a file handle
@@ -4633,7 +4626,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Check the file cache, file may already be open // Check the file cache, file may already be open
file = fileCache.findFile(fileId); file = fileCache.findFile(fileId, sess);
if (file == null) { if (file == null) {
// Get the path for the file // Get the path for the file
@@ -4656,7 +4649,7 @@ public class NFSServer extends RpcNetworkServer implements RpcProcessor {
// Add the file to the active file cache // Add the file to the active file cache
if (file != null) if (file != null)
fileCache.addFile(file, conn); fileCache.addFile(file, conn, sess);
} }
catch (AccessDeniedException ex) { catch (AccessDeniedException ex) {
if (hasDebug()) if (hasDebug())

View File

@@ -133,7 +133,7 @@ public class NFSSrvSession extends SrvSession {
public final NetworkFileCache getFileCache() public final NetworkFileCache getFileCache()
{ {
if (m_fileCache == null) if (m_fileCache == null)
m_fileCache = new NetworkFileCache(getUniqueId()); m_fileCache = new NetworkFileCache(getUniqueId(), getNFSServer().getRpcAuthenticator());
return m_fileCache; return m_fileCache;
} }

View File

@@ -17,11 +17,12 @@
package org.alfresco.filesys.server.oncrpc.nfs; package org.alfresco.filesys.server.oncrpc.nfs;
import java.util.*; import java.util.*;
import java.io.*;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.filesys.DiskInterface; import org.alfresco.filesys.server.filesys.DiskInterface;
import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.filesys.server.filesys.NetworkFile;
import org.alfresco.filesys.server.filesys.TreeConnection; import org.alfresco.filesys.server.filesys.TreeConnection;
import org.alfresco.filesys.server.oncrpc.RpcAuthenticator;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -40,7 +41,7 @@ public class NetworkFileCache {
// Default file timeout // Default file timeout
public static final long DefaultFileTimeout = 5000L; // 5 seconds public static final long DefaultFileTimeout = 5000L; // 5 seconds
// Network file cache, key is the file id // Network file cache, key is the file id
@@ -50,6 +51,10 @@ public class NetworkFileCache {
private FileExpiry m_expiryThread; private FileExpiry m_expiryThread;
// RPC authenticator
private RpcAuthenticator m_rpcAuthenticator;
// File timeout // File timeout
private long m_fileTmo = DefaultFileTimeout; private long m_fileTmo = DefaultFileTimeout;
@@ -75,17 +80,22 @@ public class NetworkFileCache {
private long m_timeout; private long m_timeout;
// Session that last accessed the file
private SrvSession m_sess;
/** /**
* Class constructor * Class constructor
* *
* @param file * @param file NetworkFile
* NetworkFile * @param conn TreeConnection
* @param conn * @param sess SrvSession
* TreeConnection
*/ */
public FileEntry(NetworkFile file, TreeConnection conn) { public FileEntry(NetworkFile file, TreeConnection conn, SrvSession sess) {
m_file = file; m_file = file;
m_conn = conn; m_conn = conn;
setSession(sess);
updateTimeout(); updateTimeout();
} }
@@ -116,6 +126,16 @@ public class NetworkFileCache {
return m_conn; return m_conn;
} }
/**
* Get the session that last accessed the file
*
* @return SrvSession
*/
public final SrvSession getSession()
{
return m_sess;
}
/** /**
* Update the file timeout * Update the file timeout
*/ */
@@ -132,6 +152,16 @@ public class NetworkFileCache {
public final void updateTimeout(long tmo) { public final void updateTimeout(long tmo) {
m_timeout = tmo; m_timeout = tmo;
} }
/**
* Set the session that last accessed the file
*
* @param sess SrvSession
*/
public final void setSession( SrvSession sess)
{
m_sess = sess;
}
}; };
/** /**
@@ -242,22 +272,31 @@ public class NetworkFileCache {
try { try {
// Set the current user using the session that last accessed the file
if ( m_rpcAuthenticator != null)
m_rpcAuthenticator.setCurrentUser( fentry.getSession(), fentry.getSession().getClientInformation());
// Get the disk interface // Get the disk interface
DiskInterface disk = (DiskInterface) fentry DiskInterface disk = (DiskInterface) fentry.getConnection().getInterface();
.getConnection().getInterface();
// Close the file // Close the file
disk.closeFile(null, disk.closeFile( fentry.getSession(), fentry.getConnection(), netFile);
fentry.getConnection(), netFile);
} catch (IOException ex) { // Commit any transactions
fentry.getSession().endTransaction();
// DEBUG
if (logger.isDebugEnabled())
logger.debug("NFSFileExpiry: Closed file=" + fentry.getFile().getFullName() + ", fid=" + fileId);
}
catch (Exception ex) {
logger.error( "File expiry exception", ex);
} }
// DEBUG
if (logger.isDebugEnabled())
logger.debug("NFSFileExpiry: Closed file=" + fentry.getFile().getFullName() + ", fid=" + fileId);
} }
} }
} }
@@ -293,10 +332,10 @@ public class NetworkFileCache {
/** /**
* Class constructor * Class constructor
* *
* @param name * @param name String
* String * @param rpcAuth RpcAuthenticator
*/ */
public NetworkFileCache(String name) { public NetworkFileCache(String name, RpcAuthenticator rpcAuth) {
// Create the file cache // Create the file cache
@@ -305,6 +344,10 @@ public class NetworkFileCache {
// Start the file expiry thread // Start the file expiry thread
m_expiryThread = new FileExpiry(DefaultFileTimeout / 4, name); m_expiryThread = new FileExpiry(DefaultFileTimeout / 4, name);
// Set the RPC authenticator
m_rpcAuthenticator = rpcAuth;
} }
/** /**
@@ -319,16 +362,22 @@ public class NetworkFileCache {
/** /**
* Add a file to the cache * Add a file to the cache
* *
* @param file * @param file NetworkFile
* NetworkFile * @param conn TreeConnection
* @param conn * @param sess SrvSession
* TreeConnection
*/ */
public synchronized final void addFile(NetworkFile file, TreeConnection conn) { public synchronized final void addFile(NetworkFile file, TreeConnection conn, SrvSession sess) {
// Add the file id mapping
synchronized (m_fileCache) { synchronized (m_fileCache) {
m_fileCache.put(new Integer(file.getFileId()), new FileEntry(file, m_fileCache.put(new Integer(file.getFileId()), new FileEntry(file, conn, sess));
conn));
} }
// DEBUG
if ( logger.isDebugEnabled())
logger.debug("Added file " + file.getName() + ", fid=" + file.getFileId());
} }
/** /**
@@ -350,11 +399,11 @@ public class NetworkFileCache {
/** /**
* Find a file via the file id * Find a file via the file id
* *
* @param id * @param id int
* int * @param sess SrvSession
* @return NetworkFile * @return NetworkFile
*/ */
public synchronized final NetworkFile findFile(int id) { public synchronized final NetworkFile findFile(int id, SrvSession sess) {
// Create the search key // Create the search key
@@ -372,6 +421,8 @@ public class NetworkFileCache {
// Update the file timeout and return the file // Update the file timeout and return the file
fentry.updateTimeout(); fentry.updateTimeout();
fentry.setSession(sess);
return fentry.getFile(); return fentry.getFile();
} }

View File

@@ -26,6 +26,7 @@ import javax.transaction.UserTransaction;
import org.alfresco.config.ConfigElement; import org.alfresco.config.ConfigElement;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver; import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
import org.alfresco.filesys.avm.AVMNetworkFile;
import org.alfresco.filesys.server.SrvSession; import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.core.DeviceContext; import org.alfresco.filesys.server.core.DeviceContext;
import org.alfresco.filesys.server.core.DeviceContextException; import org.alfresco.filesys.server.core.DeviceContextException;
@@ -682,6 +683,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
} }
} }
// Set the file id for the file using the relative path
if ( finfo != null)
finfo.setFileId( path.hashCode());
// Return the file information // Return the file information
return finfo; return finfo;
@@ -748,13 +754,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// If the state table is available see if we can speed up the search using either cached // If the state table is available see if we can speed up the search using either cached
// file information or find the folder node to be searched without having to walk the path // file information or find the folder node to be searched without having to walk the path
String[] paths = null; String[] paths = FileName.splitPath(searchPath);
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
{ {
// See if the folder to be searched has a file state, we can avoid having to walk the path // See if the folder to be searched has a file state, we can avoid having to walk the path
paths = FileName.splitPath(searchPath);
if ( paths[0] != null && paths[0].length() > 1) if ( paths[0] != null && paths[0].length() > 1)
{ {
// Find the node ref for the folder being searched // Find the node ref for the folder being searched
@@ -842,7 +847,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
// Build the search context to store the results // Build the search context to store the results
SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList); SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
// Debug // Debug
@@ -1199,6 +1204,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params); NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
// Generate a file id for the file
if ( netFile != null)
netFile.setFileId( params.getPath().hashCode());
// Create a file state for the open file // Create a file state for the open file
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
@@ -1315,9 +1325,15 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true); NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true);
// create the network file // Create the network file
NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params); NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
// Generate a file id for the file
if ( netFile != null)
netFile.setFileId( params.getPath().hashCode());
// Add a file state for the new file/folder // Add a file state for the new file/folder
if ( ctx.hasStateTable()) if ( ctx.hasStateTable())
@@ -2027,6 +2043,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
if(file.isDirectory()) if(file.isDirectory())
throw new AccessDeniedException(); throw new AccessDeniedException();
// If the content channel is not open for the file then start a transaction
if ( file instanceof ContentNetworkFile)
{
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
sess.beginReadTransaction( transactionService);
}
// Read a block of data from the file // Read a block of data from the file
int count = file.readFile(buffer, size, bufferPosition, fileOffset); int count = file.readFile(buffer, size, bufferPosition, fileOffset);
@@ -2064,7 +2090,21 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
*/ */
public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException
{ {
throw new UnsupportedOperationException("Unsupported: " + file + " (seek)"); // Check if the file is a directory
if ( file.isDirectory())
throw new AccessDeniedException();
// If the content channel is not open for the file then start a transaction
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
sess.beginReadTransaction( transactionService);
// Set the file position
return file.seekFile(pos, typ);
} }
/** /**
@@ -2083,7 +2123,17 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file, public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file,
byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException
{ {
// Write to the file // If the content channel is not open for the file then start a transaction
if ( file instanceof ContentNetworkFile)
{
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
sess.beginWriteTransaction( transactionService);
}
// Write to the file
file.writeFile(buffer, size, bufferOffset, fileOffset); file.writeFile(buffer, size, bufferOffset, fileOffset);

View File

@@ -27,11 +27,10 @@ import org.alfresco.filesys.server.filesys.FileAttribute;
import org.alfresco.filesys.server.filesys.FileInfo; import org.alfresco.filesys.server.filesys.FileInfo;
import org.alfresco.filesys.server.filesys.FileOpenParams; import org.alfresco.filesys.server.filesys.FileOpenParams;
import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.filesys.server.filesys.NetworkFile;
import org.alfresco.filesys.smb.SeekType;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.cmr.repository.ContentAccessor; import org.alfresco.service.cmr.repository.ContentAccessor;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
@@ -59,11 +58,17 @@ public class ContentNetworkFile extends NetworkFile
private NodeService nodeService; private NodeService nodeService;
private ContentService contentService; private ContentService contentService;
private NodeRef nodeRef; private NodeRef nodeRef;
/** keeps track of the read/write access */
// File channel to file content
private FileChannel channel; private FileChannel channel;
/** the original content opened */
// File content
private ContentAccessor content; private ContentAccessor content;
/** keeps track of any writes */
// Indicate if file has been written to or truncated/resized
private boolean modified; private boolean modified;
// Flag to indicate if the file channel is writable // Flag to indicate if the file channel is writable
@@ -86,9 +91,12 @@ public class ContentNetworkFile extends NetworkFile
// Check write access // Check write access
// TODO: Check access writes and compare to write requirements // TODO: Check access writes and compare to write requirements
// create the file // Create the file
ContentNetworkFile netFile = new ContentNetworkFile(transactionService, nodeService, contentService, nodeRef, path); ContentNetworkFile netFile = new ContentNetworkFile(transactionService, nodeService, contentService, nodeRef, path);
// set relevant parameters
// Set relevant parameters
if (params.isReadOnlyAccess()) if (params.isReadOnlyAccess())
{ {
netFile.setGrantedAccess(NetworkFile.READONLY); netFile.setGrantedAccess(NetworkFile.READONLY);
@@ -98,7 +106,8 @@ public class ContentNetworkFile extends NetworkFile
netFile.setGrantedAccess(NetworkFile.READWRITE); netFile.setGrantedAccess(NetworkFile.READWRITE);
} }
// check the type // Check the type
FileInfo fileInfo; FileInfo fileInfo;
try try
{ {
@@ -108,6 +117,7 @@ public class ContentNetworkFile extends NetworkFile
{ {
throw new AlfrescoRuntimeException("File not found when creating network file: " + nodeRef, e); throw new AlfrescoRuntimeException("File not found when creating network file: " + nodeRef, e);
} }
if (fileInfo.isDirectory()) if (fileInfo.isDirectory())
{ {
netFile.setAttributes(FileAttribute.Directory); netFile.setAttributes(FileAttribute.Directory);
@@ -139,14 +149,13 @@ public class ContentNetworkFile extends NetworkFile
if ( netFile.isReadOnly()) if ( netFile.isReadOnly())
netFile.setGrantedAccess(NetworkFile.READONLY); netFile.setGrantedAccess(NetworkFile.READONLY);
// done // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ logger.debug("Create file node=" + nodeRef + ", param=" + params + ", netfile=" + netFile);
logger.debug("Created network file: \n" +
" node: " + nodeRef + "\n" + // Return the network file
" param: " + params + "\n" +
" netfile: " + netFile);
}
return netFile; return netFile;
} }
@@ -181,16 +190,19 @@ public class ContentNetworkFile extends NetworkFile
*/ */
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder(50); StringBuilder str = new StringBuilder();
sb.append("ContentNetworkFile:")
.append("[ node=").append(nodeRef) str.append( "[");
.append(", channel=").append(channel) str.append( nodeRef.getId());
.append(writableChannel ? "(Write)" : "(Read)") str.append( ",channel=");
.append(", writable=").append(isWritable()) str.append( channel);
.append(", content=").append(content) if ( channel != null)
.append(", modified=").append(modified) str.append( writableChannel ? "(Write)" : "(Read)");
.append("]"); if ( modified)
return sb.toString(); str.append( ",modified");
str.append( "]");
return str.toString();
} }
/** /**
@@ -211,7 +223,8 @@ public class ContentNetworkFile extends NetworkFile
*/ */
private boolean isWritable() private boolean isWritable()
{ {
// check that we are allowed to write // Check that we are allowed to write
int access = getGrantedAccess(); int access = getGrantedAccess();
return (access == NetworkFile.READWRITE || access == NetworkFile.WRITEONLY); return (access == NetworkFile.READWRITE || access == NetworkFile.WRITEONLY);
} }
@@ -241,8 +254,11 @@ public class ContentNetworkFile extends NetworkFile
* @see NetworkFile#WRITEONLY * @see NetworkFile#WRITEONLY
* @see NetworkFile#READWRITE * @see NetworkFile#READWRITE
*/ */
private synchronized void openContent(boolean write, boolean trunc) throws AccessDeniedException, AlfrescoRuntimeException private void openContent(boolean write, boolean trunc)
throws AccessDeniedException, AlfrescoRuntimeException
{ {
// Check if the file is a directory
if (isDirectory()) if (isDirectory())
{ {
throw new AlfrescoRuntimeException("Unable to open channel for a directory network file: " + this); throw new AlfrescoRuntimeException("Unable to open channel for a directory network file: " + this);
@@ -271,11 +287,13 @@ public class ContentNetworkFile extends NetworkFile
} }
else if (channel != null) else if (channel != null)
{ {
// already have channel open // Already have channel open
return; return;
} }
// we need to create the channel // We need to create the channel
if (write && !isWritable()) if (write && !isWritable())
{ {
throw new AccessDeniedException("The network file was created for read-only: " + this); throw new AccessDeniedException("The network file was created for read-only: " + this);
@@ -284,6 +302,8 @@ public class ContentNetworkFile extends NetworkFile
content = null; content = null;
if (write) if (write)
{ {
// Get a writeable channel to the content
content = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, false); content = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, false);
// Indicate that we have a writable channel to the file // Indicate that we have a writable channel to the file
@@ -296,8 +316,12 @@ public class ContentNetworkFile extends NetworkFile
} }
else else
{ {
// Get a read-only channel to the content
content = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); content = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
// ensure that the content we are going to read is valid
// Ensure that the content we are going to read is valid
content = FileContentReader.getSafeContentReader( content = FileContentReader.getSafeContentReader(
(ContentReader) content, (ContentReader) content,
I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT), I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT),
@@ -307,7 +331,8 @@ public class ContentNetworkFile extends NetworkFile
writableChannel = false; writableChannel = false;
// get the read-only channel // Get the read-only channel
channel = ((ContentReader) content).getFileChannel(); channel = ((ContentReader) content).getFileChannel();
} }
} }
@@ -317,48 +342,44 @@ public class ContentNetworkFile extends NetworkFile
* *
* @exception IOException * @exception IOException
*/ */
public synchronized void closeFile() throws IOException public void closeFile()
throws IOException
{ {
if (isDirectory()) // ignore if this is a directory // Check if this is a directory
if (isDirectory())
{ {
// Nothing to do
return; return;
} }
else if (channel == null) // ignore if the channel hasn't been opened else if (channel == null)
{ {
// File was not read/written so channel was not opened
return; return;
} }
// Check if the file has been modified
if (modified) // file was modified if (modified)
{ {
// execute the close (with possible replication listeners, etc) and the // Close the channel
// node update in the same transaction. A transaction will be started
// by the nodeService anyway, so it is merely widening the transaction channel.close();
// boundaries. channel = null;
TransactionWork<Object> closeWork = new TransactionWork<Object>()
{ // Update node properties
public Object doWork() throws Exception
{ ContentData contentData = content.getContentData();
// close the channel nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, contentData);
// close it
channel.close();
channel = null;
// update node properties
ContentData contentData = content.getContentData();
nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, contentData);
// done
return null;
}
};
TransactionUtil.executeInUserTransaction(transactionService, closeWork);
} }
else else
{ {
// close it - it was not modified // Close it - it was not modified
channel.close(); channel.close();
channel = null; channel = null;
// no transaction used here. Any listener operations against this (now unused) content
// are irrelevant.
} }
} }
@@ -368,7 +389,8 @@ public class ContentNetworkFile extends NetworkFile
* @param size long * @param size long
* @exception IOException * @exception IOException
*/ */
public synchronized void truncateFile(long size) throws IOException public void truncateFile(long size)
throws IOException
{ {
// If the content data channel has not been opened yet and the requested size is zero // If the content data channel has not been opened yet and the requested size is zero
// then this is an open for overwrite so the existing content data is not copied // then this is an open for overwrite so the existing content data is not copied
@@ -394,14 +416,10 @@ public class ContentNetworkFile extends NetworkFile
modified = true; modified = true;
// Debug // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ logger.debug("Truncate file=" + this + ", size=" + size);
logger.debug("Truncated channel: " +
" net file: " + this + "\n" +
" size: " + size);
}
} }
/** /**
@@ -413,7 +431,8 @@ public class ContentNetworkFile extends NetworkFile
* @param fileOff long * @param fileOff long
* @exception IOException * @exception IOException
*/ */
public synchronized void writeFile(byte[] buffer, int length, int position, long fileOffset) throws IOException public void writeFile(byte[] buffer, int length, int position, long fileOffset)
throws IOException
{ {
// Open the channel for writing // Open the channel for writing
@@ -435,11 +454,7 @@ public class ContentNetworkFile extends NetworkFile
// DEBUG // DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ logger.debug("Write file=" + this + ", size=" + count);
logger.debug("Wrote to channel: " +
" net file: " + this + "\n" +
" written: " + count);
}
} }
/** /**
@@ -452,53 +467,119 @@ public class ContentNetworkFile extends NetworkFile
* @return Length of data read. * @return Length of data read.
* @exception IOException * @exception IOException
*/ */
public synchronized int readFile(byte[] buffer, int length, int position, long fileOffset) throws IOException public int readFile(byte[] buffer, int length, int position, long fileOffset)
throws IOException
{ {
// Open the channel for reading // Open the channel for reading
openContent(false, false); openContent(false, false);
// read from the channel // Read from the channel
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, position, length); ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, position, length);
int count = channel.read(byteBuffer, fileOffset); int count = channel.read(byteBuffer, fileOffset);
if (count < 0) if (count < 0)
{ {
count = 0; // doesn't obey the same rules, i.e. just returns the bytes read count = 0; // doesn't obey the same rules, i.e. just returns the bytes read
} }
// done
// DEBUG
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ logger.debug("Read file=" + this + " read=" + count);
logger.debug("Read from channel: " +
" net file: " + this + "\n" + // Return the actual count of bytes read
" read: " + count);
}
return count; return count;
} }
/**
* Open the file
*
* @param createFlag boolean
* @exception IOException
*/
@Override @Override
public synchronized void openFile(boolean createFlag) throws IOException public void openFile(boolean createFlag)
throws IOException
{ {
throw new UnsupportedOperationException(); // Wait for read/write before opening the content channel
} }
/**
* Seek to a new position in the file
*
* @param pos long
* @param typ int
* @return long
*/
@Override @Override
public synchronized long seekFile(long pos, int typ) throws IOException public long seekFile(long pos, int typ)
throws IOException
{ {
throw new UnsupportedOperationException(); // Open the file, if not already open
}
@Override openContent( false, false);
public synchronized void flushFile() throws IOException
{ // Check if the current file position is the required file position
// open the channel for writing
openContent(true, false); long curPos = channel.position();
// flush the channel - metadata flushing is not important
channel.force(false); switch (typ) {
// done
if (logger.isDebugEnabled()) // From start of file
{
logger.debug("Flushed channel: " + case SeekType.StartOfFile :
" net file: " + this); if (curPos != pos)
channel.position( pos);
break;
// From current position
case SeekType.CurrentPos :
channel.position( curPos + pos);
break;
// From end of file
case SeekType.EndOfFile :
{
long newPos = channel.size() + pos;
channel.position(newPos);
}
break;
} }
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Seek file=" + this + ", pos=" + pos + ", type=" + typ);
// Return the new file position
return channel.position();
}
/**
* Flush and buffered data for this file
*
* @exception IOException
*/
@Override
public void flushFile()
throws IOException
{
// Open the channel for writing
openContent(true, false);
// Flush the channel - metadata flushing is not important
channel.force(false);
// DEBUG
if (logger.isDebugEnabled())
logger.debug("Flush file=" + this);
} }
} }

View File

@@ -20,6 +20,7 @@ import java.io.FileNotFoundException;
import java.util.List; import java.util.List;
import org.alfresco.filesys.server.filesys.FileInfo; import org.alfresco.filesys.server.filesys.FileInfo;
import org.alfresco.filesys.server.filesys.FileName;
import org.alfresco.filesys.server.filesys.SearchContext; import org.alfresco.filesys.server.filesys.SearchContext;
import org.alfresco.filesys.server.pseudo.PseudoFile; import org.alfresco.filesys.server.pseudo.PseudoFile;
import org.alfresco.filesys.server.pseudo.PseudoFileList; import org.alfresco.filesys.server.pseudo.PseudoFileList;
@@ -51,6 +52,10 @@ public class ContentSearchContext extends SearchContext
private int resumeId; private int resumeId;
// Relative path being searched
private String m_relPath;
/** /**
* Class constructor * Class constructor
* *
@@ -58,18 +63,24 @@ public class ContentSearchContext extends SearchContext
* @param results List of file/folder nodes that match the search pattern * @param results List of file/folder nodes that match the search pattern
* @param searchStr Search path * @param searchStr Search path
* @param pseudoList List of pseudo files to be blended into the returned list of files * @param pseudoList List of pseudo files to be blended into the returned list of files
* @param relPath Relative path being searched
*/ */
protected ContentSearchContext( protected ContentSearchContext(
CifsHelper cifsHelper, CifsHelper cifsHelper,
List<NodeRef> results, List<NodeRef> results,
String searchStr, String searchStr,
PseudoFileList pseudoList) PseudoFileList pseudoList,
String relPath)
{ {
super(); super();
super.setSearchString(searchStr); super.setSearchString(searchStr);
this.cifsHelper = cifsHelper; this.cifsHelper = cifsHelper;
this.results = results; this.results = results;
this.pseudoList = pseudoList; this.pseudoList = pseudoList;
m_relPath = relPath;
if ( m_relPath != null && m_relPath.endsWith( FileName.DOS_SEPERATOR_STR) == false)
m_relPath = m_relPath + FileName.DOS_SEPERATOR_STR;
} }
/** /**
@@ -147,6 +158,16 @@ public class ContentSearchContext extends SearchContext
info.copyFrom( pinfo); info.copyFrom( pinfo);
// Generate a file id for the current file
if ( info != null && info.getFileId() == -1)
{
StringBuilder pathStr = new StringBuilder( m_relPath);
pathStr.append ( info.getFileName());
info.setFileId( pathStr.toString().hashCode());
}
// Check if we have finished with the pseudo file list, switch to the normal file list // Check if we have finished with the pseudo file list, switch to the normal file list
if ( index == (pseudoList.numberOfFiles() - 1)) if ( index == (pseudoList.numberOfFiles() - 1))
@@ -175,7 +196,14 @@ public class ContentSearchContext extends SearchContext
FileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, ""); FileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "");
info.copyFrom(nextInfo); info.copyFrom(nextInfo);
// Indicate that the file information is valid // Generate a file id for the current file
StringBuilder pathStr = new StringBuilder( m_relPath);
pathStr.append ( info.getFileName());
info.setFileId( pathStr.toString().hashCode());
// Indicate that the file information is valid
return true; return true;
} }