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 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
) );
81 // try to let the file be hidden if possible
83 aContent
.setPropertyValue("IsHidden", uno::Any( true ) );
84 } catch( uno::Exception
& ) {}
86 // Try to open one more time
87 xStream
= aContent
.openWriteableStreamNoLock();
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
);
101 throw io::NotConnectedException();
104 ShareControlFile::~ShareControlFile()
110 catch( uno::Exception
& )
114 void ShareControlFile::Close()
116 // if it is called outside of destructor the mutex must be locked
118 if ( !m_xStream
.is() )
123 if ( m_xInputStream
.is() )
124 m_xInputStream
->closeInput();
125 if ( m_xOutputStream
.is() )
126 m_xOutputStream
->closeOutput();
128 catch( uno::Exception
& )
132 m_xInputStream
.clear();
133 m_xOutputStream
.clear();
136 m_aUsersData
.clear();
140 std::vector
< o3tl::enumarray
< LockFileComponent
, OUString
> > ShareControlFile::GetUsersData()
142 ::osl::MutexGuard
aGuard( m_aMutex
);
145 throw io::NotConnectedException();
147 if ( m_aUsersData
.empty() )
149 sal_Int64 nLength
= m_xSeekable
->getLength();
150 if ( nLength
> SAL_MAX_INT32
)
151 throw uno::RuntimeException();
153 uno::Sequence
< sal_Int8
> aBuffer( static_cast<sal_Int32
>(nLength
) );
154 m_xSeekable
->seek( 0 );
156 sal_Int32 nRead
= m_xInputStream
->readBytes( aBuffer
, static_cast<sal_Int32
>(nLength
) );
157 auto aBufferRange
= asNonConstRange(aBuffer
);
159 while ( nLength
> 0 )
161 uno::Sequence
< sal_Int8
> aTmpBuf( static_cast<sal_Int32
>(nLength
) );
162 nRead
= m_xInputStream
->readBytes( aTmpBuf
, static_cast<sal_Int32
>(nLength
) );
163 if ( nRead
> nLength
)
164 throw uno::RuntimeException();
166 for ( sal_Int32 nInd
= 0; nInd
< nRead
; nInd
++ )
167 aBufferRange
[aBuffer
.getLength() - static_cast<sal_Int32
>(nLength
) + nInd
] = aTmpBuf
[nInd
];
171 ParseList( aBuffer
, m_aUsersData
);
178 void ShareControlFile::SetUsersDataAndStore( std::vector
< LockFileEntry
>&& aUsersData
)
180 ::osl::MutexGuard
aGuard( m_aMutex
);
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
= aUsersData
;
211 LockFileEntry
ShareControlFile::InsertOwnEntry()
213 ::osl::MutexGuard
aGuard( m_aMutex
);
216 throw io::NotConnectedException();
219 std::vector
< LockFileEntry
> aNewData( m_aUsersData
);
220 LockFileEntry aNewEntry
= GenerateOwnEntry();
222 bool bExists
= false;
223 sal_Int32 nNewInd
= 0;
224 for (LockFileEntry
& rEntry
: m_aUsersData
)
226 if ( rEntry
[LockFileComponent::LOCALHOST
] == aNewEntry
[LockFileComponent::LOCALHOST
]
227 && rEntry
[LockFileComponent::SYSUSERNAME
] == aNewEntry
[LockFileComponent::SYSUSERNAME
]
228 && rEntry
[LockFileComponent::USERURL
] == aNewEntry
[LockFileComponent::USERURL
] )
232 aNewData
[nNewInd
] = aNewEntry
;
238 aNewData
[nNewInd
] = rEntry
;
245 aNewData
.push_back( aNewEntry
);
247 SetUsersDataAndStore( std::move(aNewData
) );
253 bool ShareControlFile::HasOwnEntry()
255 ::osl::MutexGuard
aGuard( m_aMutex
);
259 throw io::NotConnectedException();
263 LockFileEntry aEntry
= GenerateOwnEntry();
265 for (LockFileEntry
& rEntry
: m_aUsersData
)
267 if ( rEntry
[LockFileComponent::LOCALHOST
] == aEntry
[LockFileComponent::LOCALHOST
] &&
268 rEntry
[LockFileComponent::SYSUSERNAME
] == aEntry
[LockFileComponent::SYSUSERNAME
] &&
269 rEntry
[LockFileComponent::USERURL
] == aEntry
[LockFileComponent::USERURL
] )
279 void ShareControlFile::RemoveEntry()
281 RemoveEntry(GenerateOwnEntry());
284 void ShareControlFile::RemoveEntry( const LockFileEntry
& aEntry
)
286 ::osl::MutexGuard
aGuard( m_aMutex
);
289 throw io::NotConnectedException();
293 std::vector
< LockFileEntry
> aNewData
;
295 for (LockFileEntry
& rEntry
: m_aUsersData
)
297 if ( rEntry
[LockFileComponent::LOCALHOST
] != aEntry
[LockFileComponent::LOCALHOST
]
298 || rEntry
[LockFileComponent::SYSUSERNAME
] != aEntry
[LockFileComponent::SYSUSERNAME
]
299 || rEntry
[LockFileComponent::USERURL
] != aEntry
[LockFileComponent::USERURL
] )
301 aNewData
.push_back( rEntry
);
305 const bool bNewDataEmpty
= aNewData
.empty();
306 SetUsersDataAndStore( std::move(aNewData
) );
310 // try to remove the file if it is empty
316 void ShareControlFile::RemoveFile()
318 ::osl::MutexGuard
aGuard( m_aMutex
);
321 throw io::NotConnectedException();
325 uno::Reference
<ucb::XSimpleFileAccess3
> xSimpleFileAccess(ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()));
326 xSimpleFileAccess
->kill( GetURL() );
331 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */