LibreOffice Module svl (master) 1
sharecontrolfile.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
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>
27
28#include <o3tl/enumrange.hxx>
29
30#include <rtl/string.hxx>
31#include <rtl/ustring.hxx>
32#include <rtl/ustrbuf.hxx>
33
35#include <ucbhelper/content.hxx>
36
37#include <tools/stream.hxx>
39
41
42using namespace ::com::sun::star;
43
44namespace svt {
45
46
47ShareControlFile::ShareControlFile( std::u16string_view aOrigURL )
48 : LockFileCommon(GenerateOwnLockFileURL(aOrigURL, u".~sharing."))
49{
50 if ( !m_xStream.is() && !GetURL().isEmpty() )
51 {
52 uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
54
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
58
59 uno::Reference< io::XStream > xStream;
60
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?
64
65 try
66 {
68 }
69 catch ( ucb::InteractiveIOException const & e )
70 {
71 if ( e.Code == ucb::IOErrorCode_NOT_EXISTING )
72 {
73 // Create file...
74 SvMemoryStream aStream(0,0);
75 uno::Reference< io::XInputStream > xInput( new ::utl::OInputStreamWrapper( aStream ) );
76 ucb::InsertCommandArgument aInsertArg;
77 aInsertArg.Data = xInput;
78 aInsertArg.ReplaceExisting = false;
79 aContent.executeCommand( "insert", uno::Any( aInsertArg ) );
80
81 // try to let the file be hidden if possible
82 try {
83 aContent.setPropertyValue("IsHidden", uno::Any( true ) );
84 } catch( uno::Exception& ) {}
85
86 // Try to open one more time
88 }
89 else
90 throw;
91 }
92
93 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
94 m_xInputStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
95 m_xOutputStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
96 m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY_THROW );
98 }
99
100 if ( !IsValid() )
101 throw io::NotConnectedException();
102}
103
105{
106 try
107 {
108 Close();
109 }
110 catch( uno::Exception& )
111 {}
112}
113
115{
116 // if it is called outside of destructor the mutex must be locked
117
118 if ( !m_xStream.is() )
119 return;
120
121 try
122 {
123 if ( m_xInputStream.is() )
124 m_xInputStream->closeInput();
125 if ( m_xOutputStream.is() )
126 m_xOutputStream->closeOutput();
127 }
128 catch( uno::Exception& )
129 {}
130
131 m_xStream.clear();
132 m_xInputStream.clear();
133 m_xOutputStream.clear();
134 m_xSeekable.clear();
135 m_xTruncate.clear();
136 m_aUsersData.clear();
137}
138
139
140std::vector< o3tl::enumarray< LockFileComponent, OUString > > ShareControlFile::GetUsersData()
141{
142 std::unique_lock aGuard(m_aMutex);
143 return GetUsersDataImpl(aGuard);
144}
145
146std::vector< o3tl::enumarray< LockFileComponent, OUString > > ShareControlFile::GetUsersDataImpl(std::unique_lock<std::mutex>& /*rGuard*/)
147{
148 if ( !IsValid() )
149 throw io::NotConnectedException();
150
151 if ( m_aUsersData.empty() )
152 {
153 sal_Int64 nLength = m_xSeekable->getLength();
154 if ( nLength > SAL_MAX_INT32 )
155 throw uno::RuntimeException();
156
157 uno::Sequence< sal_Int8 > aBuffer( static_cast<sal_Int32>(nLength) );
158 m_xSeekable->seek( 0 );
159
160 sal_Int32 nRead = m_xInputStream->readBytes( aBuffer, static_cast<sal_Int32>(nLength) );
161 auto aBufferRange = asNonConstRange(aBuffer);
162 nLength -= nRead;
163 while ( nLength > 0 )
164 {
165 uno::Sequence< sal_Int8 > aTmpBuf( static_cast<sal_Int32>(nLength) );
166 nRead = m_xInputStream->readBytes( aTmpBuf, static_cast<sal_Int32>(nLength) );
167 if ( nRead > nLength )
168 throw uno::RuntimeException();
169
170 for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
171 aBufferRange[aBuffer.getLength() - static_cast<sal_Int32>(nLength) + nInd] = aTmpBuf[nInd];
172 nLength -= nRead;
173 }
174
176 }
177
178 return m_aUsersData;
179}
180
181
182void ShareControlFile::SetUsersDataAndStore( std::unique_lock<std::mutex>& /*rGuard*/, std::vector< LockFileEntry >&& aUsersData )
183{
184 if ( !IsValid() )
185 throw io::NotConnectedException();
186
187 if ( !m_xTruncate.is() || !m_xOutputStream.is() || !m_xSeekable.is() )
188 throw uno::RuntimeException();
189
190 m_xTruncate->truncate();
191 m_xSeekable->seek( 0 );
192
193 OUStringBuffer aBuffer;
194 for (const auto & rData : aUsersData)
195 {
197 {
198 aBuffer.append( EscapeCharacters( rData[nEntryInd] ) );
199 if ( nEntryInd < LockFileComponent::LAST )
200 aBuffer.append( ',' );
201 else
202 aBuffer.append( ';' );
203 }
204 }
205
206 OString aStringData( OUStringToOString( aBuffer, RTL_TEXTENCODING_UTF8 ) );
207 uno::Sequence< sal_Int8 > aData( reinterpret_cast<sal_Int8 const *>(aStringData.getStr()), aStringData.getLength() );
208 m_xOutputStream->writeBytes( aData );
209 m_aUsersData = aUsersData;
210}
211
212
214{
215 std::unique_lock aGuard( m_aMutex );
216
217 if ( !IsValid() )
218 throw io::NotConnectedException();
219
220 GetUsersDataImpl(aGuard);
221 std::vector< LockFileEntry > aNewData( m_aUsersData );
222 LockFileEntry aNewEntry = GenerateOwnEntry();
223
224 bool bExists = false;
225 sal_Int32 nNewInd = 0;
226 for (LockFileEntry & rEntry : m_aUsersData)
227 {
231 {
232 if ( !bExists )
233 {
234 aNewData[nNewInd] = aNewEntry;
235 bExists = true;
236 }
237 }
238 else
239 {
240 aNewData[nNewInd] = rEntry;
241 }
242
243 nNewInd++;
244 }
245
246 if ( !bExists )
247 aNewData.push_back( aNewEntry );
248
249 SetUsersDataAndStore( aGuard, std::move(aNewData) );
250
251 return aNewEntry;
252}
253
254
256{
257 std::unique_lock aGuard( m_aMutex );
258
259 if ( !IsValid() )
260 {
261 throw io::NotConnectedException();
262 }
263
264 GetUsersDataImpl(aGuard);
266
267 for (LockFileEntry & rEntry : m_aUsersData)
268 {
272 {
273 return true;
274 }
275 }
276
277 return false;
278}
279
280
282{
284}
285
287{
288 std::unique_lock aGuard( m_aMutex );
289
290 if ( !IsValid() )
291 throw io::NotConnectedException();
292
293 GetUsersDataImpl(aGuard);
294
295 std::vector< LockFileEntry > aNewData;
296
297 for (LockFileEntry & rEntry : m_aUsersData)
298 {
302 {
303 aNewData.push_back( rEntry );
304 }
305 }
306
307 const bool bNewDataEmpty = aNewData.empty();
308 SetUsersDataAndStore( aGuard, std::move(aNewData) );
309
310 if ( bNewDataEmpty )
311 {
312 // try to remove the file if it is empty
313 RemoveFileImpl(aGuard);
314 }
315}
316
317
319{
320 std::unique_lock aGuard(m_aMutex);
321 return RemoveFileImpl(aGuard);
322}
323
324void ShareControlFile::RemoveFileImpl(std::unique_lock<std::mutex>& /*rGuard*/)
325{
326 if ( !IsValid() )
327 throw io::NotConnectedException();
328
329 Close();
330
331 uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
332 xSimpleFileAccess->kill( GetURL() );
333}
334
335} // namespace svt
336
337/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
This is a general implementation that is used in document lock file implementation and in sharing con...
static LockFileEntry GenerateOwnEntry()
static OUString EscapeCharacters(const OUString &aSource)
const OUString & GetURL() const
static void ParseList(const css::uno::Sequence< sal_Int8 > &aBuffer, std::vector< LockFileEntry > &rOutput)
std::vector< LockFileEntry > GetUsersData()
css::uno::Reference< css::io::XStream > m_xStream
css::uno::Reference< css::io::XSeekable > m_xSeekable
css::uno::Reference< css::io::XOutputStream > m_xOutputStream
css::uno::Reference< css::io::XTruncate > m_xTruncate
LockFileEntry InsertOwnEntry()
std::vector< LockFileEntry > m_aUsersData
void RemoveFileImpl(std::unique_lock< std::mutex > &rGuard)
ShareControlFile(std::u16string_view aOrigURL)
virtual ~ShareControlFile() override
css::uno::Reference< css::io::XInputStream > m_xInputStream
std::vector< LockFileEntry > GetUsersDataImpl(std::unique_lock< std::mutex > &rGuard)
void SetUsersDataAndStore(std::unique_lock< std::mutex > &rGuard, std::vector< LockFileEntry > &&aUserNames)
css::uno::Any setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue)
css::uno::Any executeCommand(const OUString &rCommandName, const css::uno::Any &rCommandArgument)
css::uno::Reference< css::io::XStream > openWriteableStreamNoLock()
css::uno::Reference< css::ucb::XContent > get() const
float u
LockFileComponent
constexpr OUStringLiteral aData
Reference< XComponentContext > getProcessComponentContext()
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
#define SAL_MAX_INT32
signed char sal_Int8
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength