1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_svl.hxx" 26 27 #include <stdio.h> 28 29 #include <com/sun/star/ucb/XSimpleFileAccess.hpp> 30 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 31 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 32 #include <com/sun/star/ucb/NameClashException.hpp> 33 #include <com/sun/star/io/WrongFormatException.hpp> 34 35 #include <osl/time.h> 36 #include <osl/security.hxx> 37 #include <osl/socket.hxx> 38 39 #include <rtl/string.hxx> 40 #include <rtl/ustring.hxx> 41 #include <rtl/strbuf.hxx> 42 #include <rtl/ustrbuf.hxx> 43 44 #include <comphelper/processfactory.hxx> 45 46 #include <tools/urlobj.hxx> 47 #include <unotools/bootstrap.hxx> 48 49 #include <ucbhelper/content.hxx> 50 51 #include <unotools/useroptions.hxx> 52 53 #include <svl/documentlockfile.hxx> 54 55 using namespace ::com::sun::star; 56 57 namespace svt { 58 59 sal_Bool DocumentLockFile::m_bAllowInteraction = sal_True; 60 61 // ---------------------------------------------------------------------- 62 DocumentLockFile::DocumentLockFile( const ::rtl::OUString& aOrigURL, const uno::Reference< lang::XMultiServiceFactory >& xFactory ) 63 : LockFileCommon( aOrigURL, xFactory, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".~lock." ) ) ) 64 { 65 } 66 67 // ---------------------------------------------------------------------- 68 DocumentLockFile::~DocumentLockFile() 69 { 70 } 71 72 // ---------------------------------------------------------------------- 73 void DocumentLockFile::WriteEntryToStream( uno::Sequence< ::rtl::OUString > aEntry, uno::Reference< io::XOutputStream > xOutput ) 74 { 75 ::osl::MutexGuard aGuard( m_aMutex ); 76 77 ::rtl::OUStringBuffer aBuffer; 78 79 for ( sal_Int32 nEntryInd = 0; nEntryInd < aEntry.getLength(); nEntryInd++ ) 80 { 81 aBuffer.append( EscapeCharacters( aEntry[nEntryInd] ) ); 82 if ( nEntryInd < aEntry.getLength() - 1 ) 83 aBuffer.append( (sal_Unicode)',' ); 84 else 85 aBuffer.append( (sal_Unicode)';' ); 86 } 87 88 ::rtl::OString aStringData( ::rtl::OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) ); 89 uno::Sequence< sal_Int8 > aData( (sal_Int8*)aStringData.getStr(), aStringData.getLength() ); 90 xOutput->writeBytes( aData ); 91 } 92 93 // ---------------------------------------------------------------------- 94 sal_Bool DocumentLockFile::CreateOwnLockFile() 95 { 96 ::osl::MutexGuard aGuard( m_aMutex ); 97 98 try 99 { 100 uno::Reference< io::XStream > xTempFile( 101 m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), 102 uno::UNO_QUERY_THROW ); 103 uno::Reference< io::XSeekable > xSeekable( xTempFile, uno::UNO_QUERY_THROW ); 104 105 uno::Reference< io::XInputStream > xInput = xTempFile->getInputStream(); 106 uno::Reference< io::XOutputStream > xOutput = xTempFile->getOutputStream(); 107 108 if ( !xInput.is() || !xOutput.is() ) 109 throw uno::RuntimeException(); 110 111 uno::Sequence< ::rtl::OUString > aNewEntry = GenerateOwnEntry(); 112 WriteEntryToStream( aNewEntry, xOutput ); 113 xOutput->closeOutput(); 114 115 xSeekable->seek( 0 ); 116 117 uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; 118 ::ucbhelper::Content aTargetContent( m_aURL, xEnv ); 119 120 ucb::InsertCommandArgument aInsertArg; 121 aInsertArg.Data = xInput; 122 aInsertArg.ReplaceExisting = sal_False; 123 uno::Any aCmdArg; 124 aCmdArg <<= aInsertArg; 125 aTargetContent.executeCommand( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ), aCmdArg ); 126 127 // try to let the file be hidden if possible 128 try { 129 aTargetContent.setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ), uno::makeAny( sal_True ) ); 130 } catch( uno::Exception& ) {} 131 } 132 catch( ucb::NameClashException& ) 133 { 134 return sal_False; 135 } 136 137 return sal_True; 138 } 139 140 // ---------------------------------------------------------------------- 141 uno::Sequence< ::rtl::OUString > DocumentLockFile::GetLockData() 142 { 143 ::osl::MutexGuard aGuard( m_aMutex ); 144 145 uno::Reference< io::XInputStream > xInput = OpenStream(); 146 if ( !xInput.is() ) 147 throw uno::RuntimeException(); 148 149 const sal_Int32 nBufLen = 32000; 150 uno::Sequence< sal_Int8 > aBuffer( nBufLen ); 151 152 sal_Int32 nRead = 0; 153 154 nRead = xInput->readBytes( aBuffer, nBufLen ); 155 xInput->closeInput(); 156 157 if ( nRead == nBufLen ) 158 throw io::WrongFormatException(); 159 160 sal_Int32 nCurPos = 0; 161 return ParseEntry( aBuffer, nCurPos ); 162 } 163 164 // ---------------------------------------------------------------------- 165 uno::Reference< io::XInputStream > DocumentLockFile::OpenStream() 166 { 167 ::osl::MutexGuard aGuard( m_aMutex ); 168 169 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); 170 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleFileAccess( 171 xFactory->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess") ), 172 uno::UNO_QUERY_THROW ); 173 174 // the file can be opened readonly, no locking will be done 175 return xSimpleFileAccess->openFileRead( m_aURL ); 176 } 177 178 // ---------------------------------------------------------------------- 179 sal_Bool DocumentLockFile::OverwriteOwnLockFile() 180 { 181 // allows to overwrite the lock file with the current data 182 try 183 { 184 uno::Reference < ::com::sun::star::ucb::XCommandEnvironment > xEnv; 185 ::ucbhelper::Content aTargetContent( m_aURL, xEnv ); 186 187 uno::Sequence< ::rtl::OUString > aNewEntry = GenerateOwnEntry(); 188 189 uno::Reference< io::XStream > xStream = aTargetContent.openWriteableStreamNoLock(); 190 uno::Reference< io::XOutputStream > xOutput = xStream->getOutputStream(); 191 uno::Reference< io::XTruncate > xTruncate( xOutput, uno::UNO_QUERY_THROW ); 192 193 xTruncate->truncate(); 194 WriteEntryToStream( aNewEntry, xOutput ); 195 xOutput->closeOutput(); 196 } 197 catch( uno::Exception& ) 198 { 199 return sal_False; 200 } 201 202 return sal_True; 203 } 204 205 // ---------------------------------------------------------------------- 206 void DocumentLockFile::RemoveFile() 207 { 208 ::osl::MutexGuard aGuard( m_aMutex ); 209 210 // TODO/LATER: the removing is not atomar, is it possible in general to make it atomar? 211 uno::Sequence< ::rtl::OUString > aNewEntry = GenerateOwnEntry(); 212 uno::Sequence< ::rtl::OUString > aFileData = GetLockData(); 213 214 if ( aFileData.getLength() < LOCKFILE_ENTRYSIZE ) 215 throw io::WrongFormatException(); 216 217 if ( !aFileData[LOCKFILE_SYSUSERNAME_ID].equals( aNewEntry[LOCKFILE_SYSUSERNAME_ID] ) 218 || !aFileData[LOCKFILE_LOCALHOST_ID].equals( aNewEntry[LOCKFILE_LOCALHOST_ID] ) 219 || !aFileData[LOCKFILE_USERURL_ID].equals( aNewEntry[LOCKFILE_USERURL_ID] ) ) 220 throw io::IOException(); // not the owner, access denied 221 222 uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); 223 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleFileAccess( 224 xFactory->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SimpleFileAccess") ), 225 uno::UNO_QUERY_THROW ); 226 xSimpleFileAccess->kill( m_aURL ); 227 } 228 229 } // namespace svt 230 231