Branch data Line data Source code
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 : : #if defined WNT
21 : : #include <windows.h>
22 : : #include <io.h>
23 : : #elif defined UNX
24 : : #include <fcntl.h>
25 : : #include <unistd.h>
26 : : #include <sys/stat.h>
27 : : #endif
28 : :
29 : : #include <ctype.h>
30 : : #include <errno.h>
31 : : #include <stdlib.h>
32 : : #include <string.h>
33 : :
34 : : #include <stdio.h>
35 : : #include "comdep.hxx"
36 : : #include <tools/fsys.hxx>
37 : : #include <tools/stream.hxx>
38 : : #include <osl/file.hxx>
39 : :
40 : : using namespace ::osl;
41 : :
42 : 1320 : FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) :
43 : : aSource ( rSource ),
44 : : aTarget ( rTarget ),
45 : : nBytesTotal ( 0 ),
46 : : nBytesCopied( 0 ),
47 : : nBlockSize ( 4096 ),
48 [ + - ][ + - ]: 1320 : pImp ( new FileCopier_Impl )
[ + - ][ + - ]
49 : : {
50 : 1320 : }
51 : :
52 : 0 : FileCopier::FileCopier( const FileCopier& rCopier ) :
53 : : aSource ( rCopier.aSource ),
54 : : aTarget ( rCopier.aTarget ),
55 : : nBytesTotal ( 0 ),
56 : : nBytesCopied ( 0 ),
57 : : aProgressLink ( rCopier.aProgressLink ),
58 : : nBlockSize ( 4096 ),
59 [ # # ][ # # ]: 0 : pImp ( new FileCopier_Impl )
[ # # ]
60 : : {
61 : 0 : }
62 : :
63 [ + - ]: 1320 : FileCopier::~FileCopier()
64 : : {
65 : 1320 : delete pImp;
66 [ - + ]: 1320 : }
67 : :
68 : 0 : FileCopier& FileCopier::operator = ( const FileCopier &rCopier )
69 : : {
70 : 0 : aSource = rCopier.aSource;
71 : 0 : aTarget = rCopier.aTarget;
72 : 0 : nBytesTotal = rCopier.nBytesTotal;
73 : 0 : nBytesCopied = rCopier.nBytesCopied;
74 : 0 : nBytesCopied = rCopier.nBytesCopied;
75 : 0 : nBlockSize = rCopier.nBlockSize;
76 : 0 : aProgressLink = rCopier.aProgressLink;
77 : 0 : *pImp = *(rCopier.pImp);
78 : 0 : return *this;
79 : : }
80 : :
81 : 3742 : sal_Bool FileCopier::Progress()
82 : : {
83 [ + - ]: 3742 : if ( !aProgressLink )
84 : 3742 : return sal_True;
85 : : else
86 : : {
87 [ # # ]: 0 : if ( aProgressLink.Call( this ) )
88 : 0 : return sal_True;
89 : 3742 : return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) );
90 : : }
91 : : }
92 : :
93 : 0 : ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget )
94 : : {
95 : : // No error or no error handler?
96 [ # # ][ # # ]: 0 : if ( !eErr || !pImp->aErrorLink )
[ # # ]
97 : : // => keep error
98 : 0 : return eErr;
99 : :
100 : : // otherwise request from ErrorHandler
101 : 0 : pImp->pErrSource = pSource;
102 : 0 : pImp->pErrTarget = pTarget;
103 : 0 : pImp->eErr = eErr;
104 : 0 : ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this );
105 : 0 : pImp->pErrSource = 0;
106 : 0 : pImp->pErrTarget = 0;
107 : 0 : return eRet;
108 : : }
109 : :
110 : 1320 : FSysError FileCopier::DoCopy_Impl( const DirEntry &rSource, const DirEntry &rTarget )
111 : : {
112 : 1320 : FSysError eRet = FSYS_ERR_OK;
113 : 1320 : ErrCode eWarn = FSYS_ERR_OK;
114 : :
115 : : // shorten target name if necessary
116 [ + - ]: 1320 : DirEntry aTgt;
117 [ + - ]: 1320 : aTgt = rTarget;
118 : :
119 : : // source is directory?
120 [ + - ]: 1320 : FileStat aSourceFileStat( rSource );
121 [ + - ][ - + ]: 1320 : if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) )
122 : : {
123 : : // recursive copy
124 [ # # ][ # # ]: 0 : eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt );
[ # # ]
125 [ # # ]: 0 : Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE );
126 [ # # ][ # # ]: 0 : for ( sal_uInt16 n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n )
[ # # ][ # # ]
127 : : {
128 [ # # ]: 0 : const DirEntry &rSubSource = aSourceDir[n];
129 : 0 : DirEntryFlag eFlag = rSubSource.GetFlag();
130 [ # # ][ # # ]: 0 : if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT )
131 : : {
132 [ # # ]: 0 : DirEntry aSubTarget( aTgt );
133 [ # # ][ # # ]: 0 : aSubTarget += rSubSource.GetName();
[ # # ][ # # ]
[ # # ]
134 [ # # ]: 0 : eRet = DoCopy_Impl( rSubSource, aSubTarget );
135 [ # # ][ # # ]: 0 : if ( eRet && !eWarn )
136 [ # # ]: 0 : eWarn = eRet;
137 : : }
138 [ # # ]: 0 : }
139 : : }
140 [ + - ][ + - ]: 1320 : else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) )
141 : : {
142 [ - + ][ # # ]: 1320 : if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) &&
[ - + ]
143 [ # # ]: 0 : aTgt.Exists() )
144 : : {
145 : : // Do not overwrite existing file in target folder.
146 : 0 : return ERRCODE_NONE;
147 : : }
148 : :
149 : : // copy file
150 : 1320 : nBytesCopied = 0;
151 [ + - ][ + - ]: 1320 : nBytesTotal = FileStat( rSource ).GetSize();
152 : :
153 : 1320 : ::rtl::OUString aFileName;
154 [ + - ][ + - ]: 1320 : FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName );
[ + - ][ + - ]
155 [ + - ][ + - ]: 1320 : SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE );
[ + - ]
156 : :
157 [ + - ]: 1320 : if ( !aSrc.GetError() )
158 : : {
159 : : #ifdef UNX
160 : : struct stat buf;
161 [ + - ][ - + ]: 1320 : if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 )
162 [ # # ]: 0 : eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
163 : : #endif
164 : 1320 : ::rtl::OUString aTargetFileName;
165 [ + - ][ + - ]: 1320 : FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName );
[ + - ][ + - ]
166 : :
167 [ + - ][ + - ]: 1320 : SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE );
[ + - ]
168 [ + - ]: 1320 : if ( !aTargetStream.GetError() )
169 : : {
170 : : #ifdef UNX
171 [ + - ][ - + ]: 1320 : if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 )
172 [ # # ]: 0 : eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
173 : : #endif
174 : 1320 : size_t nAllocSize = 0, nSize = 0;
175 : 1320 : char *pBuf = 0;
176 [ + - ][ + - ]: 3742 : while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK )
[ + + ][ + - ]
[ + + ]
177 : : {
178 : : // adjust the block-size
179 [ + + ]: 2422 : if ( nBlockSize > nAllocSize )
180 : : {
181 [ - + ]: 1320 : delete[] pBuf;
182 : 1320 : nAllocSize = nBlockSize;
183 [ + - ]: 1320 : pBuf = new char[nAllocSize];
184 : : }
185 : :
186 : : // copy one block
187 [ + - ]: 2422 : nSize = aSrc.Read( pBuf, nBlockSize );
188 [ + - ]: 2422 : aTargetStream.Write( pBuf, nSize );
189 [ - + ]: 2422 : if ( aTargetStream.GetError() )
190 [ # # ]: 0 : eRet = Error( aTargetStream.GetError(), 0, &aTgt );
191 : :
192 : : // adjust counters
193 : 2422 : nBytesCopied += nSize;
194 [ - + ]: 2422 : if ( nBytesCopied > nBytesTotal )
195 : 0 : nBytesTotal = nBytesCopied;
196 : : }
197 [ + - ]: 1320 : delete[] pBuf;
198 : : }
199 : : else
200 [ # # ]: 0 : eRet = Error( aTargetStream.GetError(), 0, &aTgt );
201 : :
202 [ + - ]: 1320 : aTargetStream.Close();
203 : :
204 : : // remove incomplete file
205 [ - + ]: 1320 : if ( nBytesCopied != nBytesTotal )
206 : : {
207 [ # # ]: 0 : aTgt.Kill();
208 [ + - ]: 1320 : }
209 : : }
210 : : else
211 [ # # ][ + - ]: 1320 : eRet = Error( aSrc.GetError(), &rSource, 0 );
212 : : }
213 [ # # ][ # # ]: 0 : else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) )
214 [ # # ]: 0 : eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 );
215 : : else
216 [ # # ]: 0 : eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 );
217 : :
218 : : #ifdef WNT
219 : : // Set LastWriteTime and Attributes of the target identical with the source
220 : :
221 : : if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) )
222 : : {
223 : : WIN32_FIND_DATA fdSource;
224 : : rtl::OString aFullSource(rtl::OUStringToOString(aSource.GetFull(), osl_getThreadTextEncoding()));
225 : : rtl::OString aFullTarget(rtl::OUStringToOString(aTgt.GetFull(), osl_getThreadTextEncoding()));
226 : : HANDLE hFind = FindFirstFile( aFullSource.getStr() , &fdSource );
227 : : if ( hFind != INVALID_HANDLE_VALUE )
228 : : {
229 : : FindClose( hFind );
230 : :
231 : : HANDLE hFile = CreateFile( aFullTarget.getStr(), GENERIC_WRITE,
232 : : FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
233 : : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
234 : :
235 : : if ( hFile != INVALID_HANDLE_VALUE )
236 : : {
237 : : SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime );
238 : : CloseHandle( hFile );
239 : : }
240 : :
241 : : SetFileAttributes( aFullTarget.getStr(), fdSource.dwFileAttributes );
242 : : }
243 : : }
244 : : #endif
245 : : // Remove File/Dir upon Move if necessary
246 [ + - ][ - + ]: 1320 : if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions & FSYS_ACTION_MOVE ) )
[ - + ]
247 : : {
248 [ # # ][ # # ]: 0 : ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 );
249 [ # # ]: 0 : if ( eKillErr != ERRCODE_WARNING_MASK )
250 : : {
251 [ # # ][ # # ]: 0 : if ( rSource.Exists() )
252 : : // Removal failed => remove copy
253 [ # # ]: 0 : aTgt.Kill( pImp->nActions );
254 [ # # ]: 0 : if ( !eWarn )
255 : 0 : eWarn = eKillErr;
256 : : }
257 : : }
258 : :
259 [ + - ][ + - ]: 1320 : return !eRet ? eWarn : eRet;
[ + - ]
260 : : }
261 : :
262 : 1320 : FSysError FileCopier::Execute( FSysAction nActions )
263 : : {
264 : 1320 : return ExecuteExact( nActions );
265 : : }
266 : :
267 : 1320 : FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact )
268 : : {
269 [ + - ]: 1320 : DirEntry aAbsSource = DirEntry( aSource);
270 [ + - ]: 1320 : DirEntry aAbsTarget = DirEntry( aTarget );
271 : 1320 : pImp->nActions = nActions;
272 : :
273 : : // check if both paths are accessible and source and target are different
274 [ + - ][ + - ]: 1320 : if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource )
[ + - ][ + - ]
[ + - ][ - + ]
[ - + ]
275 : 0 : return FSYS_ERR_ACCESSDENIED;
276 : :
277 : : // check if copy would be endless recursive into itself
278 [ - + ][ # # ]: 1320 : if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) &&
[ - + ]
279 [ # # ]: 0 : aAbsSource.Contains( aAbsTarget ) )
280 : 0 : return ERRCODE_IO_RECURSIVE;
281 : :
282 : : // target is directory?
283 [ + - ][ - + ]: 3960 : if ( eExact == FSYS_NOTEXACT &&
[ # # ][ - + ]
284 [ + - ][ + - ]: 2640 : FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) )
[ # # ][ # # ]
[ - + ][ # # ]
[ + - ][ + - ]
[ # # # # ]
285 : : // append name of source
286 [ # # ][ # # ]: 0 : aAbsTarget += aSource.GetName();
[ # # ][ # # ]
[ # # ]
287 : :
288 : : // recursive copy
289 [ + - ][ + - ]: 1320 : return DoCopy_Impl( aAbsSource, aAbsTarget );
[ + - ]
290 : : }
291 : :
292 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|