MythTV master
storagegroup.cpp
Go to the documentation of this file.
1#include <QDir>
2#include <QFile>
3#include <QUrl>
4
5#include "storagegroup.h"
6#include "mythcorecontext.h"
7#include "mythdb.h"
8#include "mythlogging.h"
9#include "filesysteminfo.h"
10#include "mythdirs.h"
11#include "mythsocket.h"
12
13#define LOC QString("SG(%1): ").arg(m_groupname)
14
15const char *StorageGroup::kDefaultStorageDir = "/mnt/store";
16
19QMap<QString, QString> StorageGroup::m_builtinGroups;
21QHash<QString,QString> StorageGroup::s_groupToUseCache;
22
23const QStringList StorageGroup::kSpecialGroups = QStringList()
24 << QT_TRANSLATE_NOOP("(StorageGroups)", "LiveTV")
25// << "Thumbnails"
26 << QT_TRANSLATE_NOOP("(StorageGroups)", "DB Backups")
27 << QT_TRANSLATE_NOOP("(StorageGroups)", "Videos")
28 << QT_TRANSLATE_NOOP("(StorageGroups)", "Trailers")
29 << QT_TRANSLATE_NOOP("(StorageGroups)", "Coverart")
30 << QT_TRANSLATE_NOOP("(StorageGroups)", "Fanart")
31 << QT_TRANSLATE_NOOP("(StorageGroups)", "Screenshots")
32 << QT_TRANSLATE_NOOP("(StorageGroups)", "Banners")
33 << QT_TRANSLATE_NOOP("(StorageGroups)", "Photographs")
34 << QT_TRANSLATE_NOOP("(StorageGroups)", "Music")
35 << QT_TRANSLATE_NOOP("(StorageGroups)", "MusicArt")
36 ;
37
38/****************************************************************************/
39
48StorageGroup::StorageGroup(QString group, QString hostname,
49 bool allowFallback) :
50 m_groupname(std::move(group)), m_hostname(std::move(hostname)),
51 m_allowFallback(allowFallback)
52{
53 m_dirlist.clear();
54
55 if (qEnvironmentVariableIsSet("MYTHTV_NOSGFALLBACK"))
56 m_allowFallback = false;
57
59}
60
62{
63 QMutexLocker locker(&m_staticInitLock);
64
66 return;
67
68 m_staticInitDone = true;
69
70 m_builtinGroups["ChannelIcons"] = GetConfDir() + "/channels";
71 m_builtinGroups["Themes"] = GetConfDir() + "/themes";
72 m_builtinGroups["Temp"] = GetConfDir() + "/tmp";
73 m_builtinGroups["Streaming"] = GetConfDir() + "/tmp/hls";
74 m_builtinGroups["3rdParty"] = GetConfDir() + "/3rdParty";
75
76 // NOLINTNEXTLINE(modernize-loop-convert)
77 for (auto it = m_builtinGroups.begin(); it != m_builtinGroups.end(); ++it)
78 {
79 QDir qdir(it.value());
80 if (!qdir.exists())
81 qdir.mkpath(it.value());
82
83 if (!qdir.exists())
84 {
85 LOG(VB_GENERAL, LOG_ERR,
86 QString("SG() Error: Could not create builtin"
87 "Storage Group directory '%1' for '%2'")
88 .arg(it.value(), it.key()));
89 }
90 }
91}
92
107void StorageGroup::Init(const QString &group, const QString &hostname,
108 const bool allowFallback)
109{
110 m_groupname = group;
112 m_allowFallback = allowFallback;
113 m_dirlist.clear();
114
115 StaticInit();
116
117 bool found = FindDirs(m_groupname, m_hostname, &m_dirlist);
118
119 if (!found && m_builtinGroups.contains(group))
120 {
121 QDir testdir(m_builtinGroups[group]);
122 if (!testdir.exists())
123 testdir.mkpath(m_builtinGroups[group]);
124
125 if (testdir.exists())
126 {
127 m_dirlist.prepend(testdir.absolutePath());
128 found = true;
129 }
130 }
131
132 if ((!found) && m_allowFallback && (m_groupname != "LiveTV") &&
133 (!hostname.isEmpty()))
134 {
135 LOG(VB_FILE, LOG_NOTICE, LOC +
136 QString("Unable to find any directories for the local "
137 "storage group '%1' on '%2', trying directories on "
138 "all hosts!").arg(group, hostname));
139 found = FindDirs(m_groupname, "", &m_dirlist);
140 if (found)
141 {
142 m_hostname = "";
143 }
144 }
145 if ((!found) && m_allowFallback && (group != "Default"))
146 {
147 LOG(VB_FILE, LOG_NOTICE, LOC +
148 QString("Unable to find storage group '%1', trying "
149 "'Default' group!").arg(group));
150 found = FindDirs("Default", m_hostname, &m_dirlist);
151 if(found)
152 {
153 m_groupname = "Default";
154 }
155 else if (!hostname.isEmpty())
156 {
157 LOG(VB_FILE, LOG_NOTICE, LOC +
158 QString("Unable to find any directories for the local "
159 "Default storage group on '%1', trying directories "
160 "in all Default groups!").arg(hostname));
161 found = FindDirs("Default", "", &m_dirlist);
162 if(found)
163 {
164 m_groupname = "Default";
165 m_hostname = "";
166 }
167 }
168 }
169
170 if (allowFallback && m_dirlist.empty())
171 {
172 QString msg = "Unable to find any Storage Group Directories. ";
173 QString tmpDir = gCoreContext->GetSetting("RecordFilePrefix");
174 if (tmpDir != "")
175 {
176 msg += QString("Using old 'RecordFilePrefix' value of '%1'")
177 .arg(tmpDir);
178 }
179 else
180 {
181 tmpDir = kDefaultStorageDir;
182 msg += QString("Using hardcoded default value of '%1'")
183 .arg(kDefaultStorageDir);
184 }
185 LOG(VB_GENERAL, LOG_ERR, LOC + msg);
186 m_dirlist << tmpDir;
187 }
188}
189
190QString StorageGroup::GetFirstDir(bool appendSlash) const
191{
192 if (m_dirlist.isEmpty())
193 return {};
194
195 QString tmp = m_dirlist[0];
196
197 if (appendSlash)
198 tmp += "/";
199
200 return tmp;
201}
202
203QStringList StorageGroup::GetDirFileList(const QString &dir,
204 const QString &lbase,
205 bool recursive, bool onlyDirs)
206{
207 QStringList files;
208 QString base = lbase;
209 QDir d(dir);
210
211 if (!d.exists())
212 return files;
213
214 if (base.split("/").size() > 20)
215 {
216 LOG(VB_GENERAL, LOG_ERR, LOC + "GetDirFileList(), 20 levels deep, "
217 "possible directory loop detected.");
218 return files;
219 }
220
221 if (!base.isEmpty())
222 base += "/";
223
224 if (recursive)
225 {
226 QStringList list =
227 d.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable);
228
229 for (const auto& p : std::as_const(list))
230 {
231 LOG(VB_FILE, LOG_DEBUG, LOC +
232 QString("GetDirFileList: Dir: %1/%2").arg(base, p));
233
234 if (onlyDirs)
235 files.append(base + p);
236
237 files << GetDirFileList(dir + "/" + p, base + p, true, onlyDirs);
238 }
239 }
240
241 if (!onlyDirs)
242 {
243 QStringList list = d.entryList(QDir::Files|QDir::Readable);
244 for (const auto& p : std::as_const(list))
245 {
246 LOG(VB_FILE, LOG_DEBUG, LOC +
247 QString("GetDirFileList: File: %1%2").arg(base, p));
248 if (recursive)
249 files.append(base + p);
250 else
251 files.append(p);
252 }
253 }
254 return files;
255}
256
257QStringList StorageGroup::GetDirList(const QString &Path, bool recursive)
258{
259 QStringList files;
260 QString tmpDir;
261 QDir d;
262 for (const auto& dir : std::as_const(m_dirlist))
263 {
264 tmpDir = dir + Path;
265 d.setPath(tmpDir);
266 if (d.exists())
267 files << GetDirFileList(tmpDir, Path, recursive, true);
268 }
269 return files;
270}
271
272QStringList StorageGroup::GetFileList(const QString &Path, bool recursive)
273{
274 QStringList files;
275 QString tmpDir;
276 QDir d;
277
278 for (const auto& dir : std::as_const(m_dirlist))
279 {
280 tmpDir = dir + Path;
281
282 d.setPath(tmpDir);
283 if (d.exists())
284 files << GetDirFileList(tmpDir, Path, recursive, false);
285 }
286
287 return files;
288}
289
290QStringList StorageGroup::GetFileInfoList(const QString &Path)
291{
292 QStringList files;
293 QString relPath;
294 bool badPath = true;
295
296 if (Path.isEmpty() || Path == "/")
297 {
298 for (const auto& dir : std::as_const(m_dirlist))
299 files << QString("sgdir::%1").arg(dir);
300
301 return files;
302 }
303
304 for (const auto& dir : std::as_const(m_dirlist))
305 {
306 if (Path.startsWith(dir))
307 {
308 relPath = Path;
309 relPath.replace(dir,"");
310 if (relPath.startsWith("/"))
311 relPath.replace(0,1,"");
312 badPath = false;
313 }
314 }
315
316 LOG(VB_FILE, LOG_INFO, LOC +
317 QString("GetFileInfoList: Reading '%1'").arg(Path));
318
319 if (badPath)
320 return files;
321
322 QDir d(Path);
323 if (!d.exists())
324 return files;
325
326 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
327 QFileInfoList list = d.entryInfoList();
328 if (list.isEmpty())
329 return files;
330
331 for (const auto& entry : std::as_const(list))
332 {
333 if (entry.fileName() == "Thumbs.db")
334 continue;
335
336 QString tmp;
337
338 if (entry.isDir())
339 tmp = QString("dir::%1::0").arg(entry.fileName());
340 else
341 {
342 tmp = QString("file::%1::%2::%3%4").arg(entry.fileName())
343 .arg(entry.size())
344 .arg(relPath, entry.fileName());
345
346 }
347 LOG(VB_FILE, LOG_DEBUG, LOC +
348 QString("GetFileInfoList: (%1)").arg(tmp));
349 files.append(tmp);
350 }
351
352 return files;
353}
354
356{
357 LOG(VB_FILE, LOG_DEBUG, LOC +
358 QString("FileExist: Testing for '%1'").arg(filename));
359 bool badPath = true;
360
361 if (filename.isEmpty())
362 return false;
363
364 for (const auto & dir : std::as_const(m_dirlist))
365 {
366 if (filename.startsWith(dir))
367 {
368 badPath = false;
369 }
370 }
371
372 if (badPath)
373 return false;
374
375 return QFile::exists(filename);
376}
377
378
379// Returns a string list of details about the file
380// in the order FILENAME, DATE, SIZE
381QStringList StorageGroup::GetFileInfo(const QString &lfilename)
382{
383 QString filename = lfilename;
384 LOG(VB_FILE, LOG_DEBUG, LOC +
385 QString("GetFileInfo: For '%1'") .arg(filename));
386
387 QStringList details;
388 bool searched = false;
389
390 if (!FileExists(filename))
391 {
392 searched = true;
394 }
395
396 if ((searched && !filename.isEmpty()) ||
398 {
399 QFileInfo fInfo(filename);
400
401 details << filename;
402 if (fInfo.lastModified().isValid()) {
403 details << QString("%1").arg(fInfo.lastModified().toSecsSinceEpoch());
404 } else {
405 details << QString::number(UINT_MAX);
406 }
407 details << QString("%1").arg(fInfo.size());
408 }
409
410 return details;
411}
412
422{
423 QString result = filename;
425
426 LOG(VB_FILE, LOG_DEBUG,
427 QString("StorageGroup::GetRelativePathname(%1)").arg(filename));
428
429 StaticInit();
430
431 if (filename.startsWith("myth://"))
432 {
433 QUrl qurl(filename);
434
435 if (qurl.hasFragment())
436 result = qurl.path() + "#" + qurl.fragment();
437 else
438 result = qurl.path();
439
440 if (result.startsWith("/"))
441 result.replace(0, 1, "");
442
443 return result;
444 }
445
446 query.prepare("SELECT DISTINCT dirname FROM storagegroup "
447 "ORDER BY dirname DESC;");
448 if (query.exec())
449 {
450 QString dirname;
451 while (query.next())
452 {
453 /* The storagegroup.dirname column uses utf8_bin collation, so Qt
454 * uses QString::fromLatin1() for toString(). Explicitly convert the
455 * value using QString::fromUtf8() to prevent corruption. */
456 dirname = QString::fromUtf8(query.value(0)
457 .toByteArray().constData());
458 if (filename.startsWith(dirname))
459 {
460 result = filename;
461 result.replace(0, dirname.length(), "");
462 if (result.startsWith("/"))
463 result.replace(0, 1, "");
464
465 LOG(VB_FILE, LOG_DEBUG,
466 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
467 .arg(filename, result));
468 return result;
469 }
470 }
471 }
472
473 query.prepare("SELECT DISTINCT data FROM settings WHERE "
474 "value = 'VideoStartupDir';");
475 if (query.exec())
476 {
477 while (query.next())
478 {
479 QString videostartupdir = query.value(0).toString();
480 QStringList videodirs = videostartupdir.split(':',
481 Qt::SkipEmptyParts);
482 for (const auto& directory : std::as_const(videodirs))
483 {
484 if (filename.startsWith(directory))
485 {
486 result = filename;
487 result.replace(0, directory.length(), "");
488 if (result.startsWith("/"))
489 result.replace(0, 1, "");
490
491 LOG(VB_FILE, LOG_DEBUG,
492 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
493 .arg(filename, result));
494 return result;
495 }
496 }
497 }
498 }
499
500 for (const auto& group : std::as_const(m_builtinGroups))
501 {
502 QDir qdir(group);
503 if (!qdir.exists())
504 qdir.mkpath(group);
505
506 const QString& directory = group;
507 if (filename.startsWith(directory))
508 {
509 result = filename;
510 result.replace(0, directory.length(), "");
511 if (result.startsWith("/"))
512 result.replace(0, 1, "");
513
514 LOG(VB_FILE, LOG_DEBUG,
515 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
516 .arg(filename, result));
517 return result;
518 }
519 }
520
521 return result;
522}
523
533bool StorageGroup::FindDirs(const QString &group, const QString &hostname,
534 QStringList *dirlist)
535{
536 bool found = false;
537 QString dirname;
539
540 StaticInit();
541
542 QString sql = "SELECT DISTINCT dirname "
543 "FROM storagegroup ";
544
545 if (!group.isEmpty())
546 {
547 sql.append("WHERE groupname = :GROUP");
548 if (!hostname.isEmpty())
549 sql.append(" AND hostname = :HOSTNAME");
550 }
551
552 query.prepare(sql);
553 if (!group.isEmpty())
554 {
555 query.bindValue(":GROUP", group);
556 if (!hostname.isEmpty())
557 query.bindValue(":HOSTNAME", hostname);
558 }
559
560 if (!query.exec() || !query.isActive())
561 MythDB::DBError("StorageGroup::StorageGroup()", query);
562
563 while (query.next())
564 {
565 /* The storagegroup.dirname column uses utf8_bin collation, so Qt
566 * uses QString::fromLatin1() for toString(). Explicitly convert the
567 * value using QString::fromUtf8() to prevent corruption. */
568 dirname = QString::fromUtf8(query.value(0)
569 .toByteArray().constData());
570 dirname = dirname.trimmed();
571 if (dirname.endsWith("/"))
572 dirname.remove(dirname.length() - 1, 1);
573
574 if (nullptr == dirlist)
575 return true;
576 (*dirlist) << dirname;
577 found = true;
578 }
579
580 if (m_builtinGroups.contains(group))
581 {
582 QDir testdir(m_builtinGroups[group]);
583 if (testdir.exists())
584 {
585 if (dirlist && !dirlist->contains(testdir.absolutePath()))
586 (*dirlist) << testdir.absolutePath();
587 found = true;
588 }
589 }
590
591 return found;
592}
593
594QString StorageGroup::FindFile(const QString &filename)
595{
596 LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindFile: Searching for '%1'")
597 .arg(filename));
598
599 QString recDir = FindFileDir(filename);
600 QString result = "";
601
602 if (!recDir.isEmpty())
603 {
604 result = recDir + "/" + filename;
605 LOG(VB_FILE, LOG_INFO, LOC +
606 QString("FindFile: Found '%1'") .arg(result));
607 }
608 else
609 {
610 LOG(VB_FILE, LOG_ERR, LOC +
611 QString("FindFile: Unable to find '%1'!") .arg(filename));
612 }
613
614 return result;
615}
616
617QString StorageGroup::FindFileDir(const QString &filename)
618{
619 QString result = "";
620 QFileInfo checkFile("");
621
622 int curDir = 0;
623 while (curDir < m_dirlist.size())
624 {
625 QString testFile = m_dirlist[curDir] + "/" + filename;
626 LOG(VB_FILE, LOG_DEBUG, LOC +
627 QString("FindFileDir: Checking '%1' for '%2'")
628 .arg(m_dirlist[curDir], testFile));
629 checkFile.setFile(testFile);
630 if (checkFile.exists() || checkFile.isSymLink())
631 return m_dirlist[curDir];
632
633 curDir++;
634 }
635
636 if (m_groupname.isEmpty() || !m_allowFallback)
637 {
638 // Not found in any dir, so try RecordFilePrefix if it exists
639 QString tmpFile =
640 gCoreContext->GetSetting("RecordFilePrefix") + "/" + filename;
641 checkFile.setFile(tmpFile);
642 if (checkFile.exists() || checkFile.isSymLink())
643 result = tmpFile;
644 }
645 else if (m_groupname != "Default")
646 {
647 // Not found in current group so try Default
648 StorageGroup sgroup("Default");
649 QString tmpFile = sgroup.FindFileDir(filename);
650 result = (tmpFile.isEmpty()) ? result : tmpFile;
651 }
652 else
653 {
654 // Not found in Default so try any dir
655 StorageGroup sgroup;
656 QString tmpFile = sgroup.FindFileDir(filename);
657 result = (tmpFile.isEmpty()) ? result : tmpFile;
658 }
659
660 return result;
661}
662
664{
665 QString nextDir;
666 int64_t nextDirFree = 0;
667
668 LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindNextDirMostFree: Starting"));
669
670 if (m_allowFallback)
671 nextDir = kDefaultStorageDir;
672
673 for (const auto & dir : std::as_const(m_dirlist))
674 {
675 if (!QDir(dir).exists())
676 {
677 LOG(VB_GENERAL, LOG_ERR, LOC +
678 QString("FindNextDirMostFree: '%1' does not exist!").arg(dir));
679 continue;
680 }
681
682 int64_t thisDirFree = FileSystemInfo(QString(), dir).getFreeSpace();
683 LOG(VB_FILE, LOG_DEBUG, LOC +
684 QString("FindNextDirMostFree: '%1' has %2 KiB free")
685 .arg(dir, QString::number(thisDirFree)));
686
687 if (thisDirFree > nextDirFree)
688 {
689 nextDir = dir;
690 nextDirFree = thisDirFree;
691 }
692 }
693
694 if (nextDir.isEmpty())
695 {
696 LOG(VB_FILE, LOG_ERR, LOC +
697 "FindNextDirMostFree: Unable to find any directories to use.");
698 }
699 else
700 {
701 LOG(VB_FILE, LOG_DEBUG, LOC +
702 QString("FindNextDirMostFree: Using '%1'").arg(nextDir));
703 }
704
705 return nextDir;
706}
707
709{
710 QString m_groupname;
711 QString dirname;
713
714 query.prepare("SELECT groupname, dirname "
715 "FROM storagegroup "
716 "WHERE hostname = :HOSTNAME;");
717 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
718 if (!query.exec() || !query.isActive())
719 {
720 MythDB::DBError("StorageGroup::CheckAllStorageGroupDirs()", query);
721 return;
722 }
723
724 LOG(VB_FILE, LOG_DEBUG, LOC +
725 "CheckAllStorageGroupDirs(): Checking All Storage Group directories");
726
727 QFile testFile("");
728 QDir testDir("");
729 while (query.next())
730 {
731 m_groupname = query.value(0).toString();
732 /* The storagegroup.dirname column uses utf8_bin collation, so Qt
733 * uses QString::fromLatin1() for toString(). Explicitly convert the
734 * value using QString::fromUtf8() to prevent corruption. */
735 dirname = QString::fromUtf8(query.value(1)
736 .toByteArray().constData());
737 dirname = dirname.trimmed();
738
739 LOG(VB_FILE, LOG_DEBUG, LOC +
740 QString("Checking directory '%1' in group '%2'.")
741 .arg(dirname, m_groupname));
742
743 testDir.setPath(dirname);
744 if (!testDir.exists())
745 {
746 LOG(VB_FILE, LOG_WARNING, LOC +
747 QString("Group '%1' references directory '%2' but this "
748 "directory does not exist. This directory "
749 "will not be used on this server.")
750 .arg(m_groupname, dirname));
751 }
752 else
753 {
754 testFile.setFileName(dirname + "/.test");
755 if (testFile.open(QIODevice::WriteOnly))
756 testFile.remove();
757 else
758 {
759 LOG(VB_GENERAL, LOG_ERR, LOC +
760 QString("Group '%1' wants to use directory '%2', but "
761 "this directory is not writeable.")
762 .arg(m_groupname, dirname));
763 }
764 }
765 }
766}
767
769{
770 QStringList groups;
771
773
774 QString sql = "SELECT DISTINCT groupname "
775 "FROM storagegroup "
776 "WHERE groupname NOT IN (";
777 for (const auto& group : std::as_const(StorageGroup::kSpecialGroups))
778 sql.append(QString(" '%1',").arg(group));
779 sql = sql.left(sql.length() - 1);
780 sql.append(" );");
781
782 query.prepare(sql);
783 if (query.exec())
784 {
785 while (query.next())
786 {
787 groups += query.value(0).toString();
788 }
789 }
790
791 groups.sort();
792 return groups;
793}
794
795QStringList StorageGroup::getGroupDirs(const QString &groupname,
796 const QString &host)
797{
798 QStringList groups;
799 QString addHost;
800
802
803 if (!host.isEmpty())
804 addHost = " AND hostname = :HOSTNAME";
805 else
806 addHost = "";
807
808 QString sql = QString("SELECT dirname,hostname "
809 "FROM storagegroup "
810 "WHERE groupname = :GROUPNAME %1").arg(addHost);
811
812 query.prepare(sql);
813 query.bindValue(":GROUPNAME", groupname);
814
815 if (!host.isEmpty())
816 query.bindValue(":HOSTNAME", host);
817
818 if (query.exec())
819 {
820 QString dirname;
821 while (query.next())
822 {
823 /* The storagegroup.dirname column uses utf8_bin collation, so Qt
824 * uses QString::fromLatin1() for toString(). Explicitly convert the
825 * value using QString::fromUtf8() to prevent corruption. */
826 dirname = QString::fromUtf8(query.value(0)
827 .toByteArray().constData());
828 groups += MythCoreContext::GenMythURL(query.value(1).toString(),
829 0,
830 dirname,
831 groupname);
832 }
833 }
834
835 groups.sort();
836 return groups;
837}
838
840{
841 QMutexLocker locker(&s_groupToUseLock);
842 s_groupToUseCache.clear();
843}
844
846 const QString &host, const QString &sgroup)
847{
848 QString tmpGroup = sgroup;
849 QString groupKey = QString("%1:%2").arg(sgroup, host);
850
851 QMutexLocker locker(&s_groupToUseLock);
852
853 if (s_groupToUseCache.contains(groupKey))
854 {
855 tmpGroup = s_groupToUseCache[groupKey];
856 }
857 else
858 {
859 if (StorageGroup::FindDirs(sgroup, host))
860 {
861 s_groupToUseCache[groupKey] = sgroup;
862 }
863 else
864 {
865 LOG(VB_FILE, LOG_DEBUG,
866 QString("GetGroupToUse(): "
867 "falling back to Videos Storage Group for host %1 "
868 "since it does not have a %2 Storage Group.")
869 .arg(host, sgroup));
870
871 tmpGroup = "Videos";
872 s_groupToUseCache[groupKey] = tmpGroup;
873 }
874 }
875
876 return tmpGroup;
877}
878
879QString StorageGroup::generate_file_url(const QString &storage_group,
880 const QString &host,
881 const QString &path)
882{
884 path, StorageGroup::GetGroupToUse(host, storage_group));
885
886}
887
888bool StorageGroup::remoteGetFileList(const QString& host, const QString& path, QStringList* list,
889 QString sgroup, bool fileNamesOnly)
890{
891
892 // Make sure the list is empty when we get started
893 list->clear();
894
895 if (sgroup.isEmpty())
896 sgroup = "Videos";
897
898 *list << "QUERY_SG_GETFILELIST";
899 *list << host;
900 *list << StorageGroup::GetGroupToUse(host, sgroup);
901 *list << path;
902 *list << QString::number(static_cast<int>(fileNamesOnly));
903
904 bool ok = false;
905
907 {
908 // since the master backend cannot connect back around to
909 // itself, and the libraries do not have access to the list
910 // of connected slave backends to query an existing connection
911 // start up a new temporary connection directly to the slave
912 // backend to query the file list
913 QString ann = QString("ANN Playback %1 0")
914 .arg(gCoreContext->GetHostName());
915 QString addr = gCoreContext->GetBackendServerIP(host);
916 int port = gCoreContext->GetBackendServerPort(host);
917 bool mismatch = false;
918
920 addr, port, ann, &mismatch);
921 if (sock)
922 {
923 ok = sock->SendReceiveStringList(*list);
924 sock->DecrRef();
925 }
926 else
927 {
928 list->clear();
929 }
930 }
931 else
932 {
934 }
935
936 // Should the SLAVE UNREACH test be here ?
937 return ok;
938}
939
940/* vim: set expandtab tabstop=4 shiftwidth=4: */
int64_t getFreeSpace() const
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
QString GetHostName(void)
MythSocket * ConnectCommandSocket(const QString &hostname, int port, const QString &announcement, bool *proto_mismatch=nullptr, int maxConnTry=-1, std::chrono::milliseconds setup_timeout=-1ms)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetBackendServerPort(void)
Returns the locally defined backend control port.
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
bool IsMasterBackend(void)
is this the actual MBE process
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, std::chrono::milliseconds timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:326
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QStringList GetDirFileList(const QString &dir, const QString &base, bool recursive=false, bool onlyDirs=false)
QStringList GetDirList(void) const
Definition: storagegroup.h:23
QString FindFileDir(const QString &filename)
QStringList m_dirlist
Definition: storagegroup.h:72
void Init(const QString &group="Default", const QString &hostname="", bool allowFallback=true)
Initilizes the groupname, hostname, and dirlist.
QString GetFirstDir(bool appendSlash=false) const
QString m_hostname
Definition: storagegroup.h:70
static QStringList getRecordingsGroups(void)
static QStringList getGroupDirs(const QString &groupname, const QString &host)
bool FileExists(const QString &filename)
static bool remoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly=false)
static const char * kDefaultStorageDir
Definition: storagegroup.h:45
static bool FindDirs(const QString &group="Default", const QString &hostname="", QStringList *dirlist=nullptr)
Finds and and optionally initialize a directory list associated with a Storage Group.
static QMap< QString, QString > m_builtinGroups
Definition: storagegroup.h:74
static QString GetGroupToUse(const QString &host, const QString &sgroup)
static QHash< QString, QString > s_groupToUseCache
Definition: storagegroup.h:77
static void ClearGroupToUseCache(void)
QStringList GetFileInfo(const QString &filename)
QString FindFile(const QString &filename)
QString m_groupname
Definition: storagegroup.h:69
bool m_allowFallback
Definition: storagegroup.h:71
static const QStringList kSpecialGroups
Definition: storagegroup.h:46
static void CheckAllStorageGroupDirs(void)
StorageGroup(QString group="", QString hostname="", bool allowFallback=true)
StorageGroup constructor.
static QMutex m_staticInitLock
Definition: storagegroup.h:67
static void StaticInit(void)
static QMutex s_groupToUseLock
Definition: storagegroup.h:76
QStringList GetFileInfoList(const QString &Path)
static QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
QString FindNextDirMostFree(void)
QStringList GetFileList(const QString &Path, bool recursive=false)
static bool m_staticInitDone
Definition: storagegroup.h:66
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
static guint32 * tmp
Definition: goom_core.cpp:26
static const iso6937table * d
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString GetConfDir(void)
Definition: mythdirs.cpp:263
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
string hostname
Definition: caa.py:17
STL namespace.
bool exists(str path)
Definition: xbmcvfs.py:51
#define LOC