gt:                 if (( attr & FileAttribute.ReadOnly) == 0)
context: /*
   * Copyright (C) 2005-2013 Alfresco Software Limited.
   *
   * This file is part of Alfresco
   *
   * Alfresco is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * Alfresco 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 Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */
  package org.alfresco.filesys.repo;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Stack;
  import java.util.StringTokenizer;
  
  import org.alfresco.error.AlfrescoRuntimeException;
  import org.alfresco.filesys.repo.CommandExecutorImpl.PropagatingException;
  import org.alfresco.jlan.server.filesys.FileAttribute;
  import org.alfresco.jlan.server.filesys.FileExistsException;
  import org.alfresco.jlan.server.filesys.FileName;
  import org.alfresco.jlan.server.filesys.FileType;
  import org.alfresco.jlan.util.WildCard;
  import org.alfresco.model.ContentModel;
  import org.alfresco.repo.model.filefolder.HiddenAspect;
  import org.alfresco.repo.model.filefolder.HiddenAspect.Visibility;
  import org.alfresco.repo.transaction.RetryingTransactionHelper;
  import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
  import org.alfresco.service.cmr.dictionary.DictionaryService;
  import org.alfresco.service.cmr.lock.LockService;
  import org.alfresco.service.cmr.lock.LockStatus;
  import org.alfresco.service.cmr.lock.LockType;
  import org.alfresco.service.cmr.model.FileFolderService;
  import org.alfresco.service.cmr.model.FileFolderUtil;
  import org.alfresco.service.cmr.model.FileInfo;
  import org.alfresco.service.cmr.repository.ContentData;
  import org.alfresco.service.cmr.repository.InvalidNodeRefException;
  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.datatype.DefaultTypeConverter;
  import org.alfresco.service.cmr.security.AccessStatus;
  import org.alfresco.service.cmr.security.PermissionService;
  import org.alfresco.service.namespace.QName;
  import org.alfresco.util.FileFilterMode.Client;
  import org.alfresco.util.PropertyCheck;
  import org.alfresco.util.SearchLanguageConversion;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  /**
   * Class with supplying helper methods and potentially acting as a cache for
   * queries.
   *  
   * @author derekh
   */
  public class CifsHelper
  {
      // Logging
      private static Log logger = LogFactory.getLog(CifsHelper.class);
      
      // Services
      private DictionaryService dictionaryService;
      private NodeService nodeService;
      private FileFolderService fileFolderService;
      private MimetypeService mimetypeService;
      private PermissionService permissionService;
      private LockService lockService;
      private HiddenAspect hiddenAspect;
      private RetryingTransactionHelper retryingTransactionHelper;
  
      private Set<QName> excludedTypes = new HashSet<QName>();
      
      private boolean isReadOnlyFlagOnFolders = false;
      
      /**
       * Class constructor
       */
      public CifsHelper()
      {
      }
      
      public void init()
      {   
          PropertyCheck.mandatory(this, "dictionaryService",dictionaryService);
          PropertyCheck.mandatory(this, "nodeService",nodeService);
          PropertyCheck.mandatory(this, "fileFolderService",fileFolderService);
          PropertyCheck.mandatory(this, "permissionService",permissionService);
          PropertyCheck.mandatory(this, "lockService",lockService);
          PropertyCheck.mandatory(this, "mimetypeService",mimetypeService);
          PropertyCheck.mandatory(this, "transactionHelper",getRetryingTransactionHelper());
      }
      
      public void setDictionaryService(DictionaryService dictionaryService)
      {
          this.dictionaryService = dictionaryService;
      }
  
  	public void setNodeService(NodeService nodeService)
      {
          this.nodeService = nodeService;
      }
  
      public void setFileFolderService(FileFolderService fileFolderService)
      {
          this.fileFolderService = fileFolderService;
      }
      
      public void setMimetypeService(MimetypeService mimetypeService)
      {
          this.mimetypeService = mimetypeService;
      }
  
      public void setPermissionService(PermissionService permissionService)
      {
          this.permissionService = permissionService;
      }
  
      public void setHiddenAspect(HiddenAspect hiddenAspect)
      {
          this.hiddenAspect = hiddenAspect;
      }
  
      /**
       * Return the node service
       * 
       * @return NodeService
       */
      protected NodeService getNodeService() {
          return nodeService;
      }
      
      public void setExcludedTypes(List<String> excludedTypes)
      {
          for(String exType:excludedTypes)
          {
              this.excludedTypes.add(QName.createQName(exType));
          }
      }
  
      /**
       * Controls whether the read only flag is set on folders. This flag, when set, may cause problematic # behaviour in
       * Windows clients and doesn't necessarily mean a folder can't be written to. See ALF-6727. Should we ever set the
       * read only flag on folders?
       * 
       * @param setReadOnlyFlagOnFolders
       *            the setReadOnlyFlagOnFolders to set
       */
      public void setReadOnlyFlagOnFolders(boolean setReadOnlyFlagOnFolders)
      {
          this.isReadOnlyFlagOnFolders = setReadOnlyFlagOnFolders;
      }
  
      /**
       * @param nodeRef
       * @return Returns true if the node is a subtype of {@link ContentModel#TYPE_FOLDER folder}
       * @throws AlfrescoRuntimeException if the type is neither related to a folder or content
       */
      public boolean isDirectory(NodeRef nodeRef)
      {
          QName nodeTypeQName = nodeService.getType(nodeRef);
          if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_FOLDER))
          {
              return true;
          }
          else if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT))
          {
              return false;
          }
          else
          {
              // it is not a directory, but what is it?
              return false;   
          }
      }
      
      /**
       * Extract a single node's file info, where the node is reference by
       * a path relative to an ancestor node.
       * 
       * @param pathRootNodeRef
       * @param path the path
       * @return Returns the existing node reference
       * @throws FileNotFoundException
       */
      public ContentFileInfo getFileInformation(final NodeRef pathRootNodeRef, final String path, final boolean readOnly, final boolean lockedFilesAsOffline) throws FileNotFoundException
      {
                 
          RetryingTransactionCallback<ContentFileInfo> cb =  new RetryingTransactionCallback<ContentFileInfo>()
          {
              /**
               * Perform a set of commands as a unit of transactional work.
               *
               * @return              Return the result of the unit of work
               * @throws Throwable    This can be anything and will guarantee either a retry or a rollback
               */
              public ContentFileInfo execute() throws IOException
              {
                  try
                  {
                  	return getFileInformationImpl(pathRootNodeRef, path, readOnly, lockedFilesAsOffline);
                  }
                  catch (FileNotFoundException e)
                  {
                      // Ensure original checked IOExceptions get propagated
                      throw new PropagatingException(e);
                  }
              }
          };
          
          try
          {
              return getRetryingTransactionHelper().doInTransaction(cb, true);
          }
          catch(PropagatingException pe)
          {          
              // Unwrap checked exceptions
              throw (FileNotFoundException) pe.getCause();
          }
      }
  
      
      public ContentFileInfo getFileInformation(final NodeRef nodeRef, final boolean readOnly, final boolean lockedFilesAsOffline) throws FileNotFoundException
      {
          RetryingTransactionCallback<ContentFileInfo> cb =  new RetryingTransactionCallback<ContentFileInfo>()
          {
              /**
               * Perform a set of commands as a unit of transactional work.
               *
               * @return              Return the result of the unit of work
               * @throws Throwable    This can be anything and will guarantee either a retry or a rollback
               */
              public ContentFileInfo execute() throws IOException
              {
                  try
                  {
                  	return getFileInformationImpl(nodeRef, readOnly, lockedFilesAsOffline);
                  }
                  catch (FileNotFoundException e)
                  {
                      // Ensure original checked IOExceptions get propagated
                      throw new PropagatingException(e);
                  }
              }
          };
          
          try
          {
              return getRetryingTransactionHelper().doInTransaction(cb, true);
          }
          catch(PropagatingException pe)
          {          
              // Unwrap checked exceptions
              throw (FileNotFoundException) pe.getCause();
          }
      	
      }
  
  
      /**
       * Extract a single node's file info, where the node is reference by
       * a path relative to an ancestor node.
       * 
       * @param pathRootNodeRef
       * @param path the path
       * @return Returns the existing node reference
       * @throws FileNotFoundException
       */
      public ContentFileInfo getFileInformationImpl(NodeRef pathRootNodeRef, String path, boolean readOnly, boolean lockedFilesAsOffline) throws FileNotFoundException
      {
          // get the node being referenced
          NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
  
          return getFileInformationImpl(nodeRef, readOnly, lockedFilesAsOffline);
      }
      
  
      /**
       * Helper method to extract file info from a specific node.
       * <p>
       * This method goes direct to the repo for all information and no data is
       * cached here.
       * 
       * @param nodeRef the node
       * @param readOnly, should the file be shown as "read only", regardless of its permissions?
       * @param lockedFilesAsOffline should a locked file be marked as offline
       * 
       * @return Returns the file information pertinent to the node
       * @throws FileNotFoundException if the path refers to a non-existent file
       */
      private ContentFileInfo getFileInformationImpl(NodeRef nodeRef, boolean readOnly, boolean lockedFilesAsOffline) throws FileNotFoundException
      {
          // get the file info
          org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
          
          // retrieve required properties and create new JLAN file info
          ContentFileInfo fileInfo = new ContentFileInfo(nodeRef);
          
          // Set the file id from the node's DBID
          long id = DefaultTypeConverter.INSTANCE.convert(Long.class, nodeService.getProperty(nodeRef, ContentModel.PROP_NODE_DBID));
          fileInfo.setFileId((int) (id & 0xFFFFFFFFL));    
          
          // unset all attribute flags
          int fileAttributes = 0;
          fileInfo.setFileAttributes(fileAttributes);
          
          if (fileFolderInfo.isFolder())
          {
              // add directory attribute
              fileAttributes |= FileAttribute.Directory;
              fileInfo.setFileAttributes(fileAttributes);
              fileInfo.setFileType(FileType.Directory);
          }
          else
          {
              Map<QName, Serializable> nodeProperties = fileFolderInfo.getProperties();
              
              // Get the file size from the content
              
              ContentData contentData = (ContentData) nodeProperties.get(ContentModel.PROP_CONTENT);
              long size = 0L;
              if (contentData != null)
              {
                  size = contentData.getSize();
              }
              fileInfo.setSize(size);
              
              // Set the allocation size by rounding up the size to a 512 byte block boundary
              
              if ( size > 0)
              {
                  fileInfo.setAllocationSize((size + 512L) & 0xFFFFFFFFFFFFFE00L);
              }
              
              // Check whether the file is locked 
              
              if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
              {
                  LockType lockType = lockService.getLockType(nodeRef);
                  
                  int attr = fileInfo.getFileAttributes();
                  
                  if(lockType != null)
                  {
                      switch(lockType)
                      {
                          case NODE_LOCK:
                              if (( attr & FileAttribute.ReadOnly) == 0)
                                  attr += FileAttribute.ReadOnly;
                              break;
                          case WRITE_LOCK:
                              LockStatus lockStatus = lockService.getLockStatus(nodeRef);
                              if (lockStatus == LockStatus.LOCK_OWNER)
                              {
                              }
                              else
                              {
                                  if (( attr & FileAttribute.ReadOnly) == 0)
                                  {
                                      attr += FileAttribute.ReadOnly;
                                  }
                          
                                  if ( lockedFilesAsOffline)
                                  {
                                      attr += FileAttribute.NTOffline;
                                  }
                              }
                              break;
                          case READ_ONLY_LOCK:
                              if (( attr & FileAttribute.ReadOnly) == 0)
                              {
                                  attr += FileAttribute.ReadOnly;
                              }
                      
                              if ( lockedFilesAsOffline)
                              {
                                  attr += FileAttribute.NTOffline;
                              }
                              break;
                      }
                  
                      fileInfo.setFileAttributes( attr);
                  }
              }
              
              // Check if it is a link node
              
              if ( fileFolderInfo.isLink())
              {
              	fileInfo.setLinkNodeRef( fileFolderInfo.getLinkNodeRef());
              }
          }
          
          // created
          Date createdDate = fileFolderInfo.getCreatedDate();
          if (createdDate != null)
          {
              long created = DefaultTypeConverter.INSTANCE.longValue(createdDate);
              fileInfo.setCreationDateTime(created);
          }
          // modified
          Date modifiedDate = fileFolderInfo.getModifiedDate();
          if (modifiedDate != null)
          {
              long modified = DefaultTypeConverter.INSTANCE.longValue(modifiedDate);
              fileInfo.setModifyDateTime(modified);
              fileInfo.setAccessDateTime(modified);
              fileInfo.setChangeDateTime(modified);
          }
          // name
          String name = fileFolderInfo.getName();
          if (name != null)
          {
              fileInfo.setFileName(name);
  
              // Check for file names that should be hidden
              if(hiddenAspect.getVisibility(Client.cifs, fileInfo.getNodeRef()) == Visibility.HiddenAttribute)
              {
              	// Add the hidden file attribute
              	int attr = fileInfo.getFileAttributes();
              	if (( attr & FileAttribute.Hidden) == 0)
              	{
              		attr += FileAttribute.Hidden;
              		fileInfo.setFileAttributes( attr);
              	}
              }
          }
          
          // Read/write access
          
          if (!fileFolderInfo.isFolder() || isReadOnlyFlagOnFolders)
          {
              boolean deniedPermission = permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED; 
              if (readOnly || deniedPermission)
              {
                  int attr = fileInfo.getFileAttributes();
  