summaryrefslogtreecommitdiffstats
path: root/ucb/source/ucp/file/filtask.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'ucb/source/ucp/file/filtask.cxx')
-rw-r--r--ucb/source/ucp/file/filtask.cxx2936
1 files changed, 2936 insertions, 0 deletions
diff --git a/ucb/source/ucp/file/filtask.cxx b/ucb/source/ucp/file/filtask.cxx
new file mode 100644
index 0000000000..930f952d00
--- /dev/null
+++ b/ucb/source/ucp/file/filtask.cxx
@@ -0,0 +1,2936 @@
+/* -*- 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 <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 */ "getCommandInfo",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<void>::get() },
+
+ { /* Name */ "getPropertySetInfo",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<void>::get() },
+
+ { /* Name */ "getPropertyValues",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<uno::Sequence< beans::Property >>::get() },
+
+ { /* Name */ "setPropertyValues",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() },
+
+ { /* Name */ "open",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<OpenCommandArgument>::get() },
+
+ { /* Name */ "transfer",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<TransferInfo>::get() },
+
+ { /* Name */ "delete",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<sal_Bool>::get() },
+
+ { /* Name */ "insert",
+ /* Handle */ -1,
+ /* ArgType */ cppu::UnoType<InsertCommandArgument>::get() },
+
+ { /* Name */ "createNewContent",
+ /* 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;
+
+ sal_Int32 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 != TASKHANDLER_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,
+ sal_Int32 &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,
+ sal_Int32 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,
+ TASKHANDLING_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 )
+ {
+ // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
+ uno::Sequence< sal_Int8 > seq( BFF, static_cast<sal_uInt32>(nrc) );
+ try
+ {
+ xOutputStream->writeBytes( seq );
+ }
+ catch (const io::NotConnectedException&)
+ {
+ installError( CommandId,
+ TASKHANDLING_NOTCONNECTED_FOR_PAGING );
+ break;
+ }
+ catch (const io::BufferSizeExceededException&)
+ {
+ installError( CommandId,
+ TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_PAGING );
+ break;
+ }
+ catch (const io::IOException&)
+ {
+ installError( CommandId,
+ TASKHANDLING_IOEXCEPTION_FOR_PAGING );
+ break;
+ }
+ }
+ else
+ {
+ installError( CommandId,
+ TASKHANDLING_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
+
+ sal_Int32 ErrorCode = pInputStream->CtorSuccess();
+
+ if( ErrorCode != TASKHANDLER_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
+
+ sal_Int32 ErrorCode = pStream->CtorSuccess();
+
+ if( ErrorCode != TASKHANDLER_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 ));
+
+ sal_Int32 ErrorCode = p->CtorSuccess();
+
+ if( ErrorCode != TASKHANDLER_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_RENAME_FOR_MOVE );
+ return;
+ }
+ else if( nError != osl::FileBase::E_None )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_NAMECLASH_FOR_MOVE );
+ return;
+ }
+ else if( nError != osl::FileBase::E_None )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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)
+{
+ OSL_ASSERT(item != nullptr && type != nullptr);
+ osl::FileBase::RC err = osl::DirectoryItem::get(fileUrl, *item);
+ if (err != osl::FileBase::E_None) {
+ task.installError(id, TASKHANDLING_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, TASKHANDLING_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, TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_RENAME_FOR_COPY );
+ return;
+ }
+ else if( nError != osl::FileBase::E_None )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_NAMECLASH_FOR_COPY );
+ return;
+ }
+ else if( nError != osl::FileBase::E_None )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_NOSUCHFILEORDIR_FOR_REMOVE,
+ nError );
+ }
+ return (!MustExist);
+ }
+
+ nError = aItem.getFileStatus( aStatus );
+ if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) )
+ {
+ installError( CommandId,
+ TASKHANDLING_VALIDFILESTATUS_FOR_REMOVE,
+ nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR );
+ 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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_VALIDFILESTATUSWHILE_FOR_REMOVE,
+ nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR );
+ 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,
+ TASKHANDLING_DIRECTORYEXHAUSTED_FOR_REMOVE,
+ nError );
+ return false;
+ }
+
+ nError = osl::Directory::remove( aUnqPath );
+ if( nError != osl::FileBase::E_None )
+ {
+ if (MustExist)
+ {
+ installError( CommandId,
+ TASKHANDLING_DELETEDIRECTORY_FOR_REMOVE,
+ nError );
+ }
+ return (!MustExist);
+ }
+ else
+ {
+ notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) );
+ erasePersistentSet( aUnqPath );
+ }
+ }
+ else // Don't know what to remove
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_FOLDER_EXISTS_MKDIR );
+ return false;
+ }
+ else
+ return true;
+ }
+ case osl::FileBase::E_INVAL:
+ {
+ installError(CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_INPUTSTREAM_FOR_WRITE );
+ return false;
+ }
+
+ // Create parent path, if necessary.
+ if ( ! ensuredir( CommandId,
+ getParentName( aUnqPath ),
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_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,
+ TASKHANDLING_NOTCONNECTED_FOR_WRITE );
+ bSuccess = false;
+ break;
+ }
+ catch( const io::BufferSizeExceededException& )
+ {
+ installError( CommandId,
+ TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_WRITE );
+ bSuccess = false;
+ break;
+ }
+ catch( const io::IOException& )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ TASKHANDLING_FILEIOERROR_FOR_WRITE,
+ err );
+ bSuccess = false;
+ break;
+ }
+ else if( nWrittenBytes != sal_uInt64( nReadBytes ) )
+ {
+ installError( CommandId,
+ TASKHANDLING_FILEIOERROR_FOR_NO_SPACE );
+ bSuccess = false;
+ break;
+ }
+ }
+ } while( nReadBytes == nRequestedBytes );
+
+ err = aFile.close();
+ if( err != osl::FileBase::E_None )
+ {
+ installError( CommandId,
+ TASKHANDLING_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,
+ sal_Int32 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
+ {
+ { "Title", -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: */