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