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 "mythcoreutil.h"
10 #include "mythdirs.h"
11 
12 #define LOC QString("SG(%1): ").arg(m_groupname)
13 
14 const char *StorageGroup::kDefaultStorageDir = "/mnt/store";
15 
18 QMap<QString, QString> StorageGroup::m_builtinGroups;
20 QHash<QString,QString> StorageGroup::s_groupToUseCache;
21 
22 const 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 
47 StorageGroup::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 
64  if (m_staticInitDone)
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 
106 void 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 
189 QString 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 
202 QStringList 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 
256 QStringList 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 
271 QStringList 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 
289 QStringList 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 
354 bool StorageGroup::FileExists(const QString &filename)
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
380 QStringList 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()) ||
396  (FileExists(filename)))
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;
423  MSqlQuery query(MSqlQuery::InitCon());
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 
532 bool StorageGroup::FindDirs(const QString &group, const QString &hostname,
533  QStringList *dirlist)
534 {
535  bool found = false;
536  QString dirname;
537  MSqlQuery query(MSqlQuery::InitCon());
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  else if (query.next())
562  {
563  do
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 (dirlist)
575  (*dirlist) << dirname;
576  else
577  return true;
578  }
579  while (query.next());
580  found = true;
581  }
582 
583  if (m_builtinGroups.contains(group))
584  {
585  QDir testdir(m_builtinGroups[group]);
586  if (testdir.exists())
587  {
588  if (dirlist && !dirlist->contains(testdir.absolutePath()))
589  (*dirlist) << testdir.absolutePath();
590  found = true;
591  }
592  }
593 
594  return found;
595 }
596 
597 QString StorageGroup::FindFile(const QString &filename)
598 {
599  LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindFile: Searching for '%1'")
600  .arg(filename));
601 
602  QString recDir = FindFileDir(filename);
603  QString result = "";
604 
605  if (!recDir.isEmpty())
606  {
607  result = recDir + "/" + filename;
608  LOG(VB_FILE, LOG_INFO, LOC +
609  QString("FindFile: Found '%1'") .arg(result));
610  }
611  else
612  {
613  LOG(VB_FILE, LOG_ERR, LOC +
614  QString("FindFile: Unable to find '%1'!") .arg(filename));
615  }
616 
617  return result;
618 }
619 
620 QString StorageGroup::FindFileDir(const QString &filename)
621 {
622  QString result = "";
623  QFileInfo checkFile("");
624 
625  int curDir = 0;
626  while (curDir < m_dirlist.size())
627  {
628  QString testFile = m_dirlist[curDir] + "/" + filename;
629  LOG(VB_FILE, LOG_DEBUG, LOC +
630  QString("FindFileDir: Checking '%1' for '%2'")
631  .arg(m_dirlist[curDir], testFile));
632  checkFile.setFile(testFile);
633  if (checkFile.exists() || checkFile.isSymLink())
634  return m_dirlist[curDir];
635 
636  curDir++;
637  }
638 
639  if (m_groupname.isEmpty() || !m_allowFallback)
640  {
641  // Not found in any dir, so try RecordFilePrefix if it exists
642  QString tmpFile =
643  gCoreContext->GetSetting("RecordFilePrefix") + "/" + filename;
644  checkFile.setFile(tmpFile);
645  if (checkFile.exists() || checkFile.isSymLink())
646  result = tmpFile;
647  }
648  else if (m_groupname != "Default")
649  {
650  // Not found in current group so try Default
651  StorageGroup sgroup("Default");
652  QString tmpFile = sgroup.FindFileDir(filename);
653  result = (tmpFile.isEmpty()) ? result : tmpFile;
654  }
655  else
656  {
657  // Not found in Default so try any dir
658  StorageGroup sgroup;
659  QString tmpFile = sgroup.FindFileDir(filename);
660  result = (tmpFile.isEmpty()) ? result : tmpFile;
661  }
662 
663  return result;
664 }
665 
667 {
668  QString nextDir;
669  int64_t nextDirFree = 0;
670  int64_t thisDirTotal = 0;
671  int64_t thisDirUsed = 0;
672  int64_t thisDirFree = 0;
673 
674  LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindNextDirMostFree: Starting"));
675 
676  if (m_allowFallback)
677  nextDir = kDefaultStorageDir;
678 
679  if (!m_dirlist.empty())
680  nextDir = m_dirlist[0];
681 
682  QDir checkDir("");
683  int curDir = 0;
684  while (curDir < m_dirlist.size())
685  {
686  checkDir.setPath(m_dirlist[curDir]);
687  if (!checkDir.exists())
688  {
689  LOG(VB_GENERAL, LOG_ERR, LOC +
690  QString("FindNextDirMostFree: '%1' does not exist!")
691  .arg(m_dirlist[curDir]));
692  curDir++;
693  continue;
694  }
695 
696  thisDirFree = getDiskSpace(m_dirlist[curDir], thisDirTotal,
697  thisDirUsed);
698  LOG(VB_FILE, LOG_DEBUG, LOC +
699  QString("FindNextDirMostFree: '%1' has %2 KiB free")
700  .arg(m_dirlist[curDir], QString::number(thisDirFree)));
701 
702  if (thisDirFree > nextDirFree)
703  {
704  nextDir = m_dirlist[curDir];
705  nextDirFree = thisDirFree;
706  }
707  curDir++;
708  }
709 
710  if (nextDir.isEmpty())
711  {
712  LOG(VB_FILE, LOG_ERR, LOC +
713  "FindNextDirMostFree: Unable to find any directories to use.");
714  }
715  else
716  {
717  LOG(VB_FILE, LOG_DEBUG, LOC +
718  QString("FindNextDirMostFree: Using '%1'").arg(nextDir));
719  }
720 
721  return nextDir;
722 }
723 
725 {
726  QString m_groupname;
727  QString dirname;
728  MSqlQuery query(MSqlQuery::InitCon());
729 
730  query.prepare("SELECT groupname, dirname "
731  "FROM storagegroup "
732  "WHERE hostname = :HOSTNAME;");
733  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
734  if (!query.exec() || !query.isActive())
735  {
736  MythDB::DBError("StorageGroup::CheckAllStorageGroupDirs()", query);
737  return;
738  }
739 
740  LOG(VB_FILE, LOG_DEBUG, LOC +
741  "CheckAllStorageGroupDirs(): Checking All Storage Group directories");
742 
743  QFile testFile("");
744  QDir testDir("");
745  while (query.next())
746  {
747  m_groupname = query.value(0).toString();
748  /* The storagegroup.dirname column uses utf8_bin collation, so Qt
749  * uses QString::fromLatin1() for toString(). Explicitly convert the
750  * value using QString::fromUtf8() to prevent corruption. */
751  dirname = QString::fromUtf8(query.value(1)
752  .toByteArray().constData());
753  dirname = dirname.trimmed();
754 
755  LOG(VB_FILE, LOG_DEBUG, LOC +
756  QString("Checking directory '%1' in group '%2'.")
757  .arg(dirname, m_groupname));
758 
759  testDir.setPath(dirname);
760  if (!testDir.exists())
761  {
762  LOG(VB_FILE, LOG_WARNING, LOC +
763  QString("Group '%1' references directory '%2' but this "
764  "directory does not exist. This directory "
765  "will not be used on this server.")
766  .arg(m_groupname, dirname));
767  }
768  else
769  {
770  testFile.setFileName(dirname + "/.test");
771  if (testFile.open(QIODevice::WriteOnly))
772  testFile.remove();
773  else
774  {
775  LOG(VB_GENERAL, LOG_ERR, LOC +
776  QString("Group '%1' wants to use directory '%2', but "
777  "this directory is not writeable.")
778  .arg(m_groupname, dirname));
779  }
780  }
781  }
782 }
783 
785 {
786  QStringList groups;
787 
788  MSqlQuery query(MSqlQuery::InitCon());
789 
790  QString sql = "SELECT DISTINCT groupname "
791  "FROM storagegroup "
792  "WHERE groupname NOT IN (";
793  for (const auto& group : std::as_const(StorageGroup::kSpecialGroups))
794  sql.append(QString(" '%1',").arg(group));
795  sql = sql.left(sql.length() - 1);
796  sql.append(" );");
797 
798  query.prepare(sql);
799  if (query.exec())
800  {
801  while (query.next())
802  {
803  groups += query.value(0).toString();
804  }
805  }
806 
807  groups.sort();
808  return groups;
809 }
810 
811 QStringList StorageGroup::getGroupDirs(const QString &groupname,
812  const QString &host)
813 {
814  QStringList groups;
815  QString addHost;
816 
817  MSqlQuery query(MSqlQuery::InitCon());
818 
819  if (!host.isEmpty())
820  addHost = " AND hostname = :HOSTNAME";
821  else
822  addHost = "";
823 
824  QString sql = QString("SELECT dirname,hostname "
825  "FROM storagegroup "
826  "WHERE groupname = :GROUPNAME %1").arg(addHost);
827 
828  query.prepare(sql);
829  query.bindValue(":GROUPNAME", groupname);
830 
831  if (!host.isEmpty())
832  query.bindValue(":HOSTNAME", host);
833 
834  if (query.exec())
835  {
836  QString dirname;
837  while (query.next())
838  {
839  /* The storagegroup.dirname column uses utf8_bin collation, so Qt
840  * uses QString::fromLatin1() for toString(). Explicitly convert the
841  * value using QString::fromUtf8() to prevent corruption. */
842  dirname = QString::fromUtf8(query.value(0)
843  .toByteArray().constData());
844  groups += MythCoreContext::GenMythURL(query.value(1).toString(),
845  0,
846  dirname,
847  groupname);
848  }
849  }
850 
851  groups.sort();
852  return groups;
853 }
854 
856 {
857  QMutexLocker locker(&s_groupToUseLock);
858  s_groupToUseCache.clear();
859 }
860 
862  const QString &host, const QString &sgroup)
863 {
864  QString tmpGroup = sgroup;
865  QString groupKey = QString("%1:%2").arg(sgroup, host);
866 
867  QMutexLocker locker(&s_groupToUseLock);
868 
869  if (s_groupToUseCache.contains(groupKey))
870  {
871  tmpGroup = s_groupToUseCache[groupKey];
872  }
873  else
874  {
875  if (StorageGroup::FindDirs(sgroup, host))
876  {
877  s_groupToUseCache[groupKey] = sgroup;
878  }
879  else
880  {
881  LOG(VB_FILE, LOG_DEBUG,
882  QString("GetGroupToUse(): "
883  "falling back to Videos Storage Group for host %1 "
884  "since it does not have a %2 Storage Group.")
885  .arg(host, sgroup));
886 
887  tmpGroup = "Videos";
888  s_groupToUseCache[groupKey] = tmpGroup;
889  }
890  }
891 
892  return tmpGroup;
893 }
894 
895 /* vim: set expandtab tabstop=4 shiftwidth=4: */
StorageGroup::getRecordingsGroups
static QStringList getRecordingsGroups(void)
Definition: storagegroup.cpp:784
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
StorageGroup::s_groupToUseLock
static QMutex s_groupToUseLock
Definition: storagegroup.h:68
mythdb.h
getDiskSpace
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
Definition: mythcoreutil.cpp:33
StorageGroup::GetDirFileList
QStringList GetDirFileList(const QString &dir, const QString &base, bool recursive=false, bool onlyDirs=false)
Definition: storagegroup.cpp:202
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:597
mythcoreutil.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
StorageGroup::m_hostname
QString m_hostname
Definition: storagegroup.h:62
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
mythdirs.h
StorageGroup::m_allowFallback
bool m_allowFallback
Definition: storagegroup.h:63
StorageGroup::FileExists
bool FileExists(const QString &filename)
Definition: storagegroup.cpp:354
StorageGroup::ClearGroupToUseCache
static void ClearGroupToUseCache(void)
Definition: storagegroup.cpp:855
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
StorageGroup::m_staticInitLock
static QMutex m_staticInitLock
Definition: storagegroup.h:59
StorageGroup::FindFileDir
QString FindFileDir(const QString &filename)
Definition: storagegroup.cpp:620
StorageGroup::StorageGroup
StorageGroup(QString group="", QString hostname="", bool allowFallback=true)
StorageGroup constructor.
Definition: storagegroup.cpp:47
StorageGroup::GetFileList
QStringList GetFileList(const QString &Path, bool recursive=false)
Definition: storagegroup.cpp:271
mythlogging.h
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:760
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:256
StorageGroup::StaticInit
static void StaticInit(void)
Definition: storagegroup.cpp:60
StorageGroup::m_staticInitDone
static bool m_staticInitDone
Definition: storagegroup.h:58
StorageGroup::FindDirs
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.
Definition: storagegroup.cpp:532
hardwareprofile.config.p
p
Definition: config.py:33
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
StorageGroup::GetFileInfo
QStringList GetFileInfo(const QString &filename)
Definition: storagegroup.cpp:380
StorageGroup::getGroupDirs
static QStringList getGroupDirs(const QString &groupname, const QString &host)
Definition: storagegroup.cpp:811
StorageGroup::GetFirstDir
QString GetFirstDir(bool appendSlash=false) const
Definition: storagegroup.cpp:189
storagegroup.h
StorageGroup::GetGroupToUse
static QString GetGroupToUse(const QString &host, const QString &sgroup)
Definition: storagegroup.cpp:861
StorageGroup::GetDirList
QStringList GetDirList(void) const
Definition: storagegroup.h:23
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
StorageGroup::GetRelativePathname
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
Definition: storagegroup.cpp:420
StorageGroup::kDefaultStorageDir
static const char * kDefaultStorageDir
Definition: storagegroup.h:45
LOC
#define LOC
Definition: storagegroup.cpp:12
mythcorecontext.h
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:666
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
std
Definition: mythchrono.h:23
StorageGroup::m_dirlist
QStringList m_dirlist
Definition: storagegroup.h:64
StorageGroup::Init
void Init(const QString &group="Default", const QString &hostname="", bool allowFallback=true)
Initilizes the groupname, hostname, and dirlist.
Definition: storagegroup.cpp:106
StorageGroup::GetFileInfoList
QStringList GetFileInfoList(const QString &Path)
Definition: storagegroup.cpp:289
StorageGroup::m_groupname
QString m_groupname
Definition: storagegroup.h:61
StorageGroup::kSpecialGroups
static const QStringList kSpecialGroups
Definition: storagegroup.h:46
StorageGroup
Definition: storagegroup.h:11
StorageGroup::m_builtinGroups
static QMap< QString, QString > m_builtinGroups
Definition: storagegroup.h:66
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
build_compdb.filename
filename
Definition: build_compdb.py:21
StorageGroup::CheckAllStorageGroupDirs
static void CheckAllStorageGroupDirs(void)
Definition: storagegroup.cpp:724
StorageGroup::s_groupToUseCache
static QHash< QString, QString > s_groupToUseCache
Definition: storagegroup.h:69
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:898
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838