35 QMap<int, FileTransfer*>::iterator i;
38 if ((*i)->GetSocket() == socket)
51 QMap<QString, SocketHandler*>::iterator i;
54 if ((*i)->GetSocket() == socket)
65 const QString &wantgroup)
67 QString lpath = QString(path);
69 if (lpath.section(
'/', -2, -2) ==
"channels")
72 QString
file = lpath.section(
'/', -1);
76 query.
prepare(
"SELECT icon FROM channel "
77 "WHERE icon LIKE :FILENAME ;");
82 lpath = query.
value(0).toString();
91 lpath = lpath.section(
'/', -1);
93 QString fpath = lpath;
94 if (fpath.endsWith(
".png"))
95 fpath = fpath.left(fpath.length() - 4);
101 if (pburl.startsWith(
"/"))
103 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
104 LOG(VB_FILE, LOG_INFO,
105 QString(
"Local file path: %1").arg(lpath));
109 LOG(VB_GENERAL, LOG_ERR,
110 QString(
"LocalFilePath unable to find local "
111 "path for '%1', found '%2' instead.")
116 else if (!lpath.isEmpty())
119 QString opath = lpath;
122 if (!wantgroup.isEmpty())
124 sgroup.
Init(wantgroup);
125 lpath = QString(path);
129 lpath = QFileInfo(lpath).fileName();
132 QString tmpFile = sgroup.
FindFile(lpath);
133 if (!tmpFile.isEmpty())
136 LOG(VB_FILE, LOG_INFO,
137 QString(
"LocalFilePath(%1 '%2'), found through "
138 "exhaustive search at '%3'")
139 .arg(path, opath, lpath));
143 LOG(VB_GENERAL, LOG_ERR, QString(
"LocalFilePath unable to "
144 "find local path for '%1'.")
175 QStringList &commands, QStringList &slist)
177 if (commands[1] ==
"FileServer")
179 if (slist.size() >= 3)
183 handler->BlockShutdown(
true);
184 handler->AllowStandardEvents(
true);
185 handler->AllowSystemEvents(
true);
187 handler->WriteStringList(QStringList(
"OK"));
190 m_fsMap.insert(commands[2], handler);
200 if (commands[1] !=
"FileTransfer")
203 if (slist.size() < 3)
206 if ((commands.size() < 3) || (commands.size() > 6))
212 bool writemode =
false;
213 bool usereadahead =
true;
214 std::chrono::milliseconds
timeout = 2s;
215 switch (commands.size())
218 timeout = std::chrono::milliseconds(commands[5].toInt());
221 usereadahead = (commands[4].toInt() != 0);
224 writemode = (commands[3].toInt() != 0);
230 QStringList::const_iterator it = slist.cbegin();
231 QString path = *(++it);
232 QString wantgroup = *(++it);
234 QStringList checkfiles;
235 while (++it != slist.cend())
240 LOG(VB_GENERAL, LOG_DEBUG,
"FileServerHandler::HandleAnnounce");
241 LOG(VB_GENERAL, LOG_INFO, QString(
"adding: %1 as remote file transfer")
246 if (wantgroup.isEmpty())
247 wantgroup =
"Default";
253 LOG(VB_GENERAL, LOG_ERR,
"Unable to determine directory "
254 "to write to in FileTransfer write command");
256 slist <<
"ERROR" <<
"filetransfer_directory_not_found";
263 LOG(VB_GENERAL, LOG_ERR, QString(
"FileTransfer write "
264 "filename is empty in path '%1'.")
267 slist <<
"ERROR" <<
"filetransfer_filename_empty";
272 if ((path.contains(
"/../")) ||
273 (path.startsWith(
"../")))
275 LOG(VB_GENERAL, LOG_ERR, QString(
"FileTransfer write "
276 "filename '%1' does not pass sanity checks.")
279 slist <<
"ERROR" <<
"filetransfer_filename_dangerous";
294 LOG(VB_GENERAL, LOG_ERR, QString(
"FileTransfer filename "
295 "'%1' is actually a directory, cannot transfer.")
298 slist <<
"ERROR" <<
"filetransfer_filename_is_a_directory";
305 QString dirPath = finfo.absolutePath();
309 if (!qdir.mkpath(dirPath))
311 LOG(VB_GENERAL, LOG_ERR, QString(
"FileTransfer "
312 "filename '%1' is in a subdirectory which does "
313 "not exist, but can not be created.")
316 slist <<
"ERROR" <<
"filetransfer_unable_to_create_subdirectory";
340 if (!checkfiles.empty())
343 QDir dir = fi.absoluteDir();
344 for (
const auto &
file : std::as_const(checkfiles))
346 if (dir.exists(
file) &&
360 QStringList &commands, QStringList &slist)
362 if (commands[1] ==
"SlaveBackend")
366 if (slist.size() >= 3)
369 if (handler ==
nullptr)
373 m_fsMap.insert(commands[2], handler);
382 bool handled =
false;
383 QString command = commands[0];
385 if (command ==
"QUERY_FILETRANSFER")
387 else if (command ==
"QUERY_FREE_SPACE")
389 else if (command ==
"QUERY_FREE_SPACE_LIST")
391 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
393 else if (command ==
"QUERY_CHECKFILE")
395 else if (command ==
"QUERY_FILE_EXISTS")
397 else if (command ==
"QUERY_FILE_HASH")
399 else if (command ==
"DELETE_FILE")
401 else if (command ==
"QUERY_SG_GETFILELIST")
403 else if (command ==
"QUERY_SG_FILEQUERY")
405 else if (command ==
"DOWNLOAD_FILE" || command ==
"DOWNLOAD_FILE_NOW")
421 for (
const auto & disk : std::as_const(disks))
422 if (!hosts.contains(disk.getHostname()))
423 hosts << disk.getHostname();
438 socket->
WriteStringList({QString::number(disks.back().getTotalSpace()),
439 QString::number(disks.back().getUsedSpace())});
447 groups.removeAll(
"LiveTV");
448 QString specialGroups = groups.join(
"', '");
451 query.
prepare(QString(
"SELECT MIN(id),dirname "
453 "WHERE hostname = :HOSTNAME "
454 "AND groupname NOT IN ( '%1' ) "
455 "GROUP BY dirname;").arg(specialGroups));
456 query.
bindValue(
":HOSTNAME", localHostName);
465 query.
prepare(
"SELECT MIN(id),dirname "
467 "WHERE groupname = :GROUP "
468 "GROUP BY dirname;");
474 QMap<QString, bool> foundDirs;
481 QString currentDir {QString::fromUtf8(query.
value(1).toByteArray().constData())};
482 if (currentDir.endsWith(
"/"))
483 currentDir.remove(currentDir.length() - 1, 1);
485 if (!foundDirs.contains(currentDir))
487 if (QDir(currentDir).
exists())
491 foundDirs[currentDir] =
true;
495 foundDirs[currentDir] =
false;
510 for (
const auto* fs : std::as_const(
m_fsMap))
527 QStringList::const_iterator it = slist.cbegin() + 2;
541 QStringList res(QString::number(
static_cast<int>(
exists)));
555 QString storageGroup =
"Default";
558 if (slist.size() == 3)
560 if (!slist[2].isEmpty())
561 storageGroup = slist[2];
563 else if (slist.size() != 2)
573 LOG(VB_GENERAL, LOG_ERR,
574 QString(
"ERROR checking for file, filename '%1' "
575 "fails sanity checks").arg(
filename));
584 if (!fullname.isEmpty())
590 struct stat fileinfo {};
591 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
593 res << QString::number(fileinfo.st_dev)
594 << QString::number(fileinfo.st_ino)
595 << QString::number(fileinfo.st_mode)
596 << QString::number(fileinfo.st_nlink)
597 << QString::number(fileinfo.st_uid)
598 << QString::number(fileinfo.st_gid)
599 << QString::number(fileinfo.st_rdev)
600 << QString::number(fileinfo.st_size)
605 << QString::number(fileinfo.st_blksize)
606 << QString::number(fileinfo.st_blocks)
608 << QString::number(fileinfo.st_atime)
609 << QString::number(fileinfo.st_mtime)
610 << QString::number(fileinfo.st_ctime);
629 QString storageGroup =
"Default";
634 switch (slist.size()) {
636 if (!slist[3].isEmpty())
640 if (!slist[2].isEmpty())
641 storageGroup = slist[2];
649 LOG(VB_GENERAL, LOG_ERR,
650 QString(
"ERROR checking for file, filename '%1' "
651 "fails sanity checks").arg(
filename));
694 if (slist.size() != 3)
706 const QString&
filename,
const QString& storagegroup)
715 LOG(VB_GENERAL, LOG_ERR,
716 QString(
"ERROR deleting file, filename '%1' fails sanity checks")
729 if (fullfile.isEmpty())
731 LOG(VB_GENERAL, LOG_ERR,
732 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(
filename));
742 QFile checkFile(fullfile);
743 if (checkFile.exists())
755 LOG(VB_GENERAL, LOG_ERR, QString(
"Error deleting file: '%1'")
778 bool fileNamesOnly =
false;
779 if (slist.size() == 5)
780 fileNamesOnly = (slist[4].toInt() != 0);
781 else if (slist.size() != 4)
783 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid Request. %1")
784 .arg(slist.join(
"[]:[]")));
791 QString wantHost = slist[1];
792 QString groupname = slist[2];
793 QString path = slist[3];
795 LOG(VB_FILE, LOG_INFO,
796 QString(
"HandleSGGetFileList: group = %1 host = %2 "
797 "path = %3 wanthost = %4")
798 .arg(groupname, host, path, wantHost));
803 LOG(VB_FILE, LOG_INFO,
"Getting local info");
809 if (res.count() == 0)
818 if (
m_fsMap.contains(wantHost))
820 remsock =
m_fsMap.value(wantHost);
827 LOG(VB_FILE, LOG_INFO,
"Getting remote info");
828 res <<
"QUERY_SG_GETFILELIST" << wantHost << groupname << path
829 << QString::number(
static_cast<int>(fileNamesOnly));
835 LOG(VB_FILE, LOG_ERR, QString(
"Failed to grab slave socket : %1 :")
837 res <<
"SLAVE UNREACHABLE: " << wantHost;
850 if (slist.size() != 4)
852 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid Request. %1")
853 .arg(slist.join(
"[]:[]")));
859 QString wantHost = slist[1];
860 QString groupname = slist[2];
863 LOG(VB_FILE, LOG_DEBUG, QString(
"HandleSGFileQuery: myth://%1@%2/%3")
864 .arg(groupname, wantHost,
filename));
869 LOG(VB_FILE, LOG_DEBUG, QString(
"Getting local info"));
873 if (res.count() == 0)
882 if (
m_fsMap.contains(wantHost))
884 remsock =
m_fsMap.value(wantHost);
891 res <<
"QUERY_SG_FILEQUERY" << wantHost << groupname <<
filename;
897 res <<
"SLAVE UNREACHABLE: " << wantHost;
906 QStringList &commands, QStringList &slist)
908 if (commands.size() != 2)
911 if (slist.size() < 2)
915 int recnum = commands[1].toInt();
922 if (slist[1] ==
"DONE")
926 LOG(VB_GENERAL, LOG_ERR,
927 QString(
"Unknown file transfer socket: %1").arg(recnum));
929 <<
"unknown_file_transfer_socket";
940 if (slist[1] ==
"REQUEST_BLOCK")
942 if (slist.size() != 3)
944 LOG(VB_GENERAL, LOG_ERR,
"Invalid QUERY_FILETRANSFER "
945 "REQUEST_BLOCK call");
946 res <<
"ERROR" <<
"invalid_call";
950 int size = slist[2].toInt();
954 else if (slist[1] ==
"WRITE_BLOCK")
956 if (slist.size() != 3)
958 LOG(VB_GENERAL, LOG_ERR,
"Invalid QUERY_FILETRANSFER "
960 res <<
"ERROR" <<
"invalid_call";
964 int size = slist[2].toInt();
968 else if (slist[1] ==
"SEEK")
970 if (slist.size() != 5)
972 LOG(VB_GENERAL, LOG_ERR,
"Invalid QUERY_FILETRANSFER SEEK call");
973 res <<
"ERROR" <<
"invalid_call";
977 long long pos = slist[2].toLongLong();
978 int whence = slist[3].toInt();
979 long long curpos = slist[4].toLongLong();
981 res << QString::number(ft->
Seek(curpos, pos, whence));
984 else if (slist[1] ==
"IS_OPEN")
986 res << QString::number(static_cast<int>(ft->
isOpen()));
988 else if (slist[1] ==
"DONE")
993 else if (slist[1] ==
"SET_TIMEOUT")
995 if (slist.size() != 3)
997 LOG(VB_GENERAL, LOG_ERR,
"Invalid QUERY_FILETRANSFER "
999 res <<
"ERROR" <<
"invalid_call";
1003 bool fast = slist[2].toInt() != 0;
1008 else if (slist[1] ==
"REQUEST_SIZE")
1016 LOG(VB_GENERAL, LOG_ERR,
"Invalid QUERY_FILETRANSFER call");
1017 res <<
"ERROR" <<
"invalid_call";
1030 if (slist.size() != 4)
1032 res <<
"ERROR" << QString(
"Bad %1 command").arg(slist[0]);
1037 bool synchronous = (slist[0] ==
"DOWNLOAD_FILE_NOW");
1038 QString srcURL = slist[1];
1039 QString storageGroup = slist[2];
1047 QFileInfo finfo(srcURL);
1051 if (outDir.isEmpty())
1053 LOG(VB_GENERAL, LOG_ERR, QString(
"Unable to determine directory "
1054 "to write to in %1 write command").arg(slist[0]));
1055 res <<
"ERROR" <<
"downloadfile_directory_not_found";
1063 LOG(VB_GENERAL, LOG_ERR, QString(
"ERROR: %1 write "
1064 "filename '%2' does not pass sanity checks.")
1066 res <<
"ERROR" <<
"downloadfile_filename_dangerous";
bool AddFile(const QString &path)
static bool HandleQueryCheckFile(SocketHandler *socket, QStringList &slist)
bool HandleFileQuery(SocketHandler *socket, QStringList &slist)
bool HandleQueryFileTransfer(SocketHandler *socket, QStringList &commands, QStringList &slist)
bool HandleQuery(SocketHandler *socket, QStringList &commands, QStringList &slist) override
QMutex m_downloadURLsLock
static void RunDeleteThread(void)
FileSystemInfoList QueryAllFileSystems(void)
QMap< QString, QString > m_downloadURLs
static FileSystemInfoList QueryFileSystems(void)
bool HandleDownloadFile(SocketHandler *socket, QStringList &slist)
bool HandleQueryFreeSpaceSummary(SocketHandler *socket)
bool HandleQueryFileHash(SocketHandler *socket, QStringList &slist)
static bool HandleQueryFileExists(SocketHandler *socket, QStringList &slist)
bool HandleAnnounce(MythSocket *socket, QStringList &commands, QStringList &slist) override
bool HandleGetFileList(SocketHandler *socket, QStringList &slist)
bool HandleQueryFreeSpaceList(SocketHandler *socket)
static bool HandleQueryFreeSpace(SocketHandler *socket)
void connectionClosed(MythSocket *socket) override
static bool DeleteFile(const QString &filename, const QString &storagegroup)
QMap< int, FileTransfer * > m_ftMap
void connectionAnnounced(MythSocket *socket, QStringList &commands, QStringList &slist) override
QMap< QString, SocketHandler * > m_fsMap
static QString LocalFilePath(const QString &path, const QString &wantgroup)
static bool HandleDeleteFile(SocketHandler *socket, QStringList &slist)
long long Seek(long long curpos, long long pos, int whence)
QString GetFileName(void)
uint64_t GetFileSize(void)
void SetTimeout(bool fast)
int RequestBlock(int size)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool isActive(void) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
bool isRunning(void) const
QString GetHostName(void)
bool IsThisHost(const QString &addr)
is this address mapped to this host
QString GetMasterHostPrefix(const QString &storageGroup=QString(), const QString &path=QString())
bool IsRegisteredFileForWrite(const QString &file)
static void DBError(const QString &where, const MSqlQuery &query)
void queueDownload(const QString &url, const QString &dest, QObject *caller, bool reload=false)
Adds a url to the download queue.
SocketHandler * GetConnectionBySocket(MythSocket *socket)
void AddSocketHandler(SocketHandler *socket)
Class for communcating between myth backends and frontends.
int GetSocketDescriptor(void) const
bool WriteStringList(const QStringList &list)
Holds information on recordings and videos.
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
bool HasPathname(void) const
Holds information on a TV Program one might wish to record.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
void BlockShutdown(bool block)
bool WriteStringList(const QStringList &strlist)
bool SendReceiveStringList(QStringList &strlist, uint min_reply_length=0)
MythSocketManager * m_parent
void Init(const QString &group="Default", const QString &hostname="", bool allowFallback=true)
Initilizes the groupname, hostname, and dirlist.
QStringList GetFileInfo(const QString &filename)
QString FindFile(const QString &filename)
static const QStringList kSpecialGroups
QStringList GetFileInfoList(const QString &Path)
QString FindNextDirMostFree(void)
QStringList GetFileList(const QString &Path, bool recursive=false)
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
DeleteThread * deletethread
QString GetPlaybackURL(ProgramInfo *pginfo, bool storePath)
QVector< FileSystemInfo > FileSystemInfoList
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString FileHash(const QString &filename)
MBASE_PUBLIC FileSystemInfoList GetInfoList(MythSocket *sock=nullptr)
MBASE_PUBLIC QStringList ToStringList(const FileSystemInfoList &fsInfos)
MBASE_PUBLIC void Consolidate(FileSystemInfoList &disks, bool merge, int64_t fuzz, const QString &total_name={})