Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / ucb / source / ucp / file / filtask.cxx
blob795788ca412564facc3d1e5ef10750a4ceac4c48
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
25 #if HAVE_FEATURE_MACOSX_SANDBOX
26 #include <sys/stat.h>
27 #endif
29 #include <com/sun/star/beans/IllegalTypeException.hpp>
30 #include <com/sun/star/beans/NotRemoveableException.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/PropertyExistException.hpp>
33 #include <com/sun/star/io/BufferSizeExceededException.hpp>
34 #include <com/sun/star/io/NotConnectedException.hpp>
35 #include <com/sun/star/io/IOException.hpp>
36 #include <com/sun/star/lang/IllegalAccessException.hpp>
37 #include <com/sun/star/task/InteractionClassification.hpp>
38 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
39 #include <com/sun/star/ucb/DuplicateCommandIdentifierException.hpp>
40 #include <com/sun/star/ucb/IOErrorCode.hpp>
41 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
42 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
43 #include <com/sun/star/ucb/NameClash.hpp>
44 #include <com/sun/star/ucb/OpenCommandArgument.hpp>
45 #include <com/sun/star/ucb/Store.hpp>
46 #include <com/sun/star/ucb/TransferInfo.hpp>
47 #include <comphelper/propertysequence.hxx>
48 #include <rtl/ref.hxx>
49 #include <rtl/uri.hxx>
51 #include "filtask.hxx"
52 #include "filcmd.hxx"
53 #include "filglob.hxx"
54 #include "filinpstr.hxx"
55 #include "filprp.hxx"
56 #include "filrset.hxx"
57 #include "filstr.hxx"
58 #include "prov.hxx"
60 /******************************************************************************/
61 /* */
62 /* TaskHandling */
63 /* */
64 /******************************************************************************/
67 using namespace fileaccess;
68 using namespace com::sun::star;
69 using namespace com::sun::star::uno;
70 using namespace com::sun::star::ucb;
72 #if OSL_DEBUG_LEVEL > 0
73 #define THROW_WHERE SAL_WHERE
74 #else
75 #define THROW_WHERE ""
76 #endif
78 TaskManager::UnqPathData::UnqPathData() = default;
80 TaskManager::UnqPathData::UnqPathData(TaskManager::UnqPathData&&) = default;
83 TaskManager::UnqPathData::~UnqPathData()
87 TaskManager::MyProperty::MyProperty( const OUString& thePropertyName )
88 : PropertyName( thePropertyName )
89 , Handle(-1)
90 , isNative(false)
91 , State(beans::PropertyState_AMBIGUOUS_VALUE)
92 , Attributes(0)
94 // empty
97 TaskManager::MyProperty::MyProperty( bool theisNative,
98 const OUString& thePropertyName,
99 sal_Int32 theHandle,
100 const css::uno::Type& theTyp,
101 const css::uno::Any& theValue,
102 const css::beans::PropertyState& theState,
103 sal_Int16 theAttributes )
104 : PropertyName( thePropertyName ),
105 Handle( theHandle ),
106 isNative( theisNative ),
107 Typ( theTyp ),
108 Value( theValue ),
109 State( theState ),
110 Attributes( theAttributes )
112 // empty
115 #include "filinl.hxx"
117 // Default properties
119 constexpr OUStringLiteral Title( u"Title" );
120 constexpr OUStringLiteral CasePreservingURL( u"CasePreservingURL" );
121 constexpr OUStringLiteral IsDocument( u"IsDocument" );
122 constexpr OUStringLiteral IsFolder( u"IsFolder" );
123 constexpr OUStringLiteral DateModified( u"DateModified" );
124 constexpr OUStringLiteral Size( u"Size" );
125 constexpr OUStringLiteral IsVolume( u"IsVolume" );
126 constexpr OUStringLiteral IsRemoveable( u"IsRemoveable" );
127 constexpr OUStringLiteral IsRemote( u"IsRemote" );
128 constexpr OUStringLiteral IsCompactDisc( u"IsCompactDisc" );
129 constexpr OUStringLiteral IsFloppy( u"IsFloppy" );
130 constexpr OUStringLiteral IsHidden( u"IsHidden" );
131 constexpr OUStringLiteral ContentType( u"ContentType" );
132 constexpr OUStringLiteral IsReadOnly( u"IsReadOnly" );
133 constexpr OUStringLiteral CreatableContentsInfo( u"CreatableContentsInfo" );
135 TaskManager::TaskManager( const uno::Reference< uno::XComponentContext >& rxContext,
136 FileProvider* pProvider, bool bWithConfig )
137 : m_nCommandId( 0 ),
138 m_pProvider( pProvider ),
139 m_xContext( rxContext ),
140 // Commands
141 m_sCommandInfo{
142 { /* Name */ "getCommandInfo",
143 /* Handle */ -1,
144 /* ArgType */ cppu::UnoType<void>::get() },
146 { /* Name */ "getPropertySetInfo",
147 /* Handle */ -1,
148 /* ArgType */ cppu::UnoType<void>::get() },
150 { /* Name */ "getPropertyValues",
151 /* Handle */ -1,
152 /* ArgType */ cppu::UnoType<uno::Sequence< beans::Property >>::get() },
154 { /* Name */ "setPropertyValues",
155 /* Handle */ -1,
156 /* ArgType */ cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() },
158 { /* Name */ "open",
159 /* Handle */ -1,
160 /* ArgType */ cppu::UnoType<OpenCommandArgument>::get() },
162 { /* Name */ "transfer",
163 /* Handle */ -1,
164 /* ArgType */ cppu::UnoType<TransferInfo>::get() },
166 { /* Name */ "delete",
167 /* Handle */ -1,
168 /* ArgType */ cppu::UnoType<sal_Bool>::get() },
170 { /* Name */ "insert",
171 /* Handle */ -1,
172 /* ArgType */ cppu::UnoType<InsertCommandArgument>::get() },
174 { /* Name */ "createNewContent",
175 /* Handle */ -1,
176 /* ArgType */ cppu::UnoType<ucb::ContentInfo>::get() } }
178 // Title
179 m_aDefaultProperties.insert( MyProperty( true,
180 Title,
181 -1 ,
182 cppu::UnoType<OUString>::get(),
183 uno::Any(),
184 beans::PropertyState_DEFAULT_VALUE,
185 beans::PropertyAttribute::MAYBEVOID
186 | beans::PropertyAttribute::BOUND ) );
188 // CasePreservingURL
189 m_aDefaultProperties.insert(
190 MyProperty( true,
191 CasePreservingURL,
192 -1 ,
193 cppu::UnoType<OUString>::get(),
194 uno::Any(),
195 beans::PropertyState_DEFAULT_VALUE,
196 beans::PropertyAttribute::MAYBEVOID
197 | beans::PropertyAttribute::BOUND
198 | beans::PropertyAttribute::READONLY ) );
201 // IsFolder
202 m_aDefaultProperties.insert( MyProperty( true,
203 IsFolder,
204 -1 ,
205 cppu::UnoType<sal_Bool>::get(),
206 uno::Any(),
207 beans::PropertyState_DEFAULT_VALUE,
208 beans::PropertyAttribute::MAYBEVOID
209 | beans::PropertyAttribute::BOUND
210 | beans::PropertyAttribute::READONLY ) );
213 // IsDocument
214 m_aDefaultProperties.insert( MyProperty( true,
215 IsDocument,
216 -1 ,
217 cppu::UnoType<sal_Bool>::get(),
218 uno::Any(),
219 beans::PropertyState_DEFAULT_VALUE,
220 beans::PropertyAttribute::MAYBEVOID
221 | beans::PropertyAttribute::BOUND
222 | beans::PropertyAttribute::READONLY ) );
224 // Removable
225 m_aDefaultProperties.insert( MyProperty( true,
226 IsVolume,
227 -1 ,
228 cppu::UnoType<sal_Bool>::get(),
229 uno::Any(),
230 beans::PropertyState_DEFAULT_VALUE,
231 beans::PropertyAttribute::MAYBEVOID
232 | beans::PropertyAttribute::BOUND
233 | beans::PropertyAttribute::READONLY ) );
236 // Removable
237 m_aDefaultProperties.insert( MyProperty( true,
238 IsRemoveable,
239 -1 ,
240 cppu::UnoType<sal_Bool>::get(),
241 uno::Any(),
242 beans::PropertyState_DEFAULT_VALUE,
243 beans::PropertyAttribute::MAYBEVOID
244 | beans::PropertyAttribute::BOUND
245 | beans::PropertyAttribute::READONLY ) );
247 // Remote
248 m_aDefaultProperties.insert( MyProperty( true,
249 IsRemote,
250 -1 ,
251 cppu::UnoType<sal_Bool>::get(),
252 uno::Any(),
253 beans::PropertyState_DEFAULT_VALUE,
254 beans::PropertyAttribute::MAYBEVOID
255 | beans::PropertyAttribute::BOUND
256 | beans::PropertyAttribute::READONLY ) );
258 // CompactDisc
259 m_aDefaultProperties.insert( MyProperty( true,
260 IsCompactDisc,
261 -1 ,
262 cppu::UnoType<sal_Bool>::get(),
263 uno::Any(),
264 beans::PropertyState_DEFAULT_VALUE,
265 beans::PropertyAttribute::MAYBEVOID
266 | beans::PropertyAttribute::BOUND
267 | beans::PropertyAttribute::READONLY ) );
269 // Floppy
270 m_aDefaultProperties.insert( MyProperty( true,
271 IsFloppy,
272 -1 ,
273 cppu::UnoType<sal_Bool>::get(),
274 uno::Any(),
275 beans::PropertyState_DEFAULT_VALUE,
276 beans::PropertyAttribute::MAYBEVOID
277 | beans::PropertyAttribute::BOUND
278 | beans::PropertyAttribute::READONLY ) );
280 // Hidden
281 m_aDefaultProperties.insert(
282 MyProperty(
283 true,
284 IsHidden,
285 -1 ,
286 cppu::UnoType<sal_Bool>::get(),
287 uno::Any(),
288 beans::PropertyState_DEFAULT_VALUE,
289 beans::PropertyAttribute::MAYBEVOID
290 | beans::PropertyAttribute::BOUND
291 #if defined(_WIN32)
293 #else
294 | beans::PropertyAttribute::READONLY)); // under unix/linux only readable
295 #endif
298 // ContentType
299 m_aDefaultProperties.insert( MyProperty( false,
300 ContentType,
301 -1 ,
302 cppu::UnoType<OUString>::get(),
303 uno::Any(OUString()),
304 beans::PropertyState_DEFAULT_VALUE,
305 beans::PropertyAttribute::MAYBEVOID
306 | beans::PropertyAttribute::BOUND
307 | beans::PropertyAttribute::READONLY ) );
310 // DateModified
311 m_aDefaultProperties.insert( MyProperty( true,
312 DateModified,
313 -1 ,
314 cppu::UnoType<util::DateTime>::get(),
315 uno::Any(),
316 beans::PropertyState_DEFAULT_VALUE,
317 beans::PropertyAttribute::MAYBEVOID
318 | beans::PropertyAttribute::BOUND ) );
320 // Size
321 m_aDefaultProperties.insert( MyProperty( true,
322 Size,
324 cppu::UnoType<sal_Int64>::get(),
325 uno::Any(),
326 beans::PropertyState_DEFAULT_VALUE,
327 beans::PropertyAttribute::MAYBEVOID
328 | beans::PropertyAttribute::BOUND ) );
330 // IsReadOnly
331 m_aDefaultProperties.insert( MyProperty( true,
332 IsReadOnly,
333 -1 ,
334 cppu::UnoType<sal_Bool>::get(),
335 uno::Any(),
336 beans::PropertyState_DEFAULT_VALUE,
337 beans::PropertyAttribute::MAYBEVOID
338 | beans::PropertyAttribute::BOUND ) );
341 // CreatableContentsInfo
342 m_aDefaultProperties.insert( MyProperty( true,
343 CreatableContentsInfo,
344 -1 ,
345 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
346 uno::Any(),
347 beans::PropertyState_DEFAULT_VALUE,
348 beans::PropertyAttribute::MAYBEVOID
349 | beans::PropertyAttribute::BOUND
350 | beans::PropertyAttribute::READONLY ) );
352 if(bWithConfig)
354 uno::Reference< XPropertySetRegistryFactory > xRegFac = ucb::Store::create( m_xContext );
355 // Open/create a registry
356 m_xFileRegistry = xRegFac->createPropertySetRegistry( OUString() );
361 TaskManager::~TaskManager()
366 void
367 TaskManager::startTask(
368 sal_Int32 CommandId,
369 const uno::Reference< XCommandEnvironment >& xCommandEnv )
371 std::unique_lock aGuard( m_aMutex );
372 TaskMap::iterator it = m_aTaskMap.find( CommandId );
373 if( it != m_aTaskMap.end() )
375 throw DuplicateCommandIdentifierException( OSL_LOG_PREFIX );
377 m_aTaskMap.emplace( CommandId, TaskHandling( xCommandEnv ));
381 void
382 TaskManager::endTask( sal_Int32 CommandId,
383 const OUString& aUncPath,
384 BaseContent* pContent)
386 std::unique_lock aGuard( m_aMutex );
387 TaskMap::iterator it = m_aTaskMap.find( CommandId );
388 if( it == m_aTaskMap.end() )
389 return;
391 sal_Int32 ErrorCode = it->second.getInstalledError();
392 sal_Int32 MinorCode = it->second.getMinorErrorCode();
393 bool isHandled = it->second.isHandled();
395 Reference< XCommandEnvironment > xComEnv
396 = it->second.getCommandEnvironment();
398 m_aTaskMap.erase( it );
400 aGuard.unlock();
402 if( ErrorCode != TASKHANDLER_NO_ERROR )
403 throw_handler(
404 ErrorCode,
405 MinorCode,
406 xComEnv,
407 aUncPath,
408 pContent,
409 isHandled);
413 void TaskManager::clearError( sal_Int32 CommandId )
415 std::unique_lock aGuard( m_aMutex );
416 TaskMap::iterator it = m_aTaskMap.find( CommandId );
417 if( it != m_aTaskMap.end() )
418 it->second.clearError();
422 void TaskManager::retrieveError( sal_Int32 CommandId,
423 sal_Int32 &ErrorCode,
424 sal_Int32 &minorCode)
426 std::unique_lock aGuard( m_aMutex );
427 TaskMap::iterator it = m_aTaskMap.find( CommandId );
428 if( it != m_aTaskMap.end() )
430 ErrorCode = it->second.getInstalledError();
431 minorCode = it->second. getMinorErrorCode();
436 void TaskManager::installError( sal_Int32 CommandId,
437 sal_Int32 ErrorCode,
438 sal_Int32 MinorCode )
440 std::unique_lock aGuard( m_aMutex );
441 TaskMap::iterator it = m_aTaskMap.find( CommandId );
442 if( it != m_aTaskMap.end() )
443 it->second.installError( ErrorCode,MinorCode );
447 sal_Int32
448 TaskManager::getCommandId()
450 std::unique_lock aGuard( m_aMutex );
451 return ++m_nCommandId;
455 void TaskManager::handleTask(
456 sal_Int32 CommandId,
457 const uno::Reference< task::XInteractionRequest >& request )
459 std::unique_lock aGuard( m_aMutex );
460 TaskMap::iterator it = m_aTaskMap.find( CommandId );
461 uno::Reference< task::XInteractionHandler > xInt;
462 if( it != m_aTaskMap.end() )
464 xInt = it->second.getInteractionHandler();
465 if( xInt.is() )
466 xInt->handle( request );
467 it->second.setHandled();
471 /*********************************************************************************/
472 /* */
473 /* de/registerNotifier-Implementation */
474 /* */
475 /*********************************************************************************/
478 // This two methods register and deregister a change listener for the content belonging
479 // to URL aUnqPath
482 void
483 TaskManager::registerNotifier( const OUString& aUnqPath, Notifier* pNotifier )
485 std::unique_lock aGuard( m_aMutex );
487 ContentMap::iterator it =
488 m_aContent.emplace( aUnqPath, UnqPathData() ).first;
490 std::vector< Notifier* >& nlist = it->second.notifier;
492 std::vector<Notifier*>::iterator it1 = std::find(nlist.begin(), nlist.end(), pNotifier);
493 if( it1 != nlist.end() ) // Every "Notifier" only once
495 return;
497 nlist.push_back( pNotifier );
501 void
502 TaskManager::deregisterNotifier( const OUString& aUnqPath,Notifier* pNotifier )
504 std::unique_lock aGuard( m_aMutex );
506 ContentMap::iterator it = m_aContent.find( aUnqPath );
507 if( it == m_aContent.end() )
508 return;
510 it->second.notifier.erase(std::remove(it->second.notifier.begin(), it->second.notifier.end(), pNotifier), it->second.notifier.end());
512 if( it->second.notifier.empty() )
513 m_aContent.erase( it );
517 /*********************************************************************************/
518 /* */
519 /* de/associate-Implementation */
520 /* */
521 /*********************************************************************************/
523 // Used to associate and deassociate a new property with
524 // the content belonging to URL UnqPath.
525 // The default value and the attributes are input
528 void
529 TaskManager::associate( const OUString& aUnqPath,
530 const OUString& PropertyName,
531 const uno::Any& DefaultValue,
532 const sal_Int16 Attributes )
534 MyProperty newProperty( false,
535 PropertyName,
537 DefaultValue.getValueType(),
538 DefaultValue,
539 beans::PropertyState_DEFAULT_VALUE,
540 Attributes );
542 auto it1 = m_aDefaultProperties.find( newProperty );
543 if( it1 != m_aDefaultProperties.end() )
544 throw beans::PropertyExistException( THROW_WHERE );
547 std::unique_lock aGuard( m_aMutex );
549 ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first;
551 // Load the XPersistentPropertySetInfo and create it, if it does not exist
552 load( it,true );
554 PropertySet& properties = it->second.properties;
555 it1 = properties.find( newProperty );
556 if( it1 != properties.end() )
557 throw beans::PropertyExistException(THROW_WHERE );
559 // Property does not exist
560 properties.insert( newProperty );
561 it->second.xC->addProperty( PropertyName,Attributes,DefaultValue );
563 notifyPropertyAdded( getPropertySetListeners( aUnqPath ), PropertyName );
567 void
568 TaskManager::deassociate( const OUString& aUnqPath,
569 const OUString& PropertyName )
571 MyProperty oldProperty( PropertyName );
573 auto it1 = m_aDefaultProperties.find( oldProperty );
574 if( it1 != m_aDefaultProperties.end() )
575 throw beans::NotRemoveableException( THROW_WHERE );
577 std::unique_lock aGuard( m_aMutex );
579 ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first;
581 load( it, false );
583 PropertySet& properties = it->second.properties;
585 it1 = properties.find( oldProperty );
586 if( it1 == properties.end() )
587 throw beans::UnknownPropertyException( PropertyName );
589 properties.erase( it1 );
591 if( it->second.xC.is() )
592 it->second.xC->removeProperty( PropertyName );
594 if( properties.size() == 9 )
596 MyProperty ContentTProperty( ContentType );
598 if( properties.find( ContentTProperty )->getState() == beans::PropertyState_DEFAULT_VALUE )
600 it->second.xS = nullptr;
601 it->second.xC = nullptr;
602 it->second.xA = nullptr;
603 if(m_xFileRegistry.is())
604 m_xFileRegistry->removePropertySet( aUnqPath );
607 aGuard.unlock();
608 notifyPropertyRemoved( getPropertySetListeners( aUnqPath ), PropertyName );
612 /*********************************************************************************/
613 /* */
614 /* page-Implementation */
615 /* */
616 /*********************************************************************************/
618 // Given an xOutputStream, this method writes the content of the file belonging to
619 // URL aUnqPath into the XOutputStream
622 void TaskManager::page( sal_Int32 CommandId,
623 const OUString& aUnqPath,
624 const uno::Reference< io::XOutputStream >& xOutputStream )
626 osl::File aFile( aUnqPath );
627 osl::FileBase::RC err = aFile.open( osl_File_OpenFlag_Read );
629 if( err != osl::FileBase::E_None )
631 aFile.close();
632 installError( CommandId,
633 TASKHANDLING_OPEN_FILE_FOR_PAGING,
634 err );
635 return;
638 const sal_uInt64 bfz = 4*1024;
639 sal_Int8 BFF[bfz];
640 sal_uInt64 nrc; // Retrieved number of Bytes;
644 err = aFile.read( static_cast<void*>(BFF),bfz,nrc );
645 if( err == osl::FileBase::E_None )
647 // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
648 uno::Sequence< sal_Int8 > seq( BFF, static_cast<sal_uInt32>(nrc) );
651 xOutputStream->writeBytes( seq );
653 catch (const io::NotConnectedException&)
655 installError( CommandId,
656 TASKHANDLING_NOTCONNECTED_FOR_PAGING );
657 break;
659 catch (const io::BufferSizeExceededException&)
661 installError( CommandId,
662 TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_PAGING );
663 break;
665 catch (const io::IOException&)
667 installError( CommandId,
668 TASKHANDLING_IOEXCEPTION_FOR_PAGING );
669 break;
672 else
674 installError( CommandId,
675 TASKHANDLING_READING_FILE_FOR_PAGING,
676 err );
677 break;
679 } while( nrc == bfz );
682 aFile.close();
687 xOutputStream->closeOutput();
689 catch (const io::NotConnectedException&)
692 catch (const io::BufferSizeExceededException&)
695 catch (const io::IOException&)
701 /*********************************************************************************/
702 /* */
703 /* open-Implementation */
704 /* */
705 /*********************************************************************************/
707 // Given a file URL aUnqPath, this methods returns a XInputStream which reads from the open file.
710 uno::Reference< io::XInputStream >
711 TaskManager::open( sal_Int32 CommandId,
712 const OUString& aUnqPath,
713 bool bLock )
715 rtl::Reference<XInputStream_impl> pInputStream(new XInputStream_impl( aUnqPath, bLock )); // from filinpstr.hxx
717 sal_Int32 ErrorCode = pInputStream->CtorSuccess();
719 if( ErrorCode != TASKHANDLER_NO_ERROR )
721 installError( CommandId,
722 ErrorCode,
723 pInputStream->getMinorError() );
725 pInputStream.clear();
728 return pInputStream;
732 /*********************************************************************************/
733 /* */
734 /* open for read/write access-Implementation */
735 /* */
736 /*********************************************************************************/
738 // Given a file URL aUnqPath, this methods returns a XStream which can be used
739 // to read and write from/to the file.
742 uno::Reference< io::XStream >
743 TaskManager::open_rw( sal_Int32 CommandId,
744 const OUString& aUnqPath,
745 bool bLock )
747 rtl::Reference<XStream_impl> pStream(new XStream_impl( aUnqPath, bLock )); // from filstr.hxx
749 sal_Int32 ErrorCode = pStream->CtorSuccess();
751 if( ErrorCode != TASKHANDLER_NO_ERROR )
753 installError( CommandId,
754 ErrorCode,
755 pStream->getMinorError() );
757 pStream.clear();
759 return pStream;
763 /*********************************************************************************/
764 /* */
765 /* ls-Implementation */
766 /* */
767 /*********************************************************************************/
769 // This method returns the result set containing the children of the directory belonging
770 // to file URL aUnqPath
773 uno::Reference< XDynamicResultSet >
774 TaskManager::ls( sal_Int32 CommandId,
775 const OUString& aUnqPath,
776 const sal_Int32 OpenMode,
777 const uno::Sequence< beans::Property >& seq,
778 const uno::Sequence< NumberedSortingInfo >& seqSort )
780 rtl::Reference<XResultSet_impl> p(new XResultSet_impl( this,aUnqPath,OpenMode,seq,seqSort ));
782 sal_Int32 ErrorCode = p->CtorSuccess();
784 if( ErrorCode != TASKHANDLER_NO_ERROR )
786 installError( CommandId,
787 ErrorCode,
788 p->getMinorError() );
790 p.clear();
793 return p;
797 /*********************************************************************************/
798 /* */
799 /* info_c implementation */
800 /* */
801 /*********************************************************************************/
802 // Info for commands
804 uno::Reference< XCommandInfo >
805 TaskManager::info_c()
807 return new XCommandInfo_impl( this );
811 /*********************************************************************************/
812 /* */
813 /* info_p-Implementation */
814 /* */
815 /*********************************************************************************/
816 // Info for the properties
818 uno::Reference< beans::XPropertySetInfo >
819 TaskManager::info_p( const OUString& aUnqPath )
821 std::unique_lock aGuard( m_aMutex );
822 return new XPropertySetInfo_impl( this,aUnqPath );
826 /*********************************************************************************/
827 /* */
828 /* setv-Implementation */
829 /* */
830 /*********************************************************************************/
832 // Sets the values of the properties belonging to fileURL aUnqPath
835 uno::Sequence< uno::Any >
836 TaskManager::setv( const OUString& aUnqPath,
837 const uno::Sequence< beans::PropertyValue >& values )
839 std::unique_lock aGuard( m_aMutex );
841 sal_Int32 propChanged = 0;
842 uno::Sequence< uno::Any > ret( values.getLength() );
843 auto retRange = asNonConstRange(ret);
844 uno::Sequence< beans::PropertyChangeEvent > seqChanged( values.getLength() );
845 auto seqChangedRange = asNonConstRange(seqChanged);
847 TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
848 PropertySet& properties = it->second.properties;
849 TaskManager::PropertySet::const_iterator it1;
850 uno::Any aAny;
852 for( sal_Int32 i = 0; i < values.getLength(); ++i )
854 MyProperty toset( values[i].Name );
855 it1 = properties.find( toset );
856 if( it1 == properties.end() )
858 retRange[i] <<= beans::UnknownPropertyException( THROW_WHERE );
859 continue;
862 aAny = it1->getValue();
863 if( aAny == values[i].Value )
864 continue; // nothing needs to be changed
866 if( it1->getAttributes() & beans::PropertyAttribute::READONLY )
868 retRange[i] <<= lang::IllegalAccessException( THROW_WHERE );
869 continue;
872 seqChangedRange[ propChanged ].PropertyName = values[i].Name;
873 seqChangedRange[ propChanged ].PropertyHandle = -1;
874 seqChangedRange[ propChanged ].Further = false;
875 seqChangedRange[ propChanged ].OldValue = aAny;
876 seqChangedRange[ propChanged++ ].NewValue = values[i].Value;
878 it1->setValue( values[i].Value ); // Put the new value into the local cash
880 if( ! it1->IsNative() )
882 // Also put logical properties into storage
883 if( !it->second.xS.is() )
884 load( it, true );
886 if( ( values[i].Name == ContentType ) &&
887 it1->getState() == beans::PropertyState_DEFAULT_VALUE )
888 { // Special logic for ContentType
889 // 09.07.01: Not reached anymore, because ContentType is readonly
890 it1->setState( beans::PropertyState_DIRECT_VALUE );
891 it->second.xC->addProperty( values[i].Name,
892 beans::PropertyAttribute::MAYBEVOID,
893 values[i].Value );
898 it->second.xS->setPropertyValue( values[i].Name,values[i].Value );
900 catch (const uno::Exception&e)
902 --propChanged; // unsuccessful setting
903 retRange[i] <<= e;
906 else
908 // native properties
909 // Setting of physical file properties
910 if( values[i].Name == Size )
912 sal_Int64 newSize = 0;
913 if( values[i].Value >>= newSize )
914 { // valid value for the size
915 osl::File aFile(aUnqPath);
916 bool err =
917 aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None ||
918 aFile.setSize(sal_uInt64(newSize)) != osl::FileBase::E_None ||
919 aFile.close() != osl::FileBase::E_None;
921 if( err )
923 --propChanged; // unsuccessful setting
924 uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence(
926 {"Uri", uno::Any(aUnqPath)}
927 }));
928 retRange[i] <<= InteractiveAugmentedIOException(
929 OUString(),
930 nullptr,
931 task::InteractionClassification_ERROR,
932 IOErrorCode_GENERAL,
933 names );
936 else
937 retRange[i] <<= beans::IllegalTypeException( THROW_WHERE );
939 else if(values[i].Name == IsReadOnly ||
940 values[i].Name == IsHidden)
942 bool value = false;
943 if( values[i].Value >>= value )
945 osl::DirectoryItem aDirItem;
946 osl::FileBase::RC err =
947 osl::DirectoryItem::get(aUnqPath,aDirItem);
948 sal_uInt64 nAttributes(0);
949 if(err == osl::FileBase::E_None)
951 osl::FileStatus aFileStatus(osl_FileStatus_Mask_Attributes);
952 err = aDirItem.getFileStatus(aFileStatus);
953 if(err == osl::FileBase::E_None &&
954 aFileStatus.isValid(osl_FileStatus_Mask_Attributes))
955 nAttributes = aFileStatus.getAttributes();
957 // now we have the attributes provided all went well.
958 if(err == osl::FileBase::E_None) {
959 if(values[i].Name == IsReadOnly)
961 nAttributes &= ~(osl_File_Attribute_OwnWrite |
962 osl_File_Attribute_GrpWrite |
963 osl_File_Attribute_OthWrite |
964 osl_File_Attribute_ReadOnly);
965 if(value)
966 nAttributes |= osl_File_Attribute_ReadOnly;
967 else
968 nAttributes |= (
969 osl_File_Attribute_OwnWrite |
970 osl_File_Attribute_GrpWrite |
971 osl_File_Attribute_OthWrite);
973 else if(values[i].Name == IsHidden)
975 nAttributes &= ~(osl_File_Attribute_Hidden);
976 if(value)
977 nAttributes |= osl_File_Attribute_Hidden;
979 err = osl::File::setAttributes(
980 aUnqPath,nAttributes);
983 if( err != osl::FileBase::E_None )
985 --propChanged; // unsuccessful setting
986 uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence(
988 {"Uri", uno::Any(aUnqPath)}
989 }));
990 IOErrorCode ioError;
991 switch( err )
993 case osl::FileBase::E_NOMEM:
994 // not enough memory for allocating structures <br>
995 ioError = IOErrorCode_OUT_OF_MEMORY;
996 break;
997 case osl::FileBase::E_INVAL:
998 // the format of the parameters was not valid<p>
999 ioError = IOErrorCode_INVALID_PARAMETER;
1000 break;
1001 case osl::FileBase::E_NAMETOOLONG:
1002 // File name too long<br>
1003 ioError = IOErrorCode_NAME_TOO_LONG;
1004 break;
1005 case osl::FileBase::E_NOENT:
1006 // No such file or directory<br>
1007 case osl::FileBase::E_NOLINK:
1008 // Link has been severed<br>
1009 ioError = IOErrorCode_NOT_EXISTING;
1010 break;
1011 case osl::FileBase::E_ROFS:
1012 // #i4735# handle ROFS transparently
1013 // as ACCESS_DENIED
1014 case osl::FileBase::E_PERM:
1015 case osl::FileBase::E_ACCES:
1016 // permission denied<br>
1017 ioError = IOErrorCode_ACCESS_DENIED;
1018 break;
1019 case osl::FileBase::E_LOOP:
1020 // Too many symbolic links encountered<br>
1021 case osl::FileBase::E_FAULT:
1022 // Bad address<br>
1023 case osl::FileBase::E_IO:
1024 // I/O error<br>
1025 case osl::FileBase::E_NOSYS:
1026 // Function not implemented<br>
1027 case osl::FileBase::E_MULTIHOP:
1028 // Multihop attempted<br>
1029 case osl::FileBase::E_INTR:
1030 // function call was interrupted<p>
1031 default:
1032 ioError = IOErrorCode_GENERAL;
1033 break;
1035 retRange[i] <<= InteractiveAugmentedIOException(
1036 OUString(),
1037 nullptr,
1038 task::InteractionClassification_ERROR,
1039 ioError,
1040 names );
1043 else
1044 retRange[i] <<= beans::IllegalTypeException( THROW_WHERE );
1047 } // end for
1049 aGuard.unlock();
1050 if( propChanged )
1052 seqChanged.realloc( propChanged );
1053 notifyPropertyChanges( getPropertyChangeNotifier( aUnqPath ), seqChanged );
1056 return ret;
1059 /*********************************************************************************/
1060 /* */
1061 /* getv-Implementation */
1062 /* */
1063 /*********************************************************************************/
1065 // Reads the values of the properties belonging to fileURL aUnqPath;
1066 // Returns an XRow object containing the values in the requested order.
1069 uno::Reference< sdbc::XRow >
1070 TaskManager::getv( sal_Int32 CommandId,
1071 const OUString& aUnqPath,
1072 const uno::Sequence< beans::Property >& properties )
1074 uno::Sequence< uno::Any > seq( properties.getLength() );
1076 sal_Int32 n_Mask;
1077 getMaskFromProperties( n_Mask,properties );
1078 osl::FileStatus aFileStatus( n_Mask );
1080 osl::DirectoryItem aDirItem;
1081 osl::FileBase::RC nError1 = osl::DirectoryItem::get( aUnqPath,aDirItem );
1082 if( nError1 != osl::FileBase::E_None )
1083 installError(CommandId,
1084 TASKHANDLING_OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED
1085 nError1);
1087 osl::FileBase::RC nError2 = aDirItem.getFileStatus( aFileStatus );
1088 if( nError1 == osl::FileBase::E_None &&
1089 nError2 != osl::FileBase::E_None )
1090 installError(CommandId,
1091 TASKHANDLING_OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED
1092 nError2);
1095 std::unique_lock aGuard( m_aMutex );
1097 TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
1098 commit( aGuard, it, aFileStatus );
1100 PropertySet& propset = it->second.properties;
1102 std::transform(properties.begin(), properties.end(), seq.getArray(),
1103 [&propset](const beans::Property& rProp) -> uno::Any {
1104 MyProperty readProp( rProp.Name );
1105 auto it1 = propset.find( readProp );
1106 if( it1 == propset.end() )
1107 return uno::Any();
1108 return it1->getValue();
1112 return new XRow_impl( this,seq );
1116 /********************************************************************************/
1117 /* */
1118 /* transfer-commandos */
1119 /* */
1120 /********************************************************************************/
1123 /********************************************************************************/
1124 /* */
1125 /* move-implementation */
1126 /* */
1127 /********************************************************************************/
1129 // Moves the content belonging to fileURL srcUnqPath to fileURL dstUnqPath.
1132 void
1133 TaskManager::move( sal_Int32 CommandId,
1134 const OUString& srcUnqPath,
1135 const OUString& dstUnqPathIn,
1136 const sal_Int32 NameClash )
1138 // --> #i88446# Method notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) ); crashes if
1139 // srcUnqPath and dstUnqPathIn are equal
1140 if( srcUnqPath == dstUnqPathIn )
1141 return;
1143 osl::FileBase::RC nError;
1144 OUString dstUnqPath( dstUnqPathIn );
1146 switch( NameClash )
1148 case NameClash::KEEP:
1150 nError = osl_File_move( srcUnqPath,dstUnqPath,true );
1151 if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST )
1153 installError( CommandId,
1154 TASKHANDLING_KEEPERROR_FOR_MOVE,
1155 nError );
1156 return;
1158 break;
1160 case NameClash::OVERWRITE:
1162 // stat to determine whether we have a symlink
1163 OUString targetPath(dstUnqPath);
1165 osl::FileStatus aStatus(osl_FileStatus_Mask_Type|osl_FileStatus_Mask_LinkTargetURL);
1166 osl::DirectoryItem aItem;
1167 (void)osl::DirectoryItem::get(dstUnqPath,aItem);
1168 (void)aItem.getFileStatus(aStatus);
1170 if( aStatus.isValid(osl_FileStatus_Mask_Type) &&
1171 aStatus.isValid(osl_FileStatus_Mask_LinkTargetURL) &&
1172 aStatus.getFileType() == osl::FileStatus::Link )
1173 targetPath = aStatus.getLinkTargetURL();
1175 // Will do nothing if file does not exist.
1176 osl::File::remove( targetPath );
1178 nError = osl_File_move( srcUnqPath,targetPath );
1179 if( nError != osl::FileBase::E_None )
1181 installError( CommandId,
1182 TASKHANDLING_OVERWRITE_FOR_MOVE,
1183 nError );
1184 return;
1186 break;
1188 case NameClash::RENAME:
1190 OUString newDstUnqPath;
1191 nError = osl_File_move( srcUnqPath,dstUnqPath,true );
1192 if( nError == osl::FileBase::E_EXIST )
1194 // "invent" a new valid title.
1196 sal_Int32 nPos = -1;
1197 sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' );
1198 sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' );
1199 if( ( nLastSlash < nLastDot ) // dot is part of last(!) path segment
1200 && ( nLastSlash != ( nLastDot - 1 ) ) ) // file name does not start with a dot
1201 nPos = nLastDot;
1202 else
1203 nPos = dstUnqPath.getLength();
1205 sal_Int32 nTry = 0;
1209 newDstUnqPath = dstUnqPath;
1211 OUString aPostfix = "_" + OUString::number( ++nTry );
1213 newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix );
1215 nError = osl_File_move( srcUnqPath,newDstUnqPath,true );
1217 while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) );
1220 if( nError == osl::FileBase::E_EXIST )
1222 installError( CommandId,
1223 TASKHANDLING_RENAME_FOR_MOVE );
1224 return;
1226 else if( nError != osl::FileBase::E_None )
1228 installError( CommandId,
1229 TASKHANDLING_RENAMEMOVE_FOR_MOVE,
1230 nError );
1231 return;
1233 else
1234 dstUnqPath = newDstUnqPath;
1236 break;
1238 case NameClash::ERROR:
1240 nError = osl_File_move( srcUnqPath,dstUnqPath,true );
1241 if( nError == osl::FileBase::E_EXIST )
1243 installError( CommandId,
1244 TASKHANDLING_NAMECLASH_FOR_MOVE );
1245 return;
1247 else if( nError != osl::FileBase::E_None )
1249 installError( CommandId,
1250 TASKHANDLING_NAMECLASHMOVE_FOR_MOVE,
1251 nError );
1252 return;
1254 break;
1256 case NameClash::ASK:
1257 default:
1259 nError = osl_File_move( srcUnqPath,dstUnqPath,true );
1260 if( nError == osl::FileBase::E_EXIST )
1262 installError( CommandId,
1263 TASKHANDLING_NAMECLASHSUPPORT_FOR_MOVE,
1264 NameClash::ASK);
1265 return;
1268 break;
1271 // Determine, whether we have moved a file or a folder
1272 osl::DirectoryItem aItem;
1273 nError = osl::DirectoryItem::get( dstUnqPath,aItem );
1274 if( nError != osl::FileBase::E_None )
1276 installError( CommandId,
1277 TASKHANDLING_TRANSFER_BY_MOVE_SOURCE,
1278 nError );
1279 return;
1281 osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
1282 nError = aItem.getFileStatus( aStatus );
1283 if( nError != osl::FileBase::E_None || ! aStatus.isValid( osl_FileStatus_Mask_Type ) )
1285 installError( CommandId,
1286 TASKHANDLING_TRANSFER_BY_MOVE_SOURCESTAT,
1287 nError );
1288 return;
1290 bool isDocument = ( aStatus.getFileType() == osl::FileStatus::Regular );
1293 copyPersistentSet( srcUnqPath,dstUnqPath,!isDocument );
1295 OUString aDstParent = getParentName( dstUnqPath );
1296 OUString aSrcParent = getParentName( srcUnqPath );
1298 notifyInsert( getContentEventListeners( aDstParent ),dstUnqPath );
1299 if( aDstParent != aSrcParent )
1300 notifyContentRemoved( getContentEventListeners( aSrcParent ),srcUnqPath );
1302 notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) );
1303 erasePersistentSet( srcUnqPath,!isDocument );
1307 /********************************************************************************/
1308 /* */
1309 /* copy-implementation */
1310 /* */
1311 /********************************************************************************/
1313 // Copies the content belonging to fileURL srcUnqPath to fileURL dstUnqPath ( files and directories )
1316 namespace {
1318 bool getType(
1319 TaskManager & task, sal_Int32 id, OUString const & fileUrl,
1320 osl::DirectoryItem * item, osl::FileStatus::Type * type)
1322 OSL_ASSERT(item != nullptr && type != nullptr);
1323 osl::FileBase::RC err = osl::DirectoryItem::get(fileUrl, *item);
1324 if (err != osl::FileBase::E_None) {
1325 task.installError(id, TASKHANDLING_TRANSFER_BY_COPY_SOURCE, err);
1326 return false;
1328 osl::FileStatus stat(osl_FileStatus_Mask_Type);
1329 err = item->getFileStatus(stat);
1330 if (err != osl::FileBase::E_None) {
1331 task.installError(id, TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT, err);
1332 return false;
1334 *type = stat.getFileType();
1335 return true;
1340 void
1341 TaskManager::copy(
1342 sal_Int32 CommandId,
1343 const OUString& srcUnqPath,
1344 const OUString& dstUnqPathIn,
1345 sal_Int32 NameClash )
1347 osl::FileBase::RC nError;
1348 OUString dstUnqPath( dstUnqPathIn );
1350 // Resolve symbolic links within the source path. If srcUnqPath denotes a
1351 // symbolic link (targeting either a file or a folder), the contents of the
1352 // target is copied (recursively, in the case of a folder). However, if
1353 // recursively copying the contents of a folder causes a symbolic link to be
1354 // copied, the symbolic link itself is copied.
1355 osl::DirectoryItem item;
1356 osl::FileStatus::Type type;
1357 if (!getType(*this, CommandId, srcUnqPath, &item, &type)) {
1358 return;
1360 OUString rslvdSrcUnqPath;
1361 if (type == osl::FileStatus::Link) {
1362 osl::FileStatus stat(osl_FileStatus_Mask_LinkTargetURL);
1363 nError = item.getFileStatus(stat);
1364 if (nError != osl::FileBase::E_None) {
1365 installError(
1366 CommandId, TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT, nError);
1367 return;
1369 rslvdSrcUnqPath = stat.getLinkTargetURL();
1370 if (!getType(*this, CommandId, srcUnqPath, &item, &type)) {
1371 return;
1373 } else {
1374 rslvdSrcUnqPath = srcUnqPath;
1377 bool isDocument
1378 = type != osl::FileStatus::Directory && type != osl::FileStatus::Volume;
1379 FileUrlType IsWhat = isDocument ? FileUrlType::File : FileUrlType::Folder;
1381 switch( NameClash )
1383 case NameClash::KEEP:
1385 nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
1386 if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST )
1388 installError( CommandId,
1389 TASKHANDLING_KEEPERROR_FOR_COPY,
1390 nError );
1391 return;
1393 break;
1395 case NameClash::OVERWRITE:
1397 // remove (..., MustExist = sal_False).
1398 remove( CommandId, dstUnqPath, IsWhat, false );
1400 // copy.
1401 nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,false );
1402 if( nError != osl::FileBase::E_None )
1404 installError( CommandId,
1405 TASKHANDLING_OVERWRITE_FOR_COPY,
1406 nError );
1407 return;
1409 break;
1411 case NameClash::RENAME:
1413 OUString newDstUnqPath = dstUnqPath;
1414 nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
1416 if( nError == osl::FileBase::E_EXIST )
1418 // "invent" a new valid title.
1420 sal_Int32 nPos = -1;
1421 sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' );
1422 sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' );
1423 if ( ( nLastSlash < nLastDot ) // dot is part of last(!) path segment
1424 && ( nLastSlash != ( nLastDot - 1 ) ) ) // file name does not start with a dot
1425 nPos = nLastDot;
1426 else
1427 nPos = dstUnqPath.getLength();
1429 sal_Int32 nTry = 0;
1433 newDstUnqPath = dstUnqPath;
1435 OUString aPostfix = "_" + OUString::number( ++nTry );
1437 newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix );
1439 nError = copy_recursive( rslvdSrcUnqPath,newDstUnqPath,IsWhat,true );
1441 while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) );
1444 if( nError == osl::FileBase::E_EXIST )
1446 installError( CommandId,
1447 TASKHANDLING_RENAME_FOR_COPY );
1448 return;
1450 else if( nError != osl::FileBase::E_None )
1452 installError( CommandId,
1453 TASKHANDLING_RENAMEMOVE_FOR_COPY,
1454 nError );
1455 return;
1457 else
1458 dstUnqPath = newDstUnqPath;
1460 break;
1462 case NameClash::ERROR:
1464 nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
1466 if( nError == osl::FileBase::E_EXIST )
1468 installError( CommandId,
1469 TASKHANDLING_NAMECLASH_FOR_COPY );
1470 return;
1472 else if( nError != osl::FileBase::E_None )
1474 installError( CommandId,
1475 TASKHANDLING_NAMECLASHMOVE_FOR_COPY,
1476 nError );
1477 return;
1479 break;
1481 case NameClash::ASK:
1482 default:
1484 nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true );
1486 if( nError == osl::FileBase::E_EXIST )
1488 installError( CommandId,
1489 TASKHANDLING_NAMECLASHSUPPORT_FOR_COPY,
1490 NameClash);
1491 return;
1493 break;
1497 copyPersistentSet( srcUnqPath,dstUnqPath, !isDocument );
1498 notifyInsert( getContentEventListeners( getParentName( dstUnqPath ) ),dstUnqPath );
1502 /********************************************************************************/
1503 /* */
1504 /* remove-implementation */
1505 /* */
1506 /********************************************************************************/
1508 // Deletes the content belonging to fileURL aUnqPath( recursively in case of directory )
1509 // Return: success of operation
1512 bool
1513 TaskManager::remove( sal_Int32 CommandId,
1514 const OUString& aUnqPath,
1515 FileUrlType IsWhat,
1516 bool MustExist )
1518 sal_Int32 nMask = osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL;
1520 osl::DirectoryItem aItem;
1521 osl::FileStatus aStatus( nMask );
1522 osl::FileBase::RC nError;
1524 if( IsWhat == FileUrlType::Unknown ) // Determine whether we are removing a directory or a file
1526 nError = osl::DirectoryItem::get( aUnqPath, aItem );
1527 if( nError != osl::FileBase::E_None )
1529 if (MustExist)
1531 installError( CommandId,
1532 TASKHANDLING_NOSUCHFILEORDIR_FOR_REMOVE,
1533 nError );
1535 return (!MustExist);
1538 nError = aItem.getFileStatus( aStatus );
1539 if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) )
1541 installError( CommandId,
1542 TASKHANDLING_VALIDFILESTATUS_FOR_REMOVE,
1543 nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR );
1544 return false;
1547 if( aStatus.getFileType() == osl::FileStatus::Regular ||
1548 aStatus.getFileType() == osl::FileStatus::Link )
1549 IsWhat = FileUrlType::File;
1550 else if( aStatus.getFileType() == osl::FileStatus::Directory ||
1551 aStatus.getFileType() == osl::FileStatus::Volume )
1552 IsWhat = FileUrlType::Folder;
1556 if( IsWhat == FileUrlType::File )
1558 nError = osl::File::remove( aUnqPath );
1559 if( nError != osl::FileBase::E_None )
1561 if (MustExist)
1563 installError( CommandId,
1564 TASKHANDLING_DELETEFILE_FOR_REMOVE,
1565 nError );
1567 return (!MustExist);
1569 else
1571 notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) );
1572 erasePersistentSet( aUnqPath ); // Removes from XPersistentPropertySet
1575 else if( IsWhat == FileUrlType::Folder )
1577 osl::Directory aDirectory( aUnqPath );
1579 nError = aDirectory.open();
1580 if( nError != osl::FileBase::E_None )
1582 if (MustExist)
1584 installError( CommandId,
1585 TASKHANDLING_OPENDIRECTORY_FOR_REMOVE,
1586 nError );
1588 return (!MustExist);
1591 bool whileSuccess = true;
1592 FileUrlType recurse = FileUrlType::Unknown;
1593 OUString name;
1595 nError = aDirectory.getNextItem( aItem );
1596 while( nError == osl::FileBase::E_None )
1598 nError = aItem.getFileStatus( aStatus );
1599 if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) )
1601 installError( CommandId,
1602 TASKHANDLING_VALIDFILESTATUSWHILE_FOR_REMOVE,
1603 nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR );
1604 whileSuccess = false;
1605 break;
1608 if( aStatus.getFileType() == osl::FileStatus::Regular ||
1609 aStatus.getFileType() == osl::FileStatus::Link )
1610 recurse = FileUrlType::File;
1611 else if( aStatus.getFileType() == osl::FileStatus::Directory ||
1612 aStatus.getFileType() == osl::FileStatus::Volume )
1613 recurse = FileUrlType::Folder;
1615 name = aStatus.getFileURL();
1616 whileSuccess = remove( CommandId, name, recurse, MustExist );
1617 if( !whileSuccess )
1618 break;
1620 nError = aDirectory.getNextItem( aItem );
1623 aDirectory.close();
1625 if( ! whileSuccess )
1626 return false; // error code is installed
1628 if( nError != osl::FileBase::E_NOENT )
1630 installError( CommandId,
1631 TASKHANDLING_DIRECTORYEXHAUSTED_FOR_REMOVE,
1632 nError );
1633 return false;
1636 nError = osl::Directory::remove( aUnqPath );
1637 if( nError != osl::FileBase::E_None )
1639 if (MustExist)
1641 installError( CommandId,
1642 TASKHANDLING_DELETEDIRECTORY_FOR_REMOVE,
1643 nError );
1645 return (!MustExist);
1647 else
1649 notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) );
1650 erasePersistentSet( aUnqPath );
1653 else // Don't know what to remove
1655 installError( CommandId,
1656 TASKHANDLING_FILETYPE_FOR_REMOVE );
1657 return false;
1660 return true;
1664 /********************************************************************************/
1665 /* */
1666 /* mkdir-implementation */
1667 /* */
1668 /********************************************************************************/
1670 // Creates new directory with given URL, recursively if necessary
1671 // Return:: success of operation
1674 bool
1675 TaskManager::mkdir( sal_Int32 CommandId,
1676 const OUString& rUnqPath,
1677 bool OverWrite )
1679 OUString aUnqPath;
1681 // remove trailing slash
1682 if ( rUnqPath.endsWith("/") )
1683 aUnqPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
1684 else
1685 aUnqPath = rUnqPath;
1687 osl::FileBase::RC nError = osl::Directory::create( aUnqPath );
1689 switch ( nError )
1691 case osl::FileBase::E_EXIST: // Directory cannot be overwritten
1693 if( !OverWrite )
1695 installError( CommandId,
1696 TASKHANDLING_FOLDER_EXISTS_MKDIR );
1697 return false;
1699 else
1700 return true;
1702 case osl::FileBase::E_INVAL:
1704 installError(CommandId,
1705 TASKHANDLING_INVALID_NAME_MKDIR);
1706 return false;
1708 case osl::FileBase::E_None:
1710 OUString aPrtPath = getParentName( aUnqPath );
1711 notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath );
1712 return true;
1714 default:
1715 return ensuredir(
1716 CommandId,
1717 aUnqPath,
1718 TASKHANDLING_CREATEDIRECTORY_MKDIR );
1723 /********************************************************************************/
1724 /* */
1725 /* mkfil-implementation */
1726 /* */
1727 /********************************************************************************/
1729 // Creates new file with given URL.
1730 // The content of aInputStream becomes the content of the file
1731 // Return:: success of operation
1734 bool
1735 TaskManager::mkfil( sal_Int32 CommandId,
1736 const OUString& aUnqPath,
1737 bool Overwrite,
1738 const uno::Reference< io::XInputStream >& aInputStream )
1740 // return value unimportant
1741 bool bSuccess = write( CommandId,
1742 aUnqPath,
1743 Overwrite,
1744 aInputStream );
1745 if ( bSuccess )
1747 OUString aPrtPath = getParentName( aUnqPath );
1748 notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath );
1750 return bSuccess;
1754 /********************************************************************************/
1755 /* */
1756 /* write-implementation */
1757 /* */
1758 /********************************************************************************/
1760 // writes to the file with given URL.
1761 // The content of aInputStream becomes the content of the file
1762 // Return:: success of operation
1765 bool
1766 TaskManager::write( sal_Int32 CommandId,
1767 const OUString& aUnqPath,
1768 bool OverWrite,
1769 const uno::Reference< io::XInputStream >& aInputStream )
1771 if( ! aInputStream.is() )
1773 installError( CommandId,
1774 TASKHANDLING_INPUTSTREAM_FOR_WRITE );
1775 return false;
1778 // Create parent path, if necessary.
1779 if ( ! ensuredir( CommandId,
1780 getParentName( aUnqPath ),
1781 TASKHANDLING_ENSUREDIR_FOR_WRITE ) )
1782 return false;
1784 osl::FileBase::RC err;
1785 osl::File aFile( aUnqPath );
1787 if( OverWrite )
1789 err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
1791 if( err != osl::FileBase::E_None )
1793 aFile.close();
1794 err = aFile.open( osl_File_OpenFlag_Write );
1796 if( err != osl::FileBase::E_None )
1798 installError( CommandId,
1799 TASKHANDLING_NO_OPEN_FILE_FOR_OVERWRITE,
1800 err );
1801 return false;
1804 // the existing file was just opened and should be overwritten now,
1805 // truncate it first
1807 err = aFile.setSize( 0 );
1808 if( err != osl::FileBase::E_None )
1810 installError( CommandId,
1811 TASKHANDLING_FILESIZE_FOR_WRITE,
1812 err );
1813 return false;
1817 else
1819 err = aFile.open( osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock );
1820 if( err == osl::FileBase::E_None ) // The file exists and shall not be overwritten
1822 installError( CommandId,
1823 TASKHANDLING_NOREPLACE_FOR_WRITE, // Now an exception
1824 err );
1826 aFile.close();
1827 return false;
1830 // as a temporary solution the creation does not lock the file at all
1831 // in future it should be possible to create the file without lock explicitly
1832 err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
1834 if( err != osl::FileBase::E_None )
1836 aFile.close();
1837 installError( CommandId,
1838 TASKHANDLING_NO_OPEN_FILE_FOR_WRITE,
1839 err );
1840 return false;
1844 bool bSuccess = true;
1846 sal_uInt64 nWrittenBytes;
1847 sal_Int32 nReadBytes = 0, nRequestedBytes = 32768 /*32k*/;
1848 uno::Sequence< sal_Int8 > seq( nRequestedBytes );
1854 nReadBytes = aInputStream->readBytes( seq,
1855 nRequestedBytes );
1857 catch( const io::NotConnectedException& )
1859 installError( CommandId,
1860 TASKHANDLING_NOTCONNECTED_FOR_WRITE );
1861 bSuccess = false;
1862 break;
1864 catch( const io::BufferSizeExceededException& )
1866 installError( CommandId,
1867 TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_WRITE );
1868 bSuccess = false;
1869 break;
1871 catch( const io::IOException& )
1873 installError( CommandId,
1874 TASKHANDLING_IOEXCEPTION_FOR_WRITE );
1875 bSuccess = false;
1876 break;
1879 if( nReadBytes )
1881 const sal_Int8* p = seq.getConstArray();
1883 err = aFile.write( static_cast<void const *>(p),
1884 sal_uInt64( nReadBytes ),
1885 nWrittenBytes );
1887 if( err != osl::FileBase::E_None )
1889 installError( CommandId,
1890 TASKHANDLING_FILEIOERROR_FOR_WRITE,
1891 err );
1892 bSuccess = false;
1893 break;
1895 else if( nWrittenBytes != sal_uInt64( nReadBytes ) )
1897 installError( CommandId,
1898 TASKHANDLING_FILEIOERROR_FOR_NO_SPACE );
1899 bSuccess = false;
1900 break;
1903 } while( nReadBytes == nRequestedBytes );
1905 err = aFile.close();
1906 if( err != osl::FileBase::E_None )
1908 installError( CommandId,
1909 TASKHANDLING_FILEIOERROR_FOR_WRITE,
1910 err );
1911 bSuccess = false;
1914 return bSuccess;
1918 /*********************************************************************************/
1919 /* */
1920 /* insertDefaultProperties-Implementation */
1921 /* */
1922 /*********************************************************************************/
1925 void TaskManager::insertDefaultProperties( const OUString& aUnqPath )
1927 std::unique_lock aGuard(m_aMutex);
1928 insertDefaultProperties(aGuard, aUnqPath);
1931 void TaskManager::insertDefaultProperties( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& aUnqPath )
1933 ContentMap::iterator it =
1934 m_aContent.emplace( aUnqPath,UnqPathData() ).first;
1936 load( it, false );
1938 MyProperty ContentTProperty( ContentType );
1940 PropertySet& properties = it->second.properties;
1941 bool ContentNotDefau = properties.find( ContentTProperty ) != properties.end();
1943 properties.reserve(properties.size() + m_aDefaultProperties.size());
1944 for (auto const& defaultprop : m_aDefaultProperties)
1946 if( !ContentNotDefau || defaultprop.getPropertyName() != ContentType )
1947 properties.insert( defaultprop );
1952 /******************************************************************************/
1953 /* */
1954 /* mapping of file urls */
1955 /* to uncpath and vice versa */
1956 /* */
1957 /******************************************************************************/
1960 bool TaskManager::getUnqFromUrl( const OUString& Url, OUString& Unq )
1962 if ( Url == "file:///" || Url == "file://localhost/" || Url == "file://127.0.0.1/" )
1964 Unq = "file:///";
1965 return false;
1968 bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Url,Unq );
1970 Unq = Url;
1972 sal_Int32 l = Unq.getLength()-1;
1973 if( ! err && Unq.endsWith("/") &&
1974 Unq.indexOf( '/', RTL_CONSTASCII_LENGTH("//") ) != -1 )
1975 Unq = Unq.copy(0, l);
1977 return err;
1981 bool TaskManager::getUrlFromUnq( const OUString& Unq,OUString& Url )
1983 bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Unq,Url );
1985 Url = Unq;
1987 return err;
1991 // Helper function for public copy
1993 osl::FileBase::RC
1994 TaskManager::copy_recursive( const OUString& srcUnqPath,
1995 const OUString& dstUnqPath,
1996 FileUrlType TypeToCopy,
1997 bool testExistBeforeCopy )
1999 osl::FileBase::RC err = osl::FileBase::E_None;
2001 if( TypeToCopy == FileUrlType::File ) // Document
2003 err = osl_File_copy( srcUnqPath,dstUnqPath,testExistBeforeCopy );
2005 else if( TypeToCopy == FileUrlType::Folder )
2007 osl::Directory aDir( srcUnqPath );
2008 (void)aDir.open();
2010 err = osl::Directory::create( dstUnqPath );
2011 osl::FileBase::RC next = err;
2012 if( err == osl::FileBase::E_None )
2014 sal_Int32 const n_Mask = osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Type;
2016 osl::DirectoryItem aDirItem;
2018 while( err == osl::FileBase::E_None )
2020 next = aDir.getNextItem( aDirItem );
2021 if (next != osl::FileBase::E_None )
2022 break;
2023 bool IsDoc = false;
2024 osl::FileStatus aFileStatus( n_Mask );
2025 aDirItem.getFileStatus( aFileStatus );
2026 if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) )
2027 IsDoc = aFileStatus.getFileType() == osl::FileStatus::Regular;
2029 // Getting the information for the next recursive copy
2030 FileUrlType newTypeToCopy = IsDoc ? FileUrlType::File : FileUrlType::Folder;
2032 OUString newSrcUnqPath;
2033 if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) )
2034 newSrcUnqPath = aFileStatus.getFileURL();
2036 OUString newDstUnqPath = dstUnqPath;
2037 OUString tit;
2038 if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) )
2039 tit = rtl::Uri::encode( aFileStatus.getFileName(),
2040 rtl_UriCharClassPchar,
2041 rtl_UriEncodeIgnoreEscapes,
2042 RTL_TEXTENCODING_UTF8 );
2044 if( !newDstUnqPath.endsWith( "/" ) )
2045 newDstUnqPath += "/";
2047 newDstUnqPath += tit;
2049 if ( newSrcUnqPath != dstUnqPath )
2050 err = copy_recursive( newSrcUnqPath,newDstUnqPath,newTypeToCopy,false );
2053 if( err == osl::FileBase::E_None && next != osl::FileBase::E_NOENT )
2054 err = next;
2056 aDir.close();
2059 return err;
2063 // Helper function for mkfil,mkdir and write
2064 // Creates whole path
2065 // returns success of the operation
2068 bool TaskManager::ensuredir( sal_Int32 CommandId,
2069 const OUString& rUnqPath,
2070 sal_Int32 errorCode )
2072 OUString aPath;
2074 if ( rUnqPath.isEmpty() )
2075 return false;
2077 if ( rUnqPath.endsWith("/") )
2078 aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
2079 else
2080 aPath = rUnqPath;
2082 #if HAVE_FEATURE_MACOSX_SANDBOX
2084 // Avoid annoying sandbox messages in the system.log from the
2085 // below aDirectory.open(), which ends up calling opendir().
2086 // Surely it is easier to just call stat()? Calling stat() on an
2087 // arbitrary (?) directory does not seem to cause any sandbox
2088 // violation, while opendir() does. (Sorry I could not be bothered
2089 // to use some complex cross-platform abstraction over stat() here
2090 // in this macOS specific code block.)
2092 OUString aDirName;
2093 struct stat s;
2094 if( osl::FileBase::getSystemPathFromFileURL( aPath, aDirName ) == osl::FileBase::E_None &&
2095 stat(OUStringToOString( aDirName, RTL_TEXTENCODING_UTF8).getStr(), &s ) == 0 &&
2096 S_ISDIR( s.st_mode ) )
2097 return sal_True;
2098 #endif
2100 // HACK: create directory on a mount point with nobrowse option
2101 // returns ENOSYS in any case !!
2102 osl::Directory aDirectory( aPath );
2103 osl::FileBase::RC nError = aDirectory.open();
2104 aDirectory.close();
2106 if( nError == osl::File::E_None )
2107 return true;
2109 nError = osl::Directory::create( aPath );
2111 if( nError == osl::File::E_None )
2112 notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath );
2114 bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
2116 if( ! bSuccess )
2118 OUString aParentDir = getParentName( aPath );
2120 if ( aParentDir != aPath )
2121 { // Create first the parent directory
2122 bSuccess = ensuredir( CommandId,
2123 getParentName( aPath ),
2124 errorCode );
2126 // After parent directory structure exists try it one's more
2128 if ( bSuccess )
2129 { // Parent directory exists, retry creation of directory
2130 nError = osl::Directory::create( aPath );
2132 if( nError == osl::File::E_None )
2133 notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath );
2135 bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
2140 if( ! bSuccess )
2141 installError( CommandId,
2142 errorCode,
2143 nError );
2145 return bSuccess;
2149 // Given a sequence of properties seq, this method determines the mask
2150 // used to instantiate an osl::FileStatus, so that a call to
2151 // osl::DirectoryItem::getFileStatus fills the required fields.
2154 void
2155 TaskManager::getMaskFromProperties(
2156 sal_Int32& n_Mask,
2157 const uno::Sequence< beans::Property >& seq )
2159 n_Mask = 0;
2160 for(const auto& rProp : seq) {
2161 if(rProp.Name == Title)
2162 n_Mask |= osl_FileStatus_Mask_FileName;
2163 else if(rProp.Name == CasePreservingURL)
2164 n_Mask |= osl_FileStatus_Mask_FileURL;
2165 else if(rProp.Name == IsDocument ||
2166 rProp.Name == IsFolder ||
2167 rProp.Name == IsVolume ||
2168 rProp.Name == IsRemoveable ||
2169 rProp.Name == IsRemote ||
2170 rProp.Name == IsCompactDisc ||
2171 rProp.Name == IsFloppy ||
2172 rProp.Name == ContentType)
2173 n_Mask |= (osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL);
2174 else if(rProp.Name == Size)
2175 n_Mask |= (osl_FileStatus_Mask_FileSize |
2176 osl_FileStatus_Mask_Type |
2177 osl_FileStatus_Mask_LinkTargetURL);
2178 else if(rProp.Name == IsHidden ||
2179 rProp.Name == IsReadOnly)
2180 n_Mask |= osl_FileStatus_Mask_Attributes;
2181 else if(rProp.Name == DateModified)
2182 n_Mask |= osl_FileStatus_Mask_ModifyTime;
2187 /*********************************************************************************/
2188 /* */
2189 /* load-Implementation */
2190 /* */
2191 /*********************************************************************************/
2193 // Load the properties from configuration, if create == true create them.
2194 // The Properties are stored under the url belonging to it->first.
2197 void
2198 TaskManager::load( const ContentMap::iterator& it, bool create )
2200 if( ( it->second.xS.is() && it->second.xC.is() && it->second.xA.is() )
2201 || !m_xFileRegistry.is() )
2202 return;
2205 uno::Reference< ucb::XPersistentPropertySet > xS = m_xFileRegistry->openPropertySet( it->first,create );
2206 if( xS.is() )
2208 uno::Reference< beans::XPropertyContainer > xC( xS,uno::UNO_QUERY );
2209 uno::Reference< beans::XPropertyAccess > xA( xS,uno::UNO_QUERY );
2211 it->second.xS = xS;
2212 it->second.xC = xC;
2213 it->second.xA = xA;
2215 // Now put in all values in the storage in the local hash;
2217 PropertySet& properties = it->second.properties;
2218 const uno::Sequence< beans::Property > seq = xS->getPropertySetInfo()->getProperties();
2220 for( const auto& rProp : seq )
2222 MyProperty readProp( false,
2223 rProp.Name,
2224 rProp.Handle,
2225 rProp.Type,
2226 xS->getPropertyValue( rProp.Name ),
2227 beans::PropertyState_DIRECT_VALUE,
2228 rProp.Attributes );
2229 properties.insert( readProp );
2232 else if( create )
2234 // Catastrophic error
2239 /*********************************************************************************/
2240 /* */
2241 /* commit-Implementation */
2242 /* */
2243 /*********************************************************************************/
2244 // Commit inserts the determined properties in the filestatus object into
2245 // the internal map, so that is possible to determine on a subsequent
2246 // setting of file properties which properties have changed without filestat
2249 void
2250 TaskManager::commit( std::unique_lock<std::mutex>& rGuard,
2251 const TaskManager::ContentMap::iterator& it,
2252 const osl::FileStatus& aFileStatus )
2254 TaskManager::PropertySet::const_iterator it1;
2256 if( it->second.properties.empty() )
2258 OUString aPath = it->first;
2259 insertDefaultProperties( rGuard, aPath );
2262 PropertySet& properties = it->second.properties;
2264 it1 = properties.find( MyProperty( Title ) );
2265 if( it1 != properties.end() )
2267 if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) )
2269 it1->setValue( uno::Any(aFileStatus.getFileName()) );
2273 it1 = properties.find( MyProperty( CasePreservingURL ) );
2274 if( it1 != properties.end() )
2276 if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) )
2278 it1->setValue( uno::Any(aFileStatus.getFileURL()) );
2283 bool isDirectory;
2285 sal_Int64 dirSize = 0;
2287 if( aFileStatus.isValid( osl_FileStatus_Mask_FileSize ) )
2288 dirSize = aFileStatus.getFileSize();
2290 if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) )
2292 bool isFile,isVolume;
2293 if( osl::FileStatus::Link == aFileStatus.getFileType() &&
2294 aFileStatus.isValid( osl_FileStatus_Mask_LinkTargetURL ) )
2296 osl::DirectoryItem aDirItem;
2297 osl::FileStatus aFileStatus2( osl_FileStatus_Mask_Type );
2298 if( osl::FileBase::E_None == osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(),aDirItem ) &&
2299 osl::FileBase::E_None == aDirItem.getFileStatus( aFileStatus2 ) &&
2300 aFileStatus2.isValid( osl_FileStatus_Mask_Type ) )
2302 isVolume = osl::FileStatus::Volume == aFileStatus2.getFileType();
2303 isDirectory =
2304 osl::FileStatus::Volume == aFileStatus2.getFileType() ||
2305 osl::FileStatus::Directory == aFileStatus2.getFileType();
2306 isFile =
2307 osl::FileStatus::Regular == aFileStatus2.getFileType();
2309 if( aFileStatus2.isValid( osl_FileStatus_Mask_FileSize ) )
2310 dirSize = aFileStatus2.getFileSize();
2312 else
2314 // extremely ugly, but otherwise default construction
2315 // of aDirItem and aFileStatus2
2316 // before the preceding if
2317 isVolume = osl::FileStatus::Volume == aFileStatus.getFileType();
2318 isDirectory =
2319 osl::FileStatus::Volume == aFileStatus.getFileType() ||
2320 osl::FileStatus::Directory == aFileStatus.getFileType();
2321 isFile =
2322 osl::FileStatus::Regular == aFileStatus.getFileType();
2325 else
2327 isVolume = osl::FileStatus::Volume == aFileStatus.getFileType();
2328 isDirectory =
2329 osl::FileStatus::Volume == aFileStatus.getFileType() ||
2330 osl::FileStatus::Directory == aFileStatus.getFileType();
2331 isFile =
2332 osl::FileStatus::Regular == aFileStatus.getFileType();
2335 it1 = properties.find( MyProperty( IsVolume ) );
2336 if( it1 != properties.end() )
2337 it1->setValue( uno::Any( isVolume ) );
2339 it1 = properties.find( MyProperty( IsFolder ) );
2340 if( it1 != properties.end() )
2341 it1->setValue( uno::Any( isDirectory ) );
2343 it1 = properties.find( MyProperty( IsDocument ) );
2344 if( it1 != properties.end() )
2345 it1->setValue( uno::Any( isFile ) );
2347 osl::VolumeInfo aVolumeInfo( osl_VolumeInfo_Mask_Attributes );
2348 if( isVolume &&
2349 osl::FileBase::E_None == osl::Directory::getVolumeInfo( it->first,aVolumeInfo ) &&
2350 aVolumeInfo.isValid( osl_VolumeInfo_Mask_Attributes ) )
2352 // Retrieve the flags;
2353 bool isRemote = aVolumeInfo.getRemoteFlag();
2354 bool isRemoveable = aVolumeInfo.getRemoveableFlag();
2355 bool isCompactDisc = aVolumeInfo.getCompactDiscFlag();
2356 bool isFloppy = aVolumeInfo.getFloppyDiskFlag();
2358 it1 = properties.find( MyProperty( IsRemote ) );
2359 if( it1 != properties.end() )
2360 it1->setValue( uno::Any( isRemote ) );
2362 it1 = properties.find( MyProperty( IsRemoveable ) );
2363 if( it1 != properties.end() )
2364 it1->setValue( uno::Any( isRemoveable ) );
2366 it1 = properties.find( MyProperty( IsCompactDisc ) );
2367 if( it1 != properties.end() )
2368 it1->setValue( uno::Any( isCompactDisc ) );
2370 it1 = properties.find( MyProperty( IsFloppy ) );
2371 if( it1 != properties.end() )
2372 it1->setValue( uno::Any( isFloppy ) );
2374 else
2376 uno::Any aAny(false);
2377 it1 = properties.find( MyProperty( IsRemote ) );
2378 if( it1 != properties.end() )
2379 it1->setValue( aAny );
2381 it1 = properties.find( MyProperty( IsRemoveable ) );
2382 if( it1 != properties.end() )
2383 it1->setValue( aAny );
2385 it1 = properties.find( MyProperty( IsCompactDisc ) );
2386 if( it1 != properties.end() )
2387 it1->setValue( aAny );
2389 it1 = properties.find( MyProperty( IsFloppy ) );
2390 if( it1 != properties.end() )
2391 it1->setValue( aAny );
2394 else
2396 isDirectory = false;
2399 it1 = properties.find( MyProperty( Size ) );
2400 if( it1 != properties.end() )
2401 it1->setValue( uno::Any( dirSize ) );
2403 it1 = properties.find( MyProperty( IsReadOnly ) );
2404 if( it1 != properties.end() )
2406 if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
2408 sal_uInt64 Attr = aFileStatus.getAttributes();
2409 bool readonly = ( Attr & osl_File_Attribute_ReadOnly ) != 0;
2410 it1->setValue( uno::Any( readonly ) );
2414 it1 = properties.find( MyProperty( IsHidden ) );
2415 if( it1 != properties.end() )
2417 if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
2419 sal_uInt64 Attr = aFileStatus.getAttributes();
2420 bool ishidden = ( Attr & osl_File_Attribute_Hidden ) != 0;
2421 it1->setValue( uno::Any( ishidden ) );
2425 it1 = properties.find( MyProperty( DateModified ) );
2426 if( it1 != properties.end() )
2428 if( aFileStatus.isValid( osl_FileStatus_Mask_ModifyTime ) )
2430 TimeValue temp = aFileStatus.getModifyTime();
2432 // Convert system time to local time (for EA)
2433 TimeValue myLocalTime;
2434 if (!osl_getLocalTimeFromSystemTime( &temp, &myLocalTime ))
2436 SAL_WARN(
2437 "ucb.ucp.file",
2438 "cannot convert (" << temp.Seconds << ", " << temp.Nanosec
2439 << ") to local time");
2440 myLocalTime = temp;
2443 oslDateTime myDateTime;
2444 osl_getDateTimeFromTimeValue( &myLocalTime, &myDateTime );
2445 util::DateTime aDateTime;
2447 aDateTime.NanoSeconds = myDateTime.NanoSeconds;
2448 aDateTime.Seconds = myDateTime.Seconds;
2449 aDateTime.Minutes = myDateTime.Minutes;
2450 aDateTime.Hours = myDateTime.Hours;
2451 aDateTime.Day = myDateTime.Day;
2452 aDateTime.Month = myDateTime.Month;
2453 aDateTime.Year = myDateTime.Year;
2454 it1->setValue( uno::Any( aDateTime ) );
2458 it1 = properties.find( MyProperty( CreatableContentsInfo ) );
2459 if( it1 != properties.end() )
2460 it1->setValue( uno::Any(
2461 isDirectory || !aFileStatus.isValid( osl_FileStatus_Mask_Type )
2462 ? queryCreatableContentsInfo()
2463 : uno::Sequence< ucb::ContentInfo >() ) );
2467 // Special optimized method for getting the properties of a
2468 // directoryitem, which is returned by osl::DirectoryItem::getNextItem()
2471 bool
2472 TaskManager::getv(
2473 const uno::Sequence< beans::Property >& properties,
2474 osl::DirectoryItem& aDirItem,
2475 OUString& aUnqPath,
2476 bool& aIsRegular,
2477 uno::Reference< sdbc::XRow > & row )
2479 uno::Sequence< uno::Any > seq( properties.getLength() );
2481 sal_Int32 n_Mask;
2482 getMaskFromProperties( n_Mask,properties );
2484 // Always retrieve the type and the target URL because item might be a link
2485 osl::FileStatus aFileStatus( n_Mask |
2486 osl_FileStatus_Mask_FileURL |
2487 osl_FileStatus_Mask_Type |
2488 osl_FileStatus_Mask_LinkTargetURL );
2490 osl::FileBase::RC aRes = aDirItem.getFileStatus( aFileStatus );
2491 if ( aRes != osl::FileBase::E_None )
2493 SAL_WARN(
2494 "ucb.ucp.file",
2495 "osl::DirectoryItem::getFileStatus failed with " << +aRes);
2496 return false;
2499 aUnqPath = aFileStatus.getFileURL();
2501 // If the directory item type is a link retrieve the type of the target
2503 if ( aFileStatus.getFileType() == osl::FileStatus::Link )
2505 // Assume failure
2506 aIsRegular = false;
2507 osl::DirectoryItem aTargetItem;
2508 (void)osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(), aTargetItem );
2509 if ( aTargetItem.is() )
2511 osl::FileStatus aTargetStatus( osl_FileStatus_Mask_Type );
2513 if ( osl::FileBase::E_None == aTargetItem.getFileStatus( aTargetStatus ) )
2514 aIsRegular =
2515 aTargetStatus.getFileType() == osl::FileStatus::Regular;
2518 else
2519 aIsRegular = aFileStatus.getFileType() == osl::FileStatus::Regular;
2522 std::unique_lock aGuard( m_aMutex );
2524 insertDefaultProperties( aGuard, aUnqPath );
2526 TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath );
2527 commit( aGuard, it, aFileStatus );
2529 PropertySet& propset = it->second.properties;
2531 std::transform(properties.begin(), properties.end(), seq.getArray(),
2532 [&propset](const beans::Property& rProp) -> uno::Any {
2533 MyProperty readProp( rProp.Name );
2534 auto it1 = propset.find( readProp );
2535 if( it1 == propset.end() )
2536 return uno::Any();
2537 return it1->getValue();
2541 row = new XRow_impl( this,seq );
2542 return true;
2546 // EventListener
2549 std::vector< ContentEventNotifier >
2550 TaskManager::getContentEventListeners( const OUString& aName )
2552 std::vector< ContentEventNotifier > listeners;
2554 std::unique_lock aGuard( m_aMutex );
2555 TaskManager::ContentMap::iterator it = m_aContent.find( aName );
2556 if( it != m_aContent.end() && !it->second.notifier.empty() )
2558 std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
2559 for (auto const& pointer : listOfNotifiers)
2561 std::optional<ContentEventNotifier> notifier = pointer->cCEL();
2562 if( notifier )
2563 listeners.push_back( std::move(*notifier) );
2567 return listeners;
2571 std::vector< ContentEventNotifier >
2572 TaskManager::getContentDeletedEventListeners( const OUString& aName )
2574 std::vector< ContentEventNotifier > listeners;
2576 std::unique_lock aGuard( m_aMutex );
2577 TaskManager::ContentMap::iterator it = m_aContent.find( aName );
2578 if( it != m_aContent.end() && !it->second.notifier.empty() )
2580 std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
2581 for (auto const& pointer : listOfNotifiers)
2583 std::optional<ContentEventNotifier> notifier = pointer->cDEL();
2584 if( notifier )
2585 listeners.push_back( std::move(*notifier) );
2589 return listeners;
2592 void TaskManager::notifyInsert(const std::vector<ContentEventNotifier>& listeners,
2593 const OUString& aChildName)
2595 for (const auto & l : listeners )
2597 l.notifyChildInserted( aChildName );
2601 void TaskManager::notifyContentDeleted(
2602 const std::vector<ContentEventNotifier>& listeners)
2604 for( auto const & l : listeners )
2606 l.notifyDeleted();
2610 void TaskManager::notifyContentRemoved(
2611 const std::vector<ContentEventNotifier>& listeners, const OUString& aChildName)
2613 for( auto const & l : listeners )
2615 l.notifyRemoved( aChildName );
2620 std::vector< PropertySetInfoChangeNotifier >
2621 TaskManager::getPropertySetListeners( const OUString& aName )
2623 std::vector< PropertySetInfoChangeNotifier > listeners;
2625 std::unique_lock aGuard( m_aMutex );
2626 TaskManager::ContentMap::iterator it = m_aContent.find( aName );
2627 if( it != m_aContent.end() && !it->second.notifier.empty() )
2629 std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
2630 for (auto const& pointer : listOfNotifiers)
2632 std::optional<PropertySetInfoChangeNotifier> notifier = pointer->cPSL();
2633 if( notifier )
2634 listeners.push_back( std::move(*notifier) );
2638 return listeners;
2641 void TaskManager::notifyPropertyAdded(
2642 const std::vector<PropertySetInfoChangeNotifier>& listeners,
2643 const OUString& aPropertyName)
2645 for( auto const & l : listeners )
2647 l.notifyPropertyAdded( aPropertyName );
2651 void TaskManager::notifyPropertyRemoved(
2652 const std::vector<PropertySetInfoChangeNotifier>& listeners,
2653 const OUString& aPropertyName)
2655 for( auto const & l : listeners )
2657 l.notifyPropertyRemoved( aPropertyName );
2662 std::vector< ContentEventNotifier >
2663 TaskManager::getContentExchangedEventListeners( const OUString& aOldPrefix,
2664 const OUString& aNewPrefix,
2665 bool withChildren )
2667 std::vector< ContentEventNotifier > aVector;
2669 sal_Int32 count;
2670 OUString aOldName;
2671 OUString aNewName;
2672 std::vector< OUString > oldChildList;
2675 std::unique_lock aGuard( m_aMutex );
2677 if( ! withChildren )
2679 aOldName = aOldPrefix;
2680 aNewName = aNewPrefix;
2681 count = 1;
2683 else
2685 for (auto const& content : m_aContent)
2687 if( isChild( aOldPrefix, content.first ) )
2689 oldChildList.push_back( content.first );
2692 count = oldChildList.size();
2696 for( sal_Int32 j = 0; j < count; ++j )
2698 if( withChildren )
2700 aOldName = oldChildList[j];
2701 aNewName = newName( aNewPrefix,aOldPrefix,aOldName );
2704 TaskManager::ContentMap::iterator itold = m_aContent.find( aOldName );
2705 if( itold != m_aContent.end() )
2707 TaskManager::ContentMap::iterator itnew = m_aContent.emplace(
2708 aNewName,UnqPathData() ).first;
2710 // copy Ownership also
2711 itnew->second.properties = std::move(itold->second.properties);
2713 // copy existing list
2714 std::vector< Notifier* > copyList;
2715 std::swap(copyList, itnew->second.notifier);
2716 itnew->second.notifier = std::move(itold->second.notifier);
2718 m_aContent.erase( itold );
2720 if (itnew != m_aContent.end())
2722 if (!itnew->second.notifier.empty())
2724 std::vector<Notifier*>& listOfNotifiers = itnew->second.notifier;
2725 for (auto const& pointer : listOfNotifiers)
2727 std::optional<ContentEventNotifier> notifier = pointer->cEXC( aNewName );
2728 if( notifier )
2729 aVector.push_back( std::move(*notifier) );
2733 // Merge with preexisting notifiers
2734 // However, these may be in status BaseContent::Deleted
2735 itnew->second.notifier.insert(itnew->second.notifier.end(),
2736 copyList.begin(), copyList.end() );
2742 return aVector;
2745 void TaskManager::notifyContentExchanged(
2746 const std::vector<ContentEventNotifier>& listeners_vec)
2748 for( auto & l : listeners_vec)
2750 l.notifyExchanged();
2755 std::vector< PropertyChangeNotifier >
2756 TaskManager::getPropertyChangeNotifier( const OUString& aName )
2758 std::vector< PropertyChangeNotifier > listeners;
2760 std::unique_lock aGuard( m_aMutex );
2761 TaskManager::ContentMap::iterator it = m_aContent.find( aName );
2762 if( it != m_aContent.end() && !it->second.notifier.empty() )
2764 std::vector<Notifier*>& listOfNotifiers = it->second.notifier;
2765 for (auto const& pointer : listOfNotifiers)
2767 std::optional<PropertyChangeNotifier> notifier = pointer->cPCL();
2768 if( notifier )
2769 listeners.push_back( std::move(*notifier) );
2773 return listeners;
2776 void TaskManager::notifyPropertyChanges(
2777 const std::vector<PropertyChangeNotifier>& listeners,
2778 const uno::Sequence<beans::PropertyChangeEvent>& seqChanged)
2780 for( auto const & l : listeners )
2782 l.notifyPropertyChanged( seqChanged );
2787 /********************************************************************************/
2788 /* remove persistent propertyset */
2789 /********************************************************************************/
2791 void
2792 TaskManager::erasePersistentSetWithoutChildren( const OUString& aUnqPath )
2795 // Release possible references
2796 std::unique_lock aGuard( m_aMutex );
2797 ContentMap::iterator it = m_aContent.find( aUnqPath );
2798 if( it != m_aContent.end() )
2800 it->second.xS = nullptr;
2801 it->second.xC = nullptr;
2802 it->second.xA = nullptr;
2804 it->second.properties.clear();
2808 m_xFileRegistry->removePropertySet( aUnqPath );
2811 void
2812 TaskManager::erasePersistentSet( const OUString& aUnqPath,
2813 bool withChildren )
2815 if( ! m_xFileRegistry.is() )
2817 OSL_ASSERT( m_xFileRegistry.is() );
2818 return;
2821 if( ! withChildren )
2823 erasePersistentSetWithoutChildren(aUnqPath);
2824 return;
2827 uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY );
2828 const uno::Sequence< OUString > seqNames = xName->getElementNames();
2830 OUString old_Name = aUnqPath;
2832 for( const auto& rName : seqNames )
2834 if( ! ( isChild( old_Name,rName ) ) )
2835 continue;
2837 old_Name = rName;
2839 erasePersistentSetWithoutChildren(old_Name);
2844 /********************************************************************************/
2845 /* copy persistent propertyset */
2846 /* from srcUnqPath to dstUnqPath */
2847 /********************************************************************************/
2849 void
2850 TaskManager::copyPersistentSetWithoutChildren( const OUString& srcUnqPath,
2851 const OUString& dstUnqPath )
2853 uno::Reference< XPersistentPropertySet > x_src =
2854 m_xFileRegistry->openPropertySet( srcUnqPath,false );
2855 m_xFileRegistry->removePropertySet( dstUnqPath );
2857 if( ! x_src.is() )
2858 return;
2860 const uno::Sequence< beans::Property > seqProperty =
2861 x_src->getPropertySetInfo()->getProperties();
2863 if( ! seqProperty.hasElements() )
2864 return;
2866 uno::Reference< XPersistentPropertySet >
2867 x_dstS = m_xFileRegistry->openPropertySet( dstUnqPath,true );
2868 uno::Reference< beans::XPropertyContainer >
2869 x_dstC( x_dstS,uno::UNO_QUERY );
2871 for( const auto& rProperty : seqProperty )
2873 x_dstC->addProperty( rProperty.Name,
2874 rProperty.Attributes,
2875 x_src->getPropertyValue( rProperty.Name ) );
2879 void
2880 TaskManager::copyPersistentSet( const OUString& srcUnqPath,
2881 const OUString& dstUnqPath,
2882 bool withChildren )
2884 if( ! m_xFileRegistry.is() )
2886 OSL_ASSERT( m_xFileRegistry.is() );
2887 return;
2890 if( ! withChildren )
2892 copyPersistentSetWithoutChildren(srcUnqPath, dstUnqPath);
2893 return;
2896 uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY );
2897 const uno::Sequence< OUString > seqNames = xName->getElementNames();
2899 OUString new_Name;
2901 for( const auto& rName : seqNames )
2903 if( ! ( isChild( srcUnqPath,rName ) ) )
2904 continue;
2906 new_Name = newName( dstUnqPath,srcUnqPath,rName );
2908 copyPersistentSetWithoutChildren(rName, new_Name);
2912 uno::Sequence< ucb::ContentInfo > TaskManager::queryCreatableContentsInfo()
2916 uno::Sequence< beans::Property > props
2918 { "Title", -1, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND }
2920 return
2922 { FileContentType, ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ucb::ContentInfoAttribute::KIND_DOCUMENT, props },
2923 { FolderContentType, ucb::ContentInfoAttribute::KIND_FOLDER, props }
2927 /*******************************************************************************/
2928 /* */
2929 /* some miscellaneous static functions */
2930 /* */
2931 /*******************************************************************************/
2933 void
2934 TaskManager::getScheme( OUString& Scheme )
2936 Scheme = "file";
2939 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */