From 78bbb5cf75a09153caba8546a71b58b170e92b5f Mon Sep 17 00:00:00 2001
From: Roger Siddons <dizygotheca@ntlworld.com>
Date: Sat, 22 Aug 2015 13:25:45 +0100
Subject: [PATCH 08/15] RemoteFile::CopyFile: Don't overwrite existing files by
default
CopyFile doesn't check for a file's existance before writing to it.
For storage groups containing multiple dirs this can lead to multiple versions of a remote file (only
one of which will be read).
This patch will fail the copy (by default) if the destination file exists.
If the overwrite flag is set the destination file is deleted first, ensuring that multiple versions
are not created.
It also adds optional verification that the copy succeeded (by comparing file sizes) as write can fail
silently if the filesystem fills up.
diff --git a/mythplugins/mythmusic/mythmusic/cdrip.cpp b/mythplugins/mythmusic/mythmusic/cdrip.cpp
index 77a5ce0..aadb893 100644
a
|
b
|
void CDRipperThread::run(void) |
394 | 394 | destFile = gCoreContext->GenMythURL(url.host(), 0, destFile, "Music"); |
395 | 395 | |
396 | 396 | QApplication::postEvent(m_parent, new RipStatusEvent(RipStatusEvent::kCopyStartEvent, 0)); |
397 | | RemoteFile::CopyFile(saveDir + outfile, destFile); |
| 397 | RemoteFile::CopyFile(saveDir + outfile, destFile, true); |
398 | 398 | QApplication::postEvent(m_parent, new RipStatusEvent(RipStatusEvent::kCopyEndEvent, 0)); |
399 | 399 | } |
400 | 400 | } |
diff --git a/mythplugins/mythmusic/mythmusic/editmetadata.cpp b/mythplugins/mythmusic/mythmusic/editmetadata.cpp
index 0370b6b..37b6301 100644
a
|
b
|
void EditMetadataDialog::customEvent(QEvent *event) |
860 | 860 | return; |
861 | 861 | } |
862 | 862 | |
863 | | RemoteFile::CopyFile(oldFilename, newFilename); |
| 863 | RemoteFile::CopyFile(oldFilename, newFilename, true); |
864 | 864 | QFile::remove(oldFilename); |
865 | 865 | |
866 | 866 | if (m_searchType == "album") |
… |
… |
void EditAlbumartDialog::doCopyImageToTag(const AlbumArtImage *image) |
1373 | 1373 | QString("AlbumArt/") + fi.fileName(), |
1374 | 1374 | "MusicArt"); |
1375 | 1375 | |
1376 | | RemoteFile::CopyFile(image->filename, saveFilename); |
| 1376 | RemoteFile::CopyFile(image->filename, saveFilename, true); |
1377 | 1377 | |
1378 | 1378 | // ask the backend to add the image to the tracks tag |
1379 | 1379 | QStringList strList("MUSIC_TAG_ADDIMAGE"); |
diff --git a/mythplugins/mythmusic/mythmusic/importmusic.cpp b/mythplugins/mythmusic/mythmusic/importmusic.cpp
index 4c465cf..f60b939 100644
a
|
b
|
FileCopyThread::FileCopyThread(const QString &src, const QString &dst) : |
53 | 53 | void FileCopyThread::run() |
54 | 54 | { |
55 | 55 | RunProlog(); |
56 | | m_result = RemoteFile::CopyFile(m_srcFile, m_dstFile); |
| 56 | m_result = RemoteFile::CopyFile(m_srcFile, m_dstFile, true); |
57 | 57 | RunEpilog(); |
58 | 58 | } |
59 | 59 | |
… |
… |
void ImportMusicDialog::addPressed() |
438 | 438 | |
439 | 439 | m_somethingWasImported = true; |
440 | 440 | |
441 | | m_tracks->at(m_currentTrack)->isNewTune = |
| 441 | m_tracks->at(m_currentTrack)->isNewTune = |
442 | 442 | isNewTune(meta->Artist(), meta->Album(), meta->Title()); |
443 | 443 | |
444 | 444 | // update the UI |
… |
… |
void ImportMusicDialog::startScan() |
543 | 543 | location.append('/'); |
544 | 544 | |
545 | 545 | MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); |
546 | | MythUIBusyDialog *busy = |
| 546 | MythUIBusyDialog *busy = |
547 | 547 | new MythUIBusyDialog(tr("Searching for music files"), |
548 | 548 | popupStack, |
549 | 549 | "scanbusydialog"); |
… |
… |
void ImportMusicDialog::setAlbum(void) |
814 | 814 | MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata; |
815 | 815 | data->setAlbum(m_defaultAlbum); |
816 | 816 | |
817 | | m_tracks->at(m_currentTrack)->isNewTune = |
| 817 | m_tracks->at(m_currentTrack)->isNewTune = |
818 | 818 | isNewTune(data->Artist(), data->Album(), data->Title()); |
819 | 819 | |
820 | 820 | fillWidgets(); |
… |
… |
void ImportCoverArtDialog::copyPressed() |
1075 | 1075 | { |
1076 | 1076 | if (m_filelist.size() > 0) |
1077 | 1077 | { |
1078 | | if (!RemoteFile::CopyFile(m_filelist[m_currentFile], m_saveFilename)) |
| 1078 | if (!RemoteFile::CopyFile(m_filelist[m_currentFile], m_saveFilename, true)) |
1079 | 1079 | { |
1080 | 1080 | //: %1 is the filename |
1081 | 1081 | ShowOkPopup(tr("Copy CoverArt Failed.\nCopying to %1").arg(m_saveFilename)); |
diff --git a/mythtv/libs/libmythbase/remotefile.cpp b/mythtv/libs/libmythbase/remotefile.cpp
index 469c292..594a6eb 100644
a
|
b
|
QString RemoteFile::GetFileHash(const QString &url) |
558 | 558 | return result; |
559 | 559 | } |
560 | 560 | |
561 | | bool RemoteFile::CopyFile (const QString& src, const QString& dst) |
| 561 | bool RemoteFile::CopyFile (const QString& src, const QString& dst, |
| 562 | bool overwrite, bool verify) |
562 | 563 | { |
563 | | LOG(VB_FILE, LOG_INFO, QString("RemoteFile::CopyFile: Copying file from '%1' to '%2'").arg(src).arg(dst)); |
| 564 | LOG(VB_FILE, LOG_INFO, |
| 565 | QString("RemoteFile::CopyFile: Copying file from '%1' to '%2'").arg(src).arg(dst)); |
564 | 566 | |
565 | 567 | // sanity check |
566 | 568 | if (src == dst) |
… |
… |
bool RemoteFile::CopyFile (const QString& src, const QString& dst) |
586 | 588 | return false; |
587 | 589 | } |
588 | 590 | |
| 591 | if (overwrite) |
| 592 | { |
| 593 | DeleteFile(dst); |
| 594 | } |
| 595 | else if (Exists(dst)) |
| 596 | { |
| 597 | LOG(VB_GENERAL, LOG_ERR, "RemoteFile::CopyFile: File already exists"); |
| 598 | return false; |
| 599 | } |
| 600 | |
589 | 601 | RemoteFile dstFile(dst, true); |
590 | 602 | if (!dstFile.isOpen()) |
591 | 603 | { |
… |
… |
bool RemoteFile::CopyFile (const QString& src, const QString& dst) |
596 | 608 | return false; |
597 | 609 | } |
598 | 610 | |
| 611 | dstFile.SetBlocking(true); |
| 612 | |
| 613 | bool success = true; |
599 | 614 | int srcLen, dstLen; |
600 | 615 | |
601 | 616 | while ((srcLen = srcFile.Read(buf, readSize)) > 0) |
… |
… |
bool RemoteFile::CopyFile (const QString& src, const QString& dst) |
605 | 620 | if (dstLen == -1 || srcLen != dstLen) |
606 | 621 | { |
607 | 622 | LOG(VB_GENERAL, LOG_ERR, |
608 | | "RemoteFile::CopyFile:: Error while trying to write to destination file."); |
609 | | srcFile.Close(); |
610 | | dstFile.Close(); |
611 | | delete[] buf; |
612 | | return false; |
| 623 | "RemoteFile::CopyFile: Error while trying to write to destination file."); |
| 624 | success = false; |
613 | 625 | } |
614 | 626 | } |
615 | 627 | |
… |
… |
bool RemoteFile::CopyFile (const QString& src, const QString& dst) |
617 | 629 | dstFile.Close(); |
618 | 630 | delete[] buf; |
619 | 631 | |
620 | | return true; |
| 632 | if (success && verify) |
| 633 | { |
| 634 | // Check written file is correct size |
| 635 | struct stat fileinfo; |
| 636 | long long dstSize = Exists(dst, &fileinfo) ? fileinfo.st_size : -1; |
| 637 | long long srcSize = srcFile.GetFileSize(); |
| 638 | if (dstSize != srcSize) |
| 639 | { |
| 640 | LOG(VB_GENERAL, LOG_ERR, |
| 641 | QString("RemoteFile::CopyFile: Copied file is wrong size (%1 rather than %2)") |
| 642 | .arg(dstSize).arg(srcSize)); |
| 643 | success = false; |
| 644 | DeleteFile(dst); |
| 645 | } |
| 646 | } |
| 647 | |
| 648 | return success; |
621 | 649 | } |
622 | 650 | |
623 | 651 | void RemoteFile::Reset(void) |
diff --git a/mythtv/libs/libmythbase/remotefile.h b/mythtv/libs/libmythbase/remotefile.h
index 3c18a05..42fd38e 100644
a
|
b
|
class MBASE_PUBLIC RemoteFile |
41 | 41 | static QStringList FindFileList(const QString &filename, const QString &host, |
42 | 42 | const QString &storageGroup, bool useRegex = false, |
43 | 43 | bool allowFallback = false); |
44 | | static bool CopyFile(const QString &src, const QString &dest); |
| 44 | static bool CopyFile(const QString &src, const QString &dest, |
| 45 | bool overwrite = false, bool verify = false); |
45 | 46 | |
46 | 47 | int Write(const void *data, int size); |
47 | 48 | int Read(void *data, int size); |