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