/* -*- 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 #include #include #if HAVE_FEATURE_MACOSX_SANDBOX #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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::get() }, { /* Name */ "getPropertySetInfo", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() }, { /* Name */ "getPropertyValues", /* Handle */ -1, /* ArgType */ cppu::UnoType>::get() }, { /* Name */ "setPropertyValues", /* Handle */ -1, /* ArgType */ cppu::UnoType>::get() }, { /* Name */ "open", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() }, { /* Name */ "transfer", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() }, { /* Name */ "delete", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() }, { /* Name */ "insert", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() }, { /* Name */ "createNewContent", /* Handle */ -1, /* ArgType */ cppu::UnoType::get() } } { // Title m_aDefaultProperties.insert( MyProperty( true, Title, -1 , cppu::UnoType::get(), uno::Any(), beans::PropertyState_DEFAULT_VALUE, beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND ) ); // CasePreservingURL m_aDefaultProperties.insert( MyProperty( true, CasePreservingURL, -1 , cppu::UnoType::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::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::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::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::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::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::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::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::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::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::get(), uno::Any(), beans::PropertyState_DEFAULT_VALUE, beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND ) ); // Size m_aDefaultProperties.insert( MyProperty( true, Size, -1, cppu::UnoType::get(), uno::Any(), beans::PropertyState_DEFAULT_VALUE, beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND ) ); // IsReadOnly m_aDefaultProperties.insert( MyProperty( true, IsReadOnly, -1 , cppu::UnoType::get(), uno::Any(), beans::PropertyState_DEFAULT_VALUE, beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND ) ); // CreatableContentsInfo m_aDefaultProperties.insert( MyProperty( true, CreatableContentsInfo, -1 , cppu::UnoType>::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::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(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(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 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 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 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 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 names(comphelper::InitAnyPropertySequence( { {"Uri", uno::Any(aUnqPath)} })); IOErrorCode ioError; switch( err ) { case osl::FileBase::E_NOMEM: // not enough memory for allocating structures
ioError = IOErrorCode_OUT_OF_MEMORY; break; case osl::FileBase::E_INVAL: // the format of the parameters was not valid

ioError = IOErrorCode_INVALID_PARAMETER; break; case osl::FileBase::E_NAMETOOLONG: // File name too long
ioError = IOErrorCode_NAME_TOO_LONG; break; case osl::FileBase::E_NOENT: // No such file or directory
case osl::FileBase::E_NOLINK: // Link has been severed
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
ioError = IOErrorCode_ACCESS_DENIED; break; case osl::FileBase::E_LOOP: // Too many symbolic links encountered
case osl::FileBase::E_FAULT: // Bad address
case osl::FileBase::E_IO: // I/O error
case osl::FileBase::E_NOSYS: // Function not implemented
case osl::FileBase::E_MULTIHOP: // Multihop attempted
case osl::FileBase::E_INTR: // function call was interrupted

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(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& /*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& 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& listOfNotifiers = it->second.notifier; for (auto const& pointer : listOfNotifiers) { std::optional 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& listOfNotifiers = it->second.notifier; for (auto const& pointer : listOfNotifiers) { std::optional notifier = pointer->cDEL(); if( notifier ) listeners.push_back( std::move(*notifier) ); } } } return listeners; } void TaskManager::notifyInsert(const std::vector& listeners, const OUString& aChildName) { for (const auto & l : listeners ) { l.notifyChildInserted( aChildName ); } } void TaskManager::notifyContentDeleted( const std::vector& listeners) { for( auto const & l : listeners ) { l.notifyDeleted(); } } void TaskManager::notifyContentRemoved( const std::vector& 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& listOfNotifiers = it->second.notifier; for (auto const& pointer : listOfNotifiers) { std::optional notifier = pointer->cPSL(); if( notifier ) listeners.push_back( std::move(*notifier) ); } } } return listeners; } void TaskManager::notifyPropertyAdded( const std::vector& listeners, const OUString& aPropertyName) { for( auto const & l : listeners ) { l.notifyPropertyAdded( aPropertyName ); } } void TaskManager::notifyPropertyRemoved( const std::vector& 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& listOfNotifiers = itnew->second.notifier; for (auto const& pointer : listOfNotifiers) { std::optional 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& 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& listOfNotifiers = it->second.notifier; for (auto const& pointer : listOfNotifiers) { std::optional notifier = pointer->cPCL(); if( notifier ) listeners.push_back( std::move(*notifier) ); } } } return listeners; } void TaskManager::notifyPropertyChanges( const std::vector& listeners, const uno::Sequence& 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::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: */