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/XSimpleFileAccess.hpp>
22 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
23 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
24 #include <com/sun/star/ucb/NameClashException.hpp>
25 #include <com/sun/star/io/WrongFormatException.hpp>
26 #include <com/sun/star/io/TempFile.hpp>
29 #include <osl/security.hxx>
30 #include <osl/socket.hxx>
31 #include <o3tl/enumrange.hxx>
33 #include <rtl/string.hxx>
34 #include <rtl/ustring.hxx>
35 #include <rtl/strbuf.hxx>
36 #include <rtl/ustrbuf.hxx>
38 #include <comphelper/processfactory.hxx>
40 #include <unotools/bootstrap.hxx>
42 #include <ucbhelper/content.hxx>
44 #include <unotools/useroptions.hxx>
46 #include <svl/documentlockfile.hxx>
48 using namespace ::com::sun::star
;
52 bool DocumentLockFile::m_bAllowInteraction
= true;
55 DocumentLockFile::DocumentLockFile( const OUString
& aOrigURL
)
56 : LockFileCommon( aOrigURL
, OUString( ".~lock." ) )
61 DocumentLockFile::~DocumentLockFile()
66 void DocumentLockFile::WriteEntryToStream( const LockFileEntry
& aEntry
, uno::Reference
< io::XOutputStream
> xOutput
)
68 ::osl::MutexGuard
aGuard( m_aMutex
);
70 OUStringBuffer aBuffer
;
72 for ( LockFileComponent lft
: o3tl::enumrange
<LockFileComponent
>() )
74 aBuffer
.append( EscapeCharacters( aEntry
[lft
] ) );
75 if ( lft
< LockFileComponent::LAST
)
76 aBuffer
.append( ',' );
78 aBuffer
.append( ';' );
81 OString
aStringData( OUStringToOString( aBuffer
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
) );
82 uno::Sequence
< sal_Int8
> aData( reinterpret_cast<sal_Int8
const *>(aStringData
.getStr()), aStringData
.getLength() );
83 xOutput
->writeBytes( aData
);
87 bool DocumentLockFile::CreateOwnLockFile()
89 ::osl::MutexGuard
aGuard( m_aMutex
);
93 uno::Reference
< io::XStream
> xTempFile(
94 io::TempFile::create( comphelper::getProcessComponentContext() ),
95 uno::UNO_QUERY_THROW
);
96 uno::Reference
< io::XSeekable
> xSeekable( xTempFile
, uno::UNO_QUERY_THROW
);
98 uno::Reference
< io::XInputStream
> xInput
= xTempFile
->getInputStream();
99 uno::Reference
< io::XOutputStream
> xOutput
= xTempFile
->getOutputStream();
101 if ( !xInput
.is() || !xOutput
.is() )
102 throw uno::RuntimeException();
104 LockFileEntry aNewEntry
= GenerateOwnEntry();
105 WriteEntryToStream( aNewEntry
, xOutput
);
106 xOutput
->closeOutput();
108 xSeekable
->seek( 0 );
110 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
111 ::ucbhelper::Content
aTargetContent( m_aURL
, xEnv
, comphelper::getProcessComponentContext() );
113 ucb::InsertCommandArgument aInsertArg
;
114 aInsertArg
.Data
= xInput
;
115 aInsertArg
.ReplaceExisting
= sal_False
;
117 aCmdArg
<<= aInsertArg
;
118 aTargetContent
.executeCommand( OUString( "insert" ), aCmdArg
);
120 // try to let the file be hidden if possible
122 aTargetContent
.setPropertyValue("IsHidden", uno::makeAny( sal_True
) );
123 } catch( uno::Exception
& ) {}
125 catch( ucb::NameClashException
& )
134 LockFileEntry
DocumentLockFile::GetLockData()
136 ::osl::MutexGuard
aGuard( m_aMutex
);
138 uno::Reference
< io::XInputStream
> xInput
= OpenStream();
140 throw uno::RuntimeException();
142 const sal_Int32 nBufLen
= 32000;
143 uno::Sequence
< sal_Int8
> aBuffer( nBufLen
);
147 nRead
= xInput
->readBytes( aBuffer
, nBufLen
);
148 xInput
->closeInput();
150 if ( nRead
== nBufLen
)
151 throw io::WrongFormatException();
153 sal_Int32 nCurPos
= 0;
154 return ParseEntry( aBuffer
, nCurPos
);
158 uno::Reference
< io::XInputStream
> DocumentLockFile::OpenStream()
160 ::osl::MutexGuard
aGuard( m_aMutex
);
162 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
163 ::ucbhelper::Content
aSourceContent( m_aURL
, xEnv
, comphelper::getProcessComponentContext() );
165 // the file can be opened readonly, no locking will be done
166 return aSourceContent
.openStream();
170 bool DocumentLockFile::OverwriteOwnLockFile()
172 // allows to overwrite the lock file with the current data
175 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
176 ::ucbhelper::Content
aTargetContent( m_aURL
, xEnv
, comphelper::getProcessComponentContext() );
178 LockFileEntry aNewEntry
= GenerateOwnEntry();
180 uno::Reference
< io::XStream
> xStream
= aTargetContent
.openWriteableStreamNoLock();
181 uno::Reference
< io::XOutputStream
> xOutput
= xStream
->getOutputStream();
182 uno::Reference
< io::XTruncate
> xTruncate( xOutput
, uno::UNO_QUERY_THROW
);
184 xTruncate
->truncate();
185 WriteEntryToStream( aNewEntry
, xOutput
);
186 xOutput
->closeOutput();
188 catch( uno::Exception
& )
197 void DocumentLockFile::RemoveFile()
199 ::osl::MutexGuard
aGuard( m_aMutex
);
201 // TODO/LATER: the removing is not atomic, is it possible in general to make it atomic?
202 LockFileEntry aNewEntry
= GenerateOwnEntry();
203 LockFileEntry aFileData
= GetLockData();
205 if ( !aFileData
[LockFileComponent::SYSUSERNAME
].equals( aNewEntry
[LockFileComponent::SYSUSERNAME
] )
206 || !aFileData
[LockFileComponent::LOCALHOST
].equals( aNewEntry
[LockFileComponent::LOCALHOST
] )
207 || !aFileData
[LockFileComponent::USERURL
].equals( aNewEntry
[LockFileComponent::USERURL
] ) )
208 throw io::IOException(); // not the owner, access denied
210 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xEnv
;
211 ::ucbhelper::Content
aCnt(m_aURL
, xEnv
, comphelper::getProcessComponentContext());
212 aCnt
.executeCommand(OUString("delete"),
218 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */