1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
22 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
23 #include <com/sun/star/ucb/XContent.hpp>
24 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
25 #include <com/sun/star/ucb/InteractiveIOException.hpp>
26 #include <com/sun/star/io/NotConnectedException.hpp>
28 #include <o3tl/enumrange.hxx>
30 #include <rtl/string.hxx>
31 #include <rtl/ustring.hxx>
32 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <ucbhelper/content.hxx>
37 #include <tools/stream.hxx>
38 #include <unotools/streamwrap.hxx>
40 #include <svl/sharecontrolfile.hxx>
42 using namespace ::com::sun::star
;
47 ShareControlFile::ShareControlFile( std::u16string_view aOrigURL
)
48 : LockFileCommon(GenerateOwnLockFileURL(aOrigURL
, u
".~sharing."))
50 if ( !m_xStream
.is() && !GetURL().isEmpty() )
52 uno::Reference
< ucb::XCommandEnvironment
> xDummyEnv
;
53 ::ucbhelper::Content
aContent( GetURL(), xDummyEnv
, comphelper::getProcessComponentContext() );
55 uno::Reference
< ucb::XContentIdentifier
> xContId( aContent
.get().is() ? aContent
.get()->getIdentifier() : nullptr );
56 if ( !xContId
.is() || xContId
->getContentProviderScheme() != "file" )
57 throw io::IOException(); // the implementation supports only local files for now
59 uno::Reference
< io::XStream
> xStream
;
61 // Currently the locking of the original document is intended to be used.
62 // That means that the shared file should be accessed only when the original document is locked and only by user who has locked the document.
63 // TODO/LATER: should the own file locking be used?
67 xStream
= aContent
.openWriteableStreamNoLock();
69 catch ( ucb::InteractiveIOException
const & e
)
71 if ( e
.Code
== ucb::IOErrorCode_NOT_EXISTING
)
74 ucb::InsertCommandArgument aInsertArg
;
75 SvMemoryStream
aStream(0,0);
76 aInsertArg
.Data
.set(new ::utl::OInputStreamWrapper(aStream
));
77 aInsertArg
.ReplaceExisting
= false;
78 aContent
.executeCommand( u
"insert"_ustr
, uno::Any( aInsertArg
) );
80 // try to let the file be hidden if possible
82 aContent
.setPropertyValue(u
"IsHidden"_ustr
, uno::Any( true ) );
83 } catch( uno::Exception
& ) {}
85 // Try to open one more time
86 xStream
= aContent
.openWriteableStreamNoLock();
92 m_xSeekable
.set( xStream
, uno::UNO_QUERY_THROW
);
93 m_xInputStream
.set( xStream
->getInputStream(), uno::UNO_SET_THROW
);
94 m_xOutputStream
.set( xStream
->getOutputStream(), uno::UNO_SET_THROW
);
95 m_xTruncate
.set( m_xOutputStream
, uno::UNO_QUERY_THROW
);
96 m_xStream
= std::move(xStream
);
100 throw io::NotConnectedException();
103 ShareControlFile::~ShareControlFile()
109 catch( uno::Exception
& )
113 void ShareControlFile::Close()
115 // if it is called outside of destructor the mutex must be locked
117 if ( !m_xStream
.is() )
122 if ( m_xInputStream
.is() )
123 m_xInputStream
->closeInput();
124 if ( m_xOutputStream
.is() )
125 m_xOutputStream
->closeOutput();
127 catch( uno::Exception
& )
131 m_xInputStream
.clear();
132 m_xOutputStream
.clear();
135 m_aUsersData
.clear();
139 std::vector
< o3tl::enumarray
< LockFileComponent
, OUString
> > ShareControlFile::GetUsersData()
141 std::unique_lock
aGuard(m_aMutex
);
142 return GetUsersDataImpl(aGuard
);
145 const std::vector
< o3tl::enumarray
< LockFileComponent
, OUString
> > & ShareControlFile::GetUsersDataImpl(std::unique_lock
<std::mutex
>& /*rGuard*/)
148 throw io::NotConnectedException();
150 if ( m_aUsersData
.empty() )
152 sal_Int64 nLength
= m_xSeekable
->getLength();
153 if (nLength
> SAL_MAX_INT32
|| nLength
< 0)
154 throw uno::RuntimeException();
156 uno::Sequence
< sal_Int8
> aBuffer( static_cast<sal_Int32
>(nLength
) );
157 m_xSeekable
->seek( 0 );
159 sal_Int32 nRead
= m_xInputStream
->readBytes( aBuffer
, static_cast<sal_Int32
>(nLength
) );
160 auto aBufferRange
= asNonConstRange(aBuffer
);
162 while ( nLength
> 0 )
164 uno::Sequence
< sal_Int8
> aTmpBuf( static_cast<sal_Int32
>(nLength
) );
165 nRead
= m_xInputStream
->readBytes( aTmpBuf
, static_cast<sal_Int32
>(nLength
) );
166 if ( nRead
> nLength
)
167 throw uno::RuntimeException();
169 for ( sal_Int32 nInd
= 0; nInd
< nRead
; nInd
++ )
170 aBufferRange
[aBuffer
.getLength() - static_cast<sal_Int32
>(nLength
) + nInd
] = aTmpBuf
[nInd
];
174 ParseList( aBuffer
, m_aUsersData
);
180 void ShareControlFile::SetUsersDataAndStore( std::unique_lock
<std::mutex
>& /*rGuard*/, std::vector
< LockFileEntry
>&& aUsersData
)
183 throw io::NotConnectedException();
185 if ( !m_xTruncate
.is() || !m_xOutputStream
.is() || !m_xSeekable
.is() )
186 throw uno::RuntimeException();
188 m_xTruncate
->truncate();
189 m_xSeekable
->seek( 0 );
191 OUStringBuffer aBuffer
;
192 for (const auto & rData
: aUsersData
)
194 for ( LockFileComponent nEntryInd
: o3tl::enumrange
<LockFileComponent
>() )
196 aBuffer
.append( EscapeCharacters( rData
[nEntryInd
] ) );
197 if ( nEntryInd
< LockFileComponent::LAST
)
198 aBuffer
.append( ',' );
200 aBuffer
.append( ';' );
204 OString
aStringData( OUStringToOString( aBuffer
, RTL_TEXTENCODING_UTF8
) );
205 uno::Sequence
< sal_Int8
> aData( reinterpret_cast<sal_Int8
const *>(aStringData
.getStr()), aStringData
.getLength() );
206 m_xOutputStream
->writeBytes( aData
);
207 m_aUsersData
= std::move(aUsersData
);
210 LockFileEntry
ShareControlFile::InsertOwnEntry()
212 std::unique_lock
aGuard( m_aMutex
);
215 throw io::NotConnectedException();
217 GetUsersDataImpl(aGuard
);
218 std::vector
< LockFileEntry
> aNewData( m_aUsersData
);
219 LockFileEntry aNewEntry
= GenerateOwnEntry();
221 bool bExists
= false;
222 sal_Int32 nNewInd
= 0;
223 for (LockFileEntry
& rEntry
: m_aUsersData
)
225 if ( rEntry
[LockFileComponent::LOCALHOST
] == aNewEntry
[LockFileComponent::LOCALHOST
]
226 && rEntry
[LockFileComponent::SYSUSERNAME
] == aNewEntry
[LockFileComponent::SYSUSERNAME
]
227 && rEntry
[LockFileComponent::USERURL
] == aNewEntry
[LockFileComponent::USERURL
] )
231 aNewData
[nNewInd
] = aNewEntry
;
237 aNewData
[nNewInd
] = rEntry
;
244 aNewData
.push_back( aNewEntry
);
246 SetUsersDataAndStore( aGuard
, std::move(aNewData
) );
252 bool ShareControlFile::HasOwnEntry()
254 std::unique_lock
aGuard( m_aMutex
);
258 throw io::NotConnectedException();
261 GetUsersDataImpl(aGuard
);
262 LockFileEntry aEntry
= GenerateOwnEntry();
264 for (LockFileEntry
& rEntry
: m_aUsersData
)
266 if ( rEntry
[LockFileComponent::LOCALHOST
] == aEntry
[LockFileComponent::LOCALHOST
] &&
267 rEntry
[LockFileComponent::SYSUSERNAME
] == aEntry
[LockFileComponent::SYSUSERNAME
] &&
268 rEntry
[LockFileComponent::USERURL
] == aEntry
[LockFileComponent::USERURL
] )
278 void ShareControlFile::RemoveEntry()
280 RemoveEntry(GenerateOwnEntry());
283 void ShareControlFile::RemoveEntry( const LockFileEntry
& aEntry
)
285 std::unique_lock
aGuard( m_aMutex
);
288 throw io::NotConnectedException();
290 GetUsersDataImpl(aGuard
);
292 std::vector
< LockFileEntry
> aNewData
;
294 for (LockFileEntry
& rEntry
: m_aUsersData
)
296 if ( rEntry
[LockFileComponent::LOCALHOST
] != aEntry
[LockFileComponent::LOCALHOST
]
297 || rEntry
[LockFileComponent::SYSUSERNAME
] != aEntry
[LockFileComponent::SYSUSERNAME
]
298 || rEntry
[LockFileComponent::USERURL
] != aEntry
[LockFileComponent::USERURL
] )
300 aNewData
.push_back( rEntry
);
304 const bool bNewDataEmpty
= aNewData
.empty();
305 SetUsersDataAndStore( aGuard
, std::move(aNewData
) );
309 // try to remove the file if it is empty
310 RemoveFileImpl(aGuard
);
315 void ShareControlFile::RemoveFile()
317 std::unique_lock
aGuard(m_aMutex
);
318 return RemoveFileImpl(aGuard
);
321 void ShareControlFile::RemoveFileImpl(std::unique_lock
<std::mutex
>& /*rGuard*/)
324 throw io::NotConnectedException();
328 uno::Reference
<ucb::XSimpleFileAccess3
> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
329 xSimpleFileAccess
->kill( GetURL() );
334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */