/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include <config_features.h>
 
#include <sal/config.h>
#include <sal/log.hxx>
 
#if HAVE_FEATURE_MACOSX_SANDBOX
#include <sys/stat.h>
#endif
 
#include <com/sun/star/beans/IllegalTypeException.hpp>
#include <com/sun/star/beans/NotRemoveableException.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyExistException.hpp>
#include <com/sun/star/io/BufferSizeExceededException.hpp>
#include <com/sun/star/io/NotConnectedException.hpp>
#include <com/sun/star/io/IOException.hpp>
#include <com/sun/star/lang/IllegalAccessException.hpp>
#include <com/sun/star/task/InteractionClassification.hpp>
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
#include <com/sun/star/ucb/DuplicateCommandIdentifierException.hpp>
#include <com/sun/star/ucb/IOErrorCode.hpp>
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include <com/sun/star/ucb/OpenCommandArgument.hpp>
#include <com/sun/star/ucb/Store.hpp>
#include <com/sun/star/ucb/TransferInfo.hpp>
#include <comphelper/propertysequence.hxx>
#include <osl/diagnose.h>
#include <rtl/ref.hxx>
#include <rtl/uri.hxx>
 
#include "filtask.hxx"
#include "filcmd.hxx"
#include "filglob.hxx"
#include "filinpstr.hxx"
#include "filprp.hxx"
#include "filrset.hxx"
#include "filstr.hxx"
#include "prov.hxx"
 
/******************************************************************************/
/*                                                                            */
/*                              TaskHandling                                  */
/*                                                                            */
/******************************************************************************/
 
 
using namespace fileaccess;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
 
#if OSL_DEBUG_LEVEL > 0
#define THROW_WHERE SAL_WHERE
#else
#define THROW_WHERE ""
#endif
 
TaskManager::UnqPathData::UnqPathData() = default;
 
TaskManager::UnqPathData::UnqPathData(TaskManager::UnqPathData&&) = default;
 
 
TaskManager::UnqPathData::~UnqPathData()
{
}
 
TaskManager::MyProperty::MyProperty( const OUString&                         thePropertyName )
    : PropertyName( thePropertyName )
    , Handle(-1)
    , isNative(false)
    , State(beans::PropertyState_AMBIGUOUS_VALUE)
    , Attributes(0)
{
    // empty
}
 
TaskManager::MyProperty::MyProperty( bool                               theisNative,
                               const OUString&                    thePropertyName,
                               sal_Int32                          theHandle,
                               const css::uno::Type&              theTyp,
                               const css::uno::Any&               theValue,
                               const css::beans::PropertyState&   theState,
                               sal_Int16                          theAttributes )
    : PropertyName( thePropertyName ),
      Handle( theHandle ),
      isNative( theisNative ),
      Typ( theTyp ),
      Value( theValue ),
      State( theState ),
      Attributes( theAttributes )
{
    // empty
}
 
#include "filinl.hxx"
 
        // Default properties
 
constexpr OUString Title( u"Title"_ustr );
constexpr OUString CasePreservingURL( u"CasePreservingURL"_ustr );
constexpr OUString IsDocument( u"IsDocument"_ustr );
constexpr OUString IsFolder( u"IsFolder"_ustr );
constexpr OUString DateModified( u"DateModified"_ustr );
constexpr OUString Size( u"Size"_ustr );
constexpr OUString IsVolume( u"IsVolume"_ustr );
constexpr OUString IsRemoveable( u"IsRemoveable"_ustr );
constexpr OUString IsRemote( u"IsRemote"_ustr );
constexpr OUString IsCompactDisc( u"IsCompactDisc"_ustr );
constexpr OUString IsFloppy( u"IsFloppy"_ustr );
constexpr OUString IsHidden( u"IsHidden"_ustr );
constexpr OUString ContentType( u"ContentType"_ustr );
constexpr OUString IsReadOnly( u"IsReadOnly"_ustr );
constexpr OUString CreatableContentsInfo( u"CreatableContentsInfo"_ustr );
 
TaskManager::TaskManager( const uno::Reference< uno::XComponentContext >& rxContext,
              FileProvider* pProvider, bool bWithConfig )
    : m_nCommandId( 0 ),
      m_pProvider( pProvider ),
      m_xContext( rxContext ),
      // Commands
      m_sCommandInfo{
          { /* Name    */ u"getCommandInfo"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<void>::get() },
 
          { /* Name    */ u"getPropertySetInfo"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<void>::get() },
 
          { /* Name    */ u"getPropertyValues"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<uno::Sequence< beans::Property >>::get() },
 
          { /* Name    */ u"setPropertyValues"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() },
 
          { /* Name    */ u"open"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<OpenCommandArgument>::get() },
 
          { /* Name    */ u"transfer"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<TransferInfo>::get() },
 
          { /* Name    */ u"delete"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<sal_Bool>::get() },
 
          { /* Name    */ u"insert"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<InsertCommandArgument>::get() },
 
          { /* Name    */ u"createNewContent"_ustr,
            /* Handle  */ -1,
            /* ArgType */ cppu::UnoType<ucb::ContentInfo>::get() } }
{
    // Title
    m_aDefaultProperties.insert( MyProperty( true,
                                             Title,
                                             -1 ,
                                             cppu::UnoType<OUString>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND ) );
 
    // CasePreservingURL
    m_aDefaultProperties.insert(
        MyProperty( true,
                    CasePreservingURL,
                    -1 ,
                    cppu::UnoType<OUString>::get(),
                    uno::Any(),
                    beans::PropertyState_DEFAULT_VALUE,
                    beans::PropertyAttribute::MAYBEVOID
                    | beans::PropertyAttribute::BOUND
                    | beans::PropertyAttribute::READONLY ) );
 
 
    // IsFolder
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsFolder,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
 
    // IsDocument
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsDocument,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    // Removable
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsVolume,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
 
    // Removable
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsRemoveable,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    // Remote
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsRemote,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    // CompactDisc
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsCompactDisc,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    // Floppy
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsFloppy,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    // Hidden
    m_aDefaultProperties.insert(
        MyProperty(
            true,
            IsHidden,
            -1 ,
            cppu::UnoType<sal_Bool>::get(),
            uno::Any(),
            beans::PropertyState_DEFAULT_VALUE,
            beans::PropertyAttribute::MAYBEVOID
            | beans::PropertyAttribute::BOUND
#if defined(_WIN32)
        ));
#else
    | beans::PropertyAttribute::READONLY)); // under unix/linux only readable
#endif
 
 
    // ContentType
    m_aDefaultProperties.insert( MyProperty( false,
                                             ContentType,
                                             -1 ,
                                             cppu::UnoType<OUString>::get(),
                                             uno::Any(OUString()),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
 
    // DateModified
    m_aDefaultProperties.insert( MyProperty( true,
                                             DateModified,
                                             -1 ,
                                             cppu::UnoType<util::DateTime>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND ) );
 
    // Size
    m_aDefaultProperties.insert( MyProperty( true,
                                             Size,
                                             -1,
                                             cppu::UnoType<sal_Int64>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND ) );
 
    // IsReadOnly
    m_aDefaultProperties.insert( MyProperty( true,
                                             IsReadOnly,
                                             -1 ,
                                             cppu::UnoType<sal_Bool>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND ) );
 
 
    // CreatableContentsInfo
    m_aDefaultProperties.insert( MyProperty( true,
                                             CreatableContentsInfo,
                                             -1 ,
                                             cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
                                             uno::Any(),
                                             beans::PropertyState_DEFAULT_VALUE,
                                             beans::PropertyAttribute::MAYBEVOID
                                             | beans::PropertyAttribute::BOUND
                                             | beans::PropertyAttribute::READONLY ) );
 
    if(bWithConfig)
    {
        uno::Reference< XPropertySetRegistryFactory > xRegFac = ucb::Store::create( m_xContext );
        // Open/create a registry
        m_xFileRegistry = xRegFac->createPropertySetRegistry( OUString() );
    }
}
 
 
TaskManager::~TaskManager()
{
}
 
 
void
TaskManager::startTask(
    sal_Int32 CommandId,
    const uno::Reference< XCommandEnvironment >& xCommandEnv )
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    if( it != m_aTaskMap.end() )
    {
        throw DuplicateCommandIdentifierException( OSL_LOG_PREFIX );
    }
    m_aTaskMap.emplace( CommandId, TaskHandling( xCommandEnv ));
}
 
 
void
TaskManager::endTask( sal_Int32 CommandId,
                      const OUString& aUncPath,
                      BaseContent* pContent)
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    if( it == m_aTaskMap.end() )
        return;
 
    TaskHandlerErr ErrorCode = it->second.getInstalledError();
    sal_Int32 MinorCode = it->second.getMinorErrorCode();
    bool isHandled = it->second.isHandled();
 
    Reference< XCommandEnvironment > xComEnv
        = it->second.getCommandEnvironment();
 
    m_aTaskMap.erase( it );
 
    aGuard.unlock();
 
    if( ErrorCode != TaskHandlerErr::NO_ERROR )
        throw_handler(
            ErrorCode,
            MinorCode,
            xComEnv,
            aUncPath,
            pContent,
            isHandled);
}
 
 
void TaskManager::clearError( sal_Int32 CommandId )
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    if( it != m_aTaskMap.end() )
        it->second.clearError();
}
 
 
void TaskManager::retrieveError( sal_Int32 CommandId,
                                          TaskHandlerErr &ErrorCode,
                                          sal_Int32 &minorCode)
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    if( it != m_aTaskMap.end() )
    {
        ErrorCode = it->second.getInstalledError();
        minorCode = it->second. getMinorErrorCode();
    }
}
 
 
void TaskManager::installError( sal_Int32 CommandId,
                                         TaskHandlerErr ErrorCode,
                                         sal_Int32 MinorCode )
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    if( it != m_aTaskMap.end() )
        it->second.installError( ErrorCode,MinorCode );
}
 
 
sal_Int32
TaskManager::getCommandId()
{
    std::unique_lock aGuard( m_aMutex );
    return ++m_nCommandId;
}
 
 
void TaskManager::handleTask(
    sal_Int32 CommandId,
    const uno::Reference< task::XInteractionRequest >& request )
{
    std::unique_lock aGuard( m_aMutex );
    TaskMap::iterator it = m_aTaskMap.find( CommandId );
    uno::Reference< task::XInteractionHandler > xInt;
    if( it != m_aTaskMap.end() )
    {
        xInt = it->second.getInteractionHandler();
        if( xInt.is() )
            xInt->handle( request );
        it->second.setHandled();
    }
}
 
/*********************************************************************************/
/*                                                                               */
/*                     de/registerNotifier-Implementation                        */
/*                                                                               */
/*********************************************************************************/
 
 
//  This two methods register and deregister a change listener for the content belonging
//  to URL aUnqPath
 
 
void
TaskManager::registerNotifier( const OUString& aUnqPath, Notifier* pNotifier )
{
    std::unique_lock aGuard( m_aMutex );
 
    ContentMap::iterator it =
        m_aContent.emplace( aUnqPath, UnqPathData() ).first;
 
    std::vector< Notifier* >& nlist = it->second.notifier;
 
    std::vector<Notifier*>::iterator it1 = std::find(nlist.begin(), nlist.end(), pNotifier);
    if( it1 != nlist.end() )               // Every "Notifier" only once
    {
        return;
    }
    nlist.push_back( pNotifier );
}
 
 
void
TaskManager::deregisterNotifier( const OUString& aUnqPath,Notifier* pNotifier )
{
    std::unique_lock aGuard( m_aMutex );
 
    ContentMap::iterator it = m_aContent.find( aUnqPath );
    if( it == m_aContent.end() )
        return;
 
    std::erase(it->second.notifier, pNotifier);
 
    if( it->second.notifier.empty() )
        m_aContent.erase( it );
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     de/associate-Implementation                               */
/*                                                                               */
/*********************************************************************************/
 
//  Used to associate and deassociate a new property with
//  the content belonging to URL UnqPath.
//  The default value and the attributes are input
 
 
void
TaskManager::associate( const OUString& aUnqPath,
                  const OUString& PropertyName,
                  const uno::Any& DefaultValue,
                  const sal_Int16 Attributes )
{
    MyProperty newProperty( false,
                            PropertyName,
                            -1,
                            DefaultValue.getValueType(),
                            DefaultValue,
                            beans::PropertyState_DEFAULT_VALUE,
                            Attributes );
 
    auto it1 = m_aDefaultProperties.find( newProperty );
    if( it1 != m_aDefaultProperties.end() )
        throw beans::PropertyExistException( THROW_WHERE );
 
    {
        std::unique_lock aGuard( m_aMutex );
 
        ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first;
 
        // Load the XPersistentPropertySetInfo and create it, if it does not exist
        load( it,true );
 
        PropertySet& properties = it->second.properties;
        it1 = properties.find( newProperty );
        if( it1 != properties.end() )
            throw beans::PropertyExistException(THROW_WHERE );
 
        // Property does not exist
        properties.insert( newProperty );
        it->second.xC->addProperty( PropertyName,Attributes,DefaultValue );
    }
    notifyPropertyAdded( getPropertySetListeners( aUnqPath ), PropertyName );
}
 
 
void
TaskManager::deassociate( const OUString& aUnqPath,
            const OUString& PropertyName )
{
    MyProperty oldProperty( PropertyName );
 
    auto it1 = m_aDefaultProperties.find( oldProperty );
    if( it1 != m_aDefaultProperties.end() )
        throw beans::NotRemoveableException( THROW_WHERE );
 
    std::unique_lock aGuard( m_aMutex );
 
    ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first;
 
    load( it, false );
 
    PropertySet& properties = it->second.properties;
 
    it1 = properties.find( oldProperty );
    if( it1 == properties.end() )
        throw beans::UnknownPropertyException( PropertyName );
 
    properties.erase( it1 );
 
    if( it->second.xC.is() )
        it->second.xC->removeProperty( PropertyName );
 
    if( properties.size() == 9 )
    {
        MyProperty ContentTProperty( ContentType );
 
        if( properties.find( ContentTProperty )->getState() == beans::PropertyState_DEFAULT_VALUE )
        {
            it->second.xS = nullptr;
            it->second.xC = nullptr;
            it->second.xA = nullptr;
            if(m_xFileRegistry.is())
                m_xFileRegistry->removePropertySet( aUnqPath );
        }
    }
    aGuard.unlock();
    notifyPropertyRemoved( getPropertySetListeners( aUnqPath ), PropertyName );
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     page-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  Given an xOutputStream, this method writes the content of the file belonging to
//  URL aUnqPath into the XOutputStream
 
 
void TaskManager::page( sal_Int32 CommandId,
                           const OUString& aUnqPath,
                           const uno::Reference< io::XOutputStream >& xOutputStream )
{
    osl::File aFile( aUnqPath );
    osl::FileBase::RC err = aFile.open( osl_File_OpenFlag_Read );
 
    if( err != osl::FileBase::E_None )
    {
        aFile.close();
        installError( CommandId,
                      TaskHandlerErr::OPEN_FILE_FOR_PAGING,
                      err );
        return;
    }
 
    const sal_uInt64 bfz = 4*1024;
    sal_Int8 BFF[bfz];
    sal_uInt64 nrc;  // Retrieved number of Bytes;
 
    do
    {
        err = aFile.read( static_cast<void*>(BFF),bfz,nrc );
        if(  err == osl::FileBase::E_None )
        {
            uno::Sequence< sal_Int8 > seq( BFF, static_cast<sal_uInt32>(nrc) );
            try
            {
                xOutputStream->writeBytes( seq );
            }
            catch (const io::NotConnectedException&)
            {
                installError( CommandId,
                              TaskHandlerErr::NOTCONNECTED_FOR_PAGING );
                break;
            }
            catch (const io::BufferSizeExceededException&)
            {
                installError( CommandId,
                              TaskHandlerErr::BUFFERSIZEEXCEEDED_FOR_PAGING );
                break;
            }
            catch (const io::IOException&)
            {
                installError( CommandId,
                              TaskHandlerErr::IOEXCEPTION_FOR_PAGING );
                break;
            }
        }
        else
        {
            installError( CommandId,
                          TaskHandlerErr::READING_FILE_FOR_PAGING,
                          err );
            break;
        }
    } while( nrc == bfz );
 
 
    aFile.close();
 
 
    try
    {
        xOutputStream->closeOutput();
    }
    catch (const io::NotConnectedException&)
    {
    }
    catch (const io::BufferSizeExceededException&)
    {
    }
    catch (const io::IOException&)
    {
    }
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     open-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  Given a file URL aUnqPath, this methods returns a XInputStream which reads from the open file.
 
 
uno::Reference< io::XInputStream >
TaskManager::open( sal_Int32 CommandId,
             const OUString& aUnqPath,
             bool bLock )
{
    rtl::Reference<XInputStream_impl> pInputStream(new XInputStream_impl( aUnqPath, bLock )); // from filinpstr.hxx
 
    TaskHandlerErr ErrorCode = pInputStream->CtorSuccess();
 
    if( ErrorCode != TaskHandlerErr::NO_ERROR )
    {
        installError( CommandId,
                      ErrorCode,
                      pInputStream->getMinorError() );
 
        pInputStream.clear();
    }
 
    return pInputStream;
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     open for read/write access-Implementation                 */
/*                                                                               */
/*********************************************************************************/
 
//  Given a file URL aUnqPath, this methods returns a XStream which can be used
//  to read and write from/to the file.
 
 
uno::Reference< io::XStream >
TaskManager::open_rw( sal_Int32 CommandId,
                const OUString& aUnqPath,
                bool bLock )
{
    rtl::Reference<XStream_impl> pStream(new XStream_impl( aUnqPath, bLock ));  // from filstr.hxx
 
    TaskHandlerErr ErrorCode = pStream->CtorSuccess();
 
    if( ErrorCode != TaskHandlerErr::NO_ERROR )
    {
        installError( CommandId,
                      ErrorCode,
                      pStream->getMinorError() );
 
        pStream.clear();
    }
    return pStream;
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                       ls-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  This method returns the result set containing the children of the directory belonging
//  to file URL aUnqPath
 
 
uno::Reference< XDynamicResultSet >
TaskManager::ls( sal_Int32 CommandId,
           const OUString& aUnqPath,
           const sal_Int32 OpenMode,
           const uno::Sequence< beans::Property >& seq,
           const uno::Sequence< NumberedSortingInfo >& seqSort )
{
    rtl::Reference<XResultSet_impl> p(new XResultSet_impl( this,aUnqPath,OpenMode,seq,seqSort ));
 
    TaskHandlerErr ErrorCode = p->CtorSuccess();
 
    if( ErrorCode != TaskHandlerErr::NO_ERROR )
    {
        installError( CommandId,
                      ErrorCode,
                      p->getMinorError() );
 
        p.clear();
    }
 
    return p;
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                          info_c implementation                                */
/*                                                                               */
/*********************************************************************************/
// Info for commands
 
uno::Reference< XCommandInfo >
TaskManager::info_c()
{
    return new XCommandInfo_impl( this );
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     info_p-Implementation                                     */
/*                                                                               */
/*********************************************************************************/
// Info for the properties
 
uno::Reference< beans::XPropertySetInfo >
TaskManager::info_p( const OUString& aUnqPath )
{
    std::unique_lock aGuard( m_aMutex );
    return new XPropertySetInfo_impl( this,aUnqPath );
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     setv-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  Sets the values of the properties belonging to fileURL aUnqPath
 
 
uno::Sequence< uno::Any >
TaskManager::setv( const OUString& aUnqPath,
             const uno::Sequence< beans::PropertyValue >& values )
{
    std::unique_lock aGuard( m_aMutex );
 
    sal_Int32 propChanged = 0;
    uno::Sequence< uno::Any > ret( values.getLength() );
    auto retRange = asNonConstRange(ret);
    uno::Sequence< beans::PropertyChangeEvent > seqChanged( values.getLength() );
    auto seqChangedRange = asNonConstRange(seqChanged);
 
    TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
    PropertySet& properties = it->second.properties;
    TaskManager::PropertySet::const_iterator it1;
    uno::Any aAny;
 
    for( sal_Int32 i = 0; i < values.getLength(); ++i )
    {
        MyProperty toset( values[i].Name );
        it1 = properties.find( toset );
        if( it1 == properties.end() )
        {
            retRange[i] <<= beans::UnknownPropertyException( THROW_WHERE );
            continue;
        }
 
        aAny = it1->getValue();
        if( aAny == values[i].Value )
            continue;  // nothing needs to be changed
 
        if( it1->getAttributes() & beans::PropertyAttribute::READONLY )
        {
            retRange[i] <<= lang::IllegalAccessException( THROW_WHERE );
            continue;
        }
 
        seqChangedRange[ propChanged   ].PropertyName = values[i].Name;
        seqChangedRange[ propChanged   ].PropertyHandle   = -1;
        seqChangedRange[ propChanged   ].Further   = false;
        seqChangedRange[ propChanged   ].OldValue = aAny;
        seqChangedRange[ propChanged++ ].NewValue = values[i].Value;
 
        it1->setValue( values[i].Value );  // Put the new value into the local cash
 
        if( ! it1->IsNative() )
        {
            // Also put logical properties into storage
            if( !it->second.xS.is() )
                load( it, true );
 
            if( ( values[i].Name == ContentType ) &&
                it1->getState() == beans::PropertyState_DEFAULT_VALUE )
            {   // Special logic for ContentType
                //  09.07.01: Not reached anymore, because ContentType is readonly
                it1->setState( beans::PropertyState_DIRECT_VALUE );
                it->second.xC->addProperty( values[i].Name,
                                            beans::PropertyAttribute::MAYBEVOID,
                                            values[i].Value );
            }
 
            try
            {
                it->second.xS->setPropertyValue( values[i].Name,values[i].Value );
            }
            catch (const uno::Exception&e)
            {
                --propChanged; // unsuccessful setting
                retRange[i] <<= e;
            }
        }
        else
        {
            // native properties
            // Setting of physical file properties
            if( values[i].Name == Size )
            {
                sal_Int64 newSize = 0;
                if( values[i].Value >>= newSize )
                {   // valid value for the size
                    osl::File aFile(aUnqPath);
                    bool err =
                        aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None ||
                        aFile.setSize(sal_uInt64(newSize)) != osl::FileBase::E_None ||
                        aFile.close() != osl::FileBase::E_None;
 
                    if( err )
                    {
                        --propChanged; // unsuccessful setting
                        uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence(
                        {
                            {"Uri", uno::Any(aUnqPath)}
                        }));
                        retRange[i] <<= InteractiveAugmentedIOException(
                            OUString(),
                            nullptr,
                            task::InteractionClassification_ERROR,
                            IOErrorCode_GENERAL,
                            names );
                    }
                }
                else
                    retRange[i] <<= beans::IllegalTypeException( THROW_WHERE );
            }
            else if(values[i].Name == IsReadOnly ||
                    values[i].Name == IsHidden)
            {
                bool value = false;
                if( values[i].Value >>= value )
                {
                    osl::DirectoryItem aDirItem;
                    osl::FileBase::RC err =
                        osl::DirectoryItem::get(aUnqPath,aDirItem);
                    sal_uInt64 nAttributes(0);
                    if(err == osl::FileBase::E_None)
                    {
                        osl::FileStatus aFileStatus(osl_FileStatus_Mask_Attributes);
                        err = aDirItem.getFileStatus(aFileStatus);
                        if(err == osl::FileBase::E_None &&
                           aFileStatus.isValid(osl_FileStatus_Mask_Attributes))
                            nAttributes = aFileStatus.getAttributes();
                    }
                    // now we have the attributes provided all went well.
                    if(err == osl::FileBase::E_None) {
                        if(values[i].Name == IsReadOnly)
                        {
                            nAttributes &= ~(osl_File_Attribute_OwnWrite |
                                             osl_File_Attribute_GrpWrite |
                                             osl_File_Attribute_OthWrite |
                                             osl_File_Attribute_ReadOnly);
                            if(value)
                                nAttributes |= osl_File_Attribute_ReadOnly;
                            else
                                nAttributes |= (
                                    osl_File_Attribute_OwnWrite |
                                    osl_File_Attribute_GrpWrite |
                                    osl_File_Attribute_OthWrite);
                        }
                        else if(values[i].Name == IsHidden)
                        {
                            nAttributes &= ~(osl_File_Attribute_Hidden);
                            if(value)
                                nAttributes |= osl_File_Attribute_Hidden;
                        }
                        err = osl::File::setAttributes(
                            aUnqPath,nAttributes);
                    }
 
                    if( err != osl::FileBase::E_None )
                    {
                        --propChanged; // unsuccessful setting
                        uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence(
                        {
                            {"Uri", uno::Any(aUnqPath)}
                        }));
                        IOErrorCode ioError;
                        switch( err )
                        {
                        case osl::FileBase::E_NOMEM:
                            // not enough memory for allocating structures <br>
                            ioError = IOErrorCode_OUT_OF_MEMORY;
                            break;
                        case osl::FileBase::E_INVAL:
                            // the format of the parameters was not valid<p>
                            ioError = IOErrorCode_INVALID_PARAMETER;
                            break;
                        case osl::FileBase::E_NAMETOOLONG:
                            // File name too long<br>
                            ioError = IOErrorCode_NAME_TOO_LONG;
                            break;
                        case osl::FileBase::E_NOENT:
                            // No such file or directory<br>
                        case osl::FileBase::E_NOLINK:
                            // Link has been severed<br>
                            ioError = IOErrorCode_NOT_EXISTING;
                            break;
                        case osl::FileBase::E_ROFS:
                            // #i4735# handle ROFS transparently
                            // as ACCESS_DENIED
                        case  osl::FileBase::E_PERM:
                        case osl::FileBase::E_ACCES:
                            // permission denied<br>
                            ioError = IOErrorCode_ACCESS_DENIED;
                            break;
                        case osl::FileBase::E_LOOP:
                            // Too many symbolic links encountered<br>
                        case osl::FileBase::E_FAULT:
                            // Bad address<br>
                        case osl::FileBase::E_IO:
                            // I/O error<br>
                        case osl::FileBase::E_NOSYS:
                            // Function not implemented<br>
                        case osl::FileBase::E_MULTIHOP:
                            // Multihop attempted<br>
                        case osl::FileBase::E_INTR:
                            // function call was interrupted<p>
                        default:
                            ioError = IOErrorCode_GENERAL;
                            break;
                        }
                        retRange[i] <<= InteractiveAugmentedIOException(
                            OUString(),
                            nullptr,
                            task::InteractionClassification_ERROR,
                            ioError,
                            names );
                    }
                }
                else
                    retRange[i] <<= beans::IllegalTypeException( THROW_WHERE );
            }
        }
    }   // end for
 
    aGuard.unlock();
    if( propChanged )
    {
        seqChanged.realloc( propChanged );
        notifyPropertyChanges( getPropertyChangeNotifier( aUnqPath ), seqChanged );
    }
 
    return ret;
}
 
/*********************************************************************************/
/*                                                                               */
/*                     getv-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  Reads the values of the properties belonging to fileURL aUnqPath;
//  Returns an XRow object containing the values in the requested order.
 
 
uno::Reference< sdbc::XRow >
TaskManager::getv( sal_Int32 CommandId,
             const OUString& aUnqPath,
             const uno::Sequence< beans::Property >& properties )
{
    uno::Sequence< uno::Any > seq( properties.getLength() );
 
    sal_Int32 n_Mask;
    getMaskFromProperties( n_Mask,properties );
    osl::FileStatus aFileStatus( n_Mask );
 
    osl::DirectoryItem aDirItem;
    osl::FileBase::RC nError1 = osl::DirectoryItem::get( aUnqPath,aDirItem );
    if( nError1 != osl::FileBase::E_None )
        installError(CommandId,
                     TaskHandlerErr::OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED
                     nError1);
 
    osl::FileBase::RC nError2 = aDirItem.getFileStatus( aFileStatus );
    if( nError1 == osl::FileBase::E_None &&
        nError2 != osl::FileBase::E_None )
        installError(CommandId,
                     TaskHandlerErr::OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED
                     nError2);
 
    {
        std::unique_lock aGuard( m_aMutex );
 
        TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
        commit( aGuard, it, aFileStatus );
 
        PropertySet& propset = it->second.properties;
 
        std::transform(properties.begin(), properties.end(), seq.getArray(),
            [&propset](const beans::Property& rProp) -> uno::Any {
                MyProperty readProp( rProp.Name );
                auto it1 = propset.find( readProp );
                if( it1 == propset.end() )
                    return uno::Any();
                return it1->getValue();
            });
    }
 
    return new XRow_impl( this,seq );
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         transfer-commandos                                   */
/*                                                                              */
/********************************************************************************/
 
 
/********************************************************************************/
/*                                                                              */
/*                         move-implementation                                  */
/*                                                                              */
/********************************************************************************/
 
//  Moves the content belonging to fileURL srcUnqPath to fileURL dstUnqPath.
 
 
void
TaskManager::move( sal_Int32 CommandId,
             const OUString& srcUnqPath,
             const OUString& dstUnqPathIn,
             const sal_Int32 NameClash )
{
    // --> #i88446# Method notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) ); crashes if
    // srcUnqPath and dstUnqPathIn are equal
    if( srcUnqPath == dstUnqPathIn )
        return;
 
    osl::FileBase::RC nError;
    OUString dstUnqPath( dstUnqPathIn );
 
    switch( NameClash )
    {
    case NameClash::KEEP:
        {
            nError = osl_File_move( srcUnqPath,dstUnqPath,true );
            if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::KEEPERROR_FOR_MOVE,
                              nError );
                return;
            }
            break;
        }
    case NameClash::OVERWRITE:
        {
            // stat to determine whether we have a symlink
            OUString targetPath(dstUnqPath);
 
            osl::FileStatus aStatus(osl_FileStatus_Mask_Type|osl_FileStatus_Mask_LinkTargetURL);
            osl::DirectoryItem aItem;
            (void)osl::DirectoryItem::get(dstUnqPath,aItem);
            (void)aItem.getFileStatus(aStatus);
 
            if( aStatus.isValid(osl_FileStatus_Mask_Type)          &&
                aStatus.isValid(osl_FileStatus_Mask_LinkTargetURL) &&
                aStatus.getFileType() == osl::FileStatus::Link )
                targetPath = aStatus.getLinkTargetURL();
 
            // Will do nothing if file does not exist.
            osl::File::remove( targetPath );
 
            nError = osl_File_move( srcUnqPath,targetPath );
            if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::OVERWRITE_FOR_MOVE,
                              nError );
                return;
            }
            break;
        }
    case NameClash::RENAME:
        {
            OUString newDstUnqPath;
            nError = osl_File_move( srcUnqPath,dstUnqPath,true );
            if( nError == osl::FileBase::E_EXIST )
            {
                // "invent" a new valid title.
 
                sal_Int32 nPos = -1;
                sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' );
                sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' );
                if( ( nLastSlash < nLastDot )                  // dot is part of last(!) path segment
                    && ( nLastSlash != ( nLastDot - 1 ) ) )    // file name does not start with a dot
                    nPos = nLastDot;
                else
                    nPos = dstUnqPath.getLength();
 
                sal_Int32 nTry = 0;
 
                do
                {
                    newDstUnqPath = dstUnqPath;
 
                    OUString aPostfix =  "_" + OUString::number( ++nTry );
 
                    newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix );
 
                    nError = osl_File_move( srcUnqPath,newDstUnqPath,true );
                }
                while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) );
            }
 
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::RENAME_FOR_MOVE );
                return;
            }
            else if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::RENAMEMOVE_FOR_MOVE,
                              nError );
                return;
            }
            else
                dstUnqPath = newDstUnqPath;
 
            break;
        }
    case NameClash::ERROR:
        {
            nError = osl_File_move( srcUnqPath,dstUnqPath,true );
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASH_FOR_MOVE );
                return;
            }
            else if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASHMOVE_FOR_MOVE,
                              nError );
                return;
            }
            break;
        }
        case NameClash::ASK:
        default:
        {
            nError = osl_File_move( srcUnqPath,dstUnqPath,true );
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASHSUPPORT_FOR_MOVE,
                              NameClash::ASK);
                return;
            }
        }
        break;
    }
 
    // Determine, whether we have moved a file or a folder
    osl::DirectoryItem aItem;
    nError = osl::DirectoryItem::get( dstUnqPath,aItem );
    if( nError != osl::FileBase::E_None )
    {
        installError( CommandId,
                      TaskHandlerErr::TRANSFER_BY_MOVE_SOURCE,
                      nError );
        return;
    }
    osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
    nError = aItem.getFileStatus( aStatus );
    if( nError != osl::FileBase::E_None || ! aStatus.isValid( osl_FileStatus_Mask_Type ) )
    {
        installError( CommandId,
                      TaskHandlerErr::TRANSFER_BY_MOVE_SOURCESTAT,
                      nError );
        return;
    }
    bool isDocument = ( aStatus.getFileType() == osl::FileStatus::Regular );
 
 
    copyPersistentSet( srcUnqPath,dstUnqPath,!isDocument );
 
    OUString aDstParent = getParentName( dstUnqPath );
    OUString aSrcParent = getParentName( srcUnqPath );
 
    notifyInsert( getContentEventListeners( aDstParent ),dstUnqPath );
    if(  aDstParent != aSrcParent )
        notifyContentRemoved( getContentEventListeners( aSrcParent ),srcUnqPath );
 
    notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) );
    erasePersistentSet( srcUnqPath,!isDocument );
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         copy-implementation                                  */
/*                                                                              */
/********************************************************************************/
 
//  Copies the content belonging to fileURL srcUnqPath to fileURL dstUnqPath ( files and directories )
 
 
namespace {
 
bool getType(
    TaskManager & task, sal_Int32 id, OUString const & fileUrl,
    osl::DirectoryItem * item, osl::FileStatus::Type * type)
{
    assert(item != nullptr && type != nullptr);
    osl::FileBase::RC err = osl::DirectoryItem::get(fileUrl, *item);
    if (err != osl::FileBase::E_None) {
        task.installError(id, TaskHandlerErr::TRANSFER_BY_COPY_SOURCE, err);
        return false;
    }
    osl::FileStatus stat(osl_FileStatus_Mask_Type);
    err = item->getFileStatus(stat);
    if (err != osl::FileBase::E_None) {
        task.installError(id, TaskHandlerErr::TRANSFER_BY_COPY_SOURCESTAT, err);
        return false;
    }
    *type = stat.getFileType();
    return true;
}
 
}
 
void
TaskManager::copy(
    sal_Int32 CommandId,
    const OUString& srcUnqPath,
    const OUString& dstUnqPathIn,
    sal_Int32 NameClash )
{
    osl::FileBase::RC nError;
    OUString dstUnqPath( dstUnqPathIn );
 
    // Resolve symbolic links within the source path.  If srcUnqPath denotes a
    // symbolic link (targeting either a file or a folder), the contents of the
    // target is copied (recursively, in the case of a folder).  However, if
    // recursively copying the contents of a folder causes a symbolic link to be
    // copied, the symbolic link itself is copied.
    osl::DirectoryItem item;
    osl::FileStatus::Type type;
    if (!getType(*this, CommandId, srcUnqPath, &item, &type)) {
        return;
    }
    OUString rslvdSrcUnqPath;
    if (type == osl::FileStatus::Link) {
        osl::FileStatus stat(osl_FileStatus_Mask_LinkTargetURL);
        nError = item.getFileStatus(stat);
        if (nError != osl::FileBase::E_None) {
            installError(
                CommandId, TaskHandlerErr::TRANSFER_BY_COPY_SOURCESTAT, nError);
            return;
        }
        rslvdSrcUnqPath = stat.getLinkTargetURL();
        if (!getType(*this, CommandId, srcUnqPath, &item, &type)) {
            return;
        }
    } else {
        rslvdSrcUnqPath = srcUnqPath;
    }
 
    bool isDocument
        = type != osl::FileStatus::Directory && type != osl::FileStatus::Volume;
    FileUrlType IsWhat = isDocument ? FileUrlType::File : FileUrlType::Folder;
 
    switch( NameClash )
    {
        case NameClash::KEEP:
        {
            nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
            if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::KEEPERROR_FOR_COPY,
                              nError );
                return;
            }
            break;
        }
        case NameClash::OVERWRITE:
        {
            // remove (..., MustExist = sal_False).
            remove( CommandId, dstUnqPath, IsWhat, false );
 
            // copy.
            nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,false );
            if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::OVERWRITE_FOR_COPY,
                              nError );
                return;
            }
            break;
        }
        case NameClash::RENAME:
        {
            OUString newDstUnqPath = dstUnqPath;
            nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
 
            if( nError == osl::FileBase::E_EXIST )
            {
                // "invent" a new valid title.
 
                sal_Int32 nPos = -1;
                sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' );
                sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' );
                if ( ( nLastSlash < nLastDot ) // dot is part of last(!) path segment
                     && ( nLastSlash != ( nLastDot - 1 ) ) ) // file name does not start with a dot
                    nPos = nLastDot;
                else
                    nPos = dstUnqPath.getLength();
 
                sal_Int32 nTry = 0;
 
                do
                {
                    newDstUnqPath = dstUnqPath;
 
                    OUString aPostfix =  "_" + OUString::number( ++nTry );
 
                    newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix );
 
                    nError = copy_recursive( rslvdSrcUnqPath,newDstUnqPath,IsWhat,true );
                }
                while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) );
            }
 
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::RENAME_FOR_COPY );
                return;
            }
            else if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::RENAMEMOVE_FOR_COPY,
                              nError );
                return;
            }
            else
                dstUnqPath = newDstUnqPath;
 
            break;
        }
        case NameClash::ERROR:
        {
            nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
 
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASH_FOR_COPY );
                return;
            }
            else if( nError != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASHMOVE_FOR_COPY,
                              nError );
                return;
            }
            break;
        }
        case NameClash::ASK:
        default:
        {
            nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
 
            if( nError == osl::FileBase::E_EXIST )
            {
                installError( CommandId,
                              TaskHandlerErr::NAMECLASHSUPPORT_FOR_COPY,
                              NameClash);
                return;
            }
            break;
        }
    }
 
    copyPersistentSet( srcUnqPath,dstUnqPath, !isDocument );
    notifyInsert( getContentEventListeners( getParentName( dstUnqPath ) ),dstUnqPath );
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         remove-implementation                                */
/*                                                                              */
/********************************************************************************/
 
//  Deletes the content belonging to fileURL aUnqPath( recursively in case of directory )
//  Return: success of operation
 
 
bool
TaskManager::remove( sal_Int32 CommandId,
               const OUString& aUnqPath,
               FileUrlType IsWhat,
               bool  MustExist )
{
    sal_Int32 nMask = osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL;
 
    osl::DirectoryItem aItem;
    osl::FileStatus aStatus( nMask );
    osl::FileBase::RC nError;
 
    if( IsWhat == FileUrlType::Unknown ) // Determine whether we are removing a directory or a file
    {
        nError = osl::DirectoryItem::get( aUnqPath, aItem );
        if( nError != osl::FileBase::E_None )
        {
            if (MustExist)
            {
                installError( CommandId,
                              TaskHandlerErr::NOSUCHFILEORDIR_FOR_REMOVE,
                              nError );
            }
            return (!MustExist);
        }
 
        nError = aItem.getFileStatus( aStatus );
        if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) )
        {
            installError( CommandId,
                          TaskHandlerErr::VALIDFILESTATUS_FOR_REMOVE,
                          nError != osl::FileBase::E_None ? nError : 0 );
            return false;
        }
 
        if( aStatus.getFileType() == osl::FileStatus::Regular ||
            aStatus.getFileType() == osl::FileStatus::Link )
            IsWhat = FileUrlType::File;
        else if(  aStatus.getFileType() == osl::FileStatus::Directory ||
                  aStatus.getFileType() == osl::FileStatus::Volume )
            IsWhat = FileUrlType::Folder;
    }
 
 
    if( IsWhat == FileUrlType::File )
    {
        nError = osl::File::remove( aUnqPath );
        if( nError != osl::FileBase::E_None )
        {
            if (MustExist)
            {
                installError( CommandId,
                              TaskHandlerErr::DELETEFILE_FOR_REMOVE,
                              nError );
            }
            return (!MustExist);
        }
        else
        {
            notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) );
            erasePersistentSet( aUnqPath ); // Removes from XPersistentPropertySet
        }
    }
    else if( IsWhat == FileUrlType::Folder )
    {
        osl::Directory aDirectory( aUnqPath );
 
        nError = aDirectory.open();
        if( nError != osl::FileBase::E_None )
        {
            if (MustExist)
            {
                installError( CommandId,
                              TaskHandlerErr::OPENDIRECTORY_FOR_REMOVE,
                              nError );
            }
            return (!MustExist);
        }
 
        bool whileSuccess = true;
        FileUrlType recurse = FileUrlType::Unknown;
        OUString name;
 
        nError = aDirectory.getNextItem( aItem );
        while( nError == osl::FileBase::E_None )
        {
            nError = aItem.getFileStatus( aStatus );
            if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) )
            {
                installError( CommandId,
                              TaskHandlerErr::VALIDFILESTATUSWHILE_FOR_REMOVE,
                              nError != osl::FileBase::E_None ? nError : 0 );
                whileSuccess = false;
                break;
            }
 
            if( aStatus.getFileType() == osl::FileStatus::Regular ||
                aStatus.getFileType() == osl::FileStatus::Link )
                recurse = FileUrlType::File;
            else if( aStatus.getFileType() == osl::FileStatus::Directory ||
                     aStatus.getFileType() == osl::FileStatus::Volume )
                recurse = FileUrlType::Folder;
 
            name = aStatus.getFileURL();
            whileSuccess = remove( CommandId, name, recurse, MustExist );
            if( !whileSuccess )
                break;
 
            nError = aDirectory.getNextItem( aItem );
        }
 
        aDirectory.close();
 
        if( ! whileSuccess )
            return false;     // error code is installed
 
        if( nError != osl::FileBase::E_NOENT )
        {
            installError( CommandId,
                          TaskHandlerErr::DIRECTORYEXHAUSTED_FOR_REMOVE,
                          nError );
            return false;
        }
 
        nError = osl::Directory::remove( aUnqPath );
        if( nError != osl::FileBase::E_None )
        {
            if (MustExist)
            {
                installError( CommandId,
                              TaskHandlerErr::DELETEDIRECTORY_FOR_REMOVE,
                              nError );
            }
            return (!MustExist);
        }
        else
        {
            notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) );
            erasePersistentSet( aUnqPath );
        }
    }
    else   // Don't know what to remove
    {
        installError( CommandId,
                      TaskHandlerErr::FILETYPE_FOR_REMOVE );
        return false;
    }
 
    return true;
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         mkdir-implementation                                 */
/*                                                                              */
/********************************************************************************/
 
//  Creates new directory with given URL, recursively if necessary
//  Return:: success of operation
 
 
bool
TaskManager::mkdir( sal_Int32 CommandId,
              const OUString& rUnqPath,
              bool OverWrite )
{
    OUString aUnqPath;
 
    // remove trailing slash
    if ( rUnqPath.endsWith("/") )
        aUnqPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aUnqPath = rUnqPath;
 
    osl::FileBase::RC nError = osl::Directory::create( aUnqPath );
 
    switch ( nError )
    {
        case osl::FileBase::E_EXIST:   // Directory cannot be overwritten
        {
            if( !OverWrite )
            {
                installError( CommandId,
                              TaskHandlerErr::FOLDER_EXISTS_MKDIR );
                return false;
            }
            else
                return true;
        }
        case osl::FileBase::E_INVAL:
        {
            installError(CommandId,
                         TaskHandlerErr::INVALID_NAME_MKDIR);
            return false;
        }
        case osl::FileBase::E_None:
        {
            OUString aPrtPath = getParentName( aUnqPath );
            notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath );
            return true;
        }
        default:
            return ensuredir(
                CommandId,
                aUnqPath,
                TaskHandlerErr::CREATEDIRECTORY_MKDIR );
    }
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         mkfil-implementation                                 */
/*                                                                              */
/********************************************************************************/
 
//  Creates new file with given URL.
//  The content of aInputStream becomes the content of the file
//  Return:: success of operation
 
 
bool
TaskManager::mkfil( sal_Int32 CommandId,
              const OUString& aUnqPath,
              bool Overwrite,
              const uno::Reference< io::XInputStream >& aInputStream )
{
    // return value unimportant
    bool bSuccess = write( CommandId,
                               aUnqPath,
                               Overwrite,
                               aInputStream );
    if ( bSuccess )
    {
        OUString aPrtPath = getParentName( aUnqPath );
        notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath );
    }
    return bSuccess;
}
 
 
/********************************************************************************/
/*                                                                              */
/*                         write-implementation                                 */
/*                                                                              */
/********************************************************************************/
 
//  writes to the file with given URL.
//  The content of aInputStream becomes the content of the file
//  Return:: success of operation
 
 
bool
TaskManager::write( sal_Int32 CommandId,
              const OUString& aUnqPath,
              bool OverWrite,
              const uno::Reference< io::XInputStream >& aInputStream )
{
    if( ! aInputStream.is() )
    {
        installError( CommandId,
                      TaskHandlerErr::INPUTSTREAM_FOR_WRITE );
        return false;
    }
 
    // Create parent path, if necessary.
    if ( ! ensuredir( CommandId,
                      getParentName( aUnqPath ),
                      TaskHandlerErr::ENSUREDIR_FOR_WRITE ) )
        return false;
 
    osl::FileBase::RC err;
    osl::File aFile( aUnqPath );
 
    if( OverWrite )
    {
        err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
 
        if( err != osl::FileBase::E_None )
        {
            aFile.close();
            err = aFile.open( osl_File_OpenFlag_Write );
 
            if( err != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::NO_OPEN_FILE_FOR_OVERWRITE,
                              err );
                return false;
            }
 
            // the existing file was just opened and should be overwritten now,
            // truncate it first
 
            err = aFile.setSize( 0 );
            if( err != osl::FileBase::E_None  )
            {
                installError( CommandId,
                              TaskHandlerErr::FILESIZE_FOR_WRITE,
                              err );
                return false;
            }
        }
    }
    else
    {
        err = aFile.open( osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock );
        if( err == osl::FileBase::E_None )  // The file exists and shall not be overwritten
        {
            installError( CommandId,
                          TaskHandlerErr::NOREPLACE_FOR_WRITE,  // Now an exception
                          err );
 
            aFile.close();
            return false;
        }
 
        // as a temporary solution the creation does not lock the file at all
        // in future it should be possible to create the file without lock explicitly
        err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
 
        if( err != osl::FileBase::E_None )
        {
            aFile.close();
            installError( CommandId,
                          TaskHandlerErr::NO_OPEN_FILE_FOR_WRITE,
                          err );
            return false;
        }
    }
 
    bool bSuccess = true;
 
    sal_uInt64 nWrittenBytes;
    sal_Int32 nReadBytes = 0, nRequestedBytes = 32768 /*32k*/;
    uno::Sequence< sal_Int8 > seq( nRequestedBytes );
 
    do
    {
        try
        {
            nReadBytes = aInputStream->readBytes( seq,
                                                  nRequestedBytes );
        }
        catch( const io::NotConnectedException& )
        {
            installError( CommandId,
                          TaskHandlerErr::NOTCONNECTED_FOR_WRITE );
            bSuccess = false;
            break;
        }
        catch( const io::BufferSizeExceededException& )
        {
            installError( CommandId,
                          TaskHandlerErr::BUFFERSIZEEXCEEDED_FOR_WRITE );
            bSuccess = false;
            break;
        }
        catch( const io::IOException& )
        {
            installError( CommandId,
                          TaskHandlerErr::IOEXCEPTION_FOR_WRITE );
            bSuccess = false;
            break;
        }
 
        if( nReadBytes )
        {
            const sal_Int8* p = seq.getConstArray();
 
            err = aFile.write( static_cast<void const *>(p),
                               sal_uInt64( nReadBytes ),
                               nWrittenBytes );
 
            if( err != osl::FileBase::E_None )
            {
                installError( CommandId,
                              TaskHandlerErr::FILEIOERROR_FOR_WRITE,
                              err );
                bSuccess = false;
                break;
            }
            else if( nWrittenBytes != sal_uInt64( nReadBytes ) )
            {
                installError( CommandId,
                              TaskHandlerErr::FILEIOERROR_FOR_NO_SPACE );
                bSuccess = false;
                break;
            }
        }
    } while( nReadBytes == nRequestedBytes );
 
    err = aFile.close();
    if( err != osl::FileBase::E_None  )
    {
        installError( CommandId,
                      TaskHandlerErr::FILEIOERROR_FOR_WRITE,
                      err );
        bSuccess = false;
    }
 
    return bSuccess;
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                 insertDefaultProperties-Implementation                        */
/*                                                                               */
/*********************************************************************************/
 
 
void TaskManager::insertDefaultProperties( const OUString& aUnqPath )
{
    std::unique_lock aGuard(m_aMutex);
    insertDefaultProperties(aGuard, aUnqPath);
}
 
void TaskManager::insertDefaultProperties( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& aUnqPath )
{
    ContentMap::iterator it =
        m_aContent.emplace( aUnqPath,UnqPathData() ).first;
 
    load( it, false );
 
    MyProperty ContentTProperty( ContentType );
 
    PropertySet& properties = it->second.properties;
    bool ContentNotDefau = properties.find( ContentTProperty ) != properties.end();
 
    properties.reserve(properties.size() + m_aDefaultProperties.size());
    for (auto const& defaultprop : m_aDefaultProperties)
    {
        if( !ContentNotDefau || defaultprop.getPropertyName() != ContentType )
            properties.insert( defaultprop );
    }
}
 
 
/******************************************************************************/
/*                                                                            */
/*                          mapping of file urls                              */
/*                          to uncpath and vice versa                         */
/*                                                                            */
/******************************************************************************/
 
 
bool TaskManager::getUnqFromUrl( const OUString& Url, OUString& Unq )
{
    if ( Url == "file:///" || Url == "file://localhost/" || Url == "file://127.0.0.1/" )
    {
        Unq = "file:///";
        return false;
    }
 
    bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Url,Unq );
 
    Unq = Url;
 
    sal_Int32 l = Unq.getLength()-1;
    if( ! err && Unq.endsWith("/") &&
        Unq.indexOf( '/', RTL_CONSTASCII_LENGTH("//") ) != -1 )
        Unq = Unq.copy(0, l);
 
    return err;
}
 
 
bool TaskManager::getUrlFromUnq( const OUString& Unq,OUString& Url )
{
    bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Unq,Url );
 
    Url = Unq;
 
    return err;
}
 
 
// Helper function for public copy
 
osl::FileBase::RC
TaskManager::copy_recursive( const OUString& srcUnqPath,
                       const OUString& dstUnqPath,
                       FileUrlType TypeToCopy,
                       bool testExistBeforeCopy )
{
    osl::FileBase::RC err = osl::FileBase::E_None;
 
    if( TypeToCopy == FileUrlType::File ) // Document
    {
        err = osl_File_copy( srcUnqPath,dstUnqPath,testExistBeforeCopy );
    }
    else if( TypeToCopy == FileUrlType::Folder )
    {
        osl::Directory aDir( srcUnqPath );
        (void)aDir.open();
 
        err = osl::Directory::create( dstUnqPath );
        osl::FileBase::RC next = err;
        if( err == osl::FileBase::E_None )
        {
            sal_Int32 const n_Mask = osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Type;
 
            osl::DirectoryItem aDirItem;
 
            while( err == osl::FileBase::E_None )
            {
                next = aDir.getNextItem( aDirItem );
                if (next != osl::FileBase::E_None )
                    break;
                bool IsDoc = false;
                osl::FileStatus aFileStatus( n_Mask );
                aDirItem.getFileStatus( aFileStatus );
                if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) )
                    IsDoc = aFileStatus.getFileType() == osl::FileStatus::Regular;
 
                // Getting the information for the next recursive copy
                FileUrlType newTypeToCopy = IsDoc ? FileUrlType::File : FileUrlType::Folder;
 
                OUString newSrcUnqPath;
                if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) )
                    newSrcUnqPath = aFileStatus.getFileURL();
 
                OUString newDstUnqPath = dstUnqPath;
                OUString tit;
                if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) )
                    tit = rtl::Uri::encode( aFileStatus.getFileName(),
                                          rtl_UriCharClassPchar,
                                          rtl_UriEncodeIgnoreEscapes,
                                          RTL_TEXTENCODING_UTF8 );
 
                if( !newDstUnqPath.endsWith( "/" ) )
                    newDstUnqPath += "/";
 
                newDstUnqPath += tit;
 
                if ( newSrcUnqPath != dstUnqPath )
                    err = copy_recursive( newSrcUnqPath,newDstUnqPath,newTypeToCopy,false );
            }
 
            if( err == osl::FileBase::E_None && next != osl::FileBase::E_NOENT )
                err = next;
        }
        aDir.close();
    }
 
    return err;
}
 
 
// Helper function for mkfil,mkdir and write
// Creates whole path
// returns success of the operation
 
 
bool TaskManager::ensuredir( sal_Int32 CommandId,
                                    const OUString& rUnqPath,
                                    TaskHandlerErr errorCode )
{
    OUString aPath;
 
    if ( rUnqPath.isEmpty() )
        return false;
 
    if ( rUnqPath.endsWith("/") )
        aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aPath = rUnqPath;
 
#if HAVE_FEATURE_MACOSX_SANDBOX
 
    // Avoid annoying sandbox messages in the system.log from the
    // below aDirectory.open(), which ends up calling opendir().
    // Surely it is easier to just call stat()? Calling stat() on an
    // arbitrary (?) directory does not seem to cause any sandbox
    // violation, while opendir() does. (Sorry I could not be bothered
    // to use some complex cross-platform abstraction over stat() here
    // in this macOS specific code block.)
 
    OUString aDirName;
    struct stat s;
    if( osl::FileBase::getSystemPathFromFileURL( aPath, aDirName ) == osl::FileBase::E_None &&
        stat(OUStringToOString( aDirName, RTL_TEXTENCODING_UTF8).getStr(), &s ) == 0 &&
        S_ISDIR( s.st_mode ) )
        return sal_True;
#endif
 
    // HACK: create directory on a mount point with nobrowse option
    // returns ENOSYS in any case !!
    osl::Directory aDirectory( aPath );
    osl::FileBase::RC nError = aDirectory.open();
    aDirectory.close();
 
    if( nError == osl::File::E_None )
        return true;
 
    nError = osl::Directory::create( aPath );
 
    if( nError == osl::File::E_None )
        notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath );
 
    bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
 
    if( ! bSuccess )
    {
        OUString aParentDir = getParentName( aPath );
 
        if ( aParentDir != aPath )
        {   // Create first the parent directory
            bSuccess = ensuredir( CommandId,
                                  getParentName( aPath ),
                                  errorCode );
 
            // After parent directory structure exists try it one's more
 
            if ( bSuccess )
            {   // Parent directory exists, retry creation of directory
                nError = osl::Directory::create( aPath );
 
                if( nError == osl::File::E_None )
                    notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath );
 
                bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
            }
        }
    }
 
    if( ! bSuccess )
        installError( CommandId,
                      errorCode,
                      nError );
 
    return bSuccess;
}
 
 
//  Given a sequence of properties seq, this method determines the mask
//  used to instantiate an osl::FileStatus, so that a call to
//  osl::DirectoryItem::getFileStatus fills the required fields.
 
 
void
TaskManager::getMaskFromProperties(
    sal_Int32& n_Mask,
    const uno::Sequence< beans::Property >& seq )
{
    n_Mask = 0;
    for(const auto& rProp : seq) {
        if(rProp.Name == Title)
            n_Mask |= osl_FileStatus_Mask_FileName;
        else if(rProp.Name == CasePreservingURL)
            n_Mask |= osl_FileStatus_Mask_FileURL;
        else if(rProp.Name == IsDocument ||
                rProp.Name == IsFolder ||
                rProp.Name == IsVolume ||
                rProp.Name == IsRemoveable ||
                rProp.Name == IsRemote ||
                rProp.Name == IsCompactDisc ||
                rProp.Name == IsFloppy ||
                rProp.Name == ContentType)
            n_Mask |= (osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL);
        else if(rProp.Name == Size)
            n_Mask |= (osl_FileStatus_Mask_FileSize |
                      osl_FileStatus_Mask_Type |
                      osl_FileStatus_Mask_LinkTargetURL);
        else if(rProp.Name == IsHidden ||
                rProp.Name == IsReadOnly)
            n_Mask |= osl_FileStatus_Mask_Attributes;
        else if(rProp.Name == DateModified)
            n_Mask |= osl_FileStatus_Mask_ModifyTime;
    }
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     load-Implementation                                       */
/*                                                                               */
/*********************************************************************************/
 
//  Load the properties from configuration, if create == true create them.
//  The Properties are stored under the url belonging to it->first.
 
 
void
TaskManager::load( const ContentMap::iterator& it, bool create )
{
    if(  ( it->second.xS.is() && it->second.xC.is() && it->second.xA.is() )
        || !m_xFileRegistry.is() )
        return;
 
 
    uno::Reference< ucb::XPersistentPropertySet > xS = m_xFileRegistry->openPropertySet( it->first,create );
    if( xS.is() )
    {
        it->second.xS = xS;
        it->second.xC.set(xS, uno::UNO_QUERY);
        it->second.xA.set(xS, uno::UNO_QUERY);
 
        // Now put in all values in the storage in the local hash;
 
        PropertySet& properties = it->second.properties;
        const uno::Sequence< beans::Property > seq = xS->getPropertySetInfo()->getProperties();
 
        for( const auto& rProp : seq )
        {
            MyProperty readProp( false,
                                 rProp.Name,
                                 rProp.Handle,
                                 rProp.Type,
                                 xS->getPropertyValue( rProp.Name ),
                                 beans::PropertyState_DIRECT_VALUE,
                                 rProp.Attributes );
            properties.insert( readProp );
        }
    }
    else if( create )
    {
        // Catastrophic error
    }
}
 
 
/*********************************************************************************/
/*                                                                               */
/*                     commit-Implementation                                     */
/*                                                                               */
/*********************************************************************************/
// Commit inserts the determined properties in the filestatus object into
// the internal map, so that is possible to determine on a subsequent
// setting of file properties which properties have changed without filestat
 
 
void
TaskManager::commit( std::unique_lock<std::mutex>& rGuard,
               const TaskManager::ContentMap::iterator& it,
               const osl::FileStatus& aFileStatus )
{
    TaskManager::PropertySet::const_iterator it1;
 
    if( it->second.properties.empty() )
    {
        OUString aPath = it->first;
        insertDefaultProperties( rGuard, aPath );
    }
 
    PropertySet& properties = it->second.properties;
 
    it1 = properties.find( MyProperty( Title ) );
    if( it1 != properties.end() )
    {
        if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) )
        {
            it1->setValue( uno::Any(aFileStatus.getFileName()) );
        }
    }
 
    it1 = properties.find( MyProperty( CasePreservingURL ) );
    if( it1 != properties.end() )
    {
        if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) )
        {
            it1->setValue( uno::Any(aFileStatus.getFileURL()) );
        }
    }
 
 
    bool isDirectory;
 
    sal_Int64 dirSize = 0;
 
    if( aFileStatus.isValid( osl_FileStatus_Mask_FileSize ) )
        dirSize = aFileStatus.getFileSize();
 
    if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) )
    {
        bool isFile,isVolume;
        if( osl::FileStatus::Link == aFileStatus.getFileType() &&
            aFileStatus.isValid( osl_FileStatus_Mask_LinkTargetURL ) )
        {
            osl::DirectoryItem aDirItem;
            osl::FileStatus aFileStatus2( osl_FileStatus_Mask_Type );
            if( osl::FileBase::E_None == osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(),aDirItem ) &&
                osl::FileBase::E_None == aDirItem.getFileStatus( aFileStatus2 )    &&
                aFileStatus2.isValid( osl_FileStatus_Mask_Type ) )
            {
                isVolume = osl::FileStatus::Volume == aFileStatus2.getFileType();
                isDirectory =
                    osl::FileStatus::Volume == aFileStatus2.getFileType() ||
                    osl::FileStatus::Directory == aFileStatus2.getFileType();
                isFile =
                    osl::FileStatus::Regular == aFileStatus2.getFileType();
 
                if( aFileStatus2.isValid( osl_FileStatus_Mask_FileSize ) )
                    dirSize = aFileStatus2.getFileSize();
            }
            else
            {
                // extremely ugly, but otherwise default construction
                // of aDirItem and aFileStatus2
                // before the preceding if
                isVolume = osl::FileStatus::Volume == aFileStatus.getFileType();
                isDirectory =
                    osl::FileStatus::Volume == aFileStatus.getFileType() ||
                    osl::FileStatus::Directory == aFileStatus.getFileType();
                isFile =
                    osl::FileStatus::Regular == aFileStatus.getFileType();
            }
        }
        else
        {
            isVolume = osl::FileStatus::Volume == aFileStatus.getFileType();
            isDirectory =
                osl::FileStatus::Volume == aFileStatus.getFileType() ||
                osl::FileStatus::Directory == aFileStatus.getFileType();
            isFile =
                osl::FileStatus::Regular == aFileStatus.getFileType();
        }
 
        it1 = properties.find( MyProperty( IsVolume ) );
        if( it1 != properties.end() )
            it1->setValue( uno::Any( isVolume ) );
 
        it1 = properties.find( MyProperty( IsFolder ) );
        if( it1 != properties.end() )
            it1->setValue( uno::Any( isDirectory ) );
 
        it1 = properties.find( MyProperty( IsDocument ) );
        if( it1 != properties.end() )
            it1->setValue( uno::Any( isFile ) );
 
        osl::VolumeInfo aVolumeInfo( osl_VolumeInfo_Mask_Attributes );
        if( isVolume &&
            osl::FileBase::E_None == osl::Directory::getVolumeInfo( it->first,aVolumeInfo ) &&
            aVolumeInfo.isValid( osl_VolumeInfo_Mask_Attributes ) )
        {
            // Retrieve the flags;
            bool isRemote = aVolumeInfo.getRemoteFlag();
            bool isRemoveable = aVolumeInfo.getRemoveableFlag();
            bool isCompactDisc = aVolumeInfo.getCompactDiscFlag();
            bool isFloppy = aVolumeInfo.getFloppyDiskFlag();
 
            it1 = properties.find( MyProperty( IsRemote ) );
            if( it1 != properties.end() )
                it1->setValue( uno::Any( isRemote ) );
 
            it1 = properties.find( MyProperty( IsRemoveable ) );
            if( it1 != properties.end() )
                it1->setValue( uno::Any( isRemoveable ) );
 
            it1 = properties.find( MyProperty( IsCompactDisc ) );
            if( it1 != properties.end() )
                it1->setValue( uno::Any( isCompactDisc ) );
 
            it1 = properties.find( MyProperty( IsFloppy ) );
            if( it1 != properties.end() )
                it1->setValue( uno::Any( isFloppy ) );
        }
        else
        {
            uno::Any aAny(false);
            it1 = properties.find( MyProperty( IsRemote ) );
            if( it1 != properties.end() )
                it1->setValue( aAny );
 
            it1 = properties.find( MyProperty( IsRemoveable ) );
            if( it1 != properties.end() )
                it1->setValue( aAny );
 
            it1 = properties.find( MyProperty( IsCompactDisc ) );
            if( it1 != properties.end() )
                it1->setValue( aAny );
 
            it1 = properties.find( MyProperty( IsFloppy ) );
            if( it1 != properties.end() )
                it1->setValue( aAny );
        }
    }
    else
    {
        isDirectory = false;
    }
 
    it1 = properties.find( MyProperty( Size ) );
    if( it1 != properties.end() )
        it1->setValue( uno::Any( dirSize ) );
 
    it1 = properties.find( MyProperty( IsReadOnly ) );
    if( it1 != properties.end() )
    {
        if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
        {
            sal_uInt64 Attr = aFileStatus.getAttributes();
            bool readonly = ( Attr & osl_File_Attribute_ReadOnly ) != 0;
            it1->setValue( uno::Any( readonly ) );
        }
    }
 
    it1 = properties.find( MyProperty( IsHidden ) );
    if( it1 != properties.end() )
    {
        if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
        {
            sal_uInt64 Attr = aFileStatus.getAttributes();
            bool ishidden = ( Attr & osl_File_Attribute_Hidden ) != 0;
            it1->setValue( uno::Any( ishidden ) );
        }
    }
 
    it1 = properties.find( MyProperty( DateModified ) );
    if( it1 != properties.end() )
    {
        if( aFileStatus.isValid( osl_FileStatus_Mask_ModifyTime ) )
        {
            TimeValue temp = aFileStatus.getModifyTime();
 
            // Convert system time to local time (for EA)
            TimeValue myLocalTime;
            if (!osl_getLocalTimeFromSystemTime( &temp, &myLocalTime ))
            {
                SAL_WARN(
                    "ucb.ucp.file",
                    "cannot convert (" << temp.Seconds << ", " << temp.Nanosec
                        << ") to local time");
                myLocalTime = temp;
            }
 
            oslDateTime myDateTime;
            osl_getDateTimeFromTimeValue( &myLocalTime, &myDateTime );
            util::DateTime aDateTime;
 
            aDateTime.NanoSeconds = myDateTime.NanoSeconds;
            aDateTime.Seconds = myDateTime.Seconds;
            aDateTime.Minutes = myDateTime.Minutes;
            aDateTime.Hours = myDateTime.Hours;
            aDateTime.Day = myDateTime.Day;
            aDateTime.Month = myDateTime.Month;
            aDateTime.Year = myDateTime.Year;
            it1->setValue( uno::Any( aDateTime ) );
        }
    }
 
    it1 = properties.find( MyProperty( CreatableContentsInfo ) );
    if( it1 != properties.end() )
        it1->setValue( uno::Any(
            isDirectory || !aFileStatus.isValid( osl_FileStatus_Mask_Type )
                ? queryCreatableContentsInfo()
                : uno::Sequence< ucb::ContentInfo >() ) );
}
 
 
// Special optimized method for getting the properties of a
// directoryitem, which is returned by osl::DirectoryItem::getNextItem()
 
 
bool
TaskManager::getv(
    const uno::Sequence< beans::Property >& properties,
    osl::DirectoryItem& aDirItem,
    OUString& aUnqPath,
    bool& aIsRegular,
    uno::Reference< sdbc::XRow > & row )
{
    uno::Sequence< uno::Any > seq( properties.getLength() );
 
    sal_Int32 n_Mask;
    getMaskFromProperties( n_Mask,properties );
 
    // Always retrieve the type and the target URL because item might be a link
    osl::FileStatus aFileStatus( n_Mask |
                                 osl_FileStatus_Mask_FileURL |
                                 osl_FileStatus_Mask_Type |
                                 osl_FileStatus_Mask_LinkTargetURL );
 
    osl::FileBase::RC aRes = aDirItem.getFileStatus( aFileStatus );
    if ( aRes != osl::FileBase::E_None )
    {
        SAL_WARN(
            "ucb.ucp.file",
            "osl::DirectoryItem::getFileStatus failed with " << +aRes);
        return false;
    }
 
    aUnqPath = aFileStatus.getFileURL();
 
    // If the directory item type is a link retrieve the type of the target
 
    if ( aFileStatus.getFileType() == osl::FileStatus::Link )
    {
        // Assume failure
        aIsRegular = false;
        osl::DirectoryItem aTargetItem;
        (void)osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(), aTargetItem );
        if ( aTargetItem.is() )
        {
            osl::FileStatus aTargetStatus( osl_FileStatus_Mask_Type );
 
            if ( osl::FileBase::E_None == aTargetItem.getFileStatus( aTargetStatus ) )
                aIsRegular =
                    aTargetStatus.getFileType() == osl::FileStatus::Regular;
        }
    }
    else
        aIsRegular = aFileStatus.getFileType() == osl::FileStatus::Regular;
 
    {
        std::unique_lock aGuard( m_aMutex );
 
        insertDefaultProperties( aGuard, aUnqPath );
 
        TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
        commit( aGuard, it, aFileStatus );
 
        PropertySet& propset = it->second.properties;
 
        std::transform(properties.begin(), properties.end(), seq.getArray(),
            [&propset](const beans::Property& rProp) -> uno::Any {
                MyProperty readProp( rProp.Name );
                auto it1 = propset.find( readProp );
                if( it1 == propset.end() )
                    return uno::Any();
                return it1->getValue();
            });
    }
 
    row = new XRow_impl( this,seq );
    return true;
}
 
 
// EventListener
 
 
std::vector< ContentEventNotifier >
TaskManager::getContentEventListeners( const OUString& aName )
{
    std::vector< ContentEventNotifier > listeners;
    {
        std::unique_lock aGuard( m_aMutex );
        TaskManager::ContentMap::iterator it = m_aContent.find( aName );
        if( it != m_aContent.end() && !it->second.notifier.empty() )
        {
            std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
            for (auto const& pointer : listOfNotifiers)
            {
                std::optional<ContentEventNotifier> notifier = pointer->cCEL();
                if( notifier )
                    listeners.push_back( std::move(*notifier) );
            }
        }
    }
    return listeners;
}
 
 
std::vector< ContentEventNotifier >
TaskManager::getContentDeletedEventListeners( const OUString& aName )
{
    std::vector< ContentEventNotifier > listeners;
    {
        std::unique_lock aGuard( m_aMutex );
        TaskManager::ContentMap::iterator it = m_aContent.find( aName );
        if( it != m_aContent.end() && !it->second.notifier.empty() )
        {
            std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
            for (auto const& pointer : listOfNotifiers)
            {
                std::optional<ContentEventNotifier> notifier = pointer->cDEL();
                if( notifier )
                    listeners.push_back( std::move(*notifier) );
            }
        }
    }
    return listeners;
}
 
void TaskManager::notifyInsert(const std::vector<ContentEventNotifier>& listeners,
                               const OUString& aChildName)
{
    for (const auto & l : listeners )
    {
        l.notifyChildInserted( aChildName );
    }
}
 
void TaskManager::notifyContentDeleted(
    const std::vector<ContentEventNotifier>& listeners)
{
    for( auto const & l : listeners )
    {
        l.notifyDeleted();
    }
}
 
void TaskManager::notifyContentRemoved(
    const std::vector<ContentEventNotifier>& listeners, const OUString& aChildName)
{
    for( auto const & l : listeners )
    {
        l.notifyRemoved( aChildName );
    }
}
 
 
std::vector< PropertySetInfoChangeNotifier >
TaskManager::getPropertySetListeners( const OUString& aName )
{
    std::vector< PropertySetInfoChangeNotifier > listeners;
    {
        std::unique_lock aGuard( m_aMutex );
        TaskManager::ContentMap::iterator it = m_aContent.find( aName );
        if( it != m_aContent.end() && !it->second.notifier.empty() )
        {
            std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
            for (auto const& pointer : listOfNotifiers)
            {
                std::optional<PropertySetInfoChangeNotifier> notifier = pointer->cPSL();
                if( notifier )
                    listeners.push_back( std::move(*notifier) );
            }
        }
    }
    return listeners;
}
 
void TaskManager::notifyPropertyAdded(
    const std::vector<PropertySetInfoChangeNotifier>& listeners,
    const OUString& aPropertyName)
{
    for( auto const & l : listeners )
    {
        l.notifyPropertyAdded( aPropertyName );
    }
}
 
void TaskManager::notifyPropertyRemoved(
    const std::vector<PropertySetInfoChangeNotifier>& listeners,
    const OUString& aPropertyName)
{
    for( auto const & l : listeners )
    {
        l.notifyPropertyRemoved( aPropertyName );
    }
}
 
 
std::vector< ContentEventNotifier >
TaskManager::getContentExchangedEventListeners( const OUString& aOldPrefix,
                                          const OUString& aNewPrefix,
                                          bool withChildren )
{
    std::vector< ContentEventNotifier > aVector;
 
    sal_Int32 count;
    OUString aOldName;
    OUString aNewName;
    std::vector< OUString > oldChildList;
 
    {
        std::unique_lock aGuard( m_aMutex );
 
        if( ! withChildren )
        {
            aOldName = aOldPrefix;
            aNewName = aNewPrefix;
            count = 1;
        }
        else
        {
            for (auto const& content : m_aContent)
            {
                if( isChild( aOldPrefix, content.first ) )
                {
                    oldChildList.push_back( content.first );
                }
            }
            count = oldChildList.size();
        }
 
 
        for( sal_Int32 j = 0; j < count; ++j )
        {
            if( withChildren )
            {
                aOldName = oldChildList[j];
                aNewName = newName( aNewPrefix,aOldPrefix,aOldName );
            }
 
            TaskManager::ContentMap::iterator itold = m_aContent.find( aOldName );
            if( itold != m_aContent.end() )
            {
                TaskManager::ContentMap::iterator itnew = m_aContent.emplace(
                    aNewName,UnqPathData() ).first;
 
                // copy Ownership also
                itnew->second.properties = std::move(itold->second.properties);
 
                // copy existing list
                std::vector< Notifier* > copyList;
                std::swap(copyList, itnew->second.notifier);
                itnew->second.notifier = std::move(itold->second.notifier);
 
                m_aContent.erase( itold );
 
                if (itnew != m_aContent.end())
                {
                    if (!itnew->second.notifier.empty())
                    {
                        std::vector<Notifier*>& listOfNotifiers = itnew->second.notifier;
                        for (auto const& pointer : listOfNotifiers)
                        {
                            std::optional<ContentEventNotifier> notifier = pointer->cEXC( aNewName );
                            if( notifier )
                                aVector.push_back( std::move(*notifier) );
                        }
                    }
 
                    // Merge with preexisting notifiers
                    // However, these may be in status BaseContent::Deleted
                    itnew->second.notifier.insert(itnew->second.notifier.end(),
                        copyList.begin(), copyList.end() );
                }
            }
        }
    }
 
    return aVector;
}
 
void TaskManager::notifyContentExchanged(
    const std::vector<ContentEventNotifier>& listeners_vec)
{
    for( auto & l : listeners_vec)
    {
        l.notifyExchanged();
    }
}
 
 
std::vector< PropertyChangeNotifier >
TaskManager::getPropertyChangeNotifier( const OUString& aName )
{
    std::vector< PropertyChangeNotifier > listeners;
    {
        std::unique_lock aGuard( m_aMutex );
        TaskManager::ContentMap::iterator it = m_aContent.find( aName );
        if( it != m_aContent.end() && !it->second.notifier.empty() )
        {
            std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
            for (auto const& pointer : listOfNotifiers)
            {
                std::optional<PropertyChangeNotifier> notifier = pointer->cPCL();
                if( notifier )
                    listeners.push_back( std::move(*notifier) );
            }
        }
    }
    return listeners;
}
 
void TaskManager::notifyPropertyChanges(
    const std::vector<PropertyChangeNotifier>& listeners,
    const uno::Sequence<beans::PropertyChangeEvent>& seqChanged)
{
    for( auto const & l : listeners )
    {
        l.notifyPropertyChanged( seqChanged );
    }
}
 
 
/********************************************************************************/
/*                       remove persistent propertyset                          */
/********************************************************************************/
 
void
TaskManager::erasePersistentSetWithoutChildren( const OUString& aUnqPath )
{
    {
        // Release possible references
        std::unique_lock aGuard( m_aMutex );
        ContentMap::iterator it = m_aContent.find( aUnqPath );
        if( it != m_aContent.end() )
        {
            it->second.xS = nullptr;
            it->second.xC = nullptr;
            it->second.xA = nullptr;
 
            it->second.properties.clear();
        }
    }
 
    m_xFileRegistry->removePropertySet( aUnqPath );
}
 
void
TaskManager::erasePersistentSet( const OUString& aUnqPath,
                           bool withChildren )
{
    if( ! m_xFileRegistry.is() )
    {
        OSL_ASSERT( m_xFileRegistry.is() );
        return;
    }
 
    if( ! withChildren )
    {
        erasePersistentSetWithoutChildren(aUnqPath);
        return;
    }
 
    uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY );
    const uno::Sequence< OUString > seqNames = xName->getElementNames();
 
    OUString old_Name = aUnqPath;
 
    for( const auto& rName : seqNames )
    {
        if( ! ( isChild( old_Name,rName ) ) )
            continue;
 
        old_Name = rName;
 
        erasePersistentSetWithoutChildren(old_Name);
    }
}
 
 
/********************************************************************************/
/*                       copy persistent propertyset                            */
/*                       from srcUnqPath to dstUnqPath                          */
/********************************************************************************/
 
void
TaskManager::copyPersistentSetWithoutChildren( const OUString& srcUnqPath,
                          const OUString& dstUnqPath )
{
    uno::Reference< XPersistentPropertySet > x_src =
            m_xFileRegistry->openPropertySet( srcUnqPath,false );
    m_xFileRegistry->removePropertySet( dstUnqPath );
 
    if( ! x_src.is() )
        return;
 
    const uno::Sequence< beans::Property > seqProperty =
        x_src->getPropertySetInfo()->getProperties();
 
    if( ! seqProperty.hasElements() )
        return;
 
    uno::Reference< XPersistentPropertySet >
        x_dstS = m_xFileRegistry->openPropertySet( dstUnqPath,true );
    uno::Reference< beans::XPropertyContainer >
        x_dstC( x_dstS,uno::UNO_QUERY );
 
    for( const auto& rProperty : seqProperty )
    {
        x_dstC->addProperty( rProperty.Name,
                             rProperty.Attributes,
                             x_src->getPropertyValue( rProperty.Name ) );
    }
}
 
void
TaskManager::copyPersistentSet( const OUString& srcUnqPath,
                          const OUString& dstUnqPath,
                          bool withChildren )
{
    if( ! m_xFileRegistry.is() )
    {
        OSL_ASSERT( m_xFileRegistry.is() );
        return;
    }
 
    if( ! withChildren )
    {
        copyPersistentSetWithoutChildren(srcUnqPath, dstUnqPath);
        return;
    }
 
    uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY );
    const uno::Sequence< OUString > seqNames = xName->getElementNames();
 
    OUString new_Name;
 
    for( const auto& rName : seqNames )
    {
        if( ! ( isChild( srcUnqPath,rName ) ) )
            continue;
 
        new_Name = newName( dstUnqPath,srcUnqPath,rName );
 
        copyPersistentSetWithoutChildren(rName, new_Name);
    }
}
 
uno::Sequence< ucb::ContentInfo > TaskManager::queryCreatableContentsInfo()
{
 
 
    uno::Sequence< beans::Property > props
    {
        { u"Title"_ustr, -1, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND }
    };
    return
    {
        { FileContentType, ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ucb::ContentInfoAttribute::KIND_DOCUMENT, props },
        { FolderContentType, ucb::ContentInfoAttribute::KIND_FOLDER, props }
    };
}
 
/*******************************************************************************/
/*                                                                             */
/*                 some miscellaneous static functions                        */
/*                                                                             */
/*******************************************************************************/
 
void
TaskManager::getScheme( OUString& Scheme )
{
  Scheme = "file";
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V783 Iterator 'itnew' is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 2708, 2717.

V784 The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits.

V784 The size of the bit mask is less than the size of the first operand. This will cause the loss of higher bits.

V547 Expression 'value' is always false.

V547 Expression 'value' is always false.

V1051 Consider checking for misprints. It's possible that the 'rslvdSrcUnqPath' should be used inside 'getType' function.