KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > smb > server > repo > ContentDiskDriver


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.smb.server.repo;
18
19 import java.io.File JavaDoc;
20 import java.io.FileNotFoundException JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.util.List JavaDoc;
24
25 import javax.transaction.UserTransaction JavaDoc;
26
27 import org.alfresco.config.ConfigElement;
28 import org.alfresco.error.AlfrescoRuntimeException;
29 import org.alfresco.filesys.server.SrvSession;
30 import org.alfresco.filesys.server.core.DeviceContext;
31 import org.alfresco.filesys.server.core.DeviceContextException;
32 import org.alfresco.filesys.server.filesys.AccessDeniedException;
33 import org.alfresco.filesys.server.filesys.AccessMode;
34 import org.alfresco.filesys.server.filesys.DiskInterface;
35 import org.alfresco.filesys.server.filesys.FileInfo;
36 import org.alfresco.filesys.server.filesys.FileName;
37 import org.alfresco.filesys.server.filesys.FileOpenParams;
38 import org.alfresco.filesys.server.filesys.FileSharingException;
39 import org.alfresco.filesys.server.filesys.FileStatus;
40 import org.alfresco.filesys.server.filesys.FileSystem;
41 import org.alfresco.filesys.server.filesys.IOControlNotImplementedException;
42 import org.alfresco.filesys.server.filesys.IOCtlInterface;
43 import org.alfresco.filesys.server.filesys.NetworkFile;
44 import org.alfresco.filesys.server.filesys.SearchContext;
45 import org.alfresco.filesys.server.filesys.SrvDiskInfo;
46 import org.alfresco.filesys.server.filesys.TreeConnection;
47 import org.alfresco.filesys.smb.SMBException;
48 import org.alfresco.filesys.smb.SMBStatus;
49 import org.alfresco.filesys.smb.SharingMode;
50 import org.alfresco.filesys.smb.server.SMBSrvSession;
51 import org.alfresco.filesys.smb.server.repo.FileState.FileStateStatus;
52 import org.alfresco.filesys.smb.server.repo.pseudo.ContentPseudoFileImpl;
53 import org.alfresco.filesys.smb.server.repo.pseudo.LocalPseudoFile;
54 import org.alfresco.filesys.smb.server.repo.pseudo.MemoryNetworkFile;
55 import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
56 import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
57 import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileList;
58 import org.alfresco.filesys.smb.server.repo.pseudo.PseudoNetworkFile;
59 import org.alfresco.filesys.util.DataBuffer;
60 import org.alfresco.filesys.util.WildCard;
61 import org.alfresco.model.ContentModel;
62 import org.alfresco.repo.security.authentication.AuthenticationComponent;
63 import org.alfresco.service.cmr.coci.CheckOutCheckInService;
64 import org.alfresco.service.cmr.lock.NodeLockedException;
65 import org.alfresco.service.cmr.repository.ContentService;
66 import org.alfresco.service.cmr.repository.NodeRef;
67 import org.alfresco.service.cmr.repository.NodeService;
68 import org.alfresco.service.cmr.repository.StoreRef;
69 import org.alfresco.service.cmr.search.SearchService;
70 import org.alfresco.service.cmr.security.AccessStatus;
71 import org.alfresco.service.cmr.security.PermissionService;
72 import org.alfresco.service.namespace.NamespaceService;
73 import org.alfresco.service.transaction.TransactionService;
74 import org.apache.commons.logging.Log;
75 import org.apache.commons.logging.LogFactory;
76
77 /**
78  * Content repository filesystem driver class
79  *
80  * <p>Provides a filesystem interface for various protocols such as SMB/CIFS and FTP.
81  *
82  * @author Derek Hulley
83  */

84 public class ContentDiskDriver implements DiskInterface, IOCtlInterface
85 {
86     // Logging
87

88     private static final Log logger = LogFactory.getLog(ContentDiskDriver.class);
89     
90     // Configuration key names
91

92     private static final String JavaDoc KEY_STORE = "store";
93     private static final String JavaDoc KEY_ROOT_PATH = "rootPath";
94     private static final String JavaDoc KEY_RELATIVE_PATH = "relativePath";
95
96     // Services and helpers
97

98     private CifsHelper cifsHelper;
99     private TransactionService transactionService;
100     private NamespaceService namespaceService;
101     private NodeService nodeService;
102     private SearchService searchService;
103     private ContentService contentService;
104     private PermissionService permissionService;
105     private CheckOutCheckInService checkInOutService;
106     
107     private AuthenticationComponent authComponent;
108     
109     // I/O control handler
110

111     private IOControlHandler m_ioHandler;
112     
113     // Pseudo files interface
114

115     private PseudoFileInterface m_pseudoFiles;
116     
117     /**
118      * Class constructor
119      *
120      * @param serviceRegistry to connect to the repository services
121      */

122     public ContentDiskDriver(CifsHelper cifsHelper)
123     {
124         this.cifsHelper = cifsHelper;
125     }
126
127     /**
128      * @param contentService the content service
129      */

130     public void setContentService(ContentService contentService)
131     {
132         this.contentService = contentService;
133     }
134
135     /**
136      * @param namespaceService the namespace service
137      */

138     public void setNamespaceService(NamespaceService namespaceService)
139     {
140         this.namespaceService = namespaceService;
141     }
142
143     /**
144      * @param nodeService the node service
145      */

146     public void setNodeService(NodeService nodeService)
147     {
148         this.nodeService = nodeService;
149     }
150     
151     /**
152      * @param searchService the search service
153      */

154     public void setSearchService(SearchService searchService)
155     {
156         this.searchService = searchService;
157     }
158
159     
160     /**
161      * @param transactionService the transaction service
162      */

163     public void setTransactionService(TransactionService transactionService)
164     {
165         this.transactionService = transactionService;
166     }
167
168     /**
169      * Set the permission service
170      *
171      * @param permissionService PermissionService
172      */

173     public void setPermissionService(PermissionService permissionService)
174     {
175         this.permissionService = permissionService;
176     }
177     
178     /**
179      * Set the check in/out service
180      *
181      * @param checkInOutService CheckOutCheckInService
182      */

183     public void setCheckInOutService(CheckOutCheckInService checkInOutService)
184     {
185         this.checkInOutService = checkInOutService;
186     }
187     
188     /**
189      * Set the authentication component
190      *
191      * @param authComponent AuthenticationComponent
192      */

193     public void setAuthenticationComponent(AuthenticationComponent authComponent)
194     {
195         this.authComponent = authComponent;
196     }
197     
198     /**
199      * Parse and validate the parameter string and create a device context object for this instance
200      * of the shared device. The same DeviceInterface implementation may be used for multiple
201      * shares.
202      *
203      * @param args ConfigElement
204      * @return DeviceContext
205      * @exception DeviceContextException
206      */

207     public DeviceContext createContext(ConfigElement cfg) throws DeviceContextException
208     {
209         // Use the system user as the authenticated context for the filesystem initialization
210

211         authComponent.setCurrentUser( authComponent.getSystemUserName());
212         
213         // Wrap the initialization in a transaction
214

215         UserTransaction JavaDoc tx = transactionService.getUserTransaction(true);
216
217         ContentContext context = null;
218         
219         try
220         {
221             // Start the transaction
222

223             if ( tx != null)
224                 tx.begin();
225             
226             // Get the store
227

228             ConfigElement storeElement = cfg.getChild(KEY_STORE);
229             if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0)
230             {
231                 throw new DeviceContextException("Device missing init value: " + KEY_STORE);
232             }
233             String JavaDoc storeValue = storeElement.getValue();
234             StoreRef storeRef = new StoreRef(storeValue);
235             
236             // Connect to the repo and ensure that the store exists
237

238             if (! nodeService.exists(storeRef))
239             {
240                 throw new DeviceContextException("Store not created prior to application startup: " + storeRef);
241             }
242             NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
243             
244             // Get the root path
245

246             ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH);
247             if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0)
248             {
249                 throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH);
250             }
251             String JavaDoc rootPath = rootPathElement.getValue();
252             
253             // Find the root node for this device
254

255             List JavaDoc<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false);
256             
257             NodeRef rootNodeRef = null;
258             
259             if (nodeRefs.size() > 1)
260             {
261                 throw new DeviceContextException("Multiple possible roots for device: \n" +
262                         " root path: " + rootPath + "\n" +
263                         " results: " + nodeRefs);
264             }
265             else if (nodeRefs.size() == 0)
266             {
267                 // nothing found
268
throw new DeviceContextException("No root found for device: \n" +
269                         " root path: " + rootPath);
270             }
271             else
272             {
273                 // we found a node
274
rootNodeRef = nodeRefs.get(0);
275             }
276
277             // Check if a relative path has been specified
278

279             ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH);
280             
281             if ( relativePathElement != null)
282             {
283                 // Make sure the path is in CIFS format
284

285                 String JavaDoc relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR);
286                 
287                 // Find the node and validate that the relative path is to a folder
288

289                 NodeRef relPathNode = cifsHelper.getNodeRef( rootNodeRef, relPath);
290                 if ( cifsHelper.isDirectory( relPathNode) == false)
291                     throw new DeviceContextException("Relative path is not a folder, " + relativePathElement.getValue());
292                 
293                 // Use the relative path node as the root of the filesystem
294

295                 rootNodeRef = relPathNode;
296             }
297             
298             // Commit the transaction
299

300             tx.commit();
301             tx = null;
302             
303             // Create the context
304

305             context = new ContentContext(storeValue, rootPath, rootNodeRef);
306
307             // Default the filesystem to look like an 80Gb sized disk with 90% free space
308

309             context.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
310             
311             // Set parameters
312

313             context.setFilesystemAttributes(FileSystem.CasePreservedNames);
314         }
315         catch (Exception JavaDoc ex)
316         {
317             logger.error("Error during create context", ex);
318         }
319         finally
320         {
321             // If there is an active transaction then roll it back
322

323             if ( tx != null)
324             {
325                 try
326                 {
327                     tx.rollback();
328                 }
329                 catch (Exception JavaDoc ex)
330                 {
331                     logger.warn("Failed to rollback transaction", ex);
332                 }
333             }
334         }
335
336         // Load the I/O control handler, if available
337

338         try
339         {
340             // Load the I/O control handler class
341

342             Object JavaDoc ioctlObj = Class.forName("org.alfresco.filesys.server.smb.repo.ContentIOControlHandler").newInstance();
343             
344             // Verify that the class is an I/O control interface
345

346             if ( ioctlObj instanceof IOControlHandler)
347             {
348                 // Set the I/O control handler, and initialize
349

350                 m_ioHandler = (IOControlHandler) ioctlObj;
351                 m_ioHandler.initialize( this, cifsHelper, transactionService, nodeService, checkInOutService);
352             }
353             
354             // Initialize the drag and drop pseudo application, if the I/O support has been enabled
355

356             if ( m_ioHandler != null)
357             {
358                 ConfigElement dragDropElem = cfg.getChild( "dragAndDrop");
359                 if ( dragDropElem != null)
360                 {
361                     // Get the pseudo file name and path to the actual file on the local filesystem
362

363                     ConfigElement pseudoName = dragDropElem.getChild( "filename");
364                     ConfigElement appPath = dragDropElem.getChild( "path");
365                     
366                     if ( pseudoName != null && appPath != null)
367                     {
368                         // Check that the application exists on the local filesystem
369

370                         URL JavaDoc appURL = this.getClass().getClassLoader().getResource(appPath.getValue());
371                         if ( appURL == null)
372                             throw new DeviceContextException("Failed to find drag and drop application, " + appPath.getValue());
373                         File JavaDoc appFile = new File JavaDoc(appURL.getFile());
374                         if ( appFile.exists() == false)
375                             throw new DeviceContextException("Drag and drop application not found, " + appPath.getValue());
376                         
377                         // Create the pseudo file for the drag and drop application
378

379                         PseudoFile dragDropPseudo = new LocalPseudoFile( pseudoName.getValue(), appFile.getAbsolutePath());
380                         context.setDragAndDropApp( dragDropPseudo);
381                     }
382                 }
383             }
384         }
385         catch (Exception JavaDoc ex)
386         {
387             if ( logger.isDebugEnabled())
388                 logger.debug("No I/O control handler available");
389         }
390
391         // Check if URL link files are enabled
392

393         ConfigElement urlFileElem = cfg.getChild( "urlFile");
394         if ( urlFileElem != null)
395         {
396             // Get the pseudo file name and web prefix path
397

398             ConfigElement pseudoName = urlFileElem.getChild( "filename");
399             ConfigElement webPath = urlFileElem.getChild( "webpath");
400             
401             if ( pseudoName != null && webPath != null)
402             {
403                 // Make sure the web prefix has a trailing slash
404

405                 String JavaDoc path = webPath.getValue();
406                 if ( path.endsWith("/") == false)
407                     path = path + "/";
408                 
409                 // URL file name must end with .url
410

411                 if ( pseudoName.getValue().endsWith(".url") == false)
412                     throw new DeviceContextException("URL link file must end with .url, " + pseudoName.getValue());
413                 
414                 // Set the URL link file name and web path
415

416                 context.setURLFileName( pseudoName.getValue());
417                 context.setURLPrefix( path);
418             }
419         }
420         
421         // Enable pseudo file support if the drag and drop app and/or URL link files are enabled
422

423         if ( context.hasDragAndDropApp() || context.hasURLFile())
424         {
425             // Create the pseudo file handler
426

427             m_pseudoFiles = new ContentPseudoFileImpl();
428         }
429         
430         // Check if locked files should be marked as offline
431

432         ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
433         if ( offlineFiles != null)
434         {
435             // Enable marking locked files as offline
436

437             cifsHelper.setMarkLockedFilesAsOffline( true);
438             
439             // Logging
440

441             logger.info("Locked files will be marked as offline");
442         }
443         
444         // Return the context for this shared filesystem
445

446         return context;
447     }
448
449     /**
450      * Check if pseudo file support is enabled
451      *
452      * @return boolean
453      */

454     public final boolean hasPseudoFileInterface()
455     {
456         return m_pseudoFiles != null ? true : false;
457     }
458     
459     /**
460      * Return the pseudo file support implementation
461      *
462      * @return PseudoFileInterface
463      */

464     public final PseudoFileInterface getPseudoFileInterface()
465     {
466         return m_pseudoFiles;
467     }
468     
469     /**
470      * Determine if the disk device is read-only.
471      *
472      * @param sess Server session
473      * @param ctx Device context
474      * @return boolean
475      * @exception java.io.IOException If an error occurs.
476      */

477     public boolean isReadOnly(SrvSession sess, DeviceContext ctx) throws IOException JavaDoc
478     {
479         return false;
480     }
481     
482     /**
483      * Get the file information for the specified file.
484      *
485      * @param sess Server session
486      * @param tree Tree connection
487      * @param name File name/path that information is required for.
488      * @return File information if valid, else null
489      * @exception java.io.IOException The exception description.
490      */

491     public FileInfo getFileInformation(SrvSession session, TreeConnection tree, String JavaDoc path) throws IOException JavaDoc
492     {
493         // Get the device root
494

495         ContentContext ctx = (ContentContext) tree.getContext();
496         NodeRef infoParentNodeRef = ctx.getRootNode();
497         
498         if ( path == null)
499             path = "";
500         
501         String JavaDoc infoPath = path;
502         
503         try
504         {
505             // Check if the path is to a pseudo file
506

507             FileInfo finfo = null;
508             
509             if ( hasPseudoFileInterface())
510             {
511                 // Get the pseudo file
512

513                 PseudoFile pfile = getPseudoFileInterface().getPseudoFile( session, tree, path);
514                 if ( pfile != null)
515                 {
516                     // DEBUG
517

518                     if ( logger.isDebugEnabled())
519                         logger.debug("getInfo using pseudo file info for " + path);
520                     return pfile.getFileInfo();
521                 }
522             }
523             
524             // Get the node ref for the path, chances are there is a file state in the cache
525

526             NodeRef nodeRef = getNodeForPath(tree, infoPath);
527             if ( nodeRef != null)
528             {
529                 // Get the file information for the node
530

531                 finfo = cifsHelper.getFileInformation(nodeRef);
532
533                 // DEBUG
534

535                 if ( logger.isDebugEnabled())
536                     logger.debug("getInfo using cached noderef for path " + path);
537             }
538             
539             // If the required node was not in the state cache, the parent folder node might be
540

541             session.beginTransaction(transactionService, true);
542             
543             if ( finfo == null)
544             {
545                 String JavaDoc[] paths = FileName.splitPath( path);
546                 
547                 if ( paths[0] != null && paths[0].length() > 1)
548                 {
549                     // Find the node ref for the folder being searched
550

551                     nodeRef = getNodeForPath(tree, paths[0]);
552                     
553                     if ( nodeRef != null)
554                     {
555                         infoParentNodeRef = nodeRef;
556                         infoPath = paths[1];
557                         
558                         // DEBUG
559

560                         if ( logger.isDebugEnabled())
561                             logger.debug("getInfo using cached noderef for parent " + path);
562                     }
563                 }
564             
565                 // Access the repository to get the file information
566

567                 finfo = cifsHelper.getFileInformation(infoParentNodeRef, infoPath);
568                 
569                 // DEBUG
570

571                 if (logger.isDebugEnabled())
572                 {
573                     logger.debug("Getting file information: \n" +
574                             " path: " + path + "\n" +
575                             " file info: " + finfo);
576                 }
577             }
578
579             // Return the file information
580

581             return finfo;
582         }
583         catch (FileNotFoundException JavaDoc e)
584         {
585             // a valid use case
586
if (logger.isDebugEnabled())
587             {
588                 logger.debug("Getting file information - File not found: \n" +
589                         " path: " + path);
590             }
591             throw e;
592         }
593         catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
594         {
595             // Debug
596

597             if ( logger.isDebugEnabled())
598                 logger.debug("Get file info - access denied, " + path);
599             
600             // Convert to a filesystem access denied status
601

602             throw new AccessDeniedException("Get file information " + path);
603         }
604         catch (AlfrescoRuntimeException ex)
605         {
606             // Debug
607

608             if ( logger.isDebugEnabled())
609                 logger.debug("Get file info error", ex);
610             
611             // Convert to a general I/O exception
612

613             throw new IOException JavaDoc("Get file information " + path);
614         }
615     }
616
617     /**
618      * Start a new search on the filesystem using the specified searchPath that may contain
619      * wildcards.
620      *
621      * @param sess Server session
622      * @param tree Tree connection
623      * @param searchPath File(s) to search for, may include wildcards.
624      * @param attrib Attributes of the file(s) to search for, see class SMBFileAttribute.
625      * @return SearchContext
626      * @exception java.io.FileNotFoundException If the search could not be started.
627      */

628     public SearchContext startSearch(SrvSession sess, TreeConnection tree, String JavaDoc searchPath, int attributes) throws FileNotFoundException JavaDoc
629     {
630         try
631         {
632             // Access the device context
633

634             ContentContext ctx = (ContentContext) tree.getContext();
635
636             String JavaDoc searchFileSpec = searchPath;
637             NodeRef searchRootNodeRef = ctx.getRootNode();
638             FileState searchFolderState = null;
639             
640             // Create the transaction
641

642             sess.beginTransaction(transactionService, true);
643             
644             // If the state table is available see if we can speed up the search using either cached
645
// file information or find the folder node to be searched without having to walk the path
646

647             String JavaDoc[] paths = null;
648             
649             if ( ctx.hasStateTable())
650             {
651                 // See if the folder to be searched has a file state, we can avoid having to walk the path
652

653                 paths = FileName.splitPath(searchPath);
654                 if ( paths[0] != null && paths[0].length() > 1)
655                 {
656                     // Find the node ref for the folder being searched
657

658                     NodeRef nodeRef = getNodeForPath(tree, paths[0]);
659                     
660                     // Get the file state for the folder being searched
661

662                     searchFolderState = getStateForPath(tree, paths[0]);
663                     if ( searchFolderState == null)
664                     {
665                         // Create a file state for the folder
666

667                         searchFolderState = ctx.getStateTable().findFileState( paths[0], true, true);
668                     }
669                     
670                     // Make sure the associated node is set
671

672                     if ( searchFolderState.hasNodeRef() == false)
673                     {
674                         // Set the associated node for the folder
675

676                         searchFolderState.setNodeRef( nodeRef);
677                     }
678                     
679                     // Add pseudo files to the folder being searched
680

681                     if ( hasPseudoFileInterface())
682                         getPseudoFileInterface().addPseudoFilesToFolder( sess, tree, paths[0]);
683
684                     // Set the search node and file spec
685

686                     if ( nodeRef != null)
687                     {
688                         searchRootNodeRef = nodeRef;
689                         searchFileSpec = paths[1];
690                         
691                         // DEBUG
692

693                         if ( logger.isDebugEnabled())
694                             logger.debug("Search using cached noderef for path " + searchPath);
695                     }
696                 }
697             }
698             
699             // Perform the search
700

701             List JavaDoc<NodeRef> results = cifsHelper.getNodeRefs(searchRootNodeRef, searchFileSpec);
702
703             // Check if there are any pseudo files for the folder being searched, for CIFS only
704

705             PseudoFileList pseudoList = null;
706             
707             if ( sess instanceof SMBSrvSession && searchFolderState != null && searchFolderState.hasPseudoFiles())
708             {
709                 // If it is a wildcard search use all pseudo files
710

711                 if ( WildCard.containsWildcards(searchFileSpec))
712                 {
713                     // Check if the folder has any associated pseudo files
714

715                     pseudoList = searchFolderState.getPseudoFileList();
716                 }
717                 else if ( results == null || results.size() == 0)
718                 {
719                     // Check if the required file is in the pseudo file list
720

721                     String JavaDoc fname = paths[1];
722                     
723                     if ( fname != null)
724                     {
725                         // Search for a matching pseudo file
726

727                         PseudoFile pfile = searchFolderState.getPseudoFileList().findFile( fname, true);
728                         if ( pfile != null)
729                         {
730                             // Create a file list with the required file
731

732                             pseudoList = new PseudoFileList();
733                             pseudoList.addFile( pfile);
734                         }
735                     }
736                 }
737             }
738             
739             // Build the search context to store the results
740

741             SearchContext searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList);
742             
743             // Debug
744

745             if (logger.isDebugEnabled())
746             {
747                 logger.debug("Started search: \n" +
748                         " search path: " + searchPath + "\n" +
749                         " attributes: " + attributes);
750             }
751             return searchCtx;
752         }
753         catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
754         {
755             // Debug
756

757             if ( logger.isDebugEnabled())
758                 logger.debug("Start search - access denied, " + searchPath);
759             
760             // Convert to a file not found status
761

762             throw new FileNotFoundException JavaDoc("Start search " + searchPath);
763         }
764         catch (AlfrescoRuntimeException ex)
765         {
766             // Debug
767

768             if ( logger.isDebugEnabled())
769                 logger.debug("Start search", ex);
770             
771             // Convert to a file not found status
772

773             throw new FileNotFoundException JavaDoc("Start search " + searchPath);
774         }
775     }
776
777     /**
778      * Check if the specified file exists, and whether it is a file or directory.
779      *
780      * @param sess Server session
781      * @param tree Tree connection
782      * @param name java.lang.String
783      * @return int
784      * @see FileStatus
785      */

786     public int fileExists(SrvSession sess, TreeConnection tree, String JavaDoc name)
787     {
788         
789         int status = FileStatus.Unknown;
790         
791         try
792         {
793             // Check for a cached file state
794

795             ContentContext ctx = (ContentContext) tree.getContext();
796             FileState fstate = null;
797             
798             if ( ctx.hasStateTable())
799                 ctx.getStateTable().findFileState(name);
800             
801             if ( fstate != null)
802             {
803                 FileStateStatus fsts = fstate.getFileStatus();
804
805                 if ( fsts == FileStateStatus.FileExists)
806                     status = FileStatus.FileExists;
807                 else if ( fsts == FileStateStatus.FolderExists)
808                     status = FileStatus.DirectoryExists;
809                 else if ( fsts == FileStateStatus.NotExist || fsts == FileStateStatus.Renamed)
810                     status = FileStatus.NotExist;
811                 
812                 // DEBUG
813

814                 if ( logger.isDebugEnabled())
815                     logger.debug("Cache hit - fileExists() " + name + ", sts=" + status);
816             }
817             else
818             {
819                 // Create the transaction
820

821                 sess.beginTransaction(transactionService, true);
822                 
823                 // Get the file information to check if the file/folder exists
824

825                 FileInfo info = getFileInformation(sess, tree, name);
826                 if (info.isDirectory())
827                 {
828                     status = FileStatus.DirectoryExists;
829                 }
830                 else
831                 {
832                     status = FileStatus.FileExists;
833                 }
834             }
835         }
836         catch (FileNotFoundException JavaDoc e)
837         {
838             status = FileStatus.NotExist;
839         }
840         catch (IOException JavaDoc e)
841         {
842             // Debug
843

844             logger.debug("File exists error, " + name, e);
845             
846             status = FileStatus.NotExist;
847         }
848
849         // done
850
if (logger.isDebugEnabled())
851         {
852             logger.debug("File status determined: \n" +
853                     " name: " + name + "\n" +
854                     " status: " + status);
855         }
856         return status;
857     }
858     
859     /**
860      * Open a file or folder
861      *
862      * @param sess SrvSession
863      * @param tree TreeConnection
864      * @param params FileOpenParams
865      * @return NetworkFile
866      * @exception IOException
867      */

868     public NetworkFile openFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException JavaDoc
869     {
870         // Create the transaction
871

872         sess.beginTransaction(transactionService, false);
873         
874         try
875         {
876             // Get the node for the path
877

878             ContentContext ctx = (ContentContext) tree.getContext();
879             
880             // Check if pseudo files are enabled
881

882             if ( hasPseudoFileInterface())
883             {
884                 // Check if the path is to a pseudo file
885

886                 PseudoFile pfile = getPseudoFileInterface().getPseudoFile( sess, tree, params.getPath());
887                 if ( pfile != null)
888                 {
889                     // Create a network file to access the pseudo file data
890

891                     return pfile.getFile( params.getPath());
892                 }
893             }
894             
895             // Not a pseudo file, try and open a normal file/folder node
896

897             NodeRef nodeRef = getNodeForPath(tree, params.getPath());
898             
899             // Check permissions on the file/folder node
900
//
901
// Check for read access
902

903             if ( params.hasAccessMode(AccessMode.NTRead) &&
904                     permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
905                 throw new AccessDeniedException("No read access to " + params.getFullPath());
906                 
907             // Check for write access
908

909             if ( params.hasAccessMode(AccessMode.NTWrite) &&
910                     permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
911                 throw new AccessDeniedException("No write access to " + params.getFullPath());
912             
913             // Check for delete access
914

915             if ( params.hasAccessMode(AccessMode.NTDelete) &&
916                     permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
917                 throw new AccessDeniedException("No delete access to " + params.getFullPath());
918             
919             // Check if there is a file state for the file
920

921             FileState fstate = null;
922             
923             if ( ctx.hasStateTable())
924             {
925                 // Check if there is a file state for the file
926

927                 fstate = ctx.getStateTable().findFileState( params.getPath());
928             
929                 if ( fstate != null)
930                 {
931                     // Check if the file exists
932

933                     if ( fstate.exists() == false)
934                         throw new FileNotFoundException JavaDoc();
935                     
936                     // Check if the open request shared access indicates exclusive file access
937

938                     if ( fstate != null && params.getSharedAccess() == SharingMode.NOSHARING &&
939                             fstate.getOpenCount() > 0)
940                         throw new FileSharingException("File already open, " + params.getPath());
941                 }
942             }
943             
944             // Create the network file
945

946             NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
947             
948             // Create a file state for the open file
949

950             if ( ctx.hasStateTable())
951             {
952                 if ( fstate == null)
953                     fstate = ctx.getStateTable().findFileState(params.getPath(), params.isDirectory(), true);
954             
955                 // Update the file state, cache the node
956

957                 fstate.incrementOpenCount();
958                 fstate.setNodeRef(nodeRef);
959             }
960             
961             // If the file has been opened for overwrite then truncate the file to zero length, this will
962
// also prevent the existing content data from being copied to the new version of the file
963

964             if ( params.isOverwrite() && netFile != null)
965             {
966                 // Truncate the file to zero length
967

968                 netFile.truncateFile( 0L);
969             }
970             
971             // Debug
972

973             if (logger.isDebugEnabled())
974             {
975                 logger.debug("Opened network file: \n" +
976                         " path: " + params.getPath() + "\n" +
977                         " file open parameters: " + params + "\n" +
978                         " network file: " + netFile);
979             }
980
981             // Return the network file
982

983             return netFile;
984         }
985         catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
986         {
987             // Debug
988

989             if ( logger.isDebugEnabled())
990                 logger.debug("Open file - access denied, " + params.getFullPath());
991             
992             // Convert to a filesystem access denied status
993

994             throw new AccessDeniedException("Open file " + params.getFullPath());
995         }
996         catch (AlfrescoRuntimeException ex)
997         {
998             // Debug
999

1000            if ( logger.isDebugEnabled())
1001                logger.debug("Open file error", ex);
1002            
1003            // Convert to a general I/O exception
1004

1005            throw new IOException JavaDoc("Open file " + params.getFullPath());
1006        }
1007    }
1008    
1009    /**
1010     * Create a new file on the file system.
1011     *
1012     * @param sess Server session
1013     * @param tree Tree connection
1014     * @param params File create parameters
1015     * @return NetworkFile
1016     * @exception java.io.IOException If an error occurs.
1017     */

1018    public NetworkFile createFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException JavaDoc
1019    {
1020        // Create the transaction
1021

1022        sess.beginTransaction(transactionService, false);
1023        
1024        try
1025        {
1026            // get the device root
1027

1028            ContentContext ctx = (ContentContext) tree.getContext();
1029            NodeRef deviceRootNodeRef = ctx.getRootNode();
1030            
1031            String JavaDoc path = params.getPath();
1032            
1033            // If the state table is available then try to find the parent folder node for the new file
1034
// to save having to walk the path
1035

1036            if ( ctx.hasStateTable())
1037            {
1038                // See if the parent folder has a file state, we can avoid having to walk the path
1039

1040                String JavaDoc[] paths = FileName.splitPath(path);
1041                if ( paths[0] != null && paths[0].length() > 1)
1042                {
1043                    // Find the node ref for the folder being searched
1044

1045                    NodeRef nodeRef = getNodeForPath(tree, paths[0]);
1046                    
1047                    if ( nodeRef != null)
1048                    {
1049                        deviceRootNodeRef = nodeRef;
1050                        path = paths[1];
1051                        
1052                        // DEBUG
1053

1054                        if ( logger.isDebugEnabled())
1055                            logger.debug("Create file using cached noderef for path " + paths[0]);
1056                    }
1057                }
1058            }
1059            
1060            // Create it - the path will be created, if necessary
1061

1062            NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, true);
1063            
1064            // create the network file
1065
NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
1066            
1067            // Add a file state for the new file/folder
1068

1069            if ( ctx.hasStateTable())
1070            {
1071                FileState fstate = ctx.getStateTable().findFileState(path, false, true);
1072                if ( fstate != null)
1073                {
1074                    // Indicate that the file is open
1075

1076                    fstate.setFileStatus(FileStateStatus.FileExists);
1077                    fstate.incrementOpenCount();
1078                    fstate.setNodeRef(nodeRef);
1079                    
1080                    // DEBUG
1081

1082                    if ( logger.isDebugEnabled())
1083                        logger.debug("Creaste file, state=" + fstate);
1084                }
1085            }
1086            
1087            // done
1088
if (logger.isDebugEnabled())
1089            {
1090                logger.debug("Created file: \n" +
1091                        " path: " + path + "\n" +
1092                        " file open parameters: " + params + "\n" +
1093                        " node: " + nodeRef + "\n" +
1094                        " network file: " + netFile);
1095            }
1096            return netFile;
1097        }
1098        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1099        {
1100            // Debug
1101

1102            if ( logger.isDebugEnabled())
1103                logger.debug("Create file - access denied, " + params.getFullPath());
1104            
1105            // Convert to a filesystem access denied status
1106

1107            throw new AccessDeniedException("Create file " + params.getFullPath());
1108        }
1109        catch (AlfrescoRuntimeException ex)
1110        {
1111            // Debug
1112

1113            if ( logger.isDebugEnabled())
1114                logger.debug("Create file error", ex);
1115            
1116            // Convert to a general I/O exception
1117

1118            throw new IOException JavaDoc("Create file " + params.getFullPath());
1119        }
1120        
1121    }
1122
1123    /**
1124     * Create a new directory on this file system.
1125     *
1126     * @param sess Server session
1127     * @param tree Tree connection.
1128     * @param params Directory create parameters
1129     * @exception java.io.IOException If an error occurs.
1130     */

1131    public void createDirectory(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException JavaDoc
1132    {
1133        // Create the transaction
1134

1135        sess.beginTransaction(transactionService, false);
1136        
1137        try
1138        {
1139            // get the device root
1140

1141            ContentContext ctx = (ContentContext) tree.getContext();
1142            NodeRef deviceRootNodeRef = ctx.getRootNode();
1143            
1144            String JavaDoc path = params.getPath();
1145            
1146            // If the state table is available then try to find the parent folder node for the new folder
1147
// to save having to walk the path
1148

1149            if ( ctx.hasStateTable())
1150            {
1151                // See if the parent folder has a file state, we can avoid having to walk the path
1152

1153                String JavaDoc[] paths = FileName.splitPath(path);
1154                if ( paths[0] != null && paths[0].length() > 1)
1155                {
1156                    // Find the node ref for the folder being searched
1157

1158                    NodeRef nodeRef = getNodeForPath(tree, paths[0]);
1159                    
1160                    if ( nodeRef != null)
1161                    {
1162                        deviceRootNodeRef = nodeRef;
1163                        path = paths[1];
1164                        
1165                        // DEBUG
1166

1167                        if ( logger.isDebugEnabled())
1168                            logger.debug("Create file using cached noderef for path " + paths[0]);
1169                    }
1170                }
1171            }
1172            
1173            // Create it - the path will be created, if necessary
1174

1175            NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, false);
1176
1177            // Add a file state for the new folder
1178

1179            if ( ctx.hasStateTable())
1180            {
1181                FileState fstate = ctx.getStateTable().findFileState(path, true, true);
1182                if ( fstate != null)
1183                {
1184                    // Indicate that the file is open
1185

1186                    fstate.setFileStatus(FileStateStatus.FolderExists);
1187                    fstate.incrementOpenCount();
1188                    fstate.setNodeRef(nodeRef);
1189                    
1190                    // DEBUG
1191

1192                    if ( logger.isDebugEnabled())
1193                        logger.debug("Creaste folder, state=" + fstate);
1194                }
1195            }
1196            
1197            // done
1198
if (logger.isDebugEnabled())
1199            {
1200                logger.debug("Created directory: \n" +
1201                        " path: " + path + "\n" +
1202                        " file open params: " + params + "\n" +
1203                        " node: " + nodeRef);
1204            }
1205        }
1206        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1207        {
1208            // Debug
1209

1210            if ( logger.isDebugEnabled())
1211                logger.debug("Create directory - access denied, " + params.getFullPath());
1212            
1213            // Convert to a filesystem access denied status
1214

1215            throw new AccessDeniedException("Create directory " + params.getFullPath());
1216        }
1217        catch (AlfrescoRuntimeException ex)
1218        {
1219            // Debug
1220

1221            if ( logger.isDebugEnabled())
1222                logger.debug("Create directory error", ex);
1223            
1224            // Convert to a general I/O exception
1225

1226            throw new IOException JavaDoc("Create directory " + params.getFullPath());
1227        }
1228    }
1229
1230    /**
1231     * Delete the directory from the filesystem.
1232     *
1233     * @param sess Server session
1234     * @param tree Tree connection
1235     * @param dir Directory name.
1236     * @exception java.io.IOException The exception description.
1237     */

1238    public void deleteDirectory(SrvSession sess, TreeConnection tree, String JavaDoc dir) throws IOException JavaDoc
1239    {
1240        // Create the transaction
1241

1242        sess.beginTransaction(transactionService, false);
1243        
1244        // get the device root
1245

1246        ContentContext ctx = (ContentContext) tree.getContext();
1247        NodeRef deviceRootNodeRef = ctx.getRootNode();
1248        
1249        try
1250        {
1251            // get the node
1252
NodeRef nodeRef = cifsHelper.getNodeRef(deviceRootNodeRef, dir);
1253            if (nodeService.exists(nodeRef))
1254            {
1255                nodeService.deleteNode(nodeRef);
1256                
1257                // Remove the file state
1258

1259                if ( ctx.hasStateTable())
1260                    ctx.getStateTable().removeFileState(dir);
1261            }
1262            // done
1263
if (logger.isDebugEnabled())
1264            {
1265                logger.debug("Deleted directory: \n" +
1266                        " directory: " + dir + "\n" +
1267                        " node: " + nodeRef);
1268            }
1269        }
1270        catch (FileNotFoundException JavaDoc e)
1271        {
1272            // already gone
1273
if (logger.isDebugEnabled())
1274            {
1275                logger.debug("Deleted directory <alfready gone>: \n" +
1276                        " directory: " + dir);
1277            }
1278        }
1279        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1280        {
1281            // Debug
1282

1283            if ( logger.isDebugEnabled())
1284                logger.debug("Delete directory - access denied, " + dir);
1285            
1286            // Convert to a filesystem access denied status
1287

1288            throw new AccessDeniedException("Delete directory " + dir);
1289        }
1290        catch (AlfrescoRuntimeException ex)
1291        {
1292            // Debug
1293

1294            if ( logger.isDebugEnabled())
1295                logger.debug("Delete directory", ex);
1296            
1297            // Convert to a general I/O exception
1298

1299            throw new IOException JavaDoc("Delete directory " + dir);
1300        }
1301    }
1302
1303    /**
1304     * Flush any buffered output for the specified file.
1305     *
1306     * @param sess Server session
1307     * @param tree Tree connection
1308     * @param file Network file context.
1309     * @exception java.io.IOException The exception description.
1310     */

1311    public void flushFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException JavaDoc
1312    {
1313        // Flush the file data
1314

1315        file.flushFile();
1316    }
1317
1318    /**
1319     * Close the file.
1320     *
1321     * @param sess Server session
1322     * @param tree Tree connection.
1323     * @param param Network file context.
1324     * @exception java.io.IOException If an error occurs.
1325     */

1326    public void closeFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException JavaDoc
1327    {
1328        // Create the transaction
1329

1330        sess.beginTransaction(transactionService, false);
1331        
1332        // Get the associated file state
1333

1334        ContentContext ctx = (ContentContext) tree.getContext();
1335        
1336        if ( ctx.hasStateTable())
1337        {
1338            FileState fstate = ctx.getStateTable().findFileState(file.getFullName());
1339            if ( fstate != null)
1340                fstate.decrementOpenCount();
1341        }
1342        
1343        // Defer to the network file to close the stream and remove the content
1344

1345        file.closeFile();
1346        
1347        // Remove the node if marked for delete
1348

1349        if (file.hasDeleteOnClose())
1350        {
1351            // Check if the file is a content file
1352

1353            if ( file instanceof ContentNetworkFile)
1354            {
1355                ContentNetworkFile contentNetFile = (ContentNetworkFile) file;
1356                NodeRef nodeRef = contentNetFile.getNodeRef();
1357                
1358                // We don't know how long the network file has had the reference, so check for existence
1359

1360                if (nodeService.exists(nodeRef))
1361                {
1362                    try
1363                    {
1364                        // Delete the file
1365

1366                        nodeService.deleteNode(nodeRef);
1367    
1368                        // Remove the file state
1369

1370                        if ( ctx.hasStateTable())
1371                            ctx.getStateTable().removeFileState(file.getFullName());
1372                    }
1373                    catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1374                    {
1375                        // Debug
1376

1377                        if ( logger.isDebugEnabled())
1378                            logger.debug("Delete on close - access denied, " + file.getFullName());
1379                        
1380                        // Convert to a filesystem access denied exception
1381

1382                        throw new AccessDeniedException("Delete on close " + file.getFullName());
1383                    }
1384                }
1385            }
1386            else if ( file instanceof PseudoNetworkFile ||
1387                      file instanceof MemoryNetworkFile)
1388            {
1389                // Delete the pseudo file
1390

1391                if ( hasPseudoFileInterface())
1392                {
1393                    // Delete the pseudo file
1394

1395                    getPseudoFileInterface().deletePseudoFile( sess, tree, file.getFullName());
1396                }
1397            }
1398        }
1399        
1400        // DEBUG
1401

1402        if (logger.isDebugEnabled())
1403        {
1404            logger.debug("Closed file: \n" +
1405                    " network file: " + file + "\n" +
1406                    " deleted on close: " + file.hasDeleteOnClose());
1407        }
1408    }
1409
1410    /**
1411     * Delete the specified file.
1412     *
1413     * @param sess Server session
1414     * @param tree Tree connection
1415     * @param file NetworkFile
1416     * @exception java.io.IOException The exception description.
1417     */

1418    public void deleteFile(SrvSession sess, TreeConnection tree, String JavaDoc name) throws IOException JavaDoc
1419    {
1420        // Create the transaction
1421

1422        sess.beginTransaction(transactionService, false);
1423        
1424        // Get the device context
1425

1426        ContentContext ctx = (ContentContext) tree.getContext();
1427        
1428        try
1429        {
1430            // get the node
1431
NodeRef nodeRef = getNodeForPath(tree, name);
1432            if (nodeService.exists(nodeRef))
1433            {
1434                nodeService.deleteNode(nodeRef);
1435                
1436                // Remove the file state
1437

1438                if ( ctx.hasStateTable())
1439                    ctx.getStateTable().removeFileState(name);
1440            }
1441            
1442            // done
1443
if (logger.isDebugEnabled())
1444            {
1445                logger.debug("Deleted file: \n" +
1446                        " file: " + name + "\n" +
1447                        " node: " + nodeRef);
1448            }
1449        }
1450        catch (FileNotFoundException JavaDoc e)
1451        {
1452            // already gone
1453
if (logger.isDebugEnabled())
1454            {
1455                logger.debug("Deleted file <alfready gone>: \n" +
1456                        " file: " + name);
1457            }
1458        }
1459        catch (NodeLockedException ex)
1460        {
1461            // Debug
1462

1463            if ( logger.isDebugEnabled())
1464                logger.debug("Delete file - access denied (locked)");
1465            
1466            // Convert to a filesystem access denied status
1467

1468            throw new AccessDeniedException("Delete " + name);
1469        }
1470        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1471        {
1472            // Debug
1473

1474            if ( logger.isDebugEnabled())
1475                logger.debug("Delete file - access denied");
1476            
1477            // Convert to a filesystem access denied status
1478

1479            throw new AccessDeniedException("Delete " + name);
1480        }
1481        catch (AlfrescoRuntimeException ex)
1482        {
1483            // Debug
1484

1485            if ( logger.isDebugEnabled())
1486                logger.debug("Delete file error", ex);
1487            
1488            // Convert to a general I/O exception
1489

1490            throw new IOException JavaDoc("Delete file " + name);
1491        }
1492    }
1493
1494    /**
1495     * Rename the specified file.
1496     *
1497     * @param sess Server session
1498     * @param tree Tree connection
1499     * @param oldName java.lang.String
1500     * @param newName java.lang.String
1501     * @exception java.io.IOException The exception description.
1502     */

1503    public void renameFile(SrvSession sess, TreeConnection tree, String JavaDoc oldName, String JavaDoc newName) throws IOException JavaDoc
1504    {
1505        // Create the transaction
1506
sess.beginTransaction(transactionService, false);
1507        
1508        try
1509        {
1510            // Get the device context
1511

1512            ContentContext ctx = (ContentContext) tree.getContext();
1513            
1514            // Get the file/folder to move
1515
NodeRef nodeToMoveRef = getNodeForPath(tree, oldName);
1516            
1517            // Get the new target folder - it must be a folder
1518
String JavaDoc[] splitPaths = FileName.splitPath(newName);
1519            NodeRef targetFolderRef = getNodeForPath(tree, splitPaths[0]);
1520            String JavaDoc name = splitPaths[1]; // the new file or folder name
1521

1522            // Update the state table
1523
boolean relinked = false;
1524            if ( ctx.hasStateTable())
1525            {
1526                // Check if the file rename can be relinked to a previous version
1527

1528                if ( !cifsHelper.isDirectory(nodeToMoveRef) )
1529                {
1530                    // Check if there is a renamed file state for the new file name
1531

1532                    FileState renState = ctx.getStateTable().removeFileState(newName);
1533                    
1534                    if ( renState != null && renState.getFileStatus() == FileStateStatus.Renamed)
1535                    {
1536                        // DEBUG
1537

1538                        if ( logger.isDebugEnabled())
1539                            logger.debug(" Found rename state, relinking, " + renState);
1540                        
1541                        // Relink the new version of the file data to the previously renamed node so that it
1542
// picks up version history and other settings.
1543

1544                        cifsHelper.relinkNode( renState.getNodeRef(), nodeToMoveRef, targetFolderRef, name);
1545                        relinked = true;
1546
1547                        // Link the node ref for the associated rename state
1548

1549                        if ( renState.hasRenameState())
1550                            renState.getRenameState().setNodeRef(nodeToMoveRef);
1551                        
1552                        // Remove the file state for the old file name
1553

1554                        ctx.getStateTable().removeFileState(oldName);
1555                        
1556                        // Get, or create, a file state for the new file path
1557

1558                        FileState fstate = ctx.getStateTable().findFileState(newName, false, true);
1559                        
1560                        fstate.setNodeRef(renState.getNodeRef());
1561                        fstate.setFileStatus(FileStateStatus.FileExists);
1562                    }
1563                    else
1564                    {
1565                        // Get or create a new file state for the old file path
1566

1567                        FileState fstate = ctx.getStateTable().findFileState(oldName, false, true);
1568                        
1569                        // Make sure the file state is cached for a short while, the file may not be open so the
1570
// file state could be expired
1571

1572                        fstate.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
1573                        
1574                        // Indicate that this is a renamed file state, set the node ref of the file that was renamed
1575

1576                        fstate.setFileStatus(FileStateStatus.Renamed);
1577                        fstate.setNodeRef(nodeToMoveRef);
1578                        
1579                        // Get, or create, a file state for the new file path
1580

1581                        FileState newState = ctx.getStateTable().findFileState(newName, false, true);
1582                        
1583                        newState.setNodeRef(nodeToMoveRef);
1584                        newState.setFileStatus(FileStateStatus.FileExists);
1585                        
1586                        // Link the renamed state to the new state
1587

1588                        fstate.setRenameState(newState);
1589                        
1590                        // DEBUG
1591

1592                        if ( logger.isDebugEnabled())
1593                            logger.debug("Cached rename state for " + oldName + ", state=" + fstate);
1594                    }
1595                }
1596                else
1597                {
1598                    // Get the file state for the folder, if available
1599

1600                    FileState fstate = ctx.getStateTable().findFileState(oldName);
1601                    
1602                    if ( fstate != null)
1603                    {
1604                        // Update the file state index to use the new name
1605

1606                        ctx.getStateTable().renameFileState(newName, fstate);
1607                    }
1608                }
1609            }
1610            
1611            if (!relinked)
1612            {
1613                cifsHelper.move(nodeToMoveRef, targetFolderRef, name);
1614            }
1615
1616            // DEBUG
1617

1618            if (logger.isDebugEnabled())
1619                logger.debug("Moved node: " + " from: " + oldName + " to: " + newName);
1620        }
1621        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1622        {
1623            // Debug
1624

1625            if ( logger.isDebugEnabled())
1626                logger.debug("Rename file - access denied, " + oldName);
1627            
1628            // Convert to a filesystem access denied status
1629

1630            throw new AccessDeniedException("Rename file " + oldName);
1631        }
1632        catch (NodeLockedException ex)
1633        {
1634            // Debug
1635

1636            if ( logger.isDebugEnabled())
1637                logger.debug("Rename file", ex);
1638            
1639            // Convert to an filesystem access denied exception
1640

1641            throw new AccessDeniedException("Node locked " + oldName);
1642        }
1643        catch (AlfrescoRuntimeException ex)
1644        {
1645            // Debug
1646

1647            if ( logger.isDebugEnabled())
1648                logger.debug("Rename file", ex);
1649            
1650            // Convert to a general I/O exception
1651

1652            throw new IOException JavaDoc("Rename file " + oldName);
1653        }
1654    }
1655
1656    /**
1657     * Set file information
1658     *
1659     * @param sess SrvSession
1660     * @param tree TreeConnection
1661     * @param name String
1662     * @param info FileInfo
1663     * @exception IOException
1664     */

1665    public void setFileInformation(SrvSession sess, TreeConnection tree, String JavaDoc name, FileInfo info) throws IOException JavaDoc
1666    {
1667        try
1668        {
1669            // Check if pseudo files are enabled
1670

1671            if ( hasPseudoFileInterface() &&
1672                    getPseudoFileInterface().isPseudoFile( sess, tree, name))
1673            {
1674                // Allow the file information to be changed
1675

1676                return;
1677            }
1678            
1679            // Get the file/folder node
1680

1681            NodeRef nodeRef = getNodeForPath(tree, name);
1682            
1683            // Check permissions on the file/folder node
1684

1685            if ( permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
1686                throw new AccessDeniedException("No write access to " + name);
1687            
1688            // Check if the file is being marked for deletion, if so then check if the file is locked
1689

1690            if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
1691            {
1692                // Check if the node is locked
1693

1694                if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE))
1695                {
1696                    // Get the lock type, if any
1697

1698                    String JavaDoc lockTypeStr = (String JavaDoc) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
1699                    
1700                    if ( lockTypeStr != null)
1701                        throw new AccessDeniedException("Node locked, cannot mark for delete");
1702                }
1703            }
1704        }
1705        catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
1706        {
1707            // Debug
1708

1709            if ( logger.isDebugEnabled())
1710                logger.debug("Set file information - access denied, " + name);
1711            
1712            // Convert to a filesystem access denied status
1713

1714            throw new AccessDeniedException("Set file information " + name);
1715        }
1716        catch (AlfrescoRuntimeException ex)
1717        {
1718            // Debug
1719

1720            if ( logger.isDebugEnabled())
1721                logger.debug("Open file error", ex);
1722            
1723            // Convert to a general I/O exception
1724

1725            throw new IOException JavaDoc("Set file information " + name);
1726        }
1727    }
1728
1729    /**
1730     * Truncate a file to the specified size
1731     *
1732     * @param sess Server session
1733     * @param tree Tree connection
1734     * @param file Network file details
1735     * @param siz New file length
1736     * @exception java.io.IOException The exception description.
1737     */

1738    public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long size) throws IOException JavaDoc
1739    {
1740        // Truncate or extend the file to the required size
1741

1742        file.truncateFile(size);
1743        
1744        // done
1745
if (logger.isDebugEnabled())
1746        {
1747            logger.debug("Truncated file: \n" +
1748                    " network file: " + file + "\n" +
1749                    " size: " + size);
1750        }
1751    }
1752
1753    /**
1754     * Read a block of data from the specified file.
1755     *
1756     * @param sess Session details
1757     * @param tree Tree connection
1758     * @param file Network file
1759     * @param buf Buffer to return data to
1760     * @param bufPos Starting position in the return buffer
1761     * @param siz Maximum size of data to return
1762     * @param filePos File offset to read data
1763     * @return Number of bytes read
1764     * @exception java.io.IOException The exception description.
1765     */

1766    public int readFile(
1767            SrvSession sess, TreeConnection tree, NetworkFile file,
1768            byte[] buffer, int bufferPosition, int size, long fileOffset) throws IOException JavaDoc
1769    {
1770        // Check if the file is a directory
1771

1772        if(file.isDirectory())
1773            throw new AccessDeniedException();
1774            
1775        // Read a block of data from the file
1776

1777        int count = file.readFile(buffer, size, bufferPosition, fileOffset);
1778        
1779        if ( count == -1)
1780        {
1781            // Read count of -1 indicates a read past the end of file
1782

1783            count = 0;
1784        }
1785        
1786        // done
1787
if (logger.isDebugEnabled())
1788        {
1789            logger.debug("Read bytes from file: \n" +
1790                    " network file: " + file + "\n" +
1791                    " buffer size: " + buffer.length + "\n" +
1792                    " buffer pos: " + bufferPosition + "\n" +
1793                    " size: " + size + "\n" +
1794                    " file offset: " + fileOffset + "\n" +
1795                    " bytes read: " + count);
1796        }
1797        return count;
1798    }
1799
1800    /**
1801     * Seek to the specified file position.
1802     *
1803     * @param sess Server session
1804     * @param tree Tree connection
1805     * @param file Network file.
1806     * @param pos Position to seek to.
1807     * @param typ Seek type.
1808     * @return New file position, relative to the start of file.
1809     */

1810    public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException JavaDoc
1811    {
1812        throw new UnsupportedOperationException JavaDoc("Unsupported: " + file + " (seek)");
1813    }
1814
1815    /**
1816     * Write a block of data to the file.
1817     *
1818     * @param sess Server session
1819     * @param tree Tree connection
1820     * @param file Network file details
1821     * @param buf byte[] Data to be written
1822     * @param bufoff Offset within the buffer that the data starts
1823     * @param siz int Data length
1824     * @param fileoff Position within the file that the data is to be written.
1825     * @return Number of bytes actually written
1826     * @exception java.io.IOException The exception description.
1827     */

1828    public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file,
1829            byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException JavaDoc
1830    {
1831        // Write to the file
1832

1833        file.writeFile(buffer, size, bufferOffset, fileOffset);
1834        
1835        // done
1836
if (logger.isDebugEnabled())
1837        {
1838            logger.debug("Wrote bytes to file: \n" +
1839                    " network file: " + file + "\n" +
1840                    " buffer size: " + buffer.length + "\n" +
1841                    " size: " + size + "\n" +
1842                    " file offset: " + fileOffset);
1843        }
1844        return size;
1845    }
1846
1847    /**
1848     * Get the node for the specified path
1849     *
1850     * @param tree TreeConnection
1851     * @param path String
1852     * @return NodeRef
1853     * @exception FileNotFoundException
1854     */

1855    public NodeRef getNodeForPath(TreeConnection tree, String JavaDoc path)
1856        throws FileNotFoundException JavaDoc
1857    {
1858        // Check if there is a cached state for the path
1859

1860        ContentContext ctx = (ContentContext) tree.getContext();
1861        
1862        if ( ctx.hasStateTable())
1863        {
1864            // Try and get the node ref from an in memory file state
1865

1866            FileState fstate = ctx.getStateTable().findFileState(path);
1867            if ( fstate != null && fstate.hasNodeRef() && fstate.exists() )
1868            {
1869                // check that the node exists
1870
if (nodeService.exists(fstate.getNodeRef()))
1871                {
1872                    return fstate.getNodeRef();
1873                }
1874                else
1875                {
1876                    ctx.getStateTable().removeFileState(path);
1877                }
1878            }
1879        }
1880        
1881        // Search the repository for the node
1882

1883        return cifsHelper.getNodeRef(ctx.getRootNode(), path);
1884    }
1885    
1886    /**
1887     * Get the file state for the specified path
1888     *
1889     * @param tree TreeConnection
1890     * @param path String
1891     * @return FileState
1892     * @exception FileNotFoundException
1893     */

1894    public FileState getStateForPath(TreeConnection tree, String JavaDoc path)
1895        throws FileNotFoundException JavaDoc
1896    {
1897        // Check if there is a cached state for the path
1898

1899        ContentContext ctx = (ContentContext) tree.getContext();
1900        FileState fstate = null;
1901        
1902        if ( ctx.hasStateTable())
1903        {
1904            // Get the file state for a file/folder
1905

1906            fstate = ctx.getStateTable().findFileState(path);
1907        }
1908        
1909        // Return the file state
1910

1911        return fstate;
1912    }
1913    
1914    /**
1915     * Connection opened to this disk device
1916     *
1917     * @param sess Server session
1918     * @param tree Tree connection
1919     */

1920    public void treeClosed(SrvSession sess, TreeConnection tree)
1921    {
1922        // Nothing to do
1923
}
1924
1925    /**
1926     * Connection closed to this device
1927     *
1928     * @param sess Server session
1929     * @param tree Tree connection
1930     */

1931    public void treeOpened(SrvSession sess, TreeConnection tree)
1932    {
1933        // Nothing to do
1934
}
1935    
1936    /**
1937     * Process a filesystem I/O control request
1938     *
1939     * @param sess Server session
1940     * @param tree Tree connection.
1941     * @param ctrlCode I/O control code
1942     * @param fid File id
1943     * @param dataBuf I/O control specific input data
1944     * @param isFSCtrl true if this is a filesystem control, or false for a device control
1945     * @param filter if bit0 is set indicates that the control applies to the share root handle
1946     * @return DataBuffer
1947     * @exception IOControlNotImplementedException
1948     * @exception SMBException
1949     */

1950    public DataBuffer processIOControl(SrvSession sess, TreeConnection tree, int ctrlCode, int fid, DataBuffer dataBuf,
1951            boolean isFSCtrl, int filter)
1952        throws IOControlNotImplementedException, SMBException
1953    {
1954        // Validate the file id
1955

1956        NetworkFile netFile = tree.findFile(fid);
1957        if ( netFile == null || netFile.isDirectory() == false)
1958            throw new SMBException(SMBStatus.NTErr, SMBStatus.NTInvalidParameter);
1959        
1960        // Check if the I/O control handler is enabled
1961

1962        if ( m_ioHandler != null)
1963            return m_ioHandler.processIOControl( sess, tree, ctrlCode, fid, dataBuf, isFSCtrl, filter);
1964        else
1965            throw new IOControlNotImplementedException();
1966    }
1967}
1968
Popular Tags