| 412 | } |
| 413 | |
| 414 | bool // true if ok |
| 415 | copy_file_api(const std::string& from_p, |
| 416 | const std::string& to_p, bool fail_if_exists) |
| 417 | { |
| 418 | const std::size_t buf_sz = 32768; |
| 419 | boost::scoped_array<char> buf(new char [buf_sz]); |
| 420 | int infile=-1, outfile=-1; // -1 means not open |
| 421 | |
| 422 | // bug fixed: code previously did a stat()on the from_file first, but that |
| 423 | // introduced a gratuitous race condition; the stat()is now done after the open() |
| 424 | |
| 425 | if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0) |
| 426 | { return false; } |
| 427 | |
| 428 | struct stat from_stat; |
| 429 | if (::stat(from_p.c_str(), &from_stat)!= 0) |
| 430 | { |
| 431 | ::close(infile); |
| 432 | return false; |
| 433 | } |
| 434 | |
| 435 | int oflag = O_CREAT | O_WRONLY | O_TRUNC; |
| 436 | if (fail_if_exists) |
| 437 | oflag |= O_EXCL; |
| 438 | if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0) |
| 439 | { |
| 440 | int open_errno = errno; |
| 441 | BOOST_ASSERT(infile >= 0); |
| 442 | ::close(infile); |
| 443 | errno = open_errno; |
| 444 | return false; |
| 445 | } |
| 446 | |
| 447 | ssize_t sz, sz_read=1, sz_write; |
| 448 | while (sz_read > 0 |
| 449 | && (sz_read = ::read(infile, buf.get(), buf_sz))> 0) |
| 450 | { |
| 451 | // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), |
| 452 | // Marc Rochkind, Addison-Wesley, 2004, page 94 |
| 453 | sz_write = 0; |
| 454 | do |
| 455 | { |
| 456 | if ((sz = ::write(outfile, buf.get() + sz_write, |
| 457 | sz_read - sz_write))< 0) |
| 458 | { |
| 459 | sz_read = sz; // cause read loop termination |
| 460 | break; // and error to be thrown after closes |
| 461 | } |
| 462 | sz_write += sz; |
| 463 | } while (sz_write < sz_read); |
| 464 | } |
| 465 | |
| 466 | if (::close(infile)< 0)sz_read = -1; |
| 467 | if (::close(outfile)< 0)sz_read = -1; |
| 468 | |
| 469 | return sz_read >= 0; |
| 470 | } |
| 471 | |