Ticket #12424: 0009-RemoteFile-Add-Move-operation.patch
File 0009-RemoteFile-Add-Move-operation.patch, 8.3 KB (added by , 8 years ago) |
---|
-
mythtv/libs/libmythbase/remotefile.cpp
From 117046af0139d6717dc96cc7a5def88b1734c0a7 Mon Sep 17 00:00:00 2001 From: Roger Siddons <dizygotheca@ntlworld.com> Date: Sat, 22 Aug 2015 14:56:17 +0100 Subject: [PATCH 09/15] RemoteFile: Add Move operation Adds support for renaming files. Remote files can only be moved within the same storage group. Between local/remote locations the source is only deleted after being successfully copied. diff --git a/mythtv/libs/libmythbase/remotefile.cpp b/mythtv/libs/libmythbase/remotefile.cpp index 594a6eb..28721f7 100644
a b bool RemoteFile::CopyFile (const QString& src, const QString& dst, 648 648 return success; 649 649 } 650 650 651 bool RemoteFile::MoveFile (const QString& src, const QString& dst, bool overwrite) 652 { 653 LOG(VB_FILE, LOG_INFO, 654 QString("RemoteFile::MoveFile: Moving file from '%1' to '%2'").arg(src).arg(dst)); 655 656 // sanity check 657 if (src == dst) 658 { 659 LOG(VB_GENERAL, LOG_ERR, "RemoteFile::MoveFile: Cannot move a file to itself"); 660 return false; 661 } 662 663 if (isLocal(src) != isLocal(dst)) 664 { 665 // Moving between local & remote requires a copy & delete 666 bool ok = CopyFile(src, dst, overwrite, true); 667 if (ok) 668 { 669 if (!DeleteFile(src)) 670 LOG(VB_FILE, LOG_ERR, 671 "RemoteFile::MoveFile: Failed to delete file after successful copy"); 672 } 673 return ok; 674 } 675 676 if (overwrite) 677 { 678 DeleteFile(dst); 679 } 680 else if (Exists(dst)) 681 { 682 LOG(VB_GENERAL, LOG_ERR, "RemoteFile::MoveFile: File already exists"); 683 return false; 684 } 685 686 if (isLocal(src)) 687 { 688 // Moving local -> local 689 QFileInfo fi(dst); 690 if (QDir().mkpath(fi.path()) && QFile::rename(src, dst)) 691 return true; 692 693 LOG(VB_FILE, LOG_ERR, "RemoteFile::MoveFile: Rename failed"); 694 return false; 695 } 696 697 // Moving remote -> remote 698 QUrl srcUrl(src); 699 QUrl dstUrl(dst); 700 701 if (srcUrl.userName() != dstUrl.userName()) 702 { 703 LOG(VB_FILE, LOG_ERR, "RemoteFile::MoveFile: Cannot change a file's Storage Group"); 704 return false; 705 } 706 707 QStringList strlist("MOVE_FILE"); 708 strlist << srcUrl.userName() << srcUrl.path() << dstUrl.path(); 709 710 gCoreContext->SendReceiveStringList(strlist); 711 712 if (!strlist.isEmpty() && strlist[0] == "1") 713 return true; 714 715 LOG(VB_FILE, LOG_ERR, QString("RemoteFile::MoveFile: MOVE_FILE failed with: %1") 716 .arg(strlist.join(","))); 717 return false; 718 } 719 651 720 void RemoteFile::Reset(void) 652 721 { 653 722 if (isLocal()) -
mythtv/libs/libmythbase/remotefile.h
diff --git a/mythtv/libs/libmythbase/remotefile.h b/mythtv/libs/libmythbase/remotefile.h index 42fd38e..7144e78 100644
a b class MBASE_PUBLIC RemoteFile 43 43 bool allowFallback = false); 44 44 static bool CopyFile(const QString &src, const QString &dest, 45 45 bool overwrite = false, bool verify = false); 46 static bool MoveFile(const QString &src, const QString &dest, 47 bool overwrite = false); 46 48 47 49 int Write(const void *data, int size); 48 50 int Read(void *data, int size); -
mythtv/programs/mythbackend/mainserver.cpp
diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index 656fa6e..b76534d 100644
a b void MainServer::ProcessRequestWork(MythSocket *sock) 611 611 else 612 612 HandleDeleteFile(listline, pbs); 613 613 } 614 else if (command == "MOVE_FILE") 615 { 616 if (listline.size() < 4) 617 SendErrorResponse(pbs, "Bad MOVE_FILE command"); 618 else 619 HandleMoveFile(pbs, listline[1], listline[2], listline[3]); 620 } 614 621 else if (command == "STOP_RECORDING") 615 622 { 616 623 HandleStopRecording(listline, pbs); … … void MainServer::GetFilesystemInfos(QList<FileSystemInfo> &fsInfos) 5154 5161 } 5155 5162 } 5156 5163 5164 void MainServer::HandleMoveFile(PlaybackSock *pbs, const QString &storagegroup, 5165 const QString &src, const QString &dst) 5166 { 5167 StorageGroup sgroup(storagegroup, "", false); 5168 QStringList retlist; 5169 5170 if (src.isEmpty() || dst.isEmpty() 5171 || src.contains("..") || dst.contains("..")) 5172 { 5173 LOG(VB_GENERAL, LOG_ERR, LOC + 5174 QString("HandleMoveFile: ERROR moving file '%1' -> '%2', " 5175 "a path fails sanity checks").arg(src, dst)); 5176 retlist << "0" << "Invalid path"; 5177 SendResponse(pbs->getSocket(), retlist); 5178 return; 5179 } 5180 5181 QString srcAbs = sgroup.FindFile(src); 5182 if (srcAbs.isEmpty()) 5183 { 5184 LOG(VB_GENERAL, LOG_ERR, LOC + 5185 QString("HandleMoveFile: Unable to find %1").arg(src)); 5186 retlist << "0" << "Source file not found"; 5187 SendResponse(pbs->getSocket(), retlist); 5188 return; 5189 } 5190 5191 // Path of files must be unique within SG. Rename will permit <sgdir1>/<dst> 5192 // even when <sgdir2>/<dst> already exists. 5193 // Directory paths do not have to be unique. 5194 QString dstAbs = sgroup.FindFile(dst); 5195 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile()) 5196 { 5197 LOG(VB_GENERAL, LOG_ERR, LOC + 5198 QString("HandleMoveFile: Destination exists at %1").arg(dstAbs)); 5199 retlist << "0" << "Destination file exists"; 5200 SendResponse(pbs->getSocket(), retlist); 5201 return; 5202 } 5203 5204 // Files never move filesystems, so use current SG dir 5205 int sgPathSize = srcAbs.size() - src.size(); 5206 dstAbs = srcAbs.mid(0, sgPathSize) + dst; 5207 5208 // Renaming on same filesystem should always be fast but is liable to delays 5209 // for unknowable reasons so we delegate to a separate thread for safety. 5210 RenameThread *renamer = new RenameThread(*this, *pbs, srcAbs, dstAbs); 5211 MThreadPool::globalInstance()->start(renamer, "Rename"); 5212 } 5213 5214 QMutex RenameThread::m_renamelock; 5215 5216 void RenameThread::run() 5217 { 5218 // Only permit one rename to run at any time 5219 QMutexLocker lock(&m_renamelock); 5220 LOG(VB_FILE, LOG_INFO, QString("MainServer::RenameThread: Renaming %1 -> %2") 5221 .arg(m_src, m_dst)); 5222 5223 QStringList retlist; 5224 QFileInfo fi(m_dst); 5225 5226 if (QDir().mkpath(fi.path()) && QFile::rename(m_src, m_dst)) 5227 { 5228 retlist << "1"; 5229 } 5230 else 5231 { 5232 retlist << "0" << "Rename failed"; 5233 LOG(VB_FILE, LOG_ERR, "MainServer::DoRenameThread: Rename failed"); 5234 } 5235 m_ms.SendResponse(m_pbs.getSocket(), retlist); 5236 } 5237 5157 5238 void TruncateThread::run(void) 5158 5239 { 5159 5240 if (m_ms) -
mythtv/programs/mythbackend/mainserver.h
diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h index 4e5e2dd..ce117d8 100644
a b class TruncateThread : public QRunnable, public DeleteStruct 92 92 void run(void); 93 93 }; 94 94 95 class RenameThread : public QRunnable 96 { 97 public: 98 RenameThread(MainServer &ms, PlaybackSock &pbs, QString src, QString dst) 99 : m_ms(ms), m_pbs(pbs), m_src(src), m_dst(dst) {} 100 void run(void); 101 102 private: 103 static QMutex m_renamelock; 104 105 MainServer &m_ms; 106 PlaybackSock &m_pbs; 107 QString m_src, m_dst; 108 }; 109 95 110 class MainServer : public QObject, public MythSocketCBs 96 111 { 97 112 Q_OBJECT … … class MainServer : public QObject, public MythSocketCBs 99 114 friend class DeleteThread; 100 115 friend class TruncateThread; 101 116 friend class FreeSpaceUpdater; 117 friend class RenameThread; 102 118 public: 103 119 MainServer(bool master, int port, 104 120 QMap<int, EncoderLink *> *tvList, … … class MainServer : public QObject, public MythSocketCBs 147 163 void GetActiveBackends(QStringList &hosts); 148 164 void HandleActiveBackendsQuery(PlaybackSock *pbs); 149 165 void HandleIsActiveBackendQuery(QStringList &slist, PlaybackSock *pbs); 166 void HandleMoveFile(PlaybackSock *pbs, const QString &storagegroup, 167 const QString &src, const QString &dst); 150 168 bool HandleDeleteFile(QStringList &slist, PlaybackSock *pbs); 151 169 bool HandleDeleteFile(QString filename, QString storagegroup, 152 170 PlaybackSock *pbs = NULL);