diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
index 073ff5dfda..7bac032105 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java
@@ -1,2671 +1,2671 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.filesys.repo;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.Date;
-import java.util.List;
-
-import javax.transaction.UserTransaction;
-
-import org.alfresco.config.ConfigElement;
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
-import org.alfresco.filesys.alfresco.AlfrescoNetworkFile;
-import org.alfresco.filesys.state.FileState;
-import org.alfresco.filesys.state.FileStateLockManager;
-import org.alfresco.filesys.state.FileState.FileStateStatus;
-import org.alfresco.jlan.server.SrvSession;
-import org.alfresco.jlan.server.core.DeviceContext;
-import org.alfresco.jlan.server.core.DeviceContextException;
-import org.alfresco.jlan.server.filesys.AccessDeniedException;
-import org.alfresco.jlan.server.filesys.AccessMode;
-import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException;
-import org.alfresco.jlan.server.filesys.DiskInterface;
-import org.alfresco.jlan.server.filesys.FileAttribute;
-import org.alfresco.jlan.server.filesys.FileInfo;
-import org.alfresco.jlan.server.filesys.FileName;
-import org.alfresco.jlan.server.filesys.FileOpenParams;
-import org.alfresco.jlan.server.filesys.FileSharingException;
-import org.alfresco.jlan.server.filesys.FileStatus;
-import org.alfresco.jlan.server.filesys.NetworkFile;
-import org.alfresco.jlan.server.filesys.SearchContext;
-import org.alfresco.jlan.server.filesys.TreeConnection;
-import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile;
-import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
-import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface;
-import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
-import org.alfresco.jlan.server.filesys.pseudo.PseudoNetworkFile;
-import org.alfresco.jlan.server.locking.FileLockingInterface;
-import org.alfresco.jlan.server.locking.LockManager;
-import org.alfresco.jlan.smb.SharingMode;
-import org.alfresco.jlan.smb.server.SMBServer;
-import org.alfresco.jlan.smb.server.SMBSrvSession;
-import org.alfresco.jlan.util.WildCard;
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.security.authentication.AuthenticationComponent;
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-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.MimetypeService;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.search.SearchService;
-import org.alfresco.service.cmr.security.AccessStatus;
-import org.alfresco.service.cmr.security.AuthenticationService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.namespace.NamespaceService;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Content repository filesystem driver class
- *
- * Provides a filesystem interface for various protocols such as SMB/CIFS and FTP.
- *
- * @author Derek Hulley
- */
-public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterface, FileLockingInterface
-{
- // Logging
-
- private static final Log logger = LogFactory.getLog(ContentDiskDriver.class);
-
- // Configuration key names
-
- private static final String KEY_STORE = "store";
- private static final String KEY_ROOT_PATH = "rootPath";
- private static final String KEY_RELATIVE_PATH = "relativePath";
-
- // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL
-
- private static final String TokenLocalName = "${localname}";
-
- // Services and helpers
-
- private CifsHelper cifsHelper;
- private NamespaceService namespaceService;
- private NodeService nodeService;
- private SearchService searchService;
- private ContentService contentService;
- private MimetypeService mimetypeService;
- private PermissionService permissionService;
- private FileFolderService fileFolderService;
-
- private AuthenticationComponent authComponent;
- private AuthenticationService authService;
-
- // Node monitor factory
-
- private NodeMonitorFactory m_nodeMonitorFactory;
-
- // Lock manager
-
- private static LockManager _lockManager = new FileStateLockManager();
-
- /**
- * Class constructor
- *
- * @param serviceRegistry to connect to the repository services
- */
- public ContentDiskDriver(CifsHelper cifsHelper)
- {
- this.cifsHelper = cifsHelper;
- }
-
- /**
- * Return the CIFS helper
- *
- * @return CifsHelper
- */
- public final CifsHelper getCifsHelper()
- {
- return this.cifsHelper;
- }
-
- /**
- * Return the authentication service
- *
- * @return AuthenticationService
- */
- public final AuthenticationService getAuthenticationService()
- {
- return authService;
- }
-
- /**
- * Return the authentication component
- *
- * @return AuthenticationComponent
- */
- public final AuthenticationComponent getAuthComponent() {
- return authComponent;
- }
-
- /**
- * Return the node service
- *
- * @return NodeService
- */
- public final NodeService getNodeService()
- {
- return this.nodeService;
- }
-
- /**
- * Return the content service
- *
- * @return ContentService
- */
- public final ContentService getContentService()
- {
- return this.contentService;
- }
-
- /**
- * Return the namespace service
- *
- * @return NamespaceService
- */
- public final NamespaceService getNamespaceService()
- {
- return this.namespaceService;
- }
-
- /**
- * Return the search service
- *
- * @return SearchService
- */
- public final SearchService getSearchService(){
- return this.searchService;
- }
-
- /**
- * Return the file folder service
- *
- * @return FileFolderService
- */
- public final FileFolderService getFileFolderService() {
- return this.fileFolderService;
- }
-
- /**
- * Return the permission service
- *
- * @return PermissionService
- */
- public final PermissionService getPermissionService() {
- return this.permissionService;
- }
-
- /**
- * @param contentService the content service
- */
- public void setContentService(ContentService contentService)
- {
- this.contentService = contentService;
- }
-
- /**
- * @param namespaceService the namespace service
- */
- public void setNamespaceService(NamespaceService namespaceService)
- {
- this.namespaceService = namespaceService;
- }
-
- /**
- * @param nodeService the node service
- */
- public void setNodeService(NodeService nodeService)
- {
- this.nodeService = nodeService;
- }
-
- /**
- * @param searchService the search service
- */
- public void setSearchService(SearchService searchService)
- {
- this.searchService = searchService;
- }
-
- /**
- * Set the permission service
- *
- * @param permissionService PermissionService
- */
- public void setPermissionService(PermissionService permissionService)
- {
- this.permissionService = permissionService;
- }
-
- /**
- * Set the authentication component
- *
- * @param authComponent AuthenticationComponent
- */
- public void setAuthenticationComponent(AuthenticationComponent authComponent)
- {
- this.authComponent = authComponent;
- }
-
- /**
- * Set the authentication service
- *
- * @param authService AuthenticationService
- */
- public void setAuthenticationService(AuthenticationService authService)
- {
- this.authService = authService;
- }
-
- /**
- * Set the file folder service
- *
- * @param fileService FileFolderService
- */
- public void setFileFolderService(FileFolderService fileService)
- {
- fileFolderService = fileService;
- }
-
- /**
- * @param mimetypeService service for helping with mimetypes and encoding
- */
- public void setMimetypeService(MimetypeService mimetypeService)
- {
- this.mimetypeService = mimetypeService;
- }
-
- /**
- * Set the node monitor factory
- *
- * @param nodeMonitorFactory NodeMonitorFactory
- */
- public void setNodeMonitorFactory(NodeMonitorFactory nodeMonitorFactory) {
- m_nodeMonitorFactory = nodeMonitorFactory;
- }
-
- /**
- * 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
- * shares.
- *
- * @param shareName String
- * @param args ConfigElement
- * @return DeviceContext
- * @exception DeviceContextException
- */
- public DeviceContext createContext(String shareName, ConfigElement cfg) throws DeviceContextException
- {
- // Wrap the initialization in a transaction
-
- UserTransaction tx = getTransactionService().getUserTransaction(true);
-
- ContentContext context = null;
-
- try
- {
- // Use the system user as the authenticated context for the filesystem initialization
-
- AuthenticationUtil.pushAuthentication();
- AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
-
- // Start the transaction
-
- if ( tx != null)
- tx.begin();
-
- // Get the store
-
- ConfigElement storeElement = cfg.getChild(KEY_STORE);
- if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0)
- {
- throw new DeviceContextException("Device missing init value: " + KEY_STORE);
- }
- String storeValue = storeElement.getValue();
- StoreRef storeRef = new StoreRef(storeValue);
-
- // Connect to the repo and ensure that the store exists
-
- if (! nodeService.exists(storeRef))
- {
- throw new DeviceContextException("Store not created prior to application startup: " + storeRef);
- }
- NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
-
- // Get the root path
-
- ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH);
- if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0)
- {
- throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH);
- }
- String rootPath = rootPathElement.getValue();
-
- // Find the root node for this device
-
- List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false);
-
- NodeRef rootNodeRef = null;
-
- if (nodeRefs.size() > 1)
- {
- throw new DeviceContextException("Multiple possible roots for device: \n" +
- " root path: " + rootPath + "\n" +
- " results: " + nodeRefs);
- }
- else if (nodeRefs.size() == 0)
- {
- // Nothing found
-
- throw new DeviceContextException("No root found for device: \n" +
- " root path: " + rootPath);
- }
- else
- {
- // We found a node
-
- rootNodeRef = nodeRefs.get(0);
- }
-
- // Check if a relative path has been specified
-
- ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH);
-
- if ( relativePathElement != null)
- {
- // Make sure the path is in CIFS format
-
- String relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR);
-
- // Find the node and validate that the relative path is to a folder
-
- NodeRef relPathNode = cifsHelper.getNodeRef( rootNodeRef, relPath);
- if ( cifsHelper.isDirectory( relPathNode) == false)
- throw new DeviceContextException("Relative path is not a folder, " + relativePathElement.getValue());
-
- // Use the relative path node as the root of the filesystem
-
- rootNodeRef = relPathNode;
- }
- else {
-
- // Make sure the default root node is a folder
-
- if ( cifsHelper.isDirectory( rootNodeRef) == false)
- throw new DeviceContextException("Root node is not a folder type node");
- }
-
- // Commit the transaction
-
- tx.commit();
- tx = null;
-
- // Create the context
-
- context = new ContentContext(shareName, storeValue, rootPath, rootNodeRef);
- }
- catch (Exception ex)
- {
- logger.error("Error during create context", ex);
- }
- finally
- {
- // Restore authentication context
-
- AuthenticationUtil.popAuthentication();
-
- // If there is an active transaction then roll it back
-
- if ( tx != null)
- {
- try
- {
- tx.rollback();
- }
- catch (Exception ex)
- {
- logger.warn("Failed to rollback transaction", ex);
- }
- }
- }
-
- // Check if URL link files are enabled
-
- ConfigElement urlFileElem = cfg.getChild( "urlFile");
- if ( urlFileElem != null)
- {
- // Get the pseudo file name and web prefix path
-
- ConfigElement pseudoName = urlFileElem.getChild( "filename");
- ConfigElement webPath = urlFileElem.getChild( "webpath");
-
- if ( pseudoName != null && webPath != null)
- {
- // Make sure the web prefix has a trailing slash
-
- String path = webPath.getValue();
- if ( path.endsWith("/") == false)
- path = path + "/";
-
- // URL file name must end with .url
-
- if ( pseudoName.getValue().endsWith(".url") == false)
- throw new DeviceContextException("URL link file must end with .url, " + pseudoName.getValue());
-
- // Check if the URL path name contains the local name token
-
- int pos = path.indexOf(TokenLocalName);
- if (pos != -1)
- {
-
- // Get the local server name
-
- String srvName = "localhost";
-
- try
- {
- srvName = InetAddress.getLocalHost().getHostName();
- }
- catch ( Exception ex)
- {
- }
-
- // Rebuild the host name substituting the token with the local server name
-
- StringBuilder hostStr = new StringBuilder();
-
- hostStr.append( path.substring(0, pos));
- hostStr.append(srvName);
-
- pos += TokenLocalName.length();
- if (pos < path.length())
- hostStr.append( path.substring(pos));
-
- path = hostStr.toString();
- }
-
- // Set the URL link file name and web path
-
- context.setURLFileName( pseudoName.getValue());
- context.setURLPrefix( path);
- }
- }
-
- // Check if locked files should be marked as offline
-
- ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
- if ( offlineFiles != null)
- {
- // Enable marking locked files as offline
-
- cifsHelper.setMarkLockedFilesAsOffline( true);
-
- // Logging
-
- logger.info("Locked files will be marked as offline");
- }
-
- // Enable file state caching
-
- context.enableStateTable( true, getStateReaper());
-
- // Initialize the I/O control handler
-
- if ( context.hasIOHandler())
- context.getIOHandler().initialize( this, context);
-
- // Install the node service monitor
-
- if ( cfg.getChild("disableNodeMonitor") == null && m_nodeMonitorFactory != null) {
-
- // Create the node monitor
-
- NodeMonitor nodeMonitor = m_nodeMonitorFactory.createNodeMonitor( this, context);
- context.setNodeMonitor( nodeMonitor);
- }
-
- // Return the context for this shared filesystem
-
- return context;
- }
-
- /**
- * Check if pseudo file support is enabled
- *
- * @param context ContentContext
- * @return boolean
- */
- public final boolean hasPseudoFileInterface(ContentContext context)
- {
- return context.hasPseudoFileInterface();
- }
-
- /**
- * Return the pseudo file support implementation
- *
- * @param context ContentContext
- * @return PseudoFileInterface
- */
- public final PseudoFileInterface getPseudoFileInterface(ContentContext context)
- {
- return context.getPseudoFileInterface();
- }
-
- /**
- * Determine if the disk device is read-only.
- *
- * @param sess Server session
- * @param ctx Device context
- * @return boolean
- * @exception java.io.IOException If an error occurs.
- */
- public boolean isReadOnly(SrvSession sess, DeviceContext ctx) throws IOException
- {
- if (cifsHelper.isReadOnly())
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Get the file information for the specified file.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param name File name/path that information is required for.
- * @return File information if valid, else null
- * @exception java.io.IOException The exception description.
- */
- public FileInfo getFileInformation(SrvSession session, TreeConnection tree, String path) throws IOException
- {
- // Start a transaction
-
- beginReadTransaction( session);
-
- // Get the device root
-
- ContentContext ctx = (ContentContext) tree.getContext();
- NodeRef infoParentNodeRef = ctx.getRootNode();
-
- if ( path == null || path.length() == 0)
- path = FileName.DOS_SEPERATOR_STR;
-
- String infoPath = path;
-
- try
- {
- // Check if the path is to a pseudo file
-
- FileInfo finfo = null;
-
- if ( hasPseudoFileInterface(ctx))
- {
- // Make sure the parent folder has a file state, and the path exists
-
- String[] paths = FileName.splitPath( path);
- FileState fstate = ctx.getStateTable().findFileState( paths[0]);
-
- if ( fstate == null)
- {
- NodeRef nodeRef = getNodeForPath(tree, paths[0]);
-
- if ( nodeRef != null)
- {
- // Get the file information for the node
-
- finfo = cifsHelper.getFileInformation(nodeRef);
- }
-
- // Create the file state
-
- fstate = ctx.getStateTable().findFileState( paths[0], true, true);
-
- fstate.setFileStatus( FileStatus.DirectoryExists);
- fstate.setNodeRef( nodeRef);
-
- // Add pseudo files to the folder
-
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added file state for pseudo files folder (getinfo) - " + paths[0]);
- }
- else if ( fstate.hasPseudoFiles() == false)
- {
- // Make sure the file state has the node ref
-
- if ( fstate.hasNodeRef() == false)
- {
- // Get the node for the folder path
-
- fstate.setNodeRef( getNodeForPath( tree, paths[0]));
- }
-
- // Add pseudo files for the parent folder
-
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
- }
-
-
- // Get the pseudo file
-
- PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( session, tree, path);
- if ( pfile != null)
- {
- // DEBUG
- if ( logger.isDebugEnabled())
- logger.debug("getInfo using pseudo file info for " + path);
-
- FileInfo pseudoFileInfo = pfile.getFileInfo();
- if (cifsHelper.isReadOnly())
- {
- int attr = pseudoFileInfo.getFileAttributes();
- if (( attr & FileAttribute.ReadOnly) == 0)
- {
- attr += FileAttribute.ReadOnly;
- pseudoFileInfo.setFileAttributes(attr);
- }
- }
- return pfile.getFileInfo();
- }
- }
-
- // Get the node ref for the path, chances are there is a file state in the cache
-
- NodeRef nodeRef = getNodeForPath(tree, infoPath);
-
- if ( nodeRef != null)
- {
- // Get the file information for the node
-
- finfo = cifsHelper.getFileInformation(nodeRef);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("getInfo using cached noderef for path " + path);
- }
-
- // If the required node was not in the state cache, the parent folder node might be
-
-
- if ( finfo == null)
- {
- String[] paths = FileName.splitPath( path);
-
- if ( paths[0] != null && paths[0].length() > 1)
- {
- // Find the node ref for the folder being searched
-
- nodeRef = getNodeForPath(tree, paths[0]);
-
- if ( nodeRef != null)
- {
- infoParentNodeRef = nodeRef;
- infoPath = paths[1];
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("getInfo using cached noderef for parent " + path);
- }
- }
-
- // Access the repository to get the file information
-
- finfo = cifsHelper.getFileInformation(infoParentNodeRef, infoPath);
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Getting file information: \n" +
- " path: " + path + "\n" +
- " file info: " + finfo);
- }
- }
-
- // Set the file id for the file using the relative path
-
- if ( finfo != null) {
-
- // Set the file id
-
- finfo.setFileId( path.hashCode());
-
- // Copy cached timestamps, if available
-
- FileState fstate = getStateForPath(tree, infoPath);
- if ( fstate != null) {
- if ( fstate.hasAccessDateTime())
- finfo.setAccessDateTime(fstate.getAccessDateTime());
- if ( fstate.hasChangeDateTime())
- finfo.setChangeDateTime(fstate.getChangeDateTime());
- if ( fstate.hasModifyDateTime())
- finfo.setModifyDateTime(fstate.getModifyDateTime());
- }
- }
-
- // Return the file information
-
- return finfo;
- }
- catch (FileNotFoundException e)
- {
- // Debug
-
- if (logger.isDebugEnabled())
- logger.debug("Getting file information - File not found: \n" +
- " path: " + path);
- throw e;
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Get file info - access denied, " + path);
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Get file information " + path);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Get file info error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Get file information " + path);
- }
- }
-
- /**
- * Start a new search on the filesystem using the specified searchPath that may contain
- * wildcards.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param searchPath File(s) to search for, may include wildcards.
- * @param attrib Attributes of the file(s) to search for, see class SMBFileAttribute.
- * @return SearchContext
- * @exception java.io.FileNotFoundException If the search could not be started.
- */
- public SearchContext startSearch(SrvSession sess, TreeConnection tree, String searchPath, int attributes) throws FileNotFoundException
- {
- try
- {
- // Access the device context
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- String searchFileSpec = searchPath;
- NodeRef searchRootNodeRef = ctx.getRootNode();
- FileState searchFolderState = null;
-
- // Create the transaction
-
- beginReadTransaction( sess);
-
- // 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
-
- String[] paths = FileName.splitPath(searchPath);
-
- if ( ctx.hasStateTable())
- {
- // See if the folder to be searched has a file state, we can avoid having to walk the path
-
- if ( paths[0] != null && paths[0].length() >= 1)
- {
- // Find the node ref for the folder being searched
-
- NodeRef nodeRef = getNodeForPath(tree, paths[0]);
-
- // Get the file state for the folder being searched
-
- searchFolderState = getStateForPath(tree, paths[0]);
- if ( searchFolderState == null)
- {
- // Create a file state for the folder
-
- searchFolderState = ctx.getStateTable().findFileState( paths[0], true, true);
- }
-
- // Make sure the associated node is set
-
- if ( searchFolderState.hasNodeRef() == false)
- {
- // Set the associated node for the folder
-
- searchFolderState.setNodeRef( nodeRef);
- }
-
- // Add pseudo files to the folder being searched
-
- if ( hasPseudoFileInterface(ctx))
- getPseudoFileInterface(ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
-
- // Set the search node and file spec
-
- if ( nodeRef != null)
- {
- searchRootNodeRef = nodeRef;
- searchFileSpec = paths[1];
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Search using cached noderef for path " + searchPath);
- }
- }
- }
-
- // Convert the all files wildcard
-
- if ( searchFileSpec.equals( "*.*"))
- searchFileSpec = "*";
-
- // Perform the search
-
- List results = cifsHelper.getNodeRefs(searchRootNodeRef, searchFileSpec);
-
- // Check if there are any pseudo files for the folder being searched, for CIFS only
-
- PseudoFileList pseudoList = null;
-
- if ( sess instanceof SMBSrvSession && searchFolderState != null && searchFolderState.hasPseudoFiles())
- {
- // If it is a wildcard search use all pseudo files
-
- if ( WildCard.containsWildcards(searchFileSpec))
- {
- // Get the list of pseudo files for the search path
-
- pseudoList = searchFolderState.getPseudoFileList();
-
- // Check if the wildcard is for all files or a subset
-
- if ( searchFileSpec.equals( "*") == false && pseudoList != null && pseudoList.numberOfFiles() > 0)
- {
- // Generate a subset of pseudo files that match the wildcard search pattern
-
- WildCard wildCard = new WildCard( searchFileSpec, false);
- PseudoFileList filterList = null;
-
- for ( int i = 0; i > pseudoList.numberOfFiles(); i++)
- {
- PseudoFile pseudoFile = pseudoList.getFileAt( i);
- if ( wildCard.matchesPattern( pseudoFile.getFileName()))
- {
- // Add the pseudo file to the filtered list
-
- if ( filterList == null)
- filterList = new PseudoFileList();
- filterList.addFile( pseudoFile);
- }
- }
-
- // Use the filtered pseudo file list, or null if there were no matches
-
- pseudoList = filterList;
- }
- }
- else if ( results == null || results.size() == 0)
- {
- // Check if the required file is in the pseudo file list
-
- String fname = paths[1];
-
- if ( fname != null)
- {
- // Search for a matching pseudo file
-
- PseudoFile pfile = searchFolderState.getPseudoFileList().findFile( fname, true);
- if ( pfile != null)
- {
- // Create a file list with the required file
-
- pseudoList = new PseudoFileList();
- pseudoList.addFile( pfile);
- }
- }
- }
- }
-
- // Build the search context to store the results
-
- SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
-
- // Debug
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Started search: \n" +
- " search path: " + searchPath + "\n" +
- " attributes: " + attributes);
- }
- return searchCtx;
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Start search - access denied, " + searchPath);
-
- // Convert to a file not found status
-
- throw new FileNotFoundException("Start search " + searchPath);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Start search", ex);
-
- // Convert to a file not found status
-
- throw new FileNotFoundException("Start search " + searchPath);
- }
- }
-
- /**
- * Check if the specified file exists, and whether it is a file or directory.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param name java.lang.String
- * @return int
- * @see FileStatus
- */
- public int fileExists(SrvSession sess, TreeConnection tree, String name)
- {
-
- int status = FileStatus.Unknown;
-
- try
- {
- // Check for a cached file state
-
- ContentContext ctx = (ContentContext) tree.getContext();
- FileState fstate = null;
-
- if ( ctx.hasStateTable())
- ctx.getStateTable().findFileState(name);
-
- if ( fstate != null)
- {
- FileStateStatus fsts = fstate.getFileStatus();
-
- if ( fsts == FileStateStatus.FileExists)
- status = FileStatus.FileExists;
- else if ( fsts == FileStateStatus.FolderExists)
- status = FileStatus.DirectoryExists;
- else if ( fsts == FileStateStatus.NotExist || fsts == FileStateStatus.Renamed)
- status = FileStatus.NotExist;
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Cache hit - fileExists() " + name + ", sts=" + status);
- }
- else
- {
- // Check if pseudo files are enabled
-
- if ( hasPseudoFileInterface(ctx))
- {
- // Check if the file name is a pseudo file name
-
- if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) {
-
- // Make sure the parent folder has a file state, and the path exists
-
- String[] paths = FileName.splitPath( name);
- fstate = ctx.getStateTable().findFileState( paths[0]);
-
- if ( fstate == null) {
-
- // Check if the path exists
-
- if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
- {
- // Create the file state
-
- fstate = ctx.getStateTable().findFileState( paths[0], true, true);
-
- fstate.setFileStatus( FileStatus.DirectoryExists);
-
- // Get the node for the folder path
-
- beginReadTransaction( sess);
- fstate.setNodeRef( getNodeForPath( tree, paths[0]));
-
- // Add pseudo files to the folder
-
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added file state for pseudo files folder (exists) - " + paths[0]);
- }
- }
- else if ( fstate.hasPseudoFiles() == false)
- {
- // Make sure the file state has the node ref
-
- if ( fstate.hasNodeRef() == false)
- {
- // Create the transaction
-
- beginReadTransaction( sess);
-
- // Get the node for the folder path
-
- fstate.setNodeRef( getNodeForPath( tree, paths[0]));
- }
-
- // Add pseudo files for the parent folder
-
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
- }
-
- // Check if the path is to a pseudo file
-
- PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name);
- if ( pfile != null)
- {
- // Indicate that the file exists
-
- status = FileStatus.FileExists;
- }
- else
- {
- // Failed to find pseudo file
-
- if ( logger.isDebugEnabled())
- logger.debug( "Failed to find pseudo file (exists) - " + name);
- }
- }
- }
-
- // If the file is not a pseudo file then search for the file
-
- if ( status == FileStatus.Unknown)
- {
- // Create the transaction
-
- beginReadTransaction( sess);
-
- // Get the file information to check if the file/folder exists
-
- FileInfo info = getFileInformation(sess, tree, name);
- if (info.isDirectory())
- {
- status = FileStatus.DirectoryExists;
- }
- else
- {
- status = FileStatus.FileExists;
- }
- }
- }
- }
- catch (FileNotFoundException e)
- {
- status = FileStatus.NotExist;
- }
- catch (IOException e)
- {
- // Debug
-
- logger.debug("File exists error, " + name, e);
-
- status = FileStatus.NotExist;
- }
-
- // Debug
-
- if (logger.isDebugEnabled())
- {
- logger.debug("File status determined: \n" +
- " name: " + name + "\n" +
- " status: " + status);
- }
-
- // Return the file/folder status
-
- return status;
- }
-
- /**
- * Open a file or folder
- *
- * @param sess SrvSession
- * @param tree TreeConnection
- * @param params FileOpenParams
- * @return NetworkFile
- * @exception IOException
- */
- public NetworkFile openFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
- {
- // Create the transaction
-
- beginReadTransaction( sess);
-
- try
- {
- // Get the node for the path
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- // Check if pseudo files are enabled
-
- if ( hasPseudoFileInterface(ctx))
- {
- // Check if the file name is a pseudo file name
-
- String path = params.getPath();
-
- if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, path)) {
-
- // Make sure the parent folder has a file state, and the path exists
-
- String[] paths = FileName.splitPath( path);
- FileState fstate = ctx.getStateTable().findFileState( paths[0]);
-
- if ( fstate == null) {
-
- // Check if the path exists
-
- if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
- {
- // Create the file state and add any pseudo files
-
- fstate = ctx.getStateTable().findFileState( paths[0], true, true);
-
- fstate.setFileStatus( FileStatus.DirectoryExists);
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added file state for pseudo files folder (open) - " + paths[0]);
- }
- }
- else if ( fstate.hasPseudoFiles() == false)
- {
- // Add pseudo files for the parent folder
-
- getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
-
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug( "Added pseudo files for folder (open) - " + paths[0]);
- }
-
- // Check if the path is to a pseudo file
-
- PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
- if ( pfile != null)
- {
- // Create a network file to access the pseudo file data
-
- return pfile.getFile( params.getPath());
- }
- else
- {
- // Failed to find pseudo file
-
- if ( logger.isDebugEnabled())
- logger.debug( "Failed to find pseudo file (open) - " + params.getPath());
- }
- }
- }
-
- // Not a pseudo file, try and open a normal file/folder node
-
- NodeRef nodeRef = getNodeForPath(tree, params.getPath());
-
- // Check permissions on the file/folder node
- //
- // Check for read access
-
- if ( params.hasAccessMode(AccessMode.NTRead) &&
- permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
- throw new AccessDeniedException("No read access to " + params.getFullPath());
-
- // Check for write access
-
- if ( params.hasAccessMode(AccessMode.NTWrite) &&
- permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
- throw new AccessDeniedException("No write access to " + params.getFullPath());
-
- // Check for delete access
-
-// if ( params.hasAccessMode(AccessMode.NTDelete) &&
-// permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
-// throw new AccessDeniedException("No delete access to " + params.getFullPath());
-
- // Check if the file has a lock
-
- String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
-
- if ( params.hasAccessMode(AccessMode.NTWrite) && lockTypeStr != null)
- throw new AccessDeniedException("File is locked, no write access to " + params.getFullPath());
-
- // Check if there is a file state for the file
-
- FileState fstate = null;
-
- if ( ctx.hasStateTable())
- {
- // Check if there is a file state for the file
-
- fstate = ctx.getStateTable().findFileState( params.getPath());
-
- if ( fstate != null)
- {
- // Check if the file exists
-
- if ( fstate.exists() == false)
- throw new FileNotFoundException();
-
- // Check if the open request shared access indicates exclusive file access
-
- if ( fstate != null && params.getSharedAccess() == SharingMode.NOSHARING &&
- fstate.getOpenCount() > 0)
- throw new FileSharingException("File already open, " + params.getPath());
- }
- }
-
- // Check if the node is a link node
-
- NodeRef linkRef = (NodeRef) nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION);
- AlfrescoNetworkFile netFile = null;
-
- if ( linkRef == null)
- {
- // Create the network file
-
- netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params);
- }
- else
- {
- // Get the CIFS server name
-
- String srvName = null;
- SMBServer cifsServer = (SMBServer) sess.getServer().getConfiguration().findServer( "CIFS");
-
- if ( cifsServer != null)
- {
- // Use the CIFS server name in the URL
-
- srvName = cifsServer.getServerName();
- }
- else
- {
- // Use the local server name in the URL
-
- srvName = InetAddress.getLocalHost().getHostName();
- }
-
- // 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( srvName);
- 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
-
- if ( netFile != null)
- netFile.setFileId( params.getPath().hashCode());
-
- // Create a file state for the open file
-
- if ( ctx.hasStateTable())
- {
- if ( fstate == null)
- fstate = ctx.getStateTable().findFileState(params.getPath(), params.isDirectory(), true);
-
- // Update the file state, cache the node
-
- fstate.incrementOpenCount();
- fstate.setNodeRef(nodeRef);
-
- // Store the state with the file
-
- netFile.setFileState( fstate);
- }
-
- // If the file has been opened for overwrite then truncate the file to zero length, this will
- // also prevent the existing content data from being copied to the new version of the file
-
- if ( params.isOverwrite() && netFile != null)
- {
- // Truncate the file to zero length
-
- netFile.truncateFile( 0L);
- }
-
- // Debug
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Opened network file: \n" +
- " path: " + params.getPath() + "\n" +
- " file open parameters: " + params + "\n" +
- " network file: " + netFile);
- }
-
- // Return the network file
-
- return netFile;
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Open file - access denied, " + params.getFullPath());
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Open file " + params.getFullPath());
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Open file error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Open file " + params.getFullPath());
- }
- }
-
- /**
- * Create a new file on the file system.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param params File create parameters
- * @return NetworkFile
- * @exception java.io.IOException If an error occurs.
- */
- public NetworkFile createFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- try
- {
- // Get the device root
-
- ContentContext ctx = (ContentContext) tree.getContext();
- NodeRef deviceRootNodeRef = ctx.getRootNode();
-
- String path = params.getPath();
-
- // If the state table is available then try to find the parent folder node for the new file
- // to save having to walk the path
-
- if ( ctx.hasStateTable())
- {
- // See if the parent folder has a file state, we can avoid having to walk the path
-
- String[] paths = FileName.splitPath(path);
- if ( paths[0] != null && paths[0].length() > 1)
- {
- // Find the node ref for the folder being searched
-
- NodeRef nodeRef = getNodeForPath(tree, paths[0]);
-
- if ( nodeRef != null)
- {
- deviceRootNodeRef = nodeRef;
- path = paths[1];
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Create file using cached noderef for path " + paths[0]);
- }
- }
- }
-
- // Create it - the path will be created, if necessary
-
- NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true);
-
- // Create the network file
-
- ContentNetworkFile netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params);
-
- // Always allow write access to a newly created file
-
- netFile.setGrantedAccess(NetworkFile.READWRITE);
-
- // Truncate the file so that the content stream is created
-
- netFile.truncateFile( 0L);
-
- // Generate a file id for the file
-
- if ( netFile != null)
- netFile.setFileId( params.getPath().hashCode());
-
- // Add a file state for the new file/folder
-
- if ( ctx.hasStateTable())
- {
- FileState fstate = ctx.getStateTable().findFileState(params.getPath(), false, true);
- if ( fstate != null)
- {
- // Indicate that the file is open
-
- fstate.setFileStatus(FileStateStatus.FileExists);
- fstate.incrementOpenCount();
- fstate.setNodeRef(nodeRef);
-
- // Store the file state with the file
-
- netFile.setFileState( fstate);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Create file, state=" + fstate);
- }
- }
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Created file: \n" +
- " path: " + path + "\n" +
- " file open parameters: " + params + "\n" +
- " node: " + nodeRef + "\n" +
- " network file: " + netFile);
- }
-
- return netFile;
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Create file - access denied, " + params.getFullPath());
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Create file " + params.getFullPath());
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Create file error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Create file " + params.getFullPath());
- }
-
- }
-
- /**
- * Create a new directory on this file system.
- *
- * @param sess Server session
- * @param tree Tree connection.
- * @param params Directory create parameters
- * @exception java.io.IOException If an error occurs.
- */
- public void createDirectory(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- try
- {
- // get the device root
-
- ContentContext ctx = (ContentContext) tree.getContext();
- NodeRef deviceRootNodeRef = ctx.getRootNode();
-
- String path = params.getPath();
-
- // If the state table is available then try to find the parent folder node for the new folder
- // to save having to walk the path
-
- if ( ctx.hasStateTable())
- {
- // See if the parent folder has a file state, we can avoid having to walk the path
-
- String[] paths = FileName.splitPath(path);
- if ( paths[0] != null && paths[0].length() > 1)
- {
- // Find the node ref for the folder being searched
-
- NodeRef nodeRef = getNodeForPath(tree, paths[0]);
-
- if ( nodeRef != null)
- {
- deviceRootNodeRef = nodeRef;
- path = paths[1];
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Create file using cached noderef for path " + paths[0]);
- }
- }
- }
-
- // Create it - the path will be created, if necessary
-
- NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, false);
-
- // Add a file state for the new folder
-
- if ( ctx.hasStateTable())
- {
- FileState fstate = ctx.getStateTable().findFileState( params.getPath(), true, true);
- if ( fstate != null)
- {
- // Indicate that the file is open
-
- fstate.setFileStatus(FileStateStatus.FolderExists);
- fstate.incrementOpenCount();
- fstate.setNodeRef(nodeRef);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Creaste folder, state=" + fstate);
- }
- }
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Created directory: \n" +
- " path: " + path + "\n" +
- " file open params: " + params + "\n" +
- " node: " + nodeRef);
- }
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Create directory - access denied, " + params.getFullPath());
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Create directory " + params.getFullPath());
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Create directory error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Create directory " + params.getFullPath());
- }
- }
-
- /**
- * Delete the directory from the filesystem.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param dir Directory name.
- * @exception java.io.IOException The exception description.
- */
- public void deleteDirectory(SrvSession sess, TreeConnection tree, String dir) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- // get the device root
-
- ContentContext ctx = (ContentContext) tree.getContext();
- NodeRef deviceRootNodeRef = ctx.getRootNode();
-
- try
- {
- // Get the node for the folder
-
- NodeRef nodeRef = cifsHelper.getNodeRef(deviceRootNodeRef, dir);
- if (fileFolderService.exists(nodeRef))
- {
- // Check if the folder is empty
-
- if ( cifsHelper.isFolderEmpty( nodeRef) == true) {
-
- // Delete the folder node
-
- fileFolderService.delete(nodeRef);
-
- // Remove the file state
-
- if ( ctx.hasStateTable())
- ctx.getStateTable().removeFileState(dir);
- }
- else
- throw new DirectoryNotEmptyException( dir);
- }
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Deleted directory: \n" +
- " directory: " + dir + "\n" +
- " node: " + nodeRef);
- }
- }
- catch (FileNotFoundException e)
- {
- // already gone
- if (logger.isDebugEnabled())
- {
- logger.debug("Deleted directory : \n" +
- " directory: " + dir);
- }
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete directory - access denied, " + dir);
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Delete directory " + dir);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete directory", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Delete directory " + dir);
- }
- }
-
- /**
- * Flush any buffered output for the specified file.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param file Network file context.
- * @exception java.io.IOException The exception description.
- */
- public void flushFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException
- {
- // Flush the file data
-
- file.flushFile();
- }
-
- /**
- * Close the file.
- *
- * @param sess Server session
- * @param tree Tree connection.
- * @param param Network file context.
- * @exception java.io.IOException If an error occurs.
- */
- public void closeFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- // Get the associated file state
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- if ( ctx.hasStateTable())
- {
- FileState fstate = ctx.getStateTable().findFileState(file.getFullName());
- if ( fstate != null)
- fstate.decrementOpenCount();
- }
-
- // Defer to the network file to close the stream and remove the content
-
- file.closeFile();
-
- // Remove the node if marked for delete
-
- if (file.hasDeleteOnClose())
- {
- // Check if the file is a noderef based file
-
- if ( file instanceof NodeRefNetworkFile)
- {
- 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
-
- if (fileFolderService.exists(nodeRef))
- {
- try
- {
- // Delete the file
-
- fileFolderService.delete(nodeRef);
-
- // Remove the file state
-
- if ( ctx.hasStateTable())
- ctx.getStateTable().removeFileState(file.getFullName());
-
- // Commit the current transaction
-
-// sess.endTransaction();
-// beginReadTransaction( sess);
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete on close - access denied, " + file.getFullName());
-
- // Convert to a filesystem access denied exception
-
- throw new AccessDeniedException("Delete on close " + file.getFullName());
- }
- }
- }
- else if ( file instanceof PseudoNetworkFile ||
- file instanceof MemoryNetworkFile)
- {
- // Delete the pseudo file
-
- if ( hasPseudoFileInterface(ctx))
- {
- // Delete the pseudo file
-
- getPseudoFileInterface(ctx).deletePseudoFile( sess, tree, file.getFullName());
- }
- }
- }
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Closed file: \n" +
- " network file: " + file + "\n" +
- " deleted on close: " + file.hasDeleteOnClose());
- }
- }
-
- /**
- * Delete the specified file.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param file NetworkFile
- * @exception java.io.IOException The exception description.
- */
- public void deleteFile(SrvSession sess, TreeConnection tree, String name) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- // Get the device context
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- try
- {
- // Get the node
-
- NodeRef nodeRef = getNodeForPath(tree, name);
- if (fileFolderService.exists(nodeRef))
- {
- fileFolderService.delete(nodeRef);
-
- // Remove the file state
-
- if ( ctx.hasStateTable())
- ctx.getStateTable().removeFileState(name);
- }
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Deleted file: \n" +
- " file: " + name + "\n" +
- " node: " + nodeRef);
- }
- }
- catch (NodeLockedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete file - access denied (locked)");
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Delete " + name);
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete file - access denied");
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Delete " + name);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Delete file error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Delete file " + name);
- }
- }
-
- /**
- * Rename the specified file.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param oldName java.lang.String
- * @param newName java.lang.String
- * @exception java.io.IOException The exception description.
- */
- public void renameFile(SrvSession sess, TreeConnection tree, String oldName, String newName) throws IOException
- {
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- try
- {
- // Get the device context
-
- 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];
-
- // Check if this is a rename within the same folder
-
- String[] oldPaths = FileName.splitPath( oldName);
-
- boolean sameFolder = false;
- if ( splitPaths[0].equalsIgnoreCase( oldPaths[0]))
- sameFolder = true;
-
- // Update the state table
-
- boolean relinked = false;
- if ( ctx.hasStateTable())
- {
- // Check if the file rename can be relinked to a previous version
-
- if ( !cifsHelper.isDirectory(nodeToMoveRef) )
- {
- // Check if there is a renamed file state for the new file name
-
- FileState renState = ctx.getStateTable().removeFileState(newName);
-
- if ( renState != null && renState.getFileStatus() == FileStateStatus.Renamed)
- {
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug(" Found rename state, relinking, " + renState);
-
- // Relink the new version of the file data to the previously renamed node so that it
- // picks up version history and other settings.
-
- cifsHelper.relinkNode( renState.getNodeRef(), nodeToMoveRef, targetFolderRef, name);
- relinked = true;
-
- // Link the node ref for the associated rename state
-
- if ( renState.hasRenameState())
- renState.getRenameState().setNodeRef(nodeToMoveRef);
-
- // Remove the file state for the old file name
-
- ctx.getStateTable().removeFileState(oldName);
-
- // Get, or create, a file state for the new file path
-
- FileState fstate = ctx.getStateTable().findFileState(newName, false, true);
-
- fstate.setNodeRef(renState.getNodeRef());
- fstate.setFileStatus(FileStateStatus.FileExists);
- }
- }
- else
- {
- // Get the file state for the folder, if available
-
- FileState fstate = ctx.getStateTable().findFileState(oldName);
-
- if ( fstate != null)
- {
- // Update the file state index to use the new name
-
- ctx.getStateTable().renameFileState(newName, fstate);
- }
- }
- }
-
- // Move the file/folder, if not relinked to previous version history
-
- if (!relinked)
- {
- // Move or rename the file/folder
-
- if ( sameFolder == true)
- {
- // Check if the new file name is a temporary file name
-
- String newNameNorm = newName.toLowerCase();
- boolean isTempFile = false;
-
- if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp")) {
-
- // Add the temporary aspect, also prevents versioning
-
- nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null);
-
- // Indicate that the new file is a temporary file
-
- isTempFile = true;
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Added Temporary aspect to renamed file " + newName);
- }
-
- // Rename the file/folder
-
- cifsHelper.rename(nodeToMoveRef, name);
-
- // Check if the temporary aspect should be removed from the renamed file
-
- String oldNameNorm = oldName.toLowerCase();
-
- if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp"))) {
-
- // Remove the temporary aspect
-
- nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Removed Temporary aspect from renamed file " + newName);
- }
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Renamed file: from: " + oldName + " to: " + newName);
- }
- else
- {
- // Move the file/folder
-
- cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Moved file: from: " + oldName + " to: " + newName);
- }
-
- // Check if we renamed a file, if so then cache the rename details for a short period
- // in case another file renamed to the old name. MS Word uses renames to move a new
- // version of a document into place so we need to reconnect the version history.
-
- if ( !cifsHelper.isDirectory(nodeToMoveRef))
- {
- // Get or create a new file state for the old file path
-
- FileState fstate = ctx.getStateTable().findFileState(oldName, false, true);
-
- // Make sure the file state is cached for a short while, the file may not be open so the
- // file state could be expired
-
- fstate.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
-
- // Indicate that this is a renamed file state, set the node ref of the file that was renamed
-
- fstate.setFileStatus(FileStateStatus.Renamed);
- fstate.setNodeRef(nodeToMoveRef);
-
- // Get, or create, a file state for the new file path
-
- FileState newState = ctx.getStateTable().findFileState(newName, false, true);
-
- newState.setNodeRef(nodeToMoveRef);
- newState.setFileStatus(FileStateStatus.FileExists);
-
- // Link the renamed state to the new state
-
- fstate.setRenameState(newState);
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- {
- logger.debug("Cached rename state for " + oldName + ", state=" + fstate);
- logger.debug(" new name " + newName + ", state=" + newState);
- }
- }
- }
-
- // DEBUG
-
- if (logger.isDebugEnabled())
- logger.debug("Moved node: from: " + oldName + " to: " + newName);
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Rename file - access denied, " + oldName);
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Rename file " + oldName);
- }
- catch (NodeLockedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Rename file", ex);
-
- // Convert to an filesystem access denied exception
-
- throw new AccessDeniedException("Node locked " + oldName);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Rename file", ex);
-
- // Convert to a general I/O exception
-
- throw new AccessDeniedException("Rename file " + oldName);
- }
- }
-
- /**
- * Set file information
- *
- * @param sess SrvSession
- * @param tree TreeConnection
- * @param name String
- * @param info FileInfo
- * @exception IOException
- */
- public void setFileInformation(SrvSession sess, TreeConnection tree, String name, FileInfo info) throws IOException
- {
- try
- {
- // Get the device context
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- // Check if pseudo files are enabled
-
- if ( hasPseudoFileInterface(ctx) &&
- getPseudoFileInterface(ctx).isPseudoFile( sess, tree, name))
- {
- // Allow the file information to be changed
-
- return;
- }
-
- // Get the file/folder node
-
- NodeRef nodeRef = getNodeForPath(tree, name);
- FileState fstate = getStateForPath(tree, name);
-
- // Check permissions on the file/folder node
-
- if ( permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
- throw new AccessDeniedException("No write access to " + name);
-
- if ( permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
- throw new AccessDeniedException("No delete access to " + name);
-
- // Check if the file is being marked for deletion, if so then check if the file is locked
-
- if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
- {
- // Start a transaction
-
- beginReadTransaction( sess);
-
- // Check if the node is locked
-
- if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE))
- {
- // Get the lock type, if any
-
- String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
-
- if ( lockTypeStr != null)
- throw new AccessDeniedException("Node locked, cannot mark for delete");
- }
-
- // Update the change date/time
-
- if ( fstate != null)
- fstate.updateChangeDateTime();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set deleteOnClose=true file=" + name);
- }
-
- // Set the creation date/time
-
- if ( info.hasSetFlag(FileInfo.SetCreationDate)) {
-
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- // Set the creation date on the file/folder node
-
- Date createDate = new Date( info.getCreationDateTime());
- nodeService.setProperty( nodeRef, ContentModel.PROP_CREATED, createDate);
-
- // Update the change date/time
-
- if ( fstate != null)
- fstate.updateChangeDateTime();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set creationDate=" + createDate + " file=" + name);
- }
-
- // Set the modification date/time
-
- if ( info.hasSetFlag(FileInfo.SetModifyDate)) {
-
- // Create the transaction
-
- beginWriteTransaction( sess);
-
- // Set the creation date on the file/folder node
-
- Date modifyDate = new Date( info.getModifyDateTime());
- nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
-
- // Update the change date/time
-
- if ( fstate != null)
- fstate.updateChangeDateTime();
-
- // DEBUG
-
- if ( logger.isDebugEnabled())
- logger.debug("Set modifyDate=" + modifyDate + " file=" + name);
- }
- }
- catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Set file information - access denied, " + name);
-
- // Convert to a filesystem access denied status
-
- throw new AccessDeniedException("Set file information " + name);
- }
- catch (AlfrescoRuntimeException ex)
- {
- // Debug
-
- if ( logger.isDebugEnabled())
- logger.debug("Open file error", ex);
-
- // Convert to a general I/O exception
-
- throw new IOException("Set file information " + name);
- }
- }
-
- /**
- * Truncate a file to the specified size
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param file Network file details
- * @param size New file length
- * @exception java.io.IOException The exception description.
- */
- public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long size) throws IOException
- {
- // Truncate or extend the file to the required size
-
- file.truncateFile(size);
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Truncated file: \n" +
- " network file: " + file + "\n" +
- " size: " + size);
- }
- }
-
- /**
- * Read a block of data from the specified file.
- *
- * @param sess Session details
- * @param tree Tree connection
- * @param file Network file
- * @param buf Buffer to return data to
- * @param bufPos Starting position in the return buffer
- * @param siz Maximum size of data to return
- * @param filePos File offset to read data
- * @return Number of bytes read
- * @exception java.io.IOException The exception description.
- */
- public int readFile(
- SrvSession sess, TreeConnection tree, NetworkFile file,
- byte[] buffer, int bufferPosition, int size, long fileOffset) throws IOException
- {
- // 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
-
- if ( file instanceof ContentNetworkFile)
- {
- ContentNetworkFile contentFile = (ContentNetworkFile) file;
-
- if ( contentFile.hasContent() == false)
- beginReadTransaction( sess);
- }
-
- // Read a block of data from the file
-
- int count = file.readFile(buffer, size, bufferPosition, fileOffset);
-
- if ( count == -1)
- {
- // Read count of -1 indicates a read past the end of file
-
- count = 0;
- }
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Read bytes from file: \n" +
- " network file: " + file + "\n" +
- " buffer size: " + buffer.length + "\n" +
- " buffer pos: " + bufferPosition + "\n" +
- " size: " + size + "\n" +
- " file offset: " + fileOffset + "\n" +
- " bytes read: " + count);
- }
- return count;
- }
-
- /**
- * Seek to the specified file position.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param file Network file.
- * @param pos Position to seek to.
- * @param typ Seek type.
- * @return New file position, relative to the start of file.
- */
- public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException
- {
- // 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)
- beginReadTransaction( sess);
-
- // Set the file position
-
- return file.seekFile(pos, typ);
- }
-
- /**
- * Write a block of data to the file.
- *
- * @param sess Server session
- * @param tree Tree connection
- * @param file Network file details
- * @param buf byte[] Data to be written
- * @param bufoff Offset within the buffer that the data starts
- * @param siz int Data length
- * @param fileoff Position within the file that the data is to be written.
- * @return Number of bytes actually written
- * @exception java.io.IOException The exception description.
- */
- public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file,
- byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException
- {
- // 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)
- beginReadTransaction( sess);
- }
-
- // Write to the file
-
- file.writeFile(buffer, size, bufferOffset, fileOffset);
-
- // done
- if (logger.isDebugEnabled())
- {
- logger.debug("Wrote bytes to file: \n" +
- " network file: " + file + "\n" +
- " buffer size: " + buffer.length + "\n" +
- " size: " + size + "\n" +
- " file offset: " + fileOffset);
- }
- return size;
- }
-
- /**
- * Get the node for the specified path
- *
- * @param tree TreeConnection
- * @param path String
- * @return NodeRef
- * @exception FileNotFoundException
- */
- public NodeRef getNodeForPath(TreeConnection tree, String path)
- throws FileNotFoundException
- {
- // Check if there is a cached state for the path
-
- ContentContext ctx = (ContentContext) tree.getContext();
-
- if ( ctx.hasStateTable())
- {
- // Try and get the node ref from an in memory file state
-
- FileState fstate = ctx.getStateTable().findFileState(path);
- if ( fstate != null && fstate.hasNodeRef() && fstate.exists() )
- {
- // Check that the node exists
-
- if (fileFolderService.exists(fstate.getNodeRef()))
- {
- // Bump the file states expiry time
-
- fstate.setExpiryTime(System.currentTimeMillis() + FileState.DefTimeout);
-
- // Return the cached noderef
-
- return fstate.getNodeRef();
- }
- else
- {
- ctx.getStateTable().removeFileState(path);
- }
- }
- }
-
- // Search the repository for the node
-
- 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 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
- *
- * @param tree TreeConnection
- * @param path String
- * @return FileState
- * @exception FileNotFoundException
- */
- public FileState getStateForPath(TreeConnection tree, String path)
- throws FileNotFoundException
- {
- // Check if there is a cached state for the path
-
- ContentContext ctx = (ContentContext) tree.getContext();
- FileState fstate = null;
-
- if ( ctx.hasStateTable())
- {
- // Get the file state for a file/folder
-
- fstate = ctx.getStateTable().findFileState(path);
- }
-
- // Return the file state
-
- return fstate;
- }
-
- /**
- * Connection opened to this disk device
- *
- * @param sess Server session
- * @param tree Tree connection
- */
- public void treeClosed(SrvSession sess, TreeConnection tree)
- {
- // Nothing to do
- }
-
- /**
- * Connection closed to this device
- *
- * @param sess Server session
- * @param tree Tree connection
- */
- public void treeOpened(SrvSession sess, TreeConnection tree)
- {
- // Nothing to do
- }
-
- /**
- * Return the lock manager used by this filesystem
- *
- * @param sess SrvSession
- * @param tree TreeConnection
- * @return LockManager
- */
- public LockManager getLockManager(SrvSession sess, TreeConnection tree) {
- return _lockManager;
- }
-}
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.filesys.repo;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Date;
+import java.util.List;
+
+import javax.transaction.UserTransaction;
+
+import org.alfresco.config.ConfigElement;
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
+import org.alfresco.filesys.alfresco.AlfrescoNetworkFile;
+import org.alfresco.filesys.state.FileState;
+import org.alfresco.filesys.state.FileStateLockManager;
+import org.alfresco.filesys.state.FileState.FileStateStatus;
+import org.alfresco.jlan.server.SrvSession;
+import org.alfresco.jlan.server.core.DeviceContext;
+import org.alfresco.jlan.server.core.DeviceContextException;
+import org.alfresco.jlan.server.filesys.AccessDeniedException;
+import org.alfresco.jlan.server.filesys.AccessMode;
+import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException;
+import org.alfresco.jlan.server.filesys.DiskInterface;
+import org.alfresco.jlan.server.filesys.FileAttribute;
+import org.alfresco.jlan.server.filesys.FileInfo;
+import org.alfresco.jlan.server.filesys.FileName;
+import org.alfresco.jlan.server.filesys.FileOpenParams;
+import org.alfresco.jlan.server.filesys.FileSharingException;
+import org.alfresco.jlan.server.filesys.FileStatus;
+import org.alfresco.jlan.server.filesys.NetworkFile;
+import org.alfresco.jlan.server.filesys.SearchContext;
+import org.alfresco.jlan.server.filesys.TreeConnection;
+import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile;
+import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
+import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface;
+import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
+import org.alfresco.jlan.server.filesys.pseudo.PseudoNetworkFile;
+import org.alfresco.jlan.server.locking.FileLockingInterface;
+import org.alfresco.jlan.server.locking.LockManager;
+import org.alfresco.jlan.smb.SharingMode;
+import org.alfresco.jlan.smb.server.SMBServer;
+import org.alfresco.jlan.smb.server.SMBSrvSession;
+import org.alfresco.jlan.util.WildCard;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.AuthenticationContext;
+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.MimetypeService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.search.SearchService;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.NamespaceService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Content repository filesystem driver class
+ *
+ * Provides a filesystem interface for various protocols such as SMB/CIFS and FTP.
+ *
+ * @author Derek Hulley
+ */
+public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterface, FileLockingInterface
+{
+ // Logging
+
+ private static final Log logger = LogFactory.getLog(ContentDiskDriver.class);
+
+ // Configuration key names
+
+ private static final String KEY_STORE = "store";
+ private static final String KEY_ROOT_PATH = "rootPath";
+ private static final String KEY_RELATIVE_PATH = "relativePath";
+
+ // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL
+
+ private static final String TokenLocalName = "${localname}";
+
+ // Services and helpers
+
+ private CifsHelper cifsHelper;
+ private NamespaceService namespaceService;
+ private NodeService nodeService;
+ private SearchService searchService;
+ private ContentService contentService;
+ private MimetypeService mimetypeService;
+ private PermissionService permissionService;
+ private FileFolderService fileFolderService;
+
+ private AuthenticationContext authenticationContext;
+ private AuthenticationService authService;
+
+ // Node monitor factory
+
+ private NodeMonitorFactory m_nodeMonitorFactory;
+
+ // Lock manager
+
+ private static LockManager _lockManager = new FileStateLockManager();
+
+ /**
+ * Class constructor
+ *
+ * @param serviceRegistry to connect to the repository services
+ */
+ public ContentDiskDriver(CifsHelper cifsHelper)
+ {
+ this.cifsHelper = cifsHelper;
+ }
+
+ /**
+ * Return the CIFS helper
+ *
+ * @return CifsHelper
+ */
+ public final CifsHelper getCifsHelper()
+ {
+ return this.cifsHelper;
+ }
+
+ /**
+ * Return the authentication service
+ *
+ * @return AuthenticationService
+ */
+ public final AuthenticationService getAuthenticationService()
+ {
+ return authService;
+ }
+
+ /**
+ * Return the authentication component
+ *
+ * @return AuthenticationContext
+ */
+ public final AuthenticationContext getAuthenticationContext() {
+ return authenticationContext;
+ }
+
+ /**
+ * Return the node service
+ *
+ * @return NodeService
+ */
+ public final NodeService getNodeService()
+ {
+ return this.nodeService;
+ }
+
+ /**
+ * Return the content service
+ *
+ * @return ContentService
+ */
+ public final ContentService getContentService()
+ {
+ return this.contentService;
+ }
+
+ /**
+ * Return the namespace service
+ *
+ * @return NamespaceService
+ */
+ public final NamespaceService getNamespaceService()
+ {
+ return this.namespaceService;
+ }
+
+ /**
+ * Return the search service
+ *
+ * @return SearchService
+ */
+ public final SearchService getSearchService(){
+ return this.searchService;
+ }
+
+ /**
+ * Return the file folder service
+ *
+ * @return FileFolderService
+ */
+ public final FileFolderService getFileFolderService() {
+ return this.fileFolderService;
+ }
+
+ /**
+ * Return the permission service
+ *
+ * @return PermissionService
+ */
+ public final PermissionService getPermissionService() {
+ return this.permissionService;
+ }
+
+ /**
+ * @param contentService the content service
+ */
+ public void setContentService(ContentService contentService)
+ {
+ this.contentService = contentService;
+ }
+
+ /**
+ * @param namespaceService the namespace service
+ */
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * @param nodeService the node service
+ */
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ /**
+ * @param searchService the search service
+ */
+ public void setSearchService(SearchService searchService)
+ {
+ this.searchService = searchService;
+ }
+
+ /**
+ * Set the permission service
+ *
+ * @param permissionService PermissionService
+ */
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
+ /**
+ * Set the authentication component
+ *
+ * @param authComponent AuthenticationContext
+ */
+ public void setAuthenticationContext(AuthenticationContext authComponent)
+ {
+ this.authenticationContext = authComponent;
+ }
+
+ /**
+ * Set the authentication service
+ *
+ * @param authService AuthenticationService
+ */
+ public void setAuthenticationService(AuthenticationService authService)
+ {
+ this.authService = authService;
+ }
+
+ /**
+ * Set the file folder service
+ *
+ * @param fileService FileFolderService
+ */
+ public void setFileFolderService(FileFolderService fileService)
+ {
+ fileFolderService = fileService;
+ }
+
+ /**
+ * @param mimetypeService service for helping with mimetypes and encoding
+ */
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
+ /**
+ * Set the node monitor factory
+ *
+ * @param nodeMonitorFactory NodeMonitorFactory
+ */
+ public void setNodeMonitorFactory(NodeMonitorFactory nodeMonitorFactory) {
+ m_nodeMonitorFactory = nodeMonitorFactory;
+ }
+
+ /**
+ * 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
+ * shares.
+ *
+ * @param shareName String
+ * @param args ConfigElement
+ * @return DeviceContext
+ * @exception DeviceContextException
+ */
+ public DeviceContext createContext(String shareName, ConfigElement cfg) throws DeviceContextException
+ {
+ // Wrap the initialization in a transaction
+
+ UserTransaction tx = getTransactionService().getUserTransaction(true);
+
+ ContentContext context = null;
+
+ try
+ {
+ // Use the system user as the authenticated context for the filesystem initialization
+
+ AuthenticationUtil.pushAuthentication();
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
+
+ // Start the transaction
+
+ if ( tx != null)
+ tx.begin();
+
+ // Get the store
+
+ ConfigElement storeElement = cfg.getChild(KEY_STORE);
+ if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0)
+ {
+ throw new DeviceContextException("Device missing init value: " + KEY_STORE);
+ }
+ String storeValue = storeElement.getValue();
+ StoreRef storeRef = new StoreRef(storeValue);
+
+ // Connect to the repo and ensure that the store exists
+
+ if (! nodeService.exists(storeRef))
+ {
+ throw new DeviceContextException("Store not created prior to application startup: " + storeRef);
+ }
+ NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
+
+ // Get the root path
+
+ ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH);
+ if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0)
+ {
+ throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH);
+ }
+ String rootPath = rootPathElement.getValue();
+
+ // Find the root node for this device
+
+ List nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false);
+
+ NodeRef rootNodeRef = null;
+
+ if (nodeRefs.size() > 1)
+ {
+ throw new DeviceContextException("Multiple possible roots for device: \n" +
+ " root path: " + rootPath + "\n" +
+ " results: " + nodeRefs);
+ }
+ else if (nodeRefs.size() == 0)
+ {
+ // Nothing found
+
+ throw new DeviceContextException("No root found for device: \n" +
+ " root path: " + rootPath);
+ }
+ else
+ {
+ // We found a node
+
+ rootNodeRef = nodeRefs.get(0);
+ }
+
+ // Check if a relative path has been specified
+
+ ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH);
+
+ if ( relativePathElement != null)
+ {
+ // Make sure the path is in CIFS format
+
+ String relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR);
+
+ // Find the node and validate that the relative path is to a folder
+
+ NodeRef relPathNode = cifsHelper.getNodeRef( rootNodeRef, relPath);
+ if ( cifsHelper.isDirectory( relPathNode) == false)
+ throw new DeviceContextException("Relative path is not a folder, " + relativePathElement.getValue());
+
+ // Use the relative path node as the root of the filesystem
+
+ rootNodeRef = relPathNode;
+ }
+ else {
+
+ // Make sure the default root node is a folder
+
+ if ( cifsHelper.isDirectory( rootNodeRef) == false)
+ throw new DeviceContextException("Root node is not a folder type node");
+ }
+
+ // Commit the transaction
+
+ tx.commit();
+ tx = null;
+
+ // Create the context
+
+ context = new ContentContext(shareName, storeValue, rootPath, rootNodeRef);
+ }
+ catch (Exception ex)
+ {
+ logger.error("Error during create context", ex);
+ }
+ finally
+ {
+ // Restore authentication context
+
+ AuthenticationUtil.popAuthentication();
+
+ // If there is an active transaction then roll it back
+
+ if ( tx != null)
+ {
+ try
+ {
+ tx.rollback();
+ }
+ catch (Exception ex)
+ {
+ logger.warn("Failed to rollback transaction", ex);
+ }
+ }
+ }
+
+ // Check if URL link files are enabled
+
+ ConfigElement urlFileElem = cfg.getChild( "urlFile");
+ if ( urlFileElem != null)
+ {
+ // Get the pseudo file name and web prefix path
+
+ ConfigElement pseudoName = urlFileElem.getChild( "filename");
+ ConfigElement webPath = urlFileElem.getChild( "webpath");
+
+ if ( pseudoName != null && webPath != null)
+ {
+ // Make sure the web prefix has a trailing slash
+
+ String path = webPath.getValue();
+ if ( path.endsWith("/") == false)
+ path = path + "/";
+
+ // URL file name must end with .url
+
+ if ( pseudoName.getValue().endsWith(".url") == false)
+ throw new DeviceContextException("URL link file must end with .url, " + pseudoName.getValue());
+
+ // Check if the URL path name contains the local name token
+
+ int pos = path.indexOf(TokenLocalName);
+ if (pos != -1)
+ {
+
+ // Get the local server name
+
+ String srvName = "localhost";
+
+ try
+ {
+ srvName = InetAddress.getLocalHost().getHostName();
+ }
+ catch ( Exception ex)
+ {
+ }
+
+ // Rebuild the host name substituting the token with the local server name
+
+ StringBuilder hostStr = new StringBuilder();
+
+ hostStr.append( path.substring(0, pos));
+ hostStr.append(srvName);
+
+ pos += TokenLocalName.length();
+ if (pos < path.length())
+ hostStr.append( path.substring(pos));
+
+ path = hostStr.toString();
+ }
+
+ // Set the URL link file name and web path
+
+ context.setURLFileName( pseudoName.getValue());
+ context.setURLPrefix( path);
+ }
+ }
+
+ // Check if locked files should be marked as offline
+
+ ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
+ if ( offlineFiles != null)
+ {
+ // Enable marking locked files as offline
+
+ cifsHelper.setMarkLockedFilesAsOffline( true);
+
+ // Logging
+
+ logger.info("Locked files will be marked as offline");
+ }
+
+ // Enable file state caching
+
+ context.enableStateTable( true, getStateReaper());
+
+ // Initialize the I/O control handler
+
+ if ( context.hasIOHandler())
+ context.getIOHandler().initialize( this, context);
+
+ // Install the node service monitor
+
+ if ( cfg.getChild("disableNodeMonitor") == null && m_nodeMonitorFactory != null) {
+
+ // Create the node monitor
+
+ NodeMonitor nodeMonitor = m_nodeMonitorFactory.createNodeMonitor( this, context);
+ context.setNodeMonitor( nodeMonitor);
+ }
+
+ // Return the context for this shared filesystem
+
+ return context;
+ }
+
+ /**
+ * Check if pseudo file support is enabled
+ *
+ * @param context ContentContext
+ * @return boolean
+ */
+ public final boolean hasPseudoFileInterface(ContentContext context)
+ {
+ return context.hasPseudoFileInterface();
+ }
+
+ /**
+ * Return the pseudo file support implementation
+ *
+ * @param context ContentContext
+ * @return PseudoFileInterface
+ */
+ public final PseudoFileInterface getPseudoFileInterface(ContentContext context)
+ {
+ return context.getPseudoFileInterface();
+ }
+
+ /**
+ * Determine if the disk device is read-only.
+ *
+ * @param sess Server session
+ * @param ctx Device context
+ * @return boolean
+ * @exception java.io.IOException If an error occurs.
+ */
+ public boolean isReadOnly(SrvSession sess, DeviceContext ctx) throws IOException
+ {
+ if (cifsHelper.isReadOnly())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the file information for the specified file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param name File name/path that information is required for.
+ * @return File information if valid, else null
+ * @exception java.io.IOException The exception description.
+ */
+ public FileInfo getFileInformation(SrvSession session, TreeConnection tree, String path) throws IOException
+ {
+ // Start a transaction
+
+ beginReadTransaction( session);
+
+ // Get the device root
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ NodeRef infoParentNodeRef = ctx.getRootNode();
+
+ if ( path == null || path.length() == 0)
+ path = FileName.DOS_SEPERATOR_STR;
+
+ String infoPath = path;
+
+ try
+ {
+ // Check if the path is to a pseudo file
+
+ FileInfo finfo = null;
+
+ if ( hasPseudoFileInterface(ctx))
+ {
+ // Make sure the parent folder has a file state, and the path exists
+
+ String[] paths = FileName.splitPath( path);
+ FileState fstate = ctx.getStateTable().findFileState( paths[0]);
+
+ if ( fstate == null)
+ {
+ NodeRef nodeRef = getNodeForPath(tree, paths[0]);
+
+ if ( nodeRef != null)
+ {
+ // Get the file information for the node
+
+ finfo = cifsHelper.getFileInformation(nodeRef);
+ }
+
+ // Create the file state
+
+ fstate = ctx.getStateTable().findFileState( paths[0], true, true);
+
+ fstate.setFileStatus( FileStatus.DirectoryExists);
+ fstate.setNodeRef( nodeRef);
+
+ // Add pseudo files to the folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added file state for pseudo files folder (getinfo) - " + paths[0]);
+ }
+ else if ( fstate.hasPseudoFiles() == false)
+ {
+ // Make sure the file state has the node ref
+
+ if ( fstate.hasNodeRef() == false)
+ {
+ // Get the node for the folder path
+
+ fstate.setNodeRef( getNodeForPath( tree, paths[0]));
+ }
+
+ // Add pseudo files for the parent folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
+ }
+
+
+ // Get the pseudo file
+
+ PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( session, tree, path);
+ if ( pfile != null)
+ {
+ // DEBUG
+ if ( logger.isDebugEnabled())
+ logger.debug("getInfo using pseudo file info for " + path);
+
+ FileInfo pseudoFileInfo = pfile.getFileInfo();
+ if (cifsHelper.isReadOnly())
+ {
+ int attr = pseudoFileInfo.getFileAttributes();
+ if (( attr & FileAttribute.ReadOnly) == 0)
+ {
+ attr += FileAttribute.ReadOnly;
+ pseudoFileInfo.setFileAttributes(attr);
+ }
+ }
+ return pfile.getFileInfo();
+ }
+ }
+
+ // Get the node ref for the path, chances are there is a file state in the cache
+
+ NodeRef nodeRef = getNodeForPath(tree, infoPath);
+
+ if ( nodeRef != null)
+ {
+ // Get the file information for the node
+
+ finfo = cifsHelper.getFileInformation(nodeRef);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("getInfo using cached noderef for path " + path);
+ }
+
+ // If the required node was not in the state cache, the parent folder node might be
+
+
+ if ( finfo == null)
+ {
+ String[] paths = FileName.splitPath( path);
+
+ if ( paths[0] != null && paths[0].length() > 1)
+ {
+ // Find the node ref for the folder being searched
+
+ nodeRef = getNodeForPath(tree, paths[0]);
+
+ if ( nodeRef != null)
+ {
+ infoParentNodeRef = nodeRef;
+ infoPath = paths[1];
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("getInfo using cached noderef for parent " + path);
+ }
+ }
+
+ // Access the repository to get the file information
+
+ finfo = cifsHelper.getFileInformation(infoParentNodeRef, infoPath);
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Getting file information: \n" +
+ " path: " + path + "\n" +
+ " file info: " + finfo);
+ }
+ }
+
+ // Set the file id for the file using the relative path
+
+ if ( finfo != null) {
+
+ // Set the file id
+
+ finfo.setFileId( path.hashCode());
+
+ // Copy cached timestamps, if available
+
+ FileState fstate = getStateForPath(tree, infoPath);
+ if ( fstate != null) {
+ if ( fstate.hasAccessDateTime())
+ finfo.setAccessDateTime(fstate.getAccessDateTime());
+ if ( fstate.hasChangeDateTime())
+ finfo.setChangeDateTime(fstate.getChangeDateTime());
+ if ( fstate.hasModifyDateTime())
+ finfo.setModifyDateTime(fstate.getModifyDateTime());
+ }
+ }
+
+ // Return the file information
+
+ return finfo;
+ }
+ catch (FileNotFoundException e)
+ {
+ // Debug
+
+ if (logger.isDebugEnabled())
+ logger.debug("Getting file information - File not found: \n" +
+ " path: " + path);
+ throw e;
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Get file info - access denied, " + path);
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Get file information " + path);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Get file info error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Get file information " + path);
+ }
+ }
+
+ /**
+ * Start a new search on the filesystem using the specified searchPath that may contain
+ * wildcards.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param searchPath File(s) to search for, may include wildcards.
+ * @param attrib Attributes of the file(s) to search for, see class SMBFileAttribute.
+ * @return SearchContext
+ * @exception java.io.FileNotFoundException If the search could not be started.
+ */
+ public SearchContext startSearch(SrvSession sess, TreeConnection tree, String searchPath, int attributes) throws FileNotFoundException
+ {
+ try
+ {
+ // Access the device context
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ String searchFileSpec = searchPath;
+ NodeRef searchRootNodeRef = ctx.getRootNode();
+ FileState searchFolderState = null;
+
+ // Create the transaction
+
+ beginReadTransaction( sess);
+
+ // 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
+
+ String[] paths = FileName.splitPath(searchPath);
+
+ if ( ctx.hasStateTable())
+ {
+ // See if the folder to be searched has a file state, we can avoid having to walk the path
+
+ if ( paths[0] != null && paths[0].length() >= 1)
+ {
+ // Find the node ref for the folder being searched
+
+ NodeRef nodeRef = getNodeForPath(tree, paths[0]);
+
+ // Get the file state for the folder being searched
+
+ searchFolderState = getStateForPath(tree, paths[0]);
+ if ( searchFolderState == null)
+ {
+ // Create a file state for the folder
+
+ searchFolderState = ctx.getStateTable().findFileState( paths[0], true, true);
+ }
+
+ // Make sure the associated node is set
+
+ if ( searchFolderState.hasNodeRef() == false)
+ {
+ // Set the associated node for the folder
+
+ searchFolderState.setNodeRef( nodeRef);
+ }
+
+ // Add pseudo files to the folder being searched
+
+ if ( hasPseudoFileInterface(ctx))
+ getPseudoFileInterface(ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Set the search node and file spec
+
+ if ( nodeRef != null)
+ {
+ searchRootNodeRef = nodeRef;
+ searchFileSpec = paths[1];
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Search using cached noderef for path " + searchPath);
+ }
+ }
+ }
+
+ // Convert the all files wildcard
+
+ if ( searchFileSpec.equals( "*.*"))
+ searchFileSpec = "*";
+
+ // Perform the search
+
+ List results = cifsHelper.getNodeRefs(searchRootNodeRef, searchFileSpec);
+
+ // Check if there are any pseudo files for the folder being searched, for CIFS only
+
+ PseudoFileList pseudoList = null;
+
+ if ( sess instanceof SMBSrvSession && searchFolderState != null && searchFolderState.hasPseudoFiles())
+ {
+ // If it is a wildcard search use all pseudo files
+
+ if ( WildCard.containsWildcards(searchFileSpec))
+ {
+ // Get the list of pseudo files for the search path
+
+ pseudoList = searchFolderState.getPseudoFileList();
+
+ // Check if the wildcard is for all files or a subset
+
+ if ( searchFileSpec.equals( "*") == false && pseudoList != null && pseudoList.numberOfFiles() > 0)
+ {
+ // Generate a subset of pseudo files that match the wildcard search pattern
+
+ WildCard wildCard = new WildCard( searchFileSpec, false);
+ PseudoFileList filterList = null;
+
+ for ( int i = 0; i > pseudoList.numberOfFiles(); i++)
+ {
+ PseudoFile pseudoFile = pseudoList.getFileAt( i);
+ if ( wildCard.matchesPattern( pseudoFile.getFileName()))
+ {
+ // Add the pseudo file to the filtered list
+
+ if ( filterList == null)
+ filterList = new PseudoFileList();
+ filterList.addFile( pseudoFile);
+ }
+ }
+
+ // Use the filtered pseudo file list, or null if there were no matches
+
+ pseudoList = filterList;
+ }
+ }
+ else if ( results == null || results.size() == 0)
+ {
+ // Check if the required file is in the pseudo file list
+
+ String fname = paths[1];
+
+ if ( fname != null)
+ {
+ // Search for a matching pseudo file
+
+ PseudoFile pfile = searchFolderState.getPseudoFileList().findFile( fname, true);
+ if ( pfile != null)
+ {
+ // Create a file list with the required file
+
+ pseudoList = new PseudoFileList();
+ pseudoList.addFile( pfile);
+ }
+ }
+ }
+ }
+
+ // Build the search context to store the results
+
+ SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Started search: \n" +
+ " search path: " + searchPath + "\n" +
+ " attributes: " + attributes);
+ }
+ return searchCtx;
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Start search - access denied, " + searchPath);
+
+ // Convert to a file not found status
+
+ throw new FileNotFoundException("Start search " + searchPath);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Start search", ex);
+
+ // Convert to a file not found status
+
+ throw new FileNotFoundException("Start search " + searchPath);
+ }
+ }
+
+ /**
+ * Check if the specified file exists, and whether it is a file or directory.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param name java.lang.String
+ * @return int
+ * @see FileStatus
+ */
+ public int fileExists(SrvSession sess, TreeConnection tree, String name)
+ {
+
+ int status = FileStatus.Unknown;
+
+ try
+ {
+ // Check for a cached file state
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ FileState fstate = null;
+
+ if ( ctx.hasStateTable())
+ ctx.getStateTable().findFileState(name);
+
+ if ( fstate != null)
+ {
+ FileStateStatus fsts = fstate.getFileStatus();
+
+ if ( fsts == FileStateStatus.FileExists)
+ status = FileStatus.FileExists;
+ else if ( fsts == FileStateStatus.FolderExists)
+ status = FileStatus.DirectoryExists;
+ else if ( fsts == FileStateStatus.NotExist || fsts == FileStateStatus.Renamed)
+ status = FileStatus.NotExist;
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Cache hit - fileExists() " + name + ", sts=" + status);
+ }
+ else
+ {
+ // Check if pseudo files are enabled
+
+ if ( hasPseudoFileInterface(ctx))
+ {
+ // Check if the file name is a pseudo file name
+
+ if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) {
+
+ // Make sure the parent folder has a file state, and the path exists
+
+ String[] paths = FileName.splitPath( name);
+ fstate = ctx.getStateTable().findFileState( paths[0]);
+
+ if ( fstate == null) {
+
+ // Check if the path exists
+
+ if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
+ {
+ // Create the file state
+
+ fstate = ctx.getStateTable().findFileState( paths[0], true, true);
+
+ fstate.setFileStatus( FileStatus.DirectoryExists);
+
+ // Get the node for the folder path
+
+ beginReadTransaction( sess);
+ fstate.setNodeRef( getNodeForPath( tree, paths[0]));
+
+ // Add pseudo files to the folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added file state for pseudo files folder (exists) - " + paths[0]);
+ }
+ }
+ else if ( fstate.hasPseudoFiles() == false)
+ {
+ // Make sure the file state has the node ref
+
+ if ( fstate.hasNodeRef() == false)
+ {
+ // Create the transaction
+
+ beginReadTransaction( sess);
+
+ // Get the node for the folder path
+
+ fstate.setNodeRef( getNodeForPath( tree, paths[0]));
+ }
+
+ // Add pseudo files for the parent folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
+ }
+
+ // Check if the path is to a pseudo file
+
+ PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name);
+ if ( pfile != null)
+ {
+ // Indicate that the file exists
+
+ status = FileStatus.FileExists;
+ }
+ else
+ {
+ // Failed to find pseudo file
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Failed to find pseudo file (exists) - " + name);
+ }
+ }
+ }
+
+ // If the file is not a pseudo file then search for the file
+
+ if ( status == FileStatus.Unknown)
+ {
+ // Create the transaction
+
+ beginReadTransaction( sess);
+
+ // Get the file information to check if the file/folder exists
+
+ FileInfo info = getFileInformation(sess, tree, name);
+ if (info.isDirectory())
+ {
+ status = FileStatus.DirectoryExists;
+ }
+ else
+ {
+ status = FileStatus.FileExists;
+ }
+ }
+ }
+ }
+ catch (FileNotFoundException e)
+ {
+ status = FileStatus.NotExist;
+ }
+ catch (IOException e)
+ {
+ // Debug
+
+ logger.debug("File exists error, " + name, e);
+
+ status = FileStatus.NotExist;
+ }
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("File status determined: \n" +
+ " name: " + name + "\n" +
+ " status: " + status);
+ }
+
+ // Return the file/folder status
+
+ return status;
+ }
+
+ /**
+ * Open a file or folder
+ *
+ * @param sess SrvSession
+ * @param tree TreeConnection
+ * @param params FileOpenParams
+ * @return NetworkFile
+ * @exception IOException
+ */
+ public NetworkFile openFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
+ {
+ // Create the transaction
+
+ beginReadTransaction( sess);
+
+ try
+ {
+ // Get the node for the path
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ // Check if pseudo files are enabled
+
+ if ( hasPseudoFileInterface(ctx))
+ {
+ // Check if the file name is a pseudo file name
+
+ String path = params.getPath();
+
+ if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, path)) {
+
+ // Make sure the parent folder has a file state, and the path exists
+
+ String[] paths = FileName.splitPath( path);
+ FileState fstate = ctx.getStateTable().findFileState( paths[0]);
+
+ if ( fstate == null) {
+
+ // Check if the path exists
+
+ if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
+ {
+ // Create the file state and add any pseudo files
+
+ fstate = ctx.getStateTable().findFileState( paths[0], true, true);
+
+ fstate.setFileStatus( FileStatus.DirectoryExists);
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added file state for pseudo files folder (open) - " + paths[0]);
+ }
+ }
+ else if ( fstate.hasPseudoFiles() == false)
+ {
+ // Add pseudo files for the parent folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Added pseudo files for folder (open) - " + paths[0]);
+ }
+
+ // Check if the path is to a pseudo file
+
+ PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
+ if ( pfile != null)
+ {
+ // Create a network file to access the pseudo file data
+
+ return pfile.getFile( params.getPath());
+ }
+ else
+ {
+ // Failed to find pseudo file
+
+ if ( logger.isDebugEnabled())
+ logger.debug( "Failed to find pseudo file (open) - " + params.getPath());
+ }
+ }
+ }
+
+ // Not a pseudo file, try and open a normal file/folder node
+
+ NodeRef nodeRef = getNodeForPath(tree, params.getPath());
+
+ // Check permissions on the file/folder node
+ //
+ // Check for read access
+
+ if ( params.hasAccessMode(AccessMode.NTRead) &&
+ permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
+ throw new AccessDeniedException("No read access to " + params.getFullPath());
+
+ // Check for write access
+
+ if ( params.hasAccessMode(AccessMode.NTWrite) &&
+ permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
+ throw new AccessDeniedException("No write access to " + params.getFullPath());
+
+ // Check for delete access
+
+// if ( params.hasAccessMode(AccessMode.NTDelete) &&
+// permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
+// throw new AccessDeniedException("No delete access to " + params.getFullPath());
+
+ // Check if the file has a lock
+
+ String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
+
+ if ( params.hasAccessMode(AccessMode.NTWrite) && lockTypeStr != null)
+ throw new AccessDeniedException("File is locked, no write access to " + params.getFullPath());
+
+ // Check if there is a file state for the file
+
+ FileState fstate = null;
+
+ if ( ctx.hasStateTable())
+ {
+ // Check if there is a file state for the file
+
+ fstate = ctx.getStateTable().findFileState( params.getPath());
+
+ if ( fstate != null)
+ {
+ // Check if the file exists
+
+ if ( fstate.exists() == false)
+ throw new FileNotFoundException();
+
+ // Check if the open request shared access indicates exclusive file access
+
+ if ( fstate != null && params.getSharedAccess() == SharingMode.NOSHARING &&
+ fstate.getOpenCount() > 0)
+ throw new FileSharingException("File already open, " + params.getPath());
+ }
+ }
+
+ // Check if the node is a link node
+
+ NodeRef linkRef = (NodeRef) nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION);
+ AlfrescoNetworkFile netFile = null;
+
+ if ( linkRef == null)
+ {
+ // Create the network file
+
+ netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params);
+ }
+ else
+ {
+ // Get the CIFS server name
+
+ String srvName = null;
+ SMBServer cifsServer = (SMBServer) sess.getServer().getConfiguration().findServer( "CIFS");
+
+ if ( cifsServer != null)
+ {
+ // Use the CIFS server name in the URL
+
+ srvName = cifsServer.getServerName();
+ }
+ else
+ {
+ // Use the local server name in the URL
+
+ srvName = InetAddress.getLocalHost().getHostName();
+ }
+
+ // 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( srvName);
+ 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
+
+ if ( netFile != null)
+ netFile.setFileId( params.getPath().hashCode());
+
+ // Create a file state for the open file
+
+ if ( ctx.hasStateTable())
+ {
+ if ( fstate == null)
+ fstate = ctx.getStateTable().findFileState(params.getPath(), params.isDirectory(), true);
+
+ // Update the file state, cache the node
+
+ fstate.incrementOpenCount();
+ fstate.setNodeRef(nodeRef);
+
+ // Store the state with the file
+
+ netFile.setFileState( fstate);
+ }
+
+ // If the file has been opened for overwrite then truncate the file to zero length, this will
+ // also prevent the existing content data from being copied to the new version of the file
+
+ if ( params.isOverwrite() && netFile != null)
+ {
+ // Truncate the file to zero length
+
+ netFile.truncateFile( 0L);
+ }
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Opened network file: \n" +
+ " path: " + params.getPath() + "\n" +
+ " file open parameters: " + params + "\n" +
+ " network file: " + netFile);
+ }
+
+ // Return the network file
+
+ return netFile;
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Open file - access denied, " + params.getFullPath());
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Open file " + params.getFullPath());
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Open file error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Open file " + params.getFullPath());
+ }
+ }
+
+ /**
+ * Create a new file on the file system.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param params File create parameters
+ * @return NetworkFile
+ * @exception java.io.IOException If an error occurs.
+ */
+ public NetworkFile createFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ try
+ {
+ // Get the device root
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ NodeRef deviceRootNodeRef = ctx.getRootNode();
+
+ String path = params.getPath();
+
+ // If the state table is available then try to find the parent folder node for the new file
+ // to save having to walk the path
+
+ if ( ctx.hasStateTable())
+ {
+ // See if the parent folder has a file state, we can avoid having to walk the path
+
+ String[] paths = FileName.splitPath(path);
+ if ( paths[0] != null && paths[0].length() > 1)
+ {
+ // Find the node ref for the folder being searched
+
+ NodeRef nodeRef = getNodeForPath(tree, paths[0]);
+
+ if ( nodeRef != null)
+ {
+ deviceRootNodeRef = nodeRef;
+ path = paths[1];
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create file using cached noderef for path " + paths[0]);
+ }
+ }
+ }
+
+ // Create it - the path will be created, if necessary
+
+ NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true);
+
+ // Create the network file
+
+ ContentNetworkFile netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params);
+
+ // Always allow write access to a newly created file
+
+ netFile.setGrantedAccess(NetworkFile.READWRITE);
+
+ // Truncate the file so that the content stream is created
+
+ netFile.truncateFile( 0L);
+
+ // Generate a file id for the file
+
+ if ( netFile != null)
+ netFile.setFileId( params.getPath().hashCode());
+
+ // Add a file state for the new file/folder
+
+ if ( ctx.hasStateTable())
+ {
+ FileState fstate = ctx.getStateTable().findFileState(params.getPath(), false, true);
+ if ( fstate != null)
+ {
+ // Indicate that the file is open
+
+ fstate.setFileStatus(FileStateStatus.FileExists);
+ fstate.incrementOpenCount();
+ fstate.setNodeRef(nodeRef);
+
+ // Store the file state with the file
+
+ netFile.setFileState( fstate);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create file, state=" + fstate);
+ }
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Created file: \n" +
+ " path: " + path + "\n" +
+ " file open parameters: " + params + "\n" +
+ " node: " + nodeRef + "\n" +
+ " network file: " + netFile);
+ }
+
+ return netFile;
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create file - access denied, " + params.getFullPath());
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Create file " + params.getFullPath());
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create file error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Create file " + params.getFullPath());
+ }
+
+ }
+
+ /**
+ * Create a new directory on this file system.
+ *
+ * @param sess Server session
+ * @param tree Tree connection.
+ * @param params Directory create parameters
+ * @exception java.io.IOException If an error occurs.
+ */
+ public void createDirectory(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ try
+ {
+ // get the device root
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ NodeRef deviceRootNodeRef = ctx.getRootNode();
+
+ String path = params.getPath();
+
+ // If the state table is available then try to find the parent folder node for the new folder
+ // to save having to walk the path
+
+ if ( ctx.hasStateTable())
+ {
+ // See if the parent folder has a file state, we can avoid having to walk the path
+
+ String[] paths = FileName.splitPath(path);
+ if ( paths[0] != null && paths[0].length() > 1)
+ {
+ // Find the node ref for the folder being searched
+
+ NodeRef nodeRef = getNodeForPath(tree, paths[0]);
+
+ if ( nodeRef != null)
+ {
+ deviceRootNodeRef = nodeRef;
+ path = paths[1];
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create file using cached noderef for path " + paths[0]);
+ }
+ }
+ }
+
+ // Create it - the path will be created, if necessary
+
+ NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, false);
+
+ // Add a file state for the new folder
+
+ if ( ctx.hasStateTable())
+ {
+ FileState fstate = ctx.getStateTable().findFileState( params.getPath(), true, true);
+ if ( fstate != null)
+ {
+ // Indicate that the file is open
+
+ fstate.setFileStatus(FileStateStatus.FolderExists);
+ fstate.incrementOpenCount();
+ fstate.setNodeRef(nodeRef);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Creaste folder, state=" + fstate);
+ }
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Created directory: \n" +
+ " path: " + path + "\n" +
+ " file open params: " + params + "\n" +
+ " node: " + nodeRef);
+ }
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create directory - access denied, " + params.getFullPath());
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Create directory " + params.getFullPath());
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Create directory error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Create directory " + params.getFullPath());
+ }
+ }
+
+ /**
+ * Delete the directory from the filesystem.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param dir Directory name.
+ * @exception java.io.IOException The exception description.
+ */
+ public void deleteDirectory(SrvSession sess, TreeConnection tree, String dir) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ // get the device root
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ NodeRef deviceRootNodeRef = ctx.getRootNode();
+
+ try
+ {
+ // Get the node for the folder
+
+ NodeRef nodeRef = cifsHelper.getNodeRef(deviceRootNodeRef, dir);
+ if (fileFolderService.exists(nodeRef))
+ {
+ // Check if the folder is empty
+
+ if ( cifsHelper.isFolderEmpty( nodeRef) == true) {
+
+ // Delete the folder node
+
+ fileFolderService.delete(nodeRef);
+
+ // Remove the file state
+
+ if ( ctx.hasStateTable())
+ ctx.getStateTable().removeFileState(dir);
+ }
+ else
+ throw new DirectoryNotEmptyException( dir);
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Deleted directory: \n" +
+ " directory: " + dir + "\n" +
+ " node: " + nodeRef);
+ }
+ }
+ catch (FileNotFoundException e)
+ {
+ // already gone
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Deleted directory : \n" +
+ " directory: " + dir);
+ }
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete directory - access denied, " + dir);
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Delete directory " + dir);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete directory", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Delete directory " + dir);
+ }
+ }
+
+ /**
+ * Flush any buffered output for the specified file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param file Network file context.
+ * @exception java.io.IOException The exception description.
+ */
+ public void flushFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException
+ {
+ // Flush the file data
+
+ file.flushFile();
+ }
+
+ /**
+ * Close the file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection.
+ * @param param Network file context.
+ * @exception java.io.IOException If an error occurs.
+ */
+ public void closeFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ // Get the associated file state
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ if ( ctx.hasStateTable())
+ {
+ FileState fstate = ctx.getStateTable().findFileState(file.getFullName());
+ if ( fstate != null)
+ fstate.decrementOpenCount();
+ }
+
+ // Defer to the network file to close the stream and remove the content
+
+ file.closeFile();
+
+ // Remove the node if marked for delete
+
+ if (file.hasDeleteOnClose())
+ {
+ // Check if the file is a noderef based file
+
+ if ( file instanceof NodeRefNetworkFile)
+ {
+ 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
+
+ if (fileFolderService.exists(nodeRef))
+ {
+ try
+ {
+ // Delete the file
+
+ fileFolderService.delete(nodeRef);
+
+ // Remove the file state
+
+ if ( ctx.hasStateTable())
+ ctx.getStateTable().removeFileState(file.getFullName());
+
+ // Commit the current transaction
+
+// sess.endTransaction();
+// beginReadTransaction( sess);
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete on close - access denied, " + file.getFullName());
+
+ // Convert to a filesystem access denied exception
+
+ throw new AccessDeniedException("Delete on close " + file.getFullName());
+ }
+ }
+ }
+ else if ( file instanceof PseudoNetworkFile ||
+ file instanceof MemoryNetworkFile)
+ {
+ // Delete the pseudo file
+
+ if ( hasPseudoFileInterface(ctx))
+ {
+ // Delete the pseudo file
+
+ getPseudoFileInterface(ctx).deletePseudoFile( sess, tree, file.getFullName());
+ }
+ }
+ }
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Closed file: \n" +
+ " network file: " + file + "\n" +
+ " deleted on close: " + file.hasDeleteOnClose());
+ }
+ }
+
+ /**
+ * Delete the specified file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param file NetworkFile
+ * @exception java.io.IOException The exception description.
+ */
+ public void deleteFile(SrvSession sess, TreeConnection tree, String name) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ // Get the device context
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ try
+ {
+ // Get the node
+
+ NodeRef nodeRef = getNodeForPath(tree, name);
+ if (fileFolderService.exists(nodeRef))
+ {
+ fileFolderService.delete(nodeRef);
+
+ // Remove the file state
+
+ if ( ctx.hasStateTable())
+ ctx.getStateTable().removeFileState(name);
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Deleted file: \n" +
+ " file: " + name + "\n" +
+ " node: " + nodeRef);
+ }
+ }
+ catch (NodeLockedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete file - access denied (locked)");
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Delete " + name);
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete file - access denied");
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Delete " + name);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Delete file error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Delete file " + name);
+ }
+ }
+
+ /**
+ * Rename the specified file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param oldName java.lang.String
+ * @param newName java.lang.String
+ * @exception java.io.IOException The exception description.
+ */
+ public void renameFile(SrvSession sess, TreeConnection tree, String oldName, String newName) throws IOException
+ {
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ try
+ {
+ // Get the device context
+
+ 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];
+
+ // Check if this is a rename within the same folder
+
+ String[] oldPaths = FileName.splitPath( oldName);
+
+ boolean sameFolder = false;
+ if ( splitPaths[0].equalsIgnoreCase( oldPaths[0]))
+ sameFolder = true;
+
+ // Update the state table
+
+ boolean relinked = false;
+ if ( ctx.hasStateTable())
+ {
+ // Check if the file rename can be relinked to a previous version
+
+ if ( !cifsHelper.isDirectory(nodeToMoveRef) )
+ {
+ // Check if there is a renamed file state for the new file name
+
+ FileState renState = ctx.getStateTable().removeFileState(newName);
+
+ if ( renState != null && renState.getFileStatus() == FileStateStatus.Renamed)
+ {
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug(" Found rename state, relinking, " + renState);
+
+ // Relink the new version of the file data to the previously renamed node so that it
+ // picks up version history and other settings.
+
+ cifsHelper.relinkNode( renState.getNodeRef(), nodeToMoveRef, targetFolderRef, name);
+ relinked = true;
+
+ // Link the node ref for the associated rename state
+
+ if ( renState.hasRenameState())
+ renState.getRenameState().setNodeRef(nodeToMoveRef);
+
+ // Remove the file state for the old file name
+
+ ctx.getStateTable().removeFileState(oldName);
+
+ // Get, or create, a file state for the new file path
+
+ FileState fstate = ctx.getStateTable().findFileState(newName, false, true);
+
+ fstate.setNodeRef(renState.getNodeRef());
+ fstate.setFileStatus(FileStateStatus.FileExists);
+ }
+ }
+ else
+ {
+ // Get the file state for the folder, if available
+
+ FileState fstate = ctx.getStateTable().findFileState(oldName);
+
+ if ( fstate != null)
+ {
+ // Update the file state index to use the new name
+
+ ctx.getStateTable().renameFileState(newName, fstate);
+ }
+ }
+ }
+
+ // Move the file/folder, if not relinked to previous version history
+
+ if (!relinked)
+ {
+ // Move or rename the file/folder
+
+ if ( sameFolder == true)
+ {
+ // Check if the new file name is a temporary file name
+
+ String newNameNorm = newName.toLowerCase();
+ boolean isTempFile = false;
+
+ if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp")) {
+
+ // Add the temporary aspect, also prevents versioning
+
+ nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null);
+
+ // Indicate that the new file is a temporary file
+
+ isTempFile = true;
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Added Temporary aspect to renamed file " + newName);
+ }
+
+ // Rename the file/folder
+
+ cifsHelper.rename(nodeToMoveRef, name);
+
+ // Check if the temporary aspect should be removed from the renamed file
+
+ String oldNameNorm = oldName.toLowerCase();
+
+ if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp"))) {
+
+ // Remove the temporary aspect
+
+ nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Removed Temporary aspect from renamed file " + newName);
+ }
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Renamed file: from: " + oldName + " to: " + newName);
+ }
+ else
+ {
+ // Move the file/folder
+
+ cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Moved file: from: " + oldName + " to: " + newName);
+ }
+
+ // Check if we renamed a file, if so then cache the rename details for a short period
+ // in case another file renamed to the old name. MS Word uses renames to move a new
+ // version of a document into place so we need to reconnect the version history.
+
+ if ( !cifsHelper.isDirectory(nodeToMoveRef))
+ {
+ // Get or create a new file state for the old file path
+
+ FileState fstate = ctx.getStateTable().findFileState(oldName, false, true);
+
+ // Make sure the file state is cached for a short while, the file may not be open so the
+ // file state could be expired
+
+ fstate.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
+
+ // Indicate that this is a renamed file state, set the node ref of the file that was renamed
+
+ fstate.setFileStatus(FileStateStatus.Renamed);
+ fstate.setNodeRef(nodeToMoveRef);
+
+ // Get, or create, a file state for the new file path
+
+ FileState newState = ctx.getStateTable().findFileState(newName, false, true);
+
+ newState.setNodeRef(nodeToMoveRef);
+ newState.setFileStatus(FileStateStatus.FileExists);
+
+ // Link the renamed state to the new state
+
+ fstate.setRenameState(newState);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ {
+ logger.debug("Cached rename state for " + oldName + ", state=" + fstate);
+ logger.debug(" new name " + newName + ", state=" + newState);
+ }
+ }
+ }
+
+ // DEBUG
+
+ if (logger.isDebugEnabled())
+ logger.debug("Moved node: from: " + oldName + " to: " + newName);
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Rename file - access denied, " + oldName);
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Rename file " + oldName);
+ }
+ catch (NodeLockedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Rename file", ex);
+
+ // Convert to an filesystem access denied exception
+
+ throw new AccessDeniedException("Node locked " + oldName);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Rename file", ex);
+
+ // Convert to a general I/O exception
+
+ throw new AccessDeniedException("Rename file " + oldName);
+ }
+ }
+
+ /**
+ * Set file information
+ *
+ * @param sess SrvSession
+ * @param tree TreeConnection
+ * @param name String
+ * @param info FileInfo
+ * @exception IOException
+ */
+ public void setFileInformation(SrvSession sess, TreeConnection tree, String name, FileInfo info) throws IOException
+ {
+ try
+ {
+ // Get the device context
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ // Check if pseudo files are enabled
+
+ if ( hasPseudoFileInterface(ctx) &&
+ getPseudoFileInterface(ctx).isPseudoFile( sess, tree, name))
+ {
+ // Allow the file information to be changed
+
+ return;
+ }
+
+ // Get the file/folder node
+
+ NodeRef nodeRef = getNodeForPath(tree, name);
+ FileState fstate = getStateForPath(tree, name);
+
+ // Check permissions on the file/folder node
+
+ if ( permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
+ throw new AccessDeniedException("No write access to " + name);
+
+ if ( permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
+ throw new AccessDeniedException("No delete access to " + name);
+
+ // Check if the file is being marked for deletion, if so then check if the file is locked
+
+ if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
+ {
+ // Start a transaction
+
+ beginReadTransaction( sess);
+
+ // Check if the node is locked
+
+ if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE))
+ {
+ // Get the lock type, if any
+
+ String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
+
+ if ( lockTypeStr != null)
+ throw new AccessDeniedException("Node locked, cannot mark for delete");
+ }
+
+ // Update the change date/time
+
+ if ( fstate != null)
+ fstate.updateChangeDateTime();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set deleteOnClose=true file=" + name);
+ }
+
+ // Set the creation date/time
+
+ if ( info.hasSetFlag(FileInfo.SetCreationDate)) {
+
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ // Set the creation date on the file/folder node
+
+ Date createDate = new Date( info.getCreationDateTime());
+ nodeService.setProperty( nodeRef, ContentModel.PROP_CREATED, createDate);
+
+ // Update the change date/time
+
+ if ( fstate != null)
+ fstate.updateChangeDateTime();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set creationDate=" + createDate + " file=" + name);
+ }
+
+ // Set the modification date/time
+
+ if ( info.hasSetFlag(FileInfo.SetModifyDate)) {
+
+ // Create the transaction
+
+ beginWriteTransaction( sess);
+
+ // Set the creation date on the file/folder node
+
+ Date modifyDate = new Date( info.getModifyDateTime());
+ nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
+
+ // Update the change date/time
+
+ if ( fstate != null)
+ fstate.updateChangeDateTime();
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set modifyDate=" + modifyDate + " file=" + name);
+ }
+ }
+ catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Set file information - access denied, " + name);
+
+ // Convert to a filesystem access denied status
+
+ throw new AccessDeniedException("Set file information " + name);
+ }
+ catch (AlfrescoRuntimeException ex)
+ {
+ // Debug
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Open file error", ex);
+
+ // Convert to a general I/O exception
+
+ throw new IOException("Set file information " + name);
+ }
+ }
+
+ /**
+ * Truncate a file to the specified size
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param file Network file details
+ * @param size New file length
+ * @exception java.io.IOException The exception description.
+ */
+ public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long size) throws IOException
+ {
+ // Truncate or extend the file to the required size
+
+ file.truncateFile(size);
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Truncated file: \n" +
+ " network file: " + file + "\n" +
+ " size: " + size);
+ }
+ }
+
+ /**
+ * Read a block of data from the specified file.
+ *
+ * @param sess Session details
+ * @param tree Tree connection
+ * @param file Network file
+ * @param buf Buffer to return data to
+ * @param bufPos Starting position in the return buffer
+ * @param siz Maximum size of data to return
+ * @param filePos File offset to read data
+ * @return Number of bytes read
+ * @exception java.io.IOException The exception description.
+ */
+ public int readFile(
+ SrvSession sess, TreeConnection tree, NetworkFile file,
+ byte[] buffer, int bufferPosition, int size, long fileOffset) throws IOException
+ {
+ // 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
+
+ if ( file instanceof ContentNetworkFile)
+ {
+ ContentNetworkFile contentFile = (ContentNetworkFile) file;
+
+ if ( contentFile.hasContent() == false)
+ beginReadTransaction( sess);
+ }
+
+ // Read a block of data from the file
+
+ int count = file.readFile(buffer, size, bufferPosition, fileOffset);
+
+ if ( count == -1)
+ {
+ // Read count of -1 indicates a read past the end of file
+
+ count = 0;
+ }
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Read bytes from file: \n" +
+ " network file: " + file + "\n" +
+ " buffer size: " + buffer.length + "\n" +
+ " buffer pos: " + bufferPosition + "\n" +
+ " size: " + size + "\n" +
+ " file offset: " + fileOffset + "\n" +
+ " bytes read: " + count);
+ }
+ return count;
+ }
+
+ /**
+ * Seek to the specified file position.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param file Network file.
+ * @param pos Position to seek to.
+ * @param typ Seek type.
+ * @return New file position, relative to the start of file.
+ */
+ public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException
+ {
+ // 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)
+ beginReadTransaction( sess);
+
+ // Set the file position
+
+ return file.seekFile(pos, typ);
+ }
+
+ /**
+ * Write a block of data to the file.
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ * @param file Network file details
+ * @param buf byte[] Data to be written
+ * @param bufoff Offset within the buffer that the data starts
+ * @param siz int Data length
+ * @param fileoff Position within the file that the data is to be written.
+ * @return Number of bytes actually written
+ * @exception java.io.IOException The exception description.
+ */
+ public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file,
+ byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException
+ {
+ // 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)
+ beginReadTransaction( sess);
+ }
+
+ // Write to the file
+
+ file.writeFile(buffer, size, bufferOffset, fileOffset);
+
+ // done
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Wrote bytes to file: \n" +
+ " network file: " + file + "\n" +
+ " buffer size: " + buffer.length + "\n" +
+ " size: " + size + "\n" +
+ " file offset: " + fileOffset);
+ }
+ return size;
+ }
+
+ /**
+ * Get the node for the specified path
+ *
+ * @param tree TreeConnection
+ * @param path String
+ * @return NodeRef
+ * @exception FileNotFoundException
+ */
+ public NodeRef getNodeForPath(TreeConnection tree, String path)
+ throws FileNotFoundException
+ {
+ // Check if there is a cached state for the path
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+
+ if ( ctx.hasStateTable())
+ {
+ // Try and get the node ref from an in memory file state
+
+ FileState fstate = ctx.getStateTable().findFileState(path);
+ if ( fstate != null && fstate.hasNodeRef() && fstate.exists() )
+ {
+ // Check that the node exists
+
+ if (fileFolderService.exists(fstate.getNodeRef()))
+ {
+ // Bump the file states expiry time
+
+ fstate.setExpiryTime(System.currentTimeMillis() + FileState.DefTimeout);
+
+ // Return the cached noderef
+
+ return fstate.getNodeRef();
+ }
+ else
+ {
+ ctx.getStateTable().removeFileState(path);
+ }
+ }
+ }
+
+ // Search the repository for the node
+
+ 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 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
+ *
+ * @param tree TreeConnection
+ * @param path String
+ * @return FileState
+ * @exception FileNotFoundException
+ */
+ public FileState getStateForPath(TreeConnection tree, String path)
+ throws FileNotFoundException
+ {
+ // Check if there is a cached state for the path
+
+ ContentContext ctx = (ContentContext) tree.getContext();
+ FileState fstate = null;
+
+ if ( ctx.hasStateTable())
+ {
+ // Get the file state for a file/folder
+
+ fstate = ctx.getStateTable().findFileState(path);
+ }
+
+ // Return the file state
+
+ return fstate;
+ }
+
+ /**
+ * Connection opened to this disk device
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ */
+ public void treeClosed(SrvSession sess, TreeConnection tree)
+ {
+ // Nothing to do
+ }
+
+ /**
+ * Connection closed to this device
+ *
+ * @param sess Server session
+ * @param tree Tree connection
+ */
+ public void treeOpened(SrvSession sess, TreeConnection tree)
+ {
+ // Nothing to do
+ }
+
+ /**
+ * Return the lock manager used by this filesystem
+ *
+ * @param sess SrvSession
+ * @param tree TreeConnection
+ * @return LockManager
+ */
+ public LockManager getLockManager(SrvSession sess, TreeConnection tree) {
+ return _lockManager;
+ }
+}
diff --git a/source/java/org/alfresco/filesys/repo/NodeMonitor.java b/source/java/org/alfresco/filesys/repo/NodeMonitor.java
index a11972ebba..11276214e7 100644
--- a/source/java/org/alfresco/filesys/repo/NodeMonitor.java
+++ b/source/java/org/alfresco/filesys/repo/NodeMonitor.java
@@ -37,7 +37,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
-import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
@@ -516,8 +516,8 @@ public class NodeMonitor extends TransactionListenerAdapter
// Use the system user as the authenticated context for the node monitor
- AuthenticationComponent authComponent = m_filesysDriver.getAuthComponent();
- authComponent.setCurrentUser( authComponent.getSystemUserName());
+ AuthenticationContext authenticationContext = m_filesysDriver.getAuthenticationContext();
+ authenticationContext.setSystemUserAsCurrentUser();
// Loop until shutdown
diff --git a/source/java/org/alfresco/jcr/test/TestData.java b/source/java/org/alfresco/jcr/test/TestData.java
index ed0075cfb7..98ed717546 100644
--- a/source/java/org/alfresco/jcr/test/TestData.java
+++ b/source/java/org/alfresco/jcr/test/TestData.java
@@ -1,148 +1,148 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.jcr.test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-
-import org.alfresco.repo.importer.ImporterBootstrap;
-import org.alfresco.repo.security.authentication.AuthenticationComponent;
-import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
-import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.cmr.view.ImporterService;
-import org.alfresco.service.namespace.NamespaceService;
-import org.alfresco.service.transaction.TransactionService;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-
-
-public class TestData
-{
- public static final String TEST_WORKSPACE = "test";
-
- /**
- * Generate Test Workspace within Repository
- *
- * @param args
- */
- public static void main(String[] args)
- {
- ApplicationContext context = new ClassPathXmlApplicationContext("org/alfresco/jcr/test/test-context.xml");
- generateTestData(context, TEST_WORKSPACE);
- System.out.println("Generated TCK test data to workspace: " + TEST_WORKSPACE);
- System.exit(0);
- }
-
- /**
- * Bootstrap Repository with JCR Test Data
- *
- * @param applicationContext
- * @param workspaceName
- */
- public static void generateTestData(final ApplicationContext applicationContext, String workspaceName)
- {
- final ServiceRegistry serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY);
- TransactionService transactionService = serviceRegistry.getTransactionService();
- RetryingTransactionCallback