diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java index 7046fd2c8a..9f8f79061f 100644 --- a/source/java/org/alfresco/filesys/avm/AVMContext.java +++ b/source/java/org/alfresco/filesys/avm/AVMContext.java @@ -346,7 +346,7 @@ public class AVMContext extends AlfrescoContext // Update the file state modify time - rootState.setLastUpdated( System.currentTimeMillis()); + rootState.updateModifyDateTime(); // Send a change notification for the deleted folder diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java index b56578aa10..539fced503 100644 --- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java +++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java @@ -25,10 +25,8 @@ package org.alfresco.filesys.avm; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.SortedMap; import java.util.StringTokenizer; @@ -41,7 +39,6 @@ import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContextException; -import org.alfresco.jlan.server.core.DeviceInterface; import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException; import org.alfresco.jlan.server.filesys.DiskInterface; @@ -81,14 +78,9 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; -import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/source/java/org/alfresco/filesys/repo/BufferedWrite.java b/source/java/org/alfresco/filesys/repo/BufferedWrite.java new file mode 100644 index 0000000000..712753a1fe --- /dev/null +++ b/source/java/org/alfresco/filesys/repo/BufferedWrite.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2006-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.filesys.repo; + +/** + * Buffered Write Class + * + *
Contains the details and data for a buffered write. + * + * @author gkspencer + */ +public class BufferedWrite { + + // Write details + + private long m_offset; + private byte[] m_data; + + /** + * Class constructor + * + * @param buf byte[] + * @param offset long + */ + public BufferedWrite( byte[] buf, long offset) { + m_data = buf; + m_offset = offset; + } + + /** + * Return the file offset + * + * @return long + */ + public final long getOffset() { + return m_offset; + } + + /** + * Return the write data + * + * @return byte[] + */ + public final byte[] getData() { + return m_data; + } + + /** + * Return the data length + * + * @return int + */ + public final int getDataLength() { + return m_data != null ? m_data.length : 0; + } + + /** + * Return the buffered write details as a string + * + * @return String + */ + public String toString() { + StringBuilder str = new StringBuilder(); + + str.append("[Data len="); + str.append(m_data.length); + str.append(",Offset="); + str.append(m_offset); + str.append("]"); + + return str.toString(); + } +} diff --git a/source/java/org/alfresco/filesys/repo/CifsHelper.java b/source/java/org/alfresco/filesys/repo/CifsHelper.java index 8ed44a7d52..1e15df2925 100644 --- a/source/java/org/alfresco/filesys/repo/CifsHelper.java +++ b/source/java/org/alfresco/filesys/repo/CifsHelper.java @@ -636,10 +636,6 @@ public class CifsHelper { try { - // Check if the new file name is a temporary file name - if ( newName.endsWith(".tmp") || newName.endsWith(".temp")) - nodeService.addAspect(nodeToRenameRef, ContentModel.ASPECT_TEMPORARY, null); - fileFolderService.rename(nodeToRenameRef, newName); } catch (org.alfresco.service.cmr.model.FileExistsException e) diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index 99a76931a4..53b3e24711 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java @@ -27,6 +27,7 @@ package org.alfresco.filesys.repo; import java.io.FileNotFoundException; import java.io.IOException; import java.net.InetAddress; +import java.util.Date; import java.util.List; import javax.transaction.UserTransaction; @@ -606,8 +607,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added file state for pseudo files folder (getinfo) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added file state for pseudo files folder (getinfo) - " + paths[0]); } else if ( fstate.hasPseudoFiles() == false) { @@ -626,8 +627,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added pseudo files for folder (exists) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added pseudo files for folder (exists) - " + paths[0]); } @@ -657,6 +658,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the node ref for the path, chances are there is a file state in the cache NodeRef nodeRef = getNodeForPath(tree, infoPath); + if ( nodeRef != null) { // Get the file information for the node @@ -665,7 +667,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // DEBUG - if ( logger.isInfoEnabled()) + if ( logger.isDebugEnabled()) logger.debug("getInfo using cached noderef for path " + path); } @@ -689,7 +691,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // DEBUG - if ( logger.isInfoEnabled()) + if ( logger.isDebugEnabled()) logger.debug("getInfo using cached noderef for parent " + path); } } @@ -710,9 +712,25 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Set the file id for the file using the relative path - if ( finfo != null) + if ( finfo != null) { + + // Set the file id + finfo.setFileId( path.hashCode()); + // Copy cached timestamps, if available + + FileState fstate = getStateForPath(tree, infoPath); + if ( fstate != null) { + if ( fstate.hasAccessDateTime()) + finfo.setAccessDateTime(fstate.getAccessDateTime()); + if ( fstate.hasChangeDateTime()) + finfo.setChangeDateTime(fstate.getChangeDateTime()); + if ( fstate.hasModifyDateTime()) + finfo.setModifyDateTime(fstate.getModifyDateTime()); + } + } + // Return the file information return finfo; @@ -1019,8 +1037,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added file state for pseudo files folder (exists) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added file state for pseudo files folder (exists) - " + paths[0]); } } else if ( fstate.hasPseudoFiles() == false) @@ -1044,8 +1062,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added pseudo files for folder (exists) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added pseudo files for folder (exists) - " + paths[0]); } // Check if the path is to a pseudo file @@ -1061,8 +1079,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Failed to find pseudo file - if ( logger.isInfoEnabled()) - logger.info( "Failed to find pseudo file (exists) - " + name); + if ( logger.isDebugEnabled()) + logger.debug( "Failed to find pseudo file (exists) - " + name); } } } @@ -1167,8 +1185,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added file state for pseudo files folder (open) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added file state for pseudo files folder (open) - " + paths[0]); } } else if ( fstate.hasPseudoFiles() == false) @@ -1179,8 +1197,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug - if ( logger.isInfoEnabled()) - logger.info( "Added pseudo files for folder (open) - " + paths[0]); + if ( logger.isDebugEnabled()) + logger.debug( "Added pseudo files for folder (open) - " + paths[0]); } // Check if the path is to a pseudo file @@ -1196,8 +1214,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Failed to find pseudo file - if ( logger.isInfoEnabled()) - logger.info( "Failed to find pseudo file (open) - " + params.getPath()); + if ( logger.isDebugEnabled()) + logger.debug( "Failed to find pseudo file (open) - " + params.getPath()); } } } @@ -1439,7 +1457,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // DEBUG - if ( logger.isInfoEnabled()) + if ( logger.isDebugEnabled()) logger.debug("Create file using cached noderef for path " + paths[0]); } } @@ -2019,9 +2037,46 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( sameFolder == true) { + // Check if the new file name is a temporary file name + + String newNameNorm = newName.toLowerCase(); + boolean isTempFile = false; + + if ( newNameNorm.endsWith(".tmp") || newNameNorm.endsWith(".temp")) { + + // Add the temporary aspect, also prevents versioning + + nodeService.addAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY, null); + + // Indicate that the new file is a temporary file + + isTempFile = true; + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Added Temporary aspect to renamed file " + newName); + } + // Rename the file/folder cifsHelper.rename(nodeToMoveRef, name); + + // Check if the temporary aspect should be removed from the renamed file + + String oldNameNorm = oldName.toLowerCase(); + + if ( isTempFile == false && (oldNameNorm.endsWith(".tmp") || oldNameNorm.endsWith(".temp"))) { + + // Remove the temporary aspect + + nodeService.removeAspect(nodeToMoveRef, ContentModel.ASPECT_TEMPORARY); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Removed Temporary aspect from renamed file " + newName); + } // DEBUG @@ -2151,6 +2206,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file/folder node NodeRef nodeRef = getNodeForPath(tree, name); + FileState fstate = getStateForPath(tree, name); // Check permissions on the file/folder node @@ -2164,6 +2220,10 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose()) { + // Start a transaction + + beginReadTransaction( sess); + // Check if the node is locked if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE)) @@ -2175,6 +2235,64 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( lockTypeStr != null) throw new AccessDeniedException("Node locked, cannot mark for delete"); } + + // Update the change date/time + + if ( fstate != null) + fstate.updateChangeDateTime(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set deleteOnClose=true file=" + name); + } + + // Set the creation date/time + + if ( info.hasSetFlag(FileInfo.SetCreationDate)) { + + // Create the transaction + + beginWriteTransaction( sess); + + // Set the creation date on the file/folder node + + Date createDate = new Date( info.getCreationDateTime()); + nodeService.setProperty( nodeRef, ContentModel.PROP_CREATED, createDate); + + // Update the change date/time + + if ( fstate != null) + fstate.updateChangeDateTime(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set creationDate=" + createDate + " file=" + name); + } + + // Set the modification date/time + + if ( info.hasSetFlag(FileInfo.SetModifyDate)) { + + // Create the transaction + + beginWriteTransaction( sess); + + // Set the creation date on the file/folder node + + Date modifyDate = new Date( info.getModifyDateTime()); + nodeService.setProperty( nodeRef, ContentModel.PROP_MODIFIED, modifyDate); + + // Update the change date/time + + if ( fstate != null) + fstate.updateChangeDateTime(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Set modifyDate=" + modifyDate + " file=" + name); } } catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java index 53f6487e22..4d6671b618 100644 --- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java +++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java @@ -69,6 +69,8 @@ public class ContentNetworkFile extends NodeRefNetworkFile { private static final Log logger = LogFactory.getLog(ContentNetworkFile.class); + // Services + private NodeService nodeService; private ContentService contentService; private MimetypeService mimetypeService; @@ -107,7 +109,20 @@ public class ContentNetworkFile extends NodeRefNetworkFile // Create the file - ContentNetworkFile netFile = new ContentNetworkFile(nodeService, contentService, mimetypeService, nodeRef, path); + ContentNetworkFile netFile = null; + + if ( isMSOfficeSpecialFile(path)) { + + // Create a file for special processing + + netFile = new MSOfficeContentNetworkFile( nodeService, contentService, mimetypeService, nodeRef, path); + } + else { + + // Create a normal content file + + netFile = new ContentNetworkFile(nodeService, contentService, mimetypeService, nodeRef, path); + } // Set relevant parameters @@ -182,7 +197,7 @@ public class ContentNetworkFile extends NodeRefNetworkFile * @param nodeRef NodeRef * @param name String */ - private ContentNetworkFile( + protected ContentNetworkFile( NodeService nodeService, ContentService contentService, MimetypeService mimetypeService, @@ -439,6 +454,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile setFileSize( size); + // Update the modification date/time + + if ( getFileState() != null) + getFileState().updateModifyDateTime(); + // DEBUG if (logger.isDebugEnabled()) @@ -475,6 +495,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile setFileSize(channel.size()); + // Update the modification date/time + + if ( getFileState() != null) + getFileState().updateModifyDateTime(); + // DEBUG if (logger.isDebugEnabled()) @@ -507,6 +532,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile count = 0; // doesn't obey the same rules, i.e. just returns the bytes read } + // Update the access date/time + + if ( getFileState() != null) + getFileState().updateAccessDateTime(); + // DEBUG if (logger.isDebugEnabled()) @@ -574,6 +604,11 @@ public class ContentNetworkFile extends NodeRefNetworkFile break; } + // Update the access date/time + + if ( getFileState() != null) + getFileState().updateAccessDateTime(); + // DEBUG if (logger.isDebugEnabled()) @@ -601,9 +636,31 @@ public class ContentNetworkFile extends NodeRefNetworkFile channel.force(false); + // Update the access date/time + + if ( getFileState() != null) + getFileState().updateAccessDateTime(); + // DEBUG if (logger.isDebugEnabled()) logger.debug("Flush file=" + this); } + + /** + * Check if the file is an MS Office document type that needs special processing + * + * @param path String + * @return boolean + */ + private static final boolean isMSOfficeSpecialFile(String path) { + + // Check if the file extension indicates a problem MS Office format + + path = path.toLowerCase(); + + if ( path.endsWith( ".xls")) + return true; + return false; + } } diff --git a/source/java/org/alfresco/filesys/repo/MSOfficeContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/MSOfficeContentNetworkFile.java new file mode 100644 index 0000000000..ce21966123 --- /dev/null +++ b/source/java/org/alfresco/filesys/repo/MSOfficeContentNetworkFile.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2006-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.filesys.repo; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Ms Office Content Network File Class + * + *
Provides special handling for MS Office files that are written to by the app even though the user does not
+ * change the file.
+ *
+ * @author gkspencer
+ */
+public class MSOfficeContentNetworkFile extends ContentNetworkFile {
+
+ private static final Log logger = LogFactory.getLog(MSOfficeContentNetworkFile.class);
+
+ // Count of file reads
+
+ private int m_readCnt;
+
+ // Buffered write list
+
+ private List