From f2c5192a7f66768658b4122a108dc3cdd4807ae6 Mon Sep 17 00:00:00 2001 From: Gary Spencer Date: Tue, 12 Dec 2006 14:07:07 +0000 Subject: [PATCH] Updates to AVM virtualization view for the latest layout with DATA and METADATA folders. Fixes to AVM filesystem transaction handling. Made SrvSession.beginTransaction() private and added beginReadTransaction() and beginWriteTransaction(). git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4580 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../java/org/alfresco/filesys/CIFSServer.java | 8 + .../alfresco/filesys/avm/AVMDiskDriver.java | 650 ++++++++++++------ .../org/alfresco/filesys/avm/AVMPath.java | 345 ++++++++-- .../alfresco/filesys/avm/AVMShareMapper.java | 2 +- .../filesys/avm/DummyFolderPseudoFile.java | 79 +++ .../alfresco/filesys/server/SrvSession.java | 28 +- .../filesys/server/auth/ClientInfo.java | 103 +++ .../server/config/ServerConfiguration.java | 360 +++++++++- .../filesys/server/filesys/FileInfo.java | 49 +- .../server/filesys/FileOpenParams.java | 56 ++ .../filesys/server/filesys/FileType.java | 72 ++ .../smb/server/repo/ContentDiskDriver.java | 27 +- .../server/repo/ContentIOControlHandler.java | 4 +- .../repo/desk/CheckInOutDesktopAction.java | 2 +- .../repo/desk/JavaScriptDesktopAction.java | 4 +- 15 files changed, 1474 insertions(+), 315 deletions(-) create mode 100644 source/java/org/alfresco/filesys/avm/DummyFolderPseudoFile.java create mode 100644 source/java/org/alfresco/filesys/server/filesys/FileType.java diff --git a/source/java/org/alfresco/filesys/CIFSServer.java b/source/java/org/alfresco/filesys/CIFSServer.java index 34fa3fe64a..6d94111123 100644 --- a/source/java/org/alfresco/filesys/CIFSServer.java +++ b/source/java/org/alfresco/filesys/CIFSServer.java @@ -199,6 +199,14 @@ public class CIFSServer extends AbstractLifecycleBean if ( srv != null) srv.shutdownServer(true); + // Stop the NFS server, if running + + server.getConfiguration().setNFSServerEnabled(false); + + srv = server.getConfiguration().findServer("NFS"); + if ( srv != null) + srv.shutdownServer(true); + // Only wait for shutdown if the SMB/CIFS server is enabled if ( server.getConfiguration().isSMBServerEnabled()) diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java index aeb6e2b1d8..be57a7d08d 100644 --- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java +++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java @@ -523,10 +523,6 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Create a path for the virtualization view avmPath = new AVMPath( path); - - // Validate that the store and version, if specified - - } else { @@ -605,14 +601,14 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is the virtualization view - if ( ctx.isVirtualizationView() && storePath.isPseudoPath()) + if ( ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) { throw new AccessDeniedException( "Cannot create folder in store/version layer, " + params.getPath()); } // Create a new file - sess.beginTransaction( m_transactionService, false); + sess.beginWriteTransaction( m_transactionService); try { @@ -649,8 +645,6 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is writable AVMContext ctx = (AVMContext) tree.getContext(); - if ( ctx.isVersion() != AVMContext.VERSION_HEAD) - throw new AccessDeniedException("Cannot create " + params.getPath() + ", filesys not writable"); // Split the path to get the file name and relative path @@ -667,14 +661,18 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is the virtualization view - if ( ctx.isVirtualizationView() && storePath.isPseudoPath()) + if ( ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) { throw new AccessDeniedException( "Cannot create file in store/version layer, " + params.getPath()); } + else if ( storePath.getVersion() != AVMContext.VERSION_HEAD) + { + throw new AccessDeniedException("Cannot create " + params.getPath() + ", filesys not writable"); + } // Create a new file - sess.beginTransaction( m_transactionService, false); + sess.beginWriteTransaction( m_transactionService); AVMNetworkFile netFile = null; @@ -687,13 +685,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Get the new file details AVMPath fileStorePath = buildStorePath( ctx, params.getPath()); - AVMNodeDescriptor nodeDesc = m_avmService.lookup( ctx.isVersion(), fileStorePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( fileStorePath.getVersion(), fileStorePath.getAVMPath()); if ( nodeDesc != null) { // Create the network file object for the new file - netFile = new AVMNetworkFile( nodeDesc, fileStorePath.getAVMPath(), ctx.isVersion(), m_avmService); + netFile = new AVMNetworkFile( nodeDesc, fileStorePath.getAVMPath(), fileStorePath.getVersion(), m_avmService); netFile.setGrantedAccess(NetworkFile.READWRITE); netFile.setFullName(params.getPath()); @@ -750,11 +748,11 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Make sure the path is to a folder before deleting it - sess.beginTransaction( m_transactionService, false); + sess.beginWriteTransaction( m_transactionService); try { - AVMNodeDescriptor nodeDesc = m_avmService.lookup( ctx.isVersion(), storePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( storePath.getVersion(), storePath.getAVMPath()); if ( nodeDesc != null) { // Check that we are deleting a folder @@ -815,11 +813,11 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Make sure the path is to a file before deleting it - sess.beginTransaction( m_transactionService, false); + sess.beginWriteTransaction( m_transactionService); try { - AVMNodeDescriptor nodeDesc = m_avmService.lookup( ctx.isVersion(), storePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( storePath.getVersion(), storePath.getAVMPath()); if ( nodeDesc != null) { // Check that we are deleting a file @@ -865,42 +863,52 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { if ( logger.isDebugEnabled()) logger.debug("File exists check, path=" + name + ", storePath=" + storePath); - // Check if the filesystem is the virtualization view + // Check if the path is valid int status = FileStatus.NotExist; - if ( ctx.isVirtualizationView() && storePath.isPseudoPath()) + if ( storePath.isValid() == false) + return status; + + // Check if the filesystem is the virtualization view + + if ( ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) { - // Check if the search path is for the root or a store folder + // Find the file state for the pseudo folder - if ( storePath.isRootPath()) + FileState fstate = findPseudoState( storePath, ctx); + + if ( fstate != null) { - return FileStatus.DirectoryExists; - } - else - { - // Get the pseudo file for the store/version folder + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug( " Found pseudo file " + fstate); + + // Check if the pseudo file is a file or folder - PseudoFile psFile = findPseudoFolder( storePath, ctx); - if ( psFile != null) - { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( " Found pseudo file " + psFile); - - return FileStatus.DirectoryExists; - } + if ( fstate.isDirectory()) + status = FileStatus.DirectoryExists; else - return FileStatus.NotExist; + status = FileStatus.FileExists; } + else + { + // Invalid pseudo file path + + status = FileStatus.NotExist; + } + + // Return the file status + + return status; } // Search for the file/folder - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); - AVMNodeDescriptor nodeDesc = m_avmService.lookup( ctx.isVersion(), storePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( storePath.getVersion(), storePath.getAVMPath()); if ( nodeDesc != null) { @@ -955,9 +963,14 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { if ( logger.isDebugEnabled()) logger.debug("Get file information, path=" + name + ", storePath=" + storePath); + // Check if hte path is valid + + if ( storePath.isValid() == false) + throw new FileNotFoundException( name); + // Check if the filesystem is the virtualization view - if ( ctx.isVirtualizationView() && storePath.isPseudoPath()) + if ( ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) { // Check if the search path is for the root, a store or version folder @@ -965,7 +978,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { { // Return dummy file informatiom for the root folder - return new FileInfo( name,0L, FileAttribute.Directory); + return new FileInfo( name, 0L, FileAttribute.Directory); } else { @@ -981,13 +994,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { return psFile.getFileInfo(); } else - return null; + throw new FileNotFoundException( name); } } // Search for the file/folder - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); FileInfo info = null; @@ -1095,7 +1108,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is the virtualization view - if ( ctx.isVirtualizationView() && storePath.isPseudoPath()) + if ( ctx.isVirtualizationView() && storePath.isReadOnlyPseudoPath()) { // Check if the path is for the root, a store or version folder @@ -1125,7 +1138,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Search for the file/folder - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); AVMNetworkFile netFile = null; @@ -1133,20 +1146,20 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { { // Get the details of the file/folder - AVMNodeDescriptor nodeDesc = m_avmService.lookup( ctx.isVersion(), storePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( storePath.getVersion(), storePath.getAVMPath()); if ( nodeDesc != null) { // Check if the filesystem is read-only and write access has been requested - if ( ctx.isVersion() != AVMContext.VERSION_HEAD && ( params.isReadWriteAccess() || params.isWriteOnlyAccess())) + if ( storePath.getVersion() != AVMContext.VERSION_HEAD && ( params.isReadWriteAccess() || params.isWriteOnlyAccess())) throw new AccessDeniedException("File " + params.getPath() + " is read-only"); // Create the network file object for the opened file/folder - netFile = new AVMNetworkFile( nodeDesc, storePath.getAVMPath(), ctx.isVersion(), m_avmService); + netFile = new AVMNetworkFile( nodeDesc, storePath.getAVMPath(), storePath.getVersion(), m_avmService); - if ( params.isReadOnlyAccess() || ctx.isVersion() != AVMContext.VERSION_HEAD) + if ( params.isReadOnlyAccess() || storePath.getVersion() != AVMContext.VERSION_HEAD) netFile.setGrantedAccess(NetworkFile.READONLY); else netFile.setGrantedAccess(NetworkFile.READWRITE); @@ -1202,7 +1215,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { AVMNetworkFile avmFile = (AVMNetworkFile) file; if ( avmFile.hasContentChannel() == false) - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); // Read the file @@ -1252,14 +1265,14 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is the virtualization view - if ( ctx.isVirtualizationView() && oldAVMPath.isPseudoPath()) + if ( ctx.isVirtualizationView() && oldAVMPath.isReadOnlyPseudoPath()) { throw new AccessDeniedException( "Cannot rename folder in store/version layer, " + oldName); } // Start a transaction for the rename - sess.beginTransaction( m_transactionService, false); + sess.beginWriteTransaction( m_transactionService); try { @@ -1304,7 +1317,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { AVMNetworkFile avmFile = (AVMNetworkFile) file; if ( avmFile.hasContentChannel() == false) - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); // Set the file position @@ -1368,60 +1381,73 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Check if the filesystem is the virtualization view - if ( avmCtx.isVirtualizationView() && storePath.isPseudoPath()) + if ( avmCtx.isVirtualizationView()) { - // Check if the search path is for the root or a store folder + // Check for a search of a pseudo folder - FileState fstate = findPseudoState( storePath, avmCtx); - - if ( fstate != null) - { - // Get the pseudo file list for the parent directory - - PseudoFileList searchList = fstate.getPseudoFileList(); - - // Check if this is a single file or wildcard search + if (storePath.isReadOnlyPseudoPath()) + { + // Get the file state for the folder being searched + + FileState fstate = findPseudoState( storePath, avmCtx); + + if ( fstate != null) + { + // Get the pseudo file list for the parent directory - if ( WildCard.containsWildcards( searchPath)) - { - // Create the search context, wildcard filter will take care of secondary filtering of the - // folder listing - - WildCard wildCardFilter = new WildCard( paths[1], false); - return new PseudoFileListSearchContext( searchList, attrib, wildCardFilter); - } - else - { - // Search the pseudo file list for the required file - - PseudoFile pseudoFile = searchList.findFile( paths[1], false); - if ( pseudoFile != null) - { - // Create a search context using the single file details - - PseudoFileList singleList = new PseudoFileList(); - singleList.addFile( pseudoFile); - - return new PseudoFileListSearchContext( singleList, attrib, null); - } - } - } - - // File not found - - throw new FileNotFoundException( searchPath); + PseudoFileList searchList = fstate.getPseudoFileList(); + + // Check if this is a single file or wildcard search + + if ( WildCard.containsWildcards( searchPath)) + { + // Create the search context, wildcard filter will take care of secondary filtering of the + // folder listing + + WildCard wildCardFilter = new WildCard( paths[1], false); + return new PseudoFileListSearchContext( searchList, attrib, wildCardFilter); + } + else + { + // Search the pseudo file list for the required file + + PseudoFile pseudoFile = searchList.findFile( paths[1], false); + if ( pseudoFile != null) + { + // Create a search context using the single file details + + PseudoFileList singleList = new PseudoFileList(); + singleList.addFile( pseudoFile); + + return new PseudoFileListSearchContext( singleList, attrib, null); + } + } + } + + // File not found + + throw new FileNotFoundException( searchPath); + } + else if ( storePath.isLevel() == AVMPath.LevelId.HeadMetaData || storePath.isLevel() == AVMPath.LevelId.VersionMetaData) + { + // Return an empty file list for now + + PseudoFileList metaFiles = new PseudoFileList(); + + return new PseudoFileListSearchContext( metaFiles, attrib, null); + } } - + // Check if the path is a wildcard search - sess.beginTransaction( m_transactionService, true); + sess.beginReadTransaction( m_transactionService); SearchContext context = null; if ( WildCard.containsWildcards( searchPath)) { // Get the file listing for the folder - AVMNodeDescriptor[] fileList = m_avmService.getDirectoryListingArray( avmCtx.isVersion(), storePath.getAVMPath(), false); + AVMNodeDescriptor[] fileList = m_avmService.getDirectoryListingArray( storePath.getVersion(), storePath.getAVMPath(), false); // Create the search context @@ -1447,7 +1473,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Get the single file/folder details - AVMNodeDescriptor nodeDesc = m_avmService.lookup( avmCtx.isVersion(), storePath.getAVMPath()); + AVMNodeDescriptor nodeDesc = m_avmService.lookup( storePath.getVersion(), storePath.getAVMPath()); if ( nodeDesc != null) { @@ -1475,12 +1501,17 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long siz) throws java.io.IOException { + // Check if the file is a directory, or only has read access + + if ( file.getGrantedAccess() == NetworkFile.READONLY) + throw new AccessDeniedException(); + // If the content channel is not open for the file then start a transaction AVMNetworkFile avmFile = (AVMNetworkFile) file; - if ( avmFile.hasContentChannel() == false) - sess.beginTransaction( m_transactionService, true); + if ( avmFile.hasContentChannel() == false || avmFile.isWritable() == false) + sess.beginWriteTransaction( m_transactionService); // Truncate or extend the file @@ -1505,9 +1536,9 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { long fileoff) throws java.io.IOException { - // Check if the file is a directory + // Check if the file is a directory, or only has read access - if ( file.isDirectory()) + if ( file.isDirectory() || file.getGrantedAccess() == NetworkFile.READONLY) throw new AccessDeniedException(); // If the content channel is not open for the file, or the channel is not writable, then start a transaction @@ -1515,7 +1546,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { AVMNetworkFile avmFile = (AVMNetworkFile) file; if ( avmFile.hasContentChannel() == false || avmFile.isWritable() == false) - sess.beginTransaction( m_transactionService, true); + sess.beginWriteTransaction( m_transactionService); // Write the data to the file @@ -1558,69 +1589,165 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { private final PseudoFile findPseudoFolder( AVMPath avmPath, AVMContext avmCtx) { // Check if the path is to a store pseudo folder + + if ( avmPath.isRootPath()) + return null; + // Get the file state for the parent of the required folder + + FileState fstate = null; + StringBuilder str = null; PseudoFile psFile = null; - if ( avmPath.hasVersion() == false) - { - // Check for the path within the store layer - - FileState fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); - PseudoFileList pseudoList = fstate.getPseudoFileList(); - - psFile = pseudoList.findFile( avmPath.getStoreName(), false); - } - else if ( avmPath.hasRelativePath() == false) - { - // Build the path to the parent store folder - - StringBuilder storeStr = new StringBuilder(); - - storeStr.append( FileName.DOS_SEPERATOR); - storeStr.append( avmPath.getStoreName()); - - // Search for the file state for the store pseudo folder - - FileState storeState = avmCtx.getStateTable().findFileState( storeStr.toString()); - if ( storeState != null) - { - // Search the store pseudo folder file list for the required version - - psFile = storeState.getPseudoFileList().findFile( avmPath.getVersionString(), false); - } - else - { - // Get the list of AVM store versions + switch ( avmPath.isLevel()) + { + // Store root folder + + case StoreRoot: + + // Get the root folder file state + + fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); + if ( fstate != null) + psFile = fstate.getPseudoFileList().findFile( avmPath.getStoreName(), false); + break; + + // Versions root or Head folder + + case VersionRoot: + case Head: + + // Create a path to the parent store + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + + // Find/create the file state for the store + + AVMPath storePath = new AVMPath( str.toString()); + fstate = findPseudoState( storePath, avmCtx); + + // Find the version root or head pseudo folder + + if ( fstate != null) + { + if ( avmPath.isLevel() == AVMPath.LevelId.Head) + psFile = fstate.getPseudoFileList().findFile( AVMPath.VersionNameHead, true); + else + psFile = fstate.getPseudoFileList().findFile( AVMPath.VersionsFolder, true); + } + break; + + // Version folder + + case Version: - try - { - // Get the list of versions for the store - - List verList = m_avmService.getAVMStoreVersions( avmPath.getStoreName()); - - // Create a file state for the store path - - storeState = avmCtx.getStateTable().findFileState( storeStr.toString(), true, true); - - // Add pseudo files for the versions to the store state - - for ( VersionDescriptor verDesc : verList) - { - // Add the version pseudo folder - - storeState.addPseudoFile( new VersionPseudoFile ( avmPath.getVersionString(), verDesc)); - } - - // Search for the required version pseudo folder - - psFile = storeState.getPseudoFileList().findFile( avmPath.getVersionString(), false); - } - catch ( AVMNotFoundException ex) - { - // Invalid store name - } - } - } + // Create a path to the versions folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionsFolder); + + // Find/create the file state for the store + + AVMPath verrootPath = new AVMPath( str.toString()); + fstate = findPseudoState( verrootPath, avmCtx); + + // Find the version pseudo file + + if ( fstate != null) + { + // Build the version folder name string + + str.setLength( 0); + + str.append( AVMPath.VersionFolderPrefix); + str.append( avmPath.getVersion()); + + // find the version folder pseduo file + + psFile = fstate.getPseudoFileList().findFile( str.toString(), true); + } + break; + + // Head data or metadata folder + + case HeadData: + case HeadMetaData: + + // Create a path to the head folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionNameHead); + + // Find/create the file state for the store + + AVMPath headPath = new AVMPath( str.toString()); + fstate = findPseudoState( headPath, avmCtx); + + // Find the data or metadata pseudo folder + + if ( fstate != null) + { + // Find the pseudo folder + + if ( avmPath.isLevel() == AVMPath.LevelId.HeadData) + { + psFile = fstate.getPseudoFileList().findFile( AVMPath.DataFolder, true); + } + else + { + psFile = fstate.getPseudoFileList().findFile( AVMPath.MetaDataFolder, true); + } + } + break; + + // Version data or metadata folder + + case VersionData: + case VersionMetaData: + + // Create a path to the version folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionFolderPrefix); + str.append( avmPath.getVersion()); + + // Find/create the file state for the store + + AVMPath verPath = new AVMPath( str.toString()); + fstate = findPseudoState( verPath, avmCtx); + + // Find the data or metadata pseudo folder + + if ( fstate != null) + { + // Find the pseudo folder + + if ( avmPath.isLevel() == AVMPath.LevelId.VersionData) + { + psFile = fstate.getPseudoFileList().findFile( AVMPath.DataFolder, true); + } + else + { + psFile = fstate.getPseudoFileList().findFile( AVMPath.MetaDataFolder, true); + } + } + break; + } // Return the pseudo file, or null if not found @@ -1636,72 +1763,148 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { */ private final FileState findPseudoState( AVMPath avmPath, AVMContext avmCtx) { + // Make sure the is to a pseudo file/folder + + if ( avmPath.isPseudoPath() == false) + return null; + // Check if the path is to a store pseudo folder FileState fstate = null; - - if ( avmPath.isRootPath()) - { - // Get the root path file state - - fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); - } - else if ( avmPath.hasVersion() == false) - { - // Build the path to the parent store folder - - StringBuilder storeStr = new StringBuilder(); - - storeStr.append( FileName.DOS_SEPERATOR); - storeStr.append( avmPath.getStoreName()); - - // Search for the file state for the store pseudo folder - - fstate = avmCtx.getStateTable().findFileState( storeStr.toString()); - - if ( fstate == null) - { - // Get the list of AVM store versions + StringBuilder str = null; - try + switch ( avmPath.isLevel()) + { + // Root of the hieararchy + + case Root: + + // Get the root path file state + + fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); + break; + + // Store folder + + case StoreRoot: + + // Build the path to the parent store folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + + // Search for the file state for the store pseudo folder + + fstate = avmCtx.getStateTable().findFileState( str.toString()); + + if ( fstate == null) { - // Get the list of versions for the store - - List verList = m_avmService.getAVMStoreVersions( avmPath.getStoreName()); - // Create a file state for the store path - fstate = avmCtx.getStateTable().findFileState( storeStr.toString(), true, true); + fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); // Add a pseudo file for the head version fstate.addPseudoFile( new VersionPseudoFile( AVMPath.VersionNameHead)); - // Add pseudo files for the versions to the store state + // Add a pseudo file for the version root folder + + fstate.addPseudoFile( new DummyFolderPseudoFile( AVMPath.VersionsFolder)); + } + break; - if ( verList.size() > 0) + // Head folder + + case Head: + + // Build the path to the store head version folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionNameHead); + + // Search for the file state for the store head version pseudo folder + + fstate = avmCtx.getStateTable().findFileState( str.toString()); + + if ( fstate == null) + { + // Create a file state for the store head folder path + + fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + + // Add a pseudo file for the data pseudo folder + + fstate.addPseudoFile( new DummyFolderPseudoFile( AVMPath.DataFolder)); + + // Add a pseudo file for the metadata pseudo folder + + fstate.addPseudoFile( new DummyFolderPseudoFile( AVMPath.MetaDataFolder)); + } + break; + + // Version root folder + + case VersionRoot: + + // Get the list of AVM store versions + + try + { + // Build the path to the parent store folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionsFolder); + + // Create a file state for the store path + + fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + + // Add pseudo folders if the list is empty + + if ( fstate.hasPseudoFiles() == false) { - StringBuilder verStr = new StringBuilder(); + // Build the version folder name for the head version - for ( VersionDescriptor verDesc : verList) + StringBuilder verStr = new StringBuilder( AVMPath.VersionFolderPrefix); + verStr.append( "-1"); + + // Add a pseudo file for the head version + + fstate.addPseudoFile( new VersionPseudoFile( verStr.toString())); + + // Get the list of versions for the store + + List verList = m_avmService.getAVMStoreVersions( avmPath.getStoreName()); + + // Add pseudo files for the versions to the store state + + if ( verList.size() > 0) { - // Generate the version string - - String verName = null; - - if ( verDesc.getVersionID() == -1) - verName = AVMPath.VersionNameHead; - else + for ( VersionDescriptor verDesc : verList) { - verStr.setLength( 0); + // Generate the version string + + String verName = null; + + verStr.setLength( AVMPath.VersionFolderPrefix.length()); verStr.append( verDesc.getVersionID()); verName = verStr.toString(); + + // Add the version pseudo folder + + fstate.addPseudoFile( new VersionPseudoFile ( verName, verDesc)); } - - // Add the version pseudo folder - - fstate.addPseudoFile( new VersionPseudoFile ( verName, verDesc)); } } } @@ -1709,11 +1912,44 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { { // Invalid store name } + break; + + // Version folder - } + case Version: + + // Build the path to the store version folder + + str = new StringBuilder(); + + str.append( FileName.DOS_SEPERATOR); + str.append( avmPath.getStoreName()); + str.append( FileName.DOS_SEPERATOR); + str.append( AVMPath.VersionFolderPrefix); + str.append( avmPath.getVersion()); + + // Search for the file state for the version pseudo folder + + fstate = avmCtx.getStateTable().findFileState( str.toString()); + + if ( fstate == null) + { + // Create a file state for the version folder path + + fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + + // Add a pseudo file for the data pseudo folder + + fstate.addPseudoFile( new DummyFolderPseudoFile( AVMPath.DataFolder)); + + // Add a pseudo file for the metadata pseudo folder + + fstate.addPseudoFile( new DummyFolderPseudoFile( AVMPath.MetaDataFolder)); + } + break; } - - // Return the file state + + // Return the file state return fstate; } diff --git a/source/java/org/alfresco/filesys/avm/AVMPath.java b/source/java/org/alfresco/filesys/avm/AVMPath.java index a6da5eb5dc..5073d08d95 100644 --- a/source/java/org/alfresco/filesys/avm/AVMPath.java +++ b/source/java/org/alfresco/filesys/avm/AVMPath.java @@ -36,13 +36,34 @@ public class AVMPath { // Version id string for the head version - public static final String VersionNameHead = "Head"; + public static final String VersionNameHead = "HEAD"; + + // Folder name for the versions folder + + public static final String VersionsFolder = "VERSION"; + + // Head and version sub-folders + + public static final String DataFolder = "DATA"; + public static final String MetaDataFolder = "METADATA"; + + // Version folder prefix + + public static final String VersionFolderPrefix = "v"; // AVM path seperator public static final char AVM_SEPERATOR = '/'; public static final String AVM_SEPERATOR_STR = "/"; + // Level identifiers + + public enum LevelId { Invalid, Root, StoreRoot, Head, HeadData, HeadMetaData, VersionRoot, Version, VersionData, VersionMetaData, StorePath }; + + // Level identifier for this path + + private LevelId m_levelId = LevelId.Invalid; + // Store name private String m_storeName; @@ -95,6 +116,16 @@ public class AVMPath { parsePath( storeName, version, path); } + + /** + * Return the level id for the path + * + * @return LevelId + */ + public LevelId isLevel() + { + return m_levelId; + } /** * Return the store name @@ -175,7 +206,7 @@ public class AVMPath { */ public final boolean isValid() { - return m_storeName == null && m_path == null ? false : true; + return m_levelId == LevelId.Invalid ? false : true; } /** @@ -185,7 +216,20 @@ public class AVMPath { */ public final boolean isPseudoPath() { - return m_version == InvalidVersionId || m_path == null ? true : false; + return m_levelId == LevelId.Invalid || m_levelId == LevelId.StorePath ? false : true; + } + + /** + * Check if hte path is a read-only part of the pseudo folder tree + * + * @return boolean + */ + public final boolean isReadOnlyPseudoPath() + { + if ( isLevel() == LevelId.Root || isLevel() == LevelId.StoreRoot || isLevel() == LevelId.VersionRoot || + isLevel() == LevelId.Head || isLevel() == LevelId.Version) + return true; + return false; } /** @@ -195,9 +239,7 @@ public class AVMPath { */ public final boolean isRootPath() { - if ( m_path != null && m_path.equals( FileName.DOS_SEPERATOR_STR)) - return true; - return false; + return m_levelId == LevelId.Root ? true : false; } /** @@ -221,85 +263,179 @@ public class AVMPath { if ( paths == null || paths.length == 0) { m_path = FileName.DOS_SEPERATOR_STR; + m_levelId = LevelId.Root; return; } // Set the store name m_storeName = paths[0]; + m_levelId = LevelId.StoreRoot; if ( paths.length > 1) { - // Validate the version id + // Validate the next element, should be either the HEAD or VERSIONS folder - String verStr = paths[1]; - if ( verStr.equalsIgnoreCase( VersionNameHead)) + String levelStr = paths[1]; + + if ( levelStr.equalsIgnoreCase( VersionNameHead)) + { m_version = -1; + m_levelId = LevelId.Head; + } + else if ( levelStr.equalsIgnoreCase( VersionsFolder)) + { + m_levelId = LevelId.VersionRoot; + } else { - try - { - // Parse the version id - - m_version = Integer.parseInt( verStr); - - // Validate the version id - - if ( m_version < 0) - { - // Invalid version id - - m_storeName = null; - return; - } - } - catch ( NumberFormatException ex) - { - m_storeName = null; - return; - } + // Invalid folder at the current level + + m_levelId = LevelId.Invalid; + return; } - // If there additional path elements build the share and AVM relative paths + // Check the next level, if available if ( paths.length > 2) { - // Build the share relative path + // If the previous level is the versions root then the next level should be a + // version id folder + + String folderName = paths[2]; + int pathIdx = 3; - StringBuilder pathStr = new StringBuilder(); - - for ( int i = 2; i < paths.length; i++) + if ( isLevel() == LevelId.VersionRoot) { - pathStr.append( FileName.DOS_SEPERATOR); - pathStr.append( paths[i]); + // Check that the folder name starts with the version folder prefix + + if ( folderName != null && folderName.startsWith( VersionFolderPrefix) && + folderName.length() > VersionFolderPrefix.length()) + { + try + { + // Parse the version id + + m_version = Integer.parseInt( folderName.substring( VersionFolderPrefix.length())); + m_levelId = LevelId.Version; + + // Validate the version id + + if ( m_version < -1) + { + // Invalid version id + + m_levelId = LevelId.Invalid; + return; + } + } + catch ( NumberFormatException ex) + { + m_levelId = LevelId.Invalid; + return; + } + + // Check for the next level + + if ( paths.length > 3) + { + // Get the next level name + + folderName = paths[3]; + pathIdx++; + + // Check for the data folder + + if ( folderName.equalsIgnoreCase( DataFolder)) + { + m_levelId = LevelId.VersionData; + + // Set the path to the root of the store + + m_path = FileName.DOS_SEPERATOR_STR; + } + else if ( folderName.equalsIgnoreCase( MetaDataFolder)) + { + m_levelId = LevelId.VersionMetaData; + + // Set the path to the root of the metadata + + m_path = FileName.DOS_SEPERATOR_STR; + } + else + { + m_levelId = LevelId.Invalid; + return; + } + } + } + else + { + m_levelId = LevelId.Invalid; + return; + } } - m_path = pathStr.toString(); + // If the previous level is head the next level should be the data or metadata folder + else if ( isLevel() == LevelId.Head) + { + // Check for the data folder + + if ( folderName.equalsIgnoreCase( DataFolder)) + { + m_levelId = LevelId.HeadData; + + // Set the path to the root of the store + + m_path = FileName.DOS_SEPERATOR_STR; + } + else if ( folderName.equalsIgnoreCase( MetaDataFolder)) + { + m_levelId = LevelId.HeadMetaData; + + // Set the path to the root of the metadata + + m_path = FileName.DOS_SEPERATOR_STR; + } + else + { + m_levelId = LevelId.Invalid; + return; + } + } + + // If there are remaining paths then build a relative path + + if ( paths.length > pathIdx) + { + StringBuilder pathStr = new StringBuilder(); + + for ( int i = pathIdx; i < paths.length; i++) + { + pathStr.append( FileName.DOS_SEPERATOR); + pathStr.append( paths[i]); + } + + m_path = pathStr.toString(); + + // Set the level to indicate a store relative path + + m_levelId = LevelId.StorePath; + } + // Build the AVM path, in :/ format - pathStr.setLength( 0); + if ( m_path != null) + { + StringBuilder pathStr = new StringBuilder(); - pathStr.append( m_storeName); - pathStr.append( ":"); - pathStr.append( m_path.replace( FileName.DOS_SEPERATOR, AVM_SEPERATOR)); - - m_avmPath = pathStr.toString(); - } - else - { - // Share relative path is the root of the share - - m_path = FileName.DOS_SEPERATOR_STR; - - // Build the AVM path - - StringBuilder pathStr = new StringBuilder(); - - pathStr.append( m_storeName); - pathStr.append( ":/"); - - m_avmPath = pathStr.toString(); + pathStr.append( m_storeName); + pathStr.append( ":"); + pathStr.append( m_path.replace( FileName.DOS_SEPERATOR, AVM_SEPERATOR)); + + m_avmPath = pathStr.toString(); + } } } } @@ -314,6 +450,8 @@ public class AVMPath { public final void parsePath( String storeName, int version, String path) { // Clear current settings + + m_levelId = LevelId.Invalid; m_storeName = null; m_version = InvalidVersionId; @@ -354,6 +492,10 @@ public class AVMPath { } m_avmPath = avmPath.toString(); + + // Indicate that the path is to a store relative path + + m_levelId = LevelId.StorePath; } /** @@ -364,20 +506,77 @@ public class AVMPath { public String toString() { StringBuilder str = new StringBuilder(); - - str.append("["); - str.append(getStoreName()); - str.append(","); - - if ( hasVersion()) - str.append(getVersion()); - else - str.append("NoVersion"); - - str.append(","); - str.append(getRelativePath()); - str.append(":"); - str.append(getAVMPath()); + + switch ( m_levelId) + { + case Invalid: + str.append("[Invalid"); + break; + case Root: + str.append("[Root"); + break; + case StoreRoot: + str.append("[StoresRoot"); + break; + case Head: + str.append("["); + str.append(getStoreName()); + str.append(":HEAD"); + break; + case HeadData: + str.append("["); + str.append(getStoreName()); + str.append(":HEAD\\"); + str.append( DataFolder); + break; + case HeadMetaData: + str.append("["); + str.append(getStoreName()); + str.append(":HEAD\\"); + str.append( MetaDataFolder); + break; + case VersionRoot: + str.append("["); + str.append(getStoreName()); + str.append(":Versions"); + break; + case Version: + str.append("["); + str.append(getStoreName()); + str.append(":"); + str.append(VersionFolderPrefix); + str.append(getVersion()); + break; + case VersionData: + str.append("["); + str.append(getStoreName()); + str.append(":"); + str.append(VersionFolderPrefix); + str.append(getVersion()); + str.append("\\"); + str.append( DataFolder); + break; + case VersionMetaData: + str.append("["); + str.append(getStoreName()); + str.append(":"); + str.append(VersionFolderPrefix); + str.append(getVersion()); + str.append("\\"); + str.append( MetaDataFolder); + break; + case StorePath: + str.append("["); + str.append(getStoreName()); + str.append(":"); + str.append(VersionFolderPrefix); + str.append(getVersion()); + str.append(","); + str.append(getRelativePath()); + str.append(":"); + str.append(getAVMPath()); + break; + } str.append("]"); return str.toString(); diff --git a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java index b7d4360b3e..7a41374b58 100644 --- a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java +++ b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java @@ -237,7 +237,7 @@ public class AVMShareMapper implements ShareMapper { AVMDiskDriver avmDrv = (AVMDiskDriver) m_config.getAvmDiskInterface(); AVMService avmService = avmDrv.getAvmService(); - sess.beginTransaction( avmDrv.getTransactionService(), true); + sess.beginReadTransaction( avmDrv.getTransactionService()); try { diff --git a/source/java/org/alfresco/filesys/avm/DummyFolderPseudoFile.java b/source/java/org/alfresco/filesys/avm/DummyFolderPseudoFile.java new file mode 100644 index 0000000000..a7b6a36c5a --- /dev/null +++ b/source/java/org/alfresco/filesys/avm/DummyFolderPseudoFile.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.avm; + +import org.alfresco.filesys.server.filesys.FileAttribute; +import org.alfresco.filesys.server.filesys.FileInfo; +import org.alfresco.filesys.server.filesys.FileName; +import org.alfresco.filesys.server.filesys.NetworkFile; +import org.alfresco.filesys.server.pseudo.PseudoFile; +import org.alfresco.filesys.server.pseudo.PseudoFolderNetworkFile; + +/** + * Dummy Folder Pseudo File Class + * + *

Represents a dummy folder within the virtualization filesystem view. + * + * @author gkspencer + */ +public class DummyFolderPseudoFile extends PseudoFile { + + /** + * Class constructor + * + * @param fname String + */ + public DummyFolderPseudoFile( String fname) + { + super( fname, FileAttribute.Directory + FileAttribute.ReadOnly); + + // Create static file information from the folder details + + FileInfo fInfo = new FileInfo( fname, 0L, FileAttribute.Directory + FileAttribute.ReadOnly); + fInfo.setCreationDateTime( System.currentTimeMillis()); + + setFileInfo( fInfo); + } + + /** + * Return a network file for reading/writing the pseudo file + * + * @param netPath String + * @return NetworkFile + */ + @Override + public NetworkFile getFile(String netPath) { + + // Split the path to get the name + + String[] paths = FileName.splitPath( netPath); + + // Create a network file for the folder + + return new PseudoFolderNetworkFile( paths[1], netPath); + } + + /** + * Return the file information for the pseudo file + * + * @return FileInfo + */ + @Override + public FileInfo getFileInfo() { + return getInfo(); + } +} diff --git a/source/java/org/alfresco/filesys/server/SrvSession.java b/source/java/org/alfresco/filesys/server/SrvSession.java index 097a9db9a3..662da219b3 100644 --- a/source/java/org/alfresco/filesys/server/SrvSession.java +++ b/source/java/org/alfresco/filesys/server/SrvSession.java @@ -468,6 +468,32 @@ public abstract class SrvSession } } + /** + * Create a read transaction, if not already active + * + * @param transService TransactionService + * @return boolean + * @exception AlfrescoRuntimeException + */ + public final boolean beginReadTransaction( TransactionService transService) + throws AlfrescoRuntimeException + { + return beginTransaction(transService, true); + } + + /** + * Create a write transaction, if not already active + * + * @param transService TransactionService + * @return boolean + * @exception AlfrescoRuntimeException + */ + public final boolean beginWriteTransaction( TransactionService transService) + throws AlfrescoRuntimeException + { + return beginTransaction(transService, false); + } + /** * Create and start a transaction, if not already active * @@ -476,7 +502,7 @@ public abstract class SrvSession * @return boolean * @exception AlfrescoRuntimeException */ - public final boolean beginTransaction(TransactionService transService, boolean readOnly) + private final boolean beginTransaction(TransactionService transService, boolean readOnly) throws AlfrescoRuntimeException { boolean created = false; diff --git a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java index 421c840583..ab287f7897 100644 --- a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java +++ b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java @@ -79,6 +79,19 @@ public class ClientInfo private NodeRef m_homeNode; + // Group and user id + + private int m_gid = -1; + private int m_uid = -1; + + // List of groups for this user + + private int[] m_groups; + + // NFS authentication type + + private int m_nfsAuthType = -1; + /** * Default constructor */ @@ -331,6 +344,56 @@ public class ClientInfo return m_homeNode; } + /** + * Get the group id + * + * @return int + */ + public final int getGid() + { + return m_gid; + } + + /** + * Return the user id + * + * @return int + */ + public final int getUid() + { + return m_uid; + } + + /** + * Determine if the client has additional groups + * + * @return boolean + */ + public final boolean hasGroupsList() + { + return m_groups != null ? true : false; + } + + /** + * Return the additional groups list + * + * @return int[] + */ + public final int[] getGroupsList() + { + return m_groups; + } + + /** + * Return the NFS authentication type + * + * @return int + */ + public final int getNFSAuthenticationType() + { + return m_nfsAuthType; + } + /** * Set the remote users domain * @@ -454,6 +517,46 @@ public class ClientInfo m_homeNode = homeNode; } + /** + * Set the group id + * + * @param gid int + */ + public final void setGid(int gid) + { + m_gid = gid; + } + + /** + * Set the user id + * + * @param uid int + */ + public final void setUid(int uid) + { + m_uid = uid; + } + + /** + * Set the groups list + * + * @param groups int[] + */ + public final void setGroupsList(int[] groups) + { + m_groups = groups; + } + + /** + * Set the NFS authentication type + * + * @param type int + */ + public final void setNFSAuthenticationType(int type) + { + m_nfsAuthType = type; + } + /** * Display the client information as a string * diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java index 70d1e904a0..912f24acef 100644 --- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java +++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java @@ -72,6 +72,8 @@ import org.alfresco.filesys.server.core.SharedDeviceList; import org.alfresco.filesys.server.filesys.DefaultShareMapper; import org.alfresco.filesys.server.filesys.DiskInterface; import org.alfresco.filesys.server.filesys.DiskSharedDevice; +//import org.alfresco.filesys.server.oncrpc.DefaultRpcAuthenticator; +//import org.alfresco.filesys.server.oncrpc.RpcAuthenticator; import org.alfresco.filesys.smb.ServerType; import org.alfresco.filesys.smb.TcpipSMB; import org.alfresco.filesys.smb.server.repo.ContentContext; @@ -107,6 +109,7 @@ public class ServerConfiguration extends AbstractLifecycleBean private static final String ConfigArea = "file-servers"; private static final String ConfigCIFS = "CIFS Server"; private static final String ConfigFTP = "FTP Server"; + private static final String ConfigNFS = "NFS Server"; private static final String ConfigFilesystems = "Filesystems"; private static final String ConfigSecurity = "Filesystem Security"; @@ -135,6 +138,11 @@ public class ServerConfiguration extends AbstractLifecycleBean private static final String DefaultFTPAnonymousAccount = "anonymous"; + // NFS server debug type strings + + private static final String m_nfsDebugStr[] = { "RXDATA", "TXDATA", "DUMPDATA", "SEARCH", "INFO", "FILE", + "FILEIO", "ERROR", "TIMING", "DIRECTORY", "SESSION" }; + // Platform types public enum PlatformType @@ -170,6 +178,7 @@ public class ServerConfiguration extends AbstractLifecycleBean private boolean m_smbEnable = true; private boolean m_ftpEnable = true; + private boolean m_nfsEnable = true; // Server name @@ -242,8 +251,8 @@ public class ServerConfiguration extends AbstractLifecycleBean // Flags to indicate if NetBIOS, native TCP/IP SMB and/or Win32 NetBIOS // should be enabled - private boolean m_netBIOSEnable = true; - private boolean m_tcpSMBEnable = false; + private boolean m_netBIOSEnable = false; + private boolean m_tcpSMBEnable = false; private boolean m_win32NBEnable = false; // Address to bind the SMB server to, if null all local addresses are used @@ -306,6 +315,43 @@ public class ServerConfiguration extends AbstractLifecycleBean private int m_ftpDebug; + //-------------------------------------------------------------------------------- + // NFS specific configuration parameters + // + // Enable the port mapper server + + private boolean m_nfsPortMapper; + + // Port mapper port + + private int m_portMapperPort; + + // Mount server port + + private int m_mountServerPort; + + // NFS server port + + private int m_nfsServerPort; + + // NFS debug flags + + private int m_nfsDebug; + + // Port mapper and mount server debug enable + + private boolean m_portMapDebug; + private boolean m_mountServerDebug; + + // Thread pool size and packet pool size + + private int m_nfsThreadPoolSize; + private int m_nfsPacketPoolSize; + + // RPC authenticator implementation + +// private RpcAuthenticator m_rpcAuthenticator; + // -------------------------------------------------------------------------------- // Global server configuration // @@ -624,6 +670,26 @@ public class ServerConfiguration extends AbstractLifecycleBean logger.error("FTP server configuration error, " + ex.getMessage(), ex); } + + // Initialize the NFS server + + try + { + // Process the NFS server configuration + + config = configService.getConfig(ConfigNFS, configCtx); + processNFSServerConfig(config); + + // Log the successful startup + + logger.info("NFS server started"); + } + catch (Exception ex) + { + // Configuration error + + logger.error("FTP server configuration error, " + ex.getMessage(), ex); + } } else { @@ -1596,6 +1662,174 @@ public class ServerConfiguration extends AbstractLifecycleBean } } + /** + * Process the NFS server configuration + * + * @param config Config + */ + private final void processNFSServerConfig(Config config) + { +/** + // If the configuration section is not valid then NFS is disabled + + if ( config == null) + { + setNFSServerEnabled(false); + return; + } + + // Check if the port mapper is enabled + + if ( config.getConfigElement("enablePortMapper") != null) + m_nfsPortMapper = true; + + // Check for the thread pool size + + ConfigElement elem = config.getConfigElement("ThreadPool"); + + if ( elem != null) { + + try { + + // Convert the pool size value + + int poolSize = Integer.parseInt(elem.getValue()); + + // Range check the pool size value + + if ( poolSize < 4) + throw new AlfrescoRuntimeException("NFS thread pool size is below minimum of 4"); + + // Set the thread pool size + + m_nfsThreadPoolSize = poolSize; + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NFS thread pool size setting, " + elem.getValue()); + } + } + + // NFS packet pool size + + elem = config.getConfigElement("PacketPool"); + + if ( elem != null) { + + try { + + // Convert the packet pool size value + + int pktPoolSize = Integer.parseInt(elem.getValue()); + + // Range check the pool size value + + if ( pktPoolSize < 10) + throw new AlfrescoRuntimeException("NFS packet pool size is below minimum of 10"); + + if ( pktPoolSize < getNFSThreadPoolSize() + 1) + throw new AlfrescoRuntimeException("NFS packet pool must be at least thread pool size plus one"); + + // Set the packet pool size + + m_nfsPacketPoolSize = pktPoolSize; + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NFS packet pool size setting, " + elem.getValue()); + } + } + + // Check for a port mapper server port + + elem = config.getConfigElement("PortMapperPort"); + if ( elem != null) { + try { + m_portMapperPort = Integer.parseInt(elem.getValue()); + if ( getPortMapperPort() <= 0 || getPortMapperPort() >= 65535) + throw new AlfrescoRuntimeException("Port mapper server port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid port mapper server port"); + } + } + + // Check for a mount server port + + elem = config.getConfigElement("MountServerPort"); + if ( elem != null) { + try { + m_mountServerPort = Integer.parseInt(elem.getValue()); + if ( getMountServerPort() <= 0 || getMountServerPort() >= 65535) + throw new AlfrescoRuntimeException("Mount server port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid mount server port"); + } + } + + // Check for an NFS server port + + elem = config.getConfigElement("NFSServerPort"); + if ( elem != null) { + try { + m_nfsServerPort = Integer.parseInt(elem.getValue()); + if ( getNFSServerPort() <= 0 || getNFSServerPort() >= 65535) + throw new AlfrescoRuntimeException("NFS server port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NFS server port"); + } + } + + // Check if NFS debug is enabled + + elem = config.getConfigElement("debug"); + if (elem != null) { + + // Check for NFS debug flags + + String flags = elem.getAttribute("flags"); + int nfsDbg = 0; + + if ( flags != null) { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags,","); + + while ( token.hasMoreTokens()) { + + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while ( idx < m_nfsDebugStr.length && m_nfsDebugStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if ( idx >= m_nfsDebugStr.length) + throw new AlfrescoRuntimeException("Invalid NFS debug flag, " + dbg); + + // Set the debug flag + + nfsDbg += 1 << idx; + } + } + + // Set the NFS debug flags + + m_nfsDebug = nfsDbg; + } + + // Create the RPC authenticator + + m_rpcAuthenticator = new DefaultRpcAuthenticator(); +**/ + } + /** * Process the filesystems configuration * @@ -2931,6 +3165,16 @@ public class ServerConfiguration extends AbstractLifecycleBean m_ftpEnable = ena; } + /** + * Set the NFS server enabled state + * + * @param ena boolean + */ + public final void setNFSServerEnabled(boolean ena) + { + m_nfsEnable = ena; + } + /** * Set the authenticator to be used to authenticate users and share connections for CIFS. * @@ -3445,6 +3689,118 @@ public class ServerConfiguration extends AbstractLifecycleBean m_ftpDebug = dbg; } + /** + * Check if the NFS server is enabled + * + * @return boolean + */ + public final boolean isNFSServerEnabled() + { + return m_nfsEnable; + } + + /** + * Determine if port mapper debug is enabled + * + * @return boolean + */ + public final boolean hasPortMapperDebug() + { + return m_portMapDebug; + } + + /** + * Determine if mount server debug is enabled + * + * @return boolean + */ + public final boolean hasMountServerDebug() + { + return m_mountServerDebug; + } + + /** + * Check if the NFS port mapper is enabled + * + * @return boolean + */ + public final boolean hasNFSPortMapper() + { + return m_nfsPortMapper; + } + + /** + * Return the port for port mapper to use, or zero for the default port + * + * @return int + */ + public final int getPortMapperPort() + { + return m_portMapperPort; + } + + /** + * Return the port the mount server should use, or zero for the default port + * + * @return int + */ + public final int getMountServerPort() + { + return m_mountServerPort; + } + + /** + * Return the port the NFS server should use, or zero for the default port + * + * @return int + */ + public final int getNFSServerPort() + { + return m_nfsServerPort; + } + + /** + * Return the NFS debug flags + * + * @return int + */ + public final int getNFSDebug() + { + return m_nfsDebug; + } + + /** + * Return the NFS thread pool size + * + * @return int + */ + public final int getNFSThreadPoolSize() + { + return m_nfsThreadPoolSize; + } + + /** + * Return the NFS server packet pool size, or -1 for the default size + * + * @return int + */ + public final int getNFSPacketPoolSize() + { + return m_nfsPacketPoolSize; + } + + /** + * Get the authenticator object that is used to provide RPC authentication (for the portmapper, mount server and + * NFS server) + * + * @return RpcAuthenticator + */ +/** + public final RpcAuthenticator getRpcAuthenticator() + { + return m_rpcAuthenticator; + } +**/ /** * Close the server configuration, used to close various components that are shared between protocol * handlers. diff --git a/source/java/org/alfresco/filesys/server/filesys/FileInfo.java b/source/java/org/alfresco/filesys/server/filesys/FileInfo.java index 331b13cd76..c4b7ee184f 100644 --- a/source/java/org/alfresco/filesys/server/filesys/FileInfo.java +++ b/source/java/org/alfresco/filesys/server/filesys/FileInfo.java @@ -38,17 +38,17 @@ public class FileInfo implements Serializable // // Set file information flags - public static final int SetFileSize = 0x0001; - public static final int SetAllocationSize = 0x0002; - public static final int SetAttributes = 0x0004; - public static final int SetModifyDate = 0x0008; - public static final int SetCreationDate = 0x0010; - public static final int SetAccessDate = 0x0020; - public static final int SetChangeDate = 0x0040; - public static final int SetGid = 0x0080; - public static final int SetUid = 0x0100; - public static final int SetMode = 0x0200; - public static final int SetDeleteOnClose = 0x0400; + public static final int SetFileSize = 0x0001; + public static final int SetAllocationSize = 0x0002; + public static final int SetAttributes = 0x0004; + public static final int SetModifyDate = 0x0008; + public static final int SetCreationDate = 0x0010; + public static final int SetAccessDate = 0x0020; + public static final int SetChangeDate = 0x0040; + public static final int SetGid = 0x0080; + public static final int SetUid = 0x0100; + public static final int SetMode = 0x0200; + public static final int SetDeleteOnClose = 0x0400; // File name string @@ -108,10 +108,13 @@ public class FileInfo implements Serializable private boolean m_deleteOnClose; + // File type + + private int m_fileType; + // Set file information flags // - // Used to indicate which values in the file information object are valid and should be used to - // set + // Used to indicate which values in the file information object are valid and should be used to set // the file information. private int m_setFlags; @@ -527,6 +530,16 @@ public class FileInfo implements Serializable return (m_attr & FileAttribute.Archive) != 0 ? true : false; } + /** + * Return the file type + * + * @return int + */ + public final int isFileType() + { + return m_fileType; + } + /** * Determine if the group id field has been set * @@ -833,6 +846,16 @@ public class FileInfo implements Serializable m_mode = mode; } + /** + * Set the file type + * + * @param typ int + */ + public final void setFileType(int typ) + { + m_fileType = typ; + } + /** * Set the set file information flags to indicated which values are to be set * diff --git a/source/java/org/alfresco/filesys/server/filesys/FileOpenParams.java b/source/java/org/alfresco/filesys/server/filesys/FileOpenParams.java index 5ac1237492..2438e2f645 100644 --- a/source/java/org/alfresco/filesys/server/filesys/FileOpenParams.java +++ b/source/java/org/alfresco/filesys/server/filesys/FileOpenParams.java @@ -101,6 +101,11 @@ public class FileOpenParams private int m_mode = -1; + // File type and symbolic name + + private int m_fileType; + private String m_symName; + /** * Class constructor for Core SMB dialect Open SMB requests * @@ -454,6 +459,36 @@ public class FileOpenParams return false; } + /** + * Return the file type + * + * @return int + */ + public final int isFileType() + { + return m_fileType; + } + + /** + * determine if the target of the create/open is a symbolic link + * + * @return boolean + */ + public final boolean isSymbolicLink() + { + return isFileType() == FileType.SymbolicLink; + } + + /** + * Return the symbolic link name + * + * @return String + */ + public final String getSymbolicLinkName() + { + return m_symName; + } + /** * Return the shared access mode, zero equals allow any shared access * @@ -584,6 +619,27 @@ public class FileOpenParams m_createOptions = m_createOptions | flag; } + /** + * Set the file type + * + * @param typ int + */ + public final void setFileType(int typ) + { + m_fileType = typ; + } + + /** + * Set the symbolic link name + * + * @param name String + */ + public final void setSymbolicLink(String name) + { + m_symName = name; + m_fileType = FileType.SymbolicLink; + } + /** * Convert a Core/LanMan access mode to an NT access mode * diff --git a/source/java/org/alfresco/filesys/server/filesys/FileType.java b/source/java/org/alfresco/filesys/server/filesys/FileType.java new file mode 100644 index 0000000000..8ec7729d95 --- /dev/null +++ b/source/java/org/alfresco/filesys/server/filesys/FileType.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.filesys.server.filesys; + +/* + * FileType.java + * + * Copyright (c) Starlasoft 2006. All rights reserved. + */ + +/** + * File Type Class + * + *

File type constants. + * + * @author GKSpencer + */ +public class FileType { + + // File types + + public static final int RegularFile = 1; + public static final int Directory = 2; + public static final int SymbolicLink = 3; + public static final int HardLink = 4; + public static final int Device = 5; + + /** + * Return a file type as a string + * + * @param typ int + * @return String + */ + public final static String asString(int typ) { + + String typStr = "Unknown"; + + switch (typ) { + case RegularFile: + typStr = "File"; + break; + case Directory: + typStr = "Directory"; + break; + case SymbolicLink: + typStr = "SymbolicLink"; + break; + case HardLink: + typStr = "HardLink"; + break; + case Device: + typStr = "Device"; + break; + } + + return typStr; + } +} diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java index 66fb6e83c5..338456f2d4 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java @@ -571,7 +571,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Get the file information for the node - session.beginTransaction(transactionService, true); + session.beginReadTransaction(transactionService); finfo = cifsHelper.getFileInformation(nodeRef); // DEBUG @@ -587,7 +587,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Start a transaction - session.beginTransaction(transactionService, true); + session.beginReadTransaction(transactionService); String[] paths = FileName.splitPath( path); @@ -684,7 +684,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Create the transaction - sess.beginTransaction(transactionService, true); + sess.beginReadTransaction(transactionService); // 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 @@ -887,7 +887,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the node for the folder path - sess.beginTransaction(transactionService, true); + sess.beginReadTransaction(transactionService); fstate.setNodeRef( getNodeForPath( tree, paths[0])); // Add pseudo files to the folder @@ -908,7 +908,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, true); + sess.beginReadTransaction(transactionService); // Get the node for the folder path @@ -950,7 +950,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, true); + sess.beginReadTransaction(transactionService); // Get the file information to check if the file/folder exists @@ -1006,7 +1006,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); try { @@ -1213,7 +1213,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); try { @@ -1327,7 +1327,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); try { @@ -1434,7 +1434,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); // get the device root @@ -1522,7 +1522,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); // Get the associated file state @@ -1614,7 +1614,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the transaction - sess.beginTransaction(transactionService, false); + sess.beginWriteTransaction(transactionService); // Get the device context @@ -1690,7 +1690,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa public void renameFile(SrvSession sess, TreeConnection tree, String oldName, String newName) throws IOException { // Create the transaction - sess.beginTransaction(transactionService, false); + + sess.beginWriteTransaction(transactionService); try { diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java index 669f48f200..fd8495cd57 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java @@ -285,7 +285,7 @@ public class ContentIOControlHandler implements IOControlHandler { // Start a transaction - sess.beginTransaction( getTransactionService(), true); + sess.beginReadTransaction( getTransactionService()); // Get the file name from the request @@ -531,7 +531,7 @@ public class ContentIOControlHandler implements IOControlHandler // Start a transaction - sess.beginTransaction( getTransactionService(), true); + sess.beginReadTransaction( getTransactionService()); // Get an authentication ticket for the client, or validate the existing ticket. The ticket can be used when // generating URLs for the client-side application so that the user does not have to re-authenticate diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java index fe81a52957..b2e55942cb 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java @@ -84,7 +84,7 @@ public class CheckInOutDesktopAction extends DesktopAction { // Start a transaction - params.getSession().beginTransaction( transService, false); + params.getSession().beginWriteTransaction( transService); // Process the list of target nodes diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java index ebf193a8bd..c3d2bc20ec 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java @@ -274,7 +274,7 @@ public class JavaScriptDesktopAction extends DesktopAction { // Start a transaction TransactionService transService = getServiceRegistry().getTransactionService(); - params.getSession().beginTransaction( transService, false); + params.getSession().beginWriteTransaction( transService); // Access the script service @@ -293,7 +293,7 @@ public class JavaScriptDesktopAction extends DesktopAction { // Start a transaction - params.getSession().beginTransaction( transService, false); + params.getSession().beginWriteTransaction( transService); // Run the script