1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #if defined WNT 32 #ifndef _SVWIN_H 33 #include <io.h> 34 #include <tools/svwin.h> 35 #endif 36 37 #elif defined(OS2) 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <fcntl.h> 41 #include <share.h> 42 #include <io.h> 43 44 #elif defined UNX 45 #include <fcntl.h> 46 #include <unistd.h> 47 #include <sys/stat.h> 48 49 #endif 50 51 #include <ctype.h> 52 #include <errno.h> 53 #include <stdlib.h> 54 #include <string.h> 55 56 #include <stdio.h> 57 #include "comdep.hxx" 58 #include <tools/fsys.hxx> 59 #include <tools/stream.hxx> 60 #include <osl/file.hxx> 61 62 using namespace ::osl; 63 64 /************************************************************************* 65 |* 66 |* FileCopier::FileCopier() 67 |* 68 |* Beschreibung FSYS.SDW 69 |* Ersterstellung MI 13.04.94 70 |* Letzte Aenderung MI 13.04.94 71 |* 72 *************************************************************************/ 73 74 FileCopier::FileCopier() : 75 76 nBytesTotal ( 0 ), 77 nBytesCopied( 0 ), 78 nBlockSize ( 4096 ), 79 pImp ( new FileCopier_Impl ) 80 81 { 82 } 83 84 // ----------------------------------------------------------------------- 85 86 FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) : 87 88 aSource ( rSource ), 89 aTarget ( rTarget ), 90 nBytesTotal ( 0 ), 91 nBytesCopied( 0 ), 92 nBlockSize ( 4096 ), 93 pImp ( new FileCopier_Impl ) 94 95 { 96 } 97 98 // ----------------------------------------------------------------------- 99 100 FileCopier::FileCopier( const FileCopier& rCopier ) : 101 102 aSource ( rCopier.aSource ), 103 aTarget ( rCopier.aTarget ), 104 nBytesTotal ( 0 ), 105 nBytesCopied ( 0 ), 106 aProgressLink ( rCopier.aProgressLink ), 107 nBlockSize ( 4096 ), 108 pImp ( new FileCopier_Impl ) 109 110 { 111 } 112 113 /************************************************************************* 114 |* 115 |* FileCopier::~FileCopier() 116 |* 117 |* Beschreibung FSYS.SDW 118 |* Ersterstellung MI 13.04.94 119 |* Letzte Aenderung MI 13.04.94 120 |* 121 *************************************************************************/ 122 123 FileCopier::~FileCopier() 124 { 125 delete pImp; 126 } 127 128 /************************************************************************* 129 |* 130 |* FileCopier::operator =() 131 |* 132 |* Beschreibung FSYS.SDW 133 |* Ersterstellung MI 13.04.94 134 |* Letzte Aenderung MI 13.04.94 135 |* 136 *************************************************************************/ 137 138 FileCopier& FileCopier::operator = ( const FileCopier &rCopier ) 139 { 140 aSource = rCopier.aSource; 141 aTarget = rCopier.aTarget; 142 nBytesTotal = rCopier.nBytesTotal; 143 nBytesCopied = rCopier.nBytesCopied; 144 nBytesCopied = rCopier.nBytesCopied; 145 nBlockSize = rCopier.nBlockSize; 146 aProgressLink = rCopier.aProgressLink; 147 *pImp = *(rCopier.pImp); 148 return *this; 149 } 150 151 /************************************************************************* 152 |* 153 |* FileCopier::Progress() 154 |* 155 |* Beschreibung FSYS.SDW 156 |* Ersterstellung MI 13.04.94 157 |* Letzte Aenderung MI 13.04.94 158 |* 159 *************************************************************************/ 160 161 sal_Bool FileCopier::Progress() 162 { 163 if ( !aProgressLink ) 164 return sal_True; 165 else 166 { 167 if ( aProgressLink.Call( this ) ) 168 return sal_True; 169 return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) ); 170 } 171 } 172 173 //--------------------------------------------------------------------------- 174 175 ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget ) 176 { 177 // kein Fehler oder kein ErrorHandler? 178 if ( !eErr || !pImp->aErrorLink ) 179 // => Error beibehalten 180 return eErr; 181 182 // sonst gesetzten ErrorHandler fragen 183 pImp->pErrSource = pSource; 184 pImp->pErrTarget = pTarget; 185 pImp->eErr = eErr; 186 ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this ); 187 pImp->pErrSource = 0; 188 pImp->pErrTarget = 0; 189 return eRet; 190 } 191 192 //--------------------------------------------------------------------------- 193 194 const DirEntry* FileCopier::GetErrorSource() const 195 { 196 return pImp->pErrSource; 197 } 198 199 //--------------------------------------------------------------------------- 200 201 const DirEntry* FileCopier::GetErrorTarget() const 202 { 203 return pImp->pErrTarget; 204 } 205 206 //--------------------------------------------------------------------------- 207 208 ErrCode FileCopier::GetError() const 209 { 210 return pImp->eErr; 211 } 212 213 //--------------------------------------------------------------------------- 214 215 void FileCopier::SetErrorHdl( const Link &rLink ) 216 { 217 pImp->aErrorLink = rLink; 218 } 219 220 //--------------------------------------------------------------------------- 221 222 const Link& FileCopier::GetErrorHdl() const 223 { 224 return pImp->aErrorLink ; 225 } 226 227 /************************************************************************* 228 |* 229 |* FileCopier::Execute() 230 |* 231 |* Beschreibung FSYS.SDW 232 |* Ersterstellung MI 13.04.94 233 |* Letzte Aenderung PB 16.06.00 234 |* 235 *************************************************************************/ 236 237 FSysError FileCopier::DoCopy_Impl( 238 const DirEntry &rSource, const DirEntry &rTarget ) 239 { 240 FSysError eRet = FSYS_ERR_OK; 241 ErrCode eWarn = FSYS_ERR_OK; 242 243 // HPFS->FAT? 244 FSysPathStyle eSourceStyle = DirEntry::GetPathStyle( rSource.ImpGetTopPtr()->GetName() ); 245 FSysPathStyle eTargetStyle = DirEntry::GetPathStyle( rTarget.ImpGetTopPtr()->GetName() ); 246 sal_Bool bMakeShortNames = ( eSourceStyle == FSYS_STYLE_HPFS && eTargetStyle == FSYS_STYLE_FAT ); 247 248 // Zieldateiname ggf. kuerzen 249 DirEntry aTgt; 250 if ( bMakeShortNames ) 251 { 252 aTgt = rTarget.GetPath(); 253 aTgt.MakeShortName( rTarget.GetName() ); 254 } 255 else 256 aTgt = rTarget; 257 258 // kein Move wenn Namen gekuerzt werden muessten 259 if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTgt != rTarget ) 260 return ERRCODE_IO_NAMETOOLONG; 261 262 // source is directory? 263 FileStat aSourceFileStat( rSource ); 264 if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) ) 265 { 266 #ifdef OS2 267 CHAR szSource[CCHMAXPATHCOMP]; 268 HOBJECT hSourceObject; 269 270 strcpy(szSource, ByteString(rSource.GetFull(), osl_getThreadTextEncoding()).GetBuffer()); 271 hSourceObject = WinQueryObject(szSource); 272 273 if ( hSourceObject ) 274 { 275 PSZ pszSourceName; 276 PSZ pszTargetName; 277 CHAR szTarget[CCHMAXPATHCOMP]; 278 HOBJECT hTargetObject; 279 HOBJECT hReturn = NULLHANDLE; 280 281 strcpy(szTarget, ByteString(rTarget.GetFull(), osl_getThreadTextEncoding()).GetBuffer()); 282 pszTargetName = strrchr(szTarget, '\\'); 283 pszSourceName = strrchr(szSource, '\\'); 284 285 hTargetObject = WinQueryObject(szTarget); 286 287 if ( hTargetObject ) 288 WinDestroyObject(hTargetObject); 289 290 if ( pszTargetName && pszSourceName ) 291 { 292 *pszTargetName = '\0'; 293 pszSourceName++; 294 pszTargetName++; 295 296 if(strcmp(pszSourceName, pszTargetName) == 0) 297 { 298 hTargetObject = WinQueryObject(szTarget); 299 300 if(pImp->nActions & FSYS_ACTION_MOVE) 301 { 302 hReturn = WinMoveObject(hSourceObject, hTargetObject, 0); 303 } 304 else 305 { 306 hReturn = WinCopyObject(hSourceObject, hTargetObject, 0); 307 } 308 if ( bMakeShortNames && aTarget.Exists() ) 309 aTarget.Kill(); 310 return hReturn ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN; 311 } 312 } 313 } 314 #endif 315 // recursive copy 316 eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt ); 317 Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE ); 318 for ( sal_uInt16 n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n ) 319 { 320 const DirEntry &rSubSource = aSourceDir[n]; 321 DirEntryFlag eFlag = rSubSource.GetFlag(); 322 if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT ) 323 { 324 DirEntry aSubTarget( aTgt ); 325 aSubTarget += rSubSource.GetName(); 326 eRet = DoCopy_Impl( rSubSource, aSubTarget ); 327 if ( eRet && !eWarn ) 328 eWarn = eRet; 329 } 330 } 331 } 332 else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) ) 333 { 334 if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) && 335 aTgt.Exists() ) 336 { 337 // Do not overwrite existing file in target folder. 338 return ERRCODE_NONE; 339 } 340 341 // copy file 342 nBytesCopied = 0; 343 nBytesTotal = FileStat( rSource ).GetSize(); 344 345 ::rtl::OUString aFileName; 346 FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName ); 347 SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE ); 348 349 if ( !aSrc.GetError() ) 350 { 351 #ifdef UNX 352 struct stat buf; 353 if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 ) 354 eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt ); 355 #endif 356 ::rtl::OUString aTargetFileName; 357 FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName ); 358 359 SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE ); 360 if ( !aTargetStream.GetError() ) 361 { 362 #ifdef UNX 363 if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 ) 364 eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt ); 365 #endif 366 size_t nAllocSize = 0, nSize = 0; 367 char *pBuf = 0; 368 while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK ) 369 { 370 // adjust the block-size 371 if ( nBlockSize > nAllocSize ) 372 { 373 delete[] pBuf; 374 nAllocSize = nBlockSize; 375 pBuf = new char[nAllocSize]; 376 } 377 378 // copy one block 379 nSize = aSrc.Read( pBuf, nBlockSize ); 380 aTargetStream.Write( pBuf, nSize ); 381 if ( aTargetStream.GetError() ) 382 eRet = Error( aTargetStream.GetError(), 0, &aTgt ); 383 384 // adjust counters 385 nBytesCopied += nSize; 386 if ( nBytesCopied > nBytesTotal ) 387 nBytesTotal = nBytesCopied; 388 } 389 delete[] pBuf; 390 } 391 else 392 eRet = Error( aTargetStream.GetError(), 0, &aTgt ); 393 394 // unvollstaendiges File wieder loeschen 395 aTargetStream.Close(); 396 397 if ( nBytesCopied != nBytesTotal ) 398 { 399 aTgt.Kill(); 400 } 401 } 402 else 403 eRet = Error( aSrc.GetError(), &rSource, 0 ); 404 } 405 else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) ) 406 eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 ); 407 else 408 eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 ); 409 410 #ifdef WNT 411 // Set LastWriteTime and Attributes of the target identical with the source 412 413 if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) ) 414 { 415 WIN32_FIND_DATA fdSource; 416 ByteString aFullSource(aSource.GetFull(), osl_getThreadTextEncoding()); 417 ByteString aFullTarget(aTgt.GetFull(), osl_getThreadTextEncoding()); 418 HANDLE hFind = FindFirstFile( aFullSource.GetBuffer() , &fdSource ); 419 if ( hFind != INVALID_HANDLE_VALUE ) 420 { 421 FindClose( hFind ); 422 423 HANDLE hFile = CreateFile( aFullTarget.GetBuffer(), GENERIC_WRITE, 424 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 425 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 426 427 if ( hFile != INVALID_HANDLE_VALUE ) 428 { 429 SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime ); 430 CloseHandle( hFile ); 431 } 432 433 SetFileAttributes( aFullTarget.GetBuffer(), fdSource.dwFileAttributes ); 434 } 435 } 436 #endif 437 // bei Move ggf. das File/Dir loeschen 438 if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions & FSYS_ACTION_MOVE ) ) 439 { 440 ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 ); 441 if ( eKillErr != ERRCODE_WARNING_MASK ) 442 { 443 if ( rSource.Exists() ) 444 // loeschen ging nicht => dann die Kopie wieder loeschen 445 aTgt.Kill( pImp->nActions ); 446 if ( !eWarn ) 447 eWarn = eKillErr; 448 } 449 } 450 451 return !eRet ? eWarn : eRet; 452 } 453 454 // ----------------------------------------------------------------------- 455 456 FSysError FileCopier::Execute( FSysAction nActions ) 457 { 458 return ExecuteExact( nActions ); 459 } 460 461 // ----------------------------------------------------------------------- 462 463 FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact ) 464 { 465 DirEntry aAbsSource = DirEntry( aSource); 466 DirEntry aAbsTarget = DirEntry( aTarget ); 467 pImp->nActions = nActions; 468 469 // check if both pathes are accessible and source and target are different 470 if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource ) 471 return FSYS_ERR_ACCESSDENIED; 472 473 // check if copy would be endless recursive into itself 474 if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) && 475 aAbsSource.Contains( aAbsTarget ) ) 476 return ERRCODE_IO_RECURSIVE; 477 478 // target is directory? 479 if ( eExact == FSYS_NOTEXACT && 480 FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) ) 481 // append name of source 482 aAbsTarget += aSource.GetName(); 483 484 // recursive copy 485 return DoCopy_Impl( aAbsSource, aAbsTarget ); 486 } 487