00001 #include <QDir>
00002 #include <QFile>
00003 #include <QRegExp>
00004 #include <QUrl>
00005
00006 #include "storagegroup.h"
00007 #include "mythcorecontext.h"
00008 #include "mythdb.h"
00009 #include "mythlogging.h"
00010 #include "mythcoreutil.h"
00011 #include "mythdirs.h"
00012
00013 #define LOC QString("SG(%1): ").arg(m_groupname)
00014
00015 const char *StorageGroup::kDefaultStorageDir = "/mnt/store";
00016
00017 QMutex StorageGroup::m_staticInitLock;
00018 bool StorageGroup::m_staticInitDone = false;
00019 QMap<QString, QString> StorageGroup::m_builtinGroups;
00020 QMutex StorageGroup::s_groupToUseLock;
00021 QHash<QString,QString> StorageGroup::s_groupToUseCache;
00022
00023 const QStringList StorageGroup::kSpecialGroups = QStringList()
00024 << "LiveTV"
00025
00026 << "DB Backups"
00027 << "Videos"
00028 << "Trailers"
00029 << "Coverart"
00030 << "Fanart"
00031 << "Screenshots"
00032 << "Banners"
00033 ;
00034
00035
00036
00045 StorageGroup::StorageGroup(const QString group, const QString hostname,
00046 bool allowFallback) :
00047 m_groupname(group), m_hostname(hostname), m_allowFallback(allowFallback)
00048 {
00049 m_groupname.detach();
00050 m_hostname.detach();
00051 m_dirlist.clear();
00052
00053 if (getenv("MYTHTV_NOSGFALLBACK"))
00054 m_allowFallback = false;
00055
00056 Init(m_groupname, m_hostname, m_allowFallback);
00057 }
00058
00059 void StorageGroup::StaticInit(void)
00060 {
00061 QMutexLocker locker(&m_staticInitLock);
00062
00063 if (m_staticInitDone)
00064 return;
00065
00066 m_staticInitDone = true;
00067
00068 m_builtinGroups["ChannelIcons"] = GetConfDir() + "/channels";
00069 m_builtinGroups["Themes"] = GetConfDir() + "/themes";
00070 m_builtinGroups["Temp"] = GetConfDir() + "/tmp";
00071 m_builtinGroups["Streaming"] = GetConfDir() + "/tmp/hls";
00072 m_builtinGroups["3rdParty"] = GetConfDir() + "/3rdParty";
00073
00074 QMap<QString, QString>::iterator it = m_builtinGroups.begin();
00075 for (; it != m_builtinGroups.end(); ++it)
00076 {
00077 QDir qdir(it.value());
00078 if (!qdir.exists())
00079 qdir.mkpath(it.value());
00080
00081 if (!qdir.exists())
00082 LOG(VB_GENERAL, LOG_ERR,
00083 QString("SG() Error: Could not create builtin"
00084 "Storage Group directory '%1' for '%2'").arg(it.value())
00085 .arg(it.key()));
00086 }
00087 }
00088
00101 void StorageGroup::Init(const QString group, const QString hostname,
00102 const bool allowFallback)
00103 {
00104 bool found = false;
00105 m_groupname = group; m_groupname.detach();
00106 m_hostname = hostname; m_hostname.detach();
00107 m_allowFallback = allowFallback;
00108 m_dirlist.clear();
00109
00110 StaticInit();
00111
00112 found = FindDirs(m_groupname, m_hostname, &m_dirlist);
00113
00114 if (!found && m_builtinGroups.contains(group))
00115 {
00116 QDir testdir(m_builtinGroups[group]);
00117 if (!testdir.exists())
00118 testdir.mkpath(m_builtinGroups[group]);
00119
00120 if (testdir.exists())
00121 {
00122 m_dirlist.prepend(testdir.absolutePath());
00123 found = true;
00124 }
00125 }
00126
00127 if ((!found) && m_allowFallback && (m_groupname != "LiveTV") &&
00128 (!hostname.isEmpty()))
00129 {
00130 LOG(VB_FILE, LOG_NOTICE, LOC +
00131 QString("Unable to find any directories for the local "
00132 "storage group '%1' on '%2', trying directories on "
00133 "all hosts!").arg(group).arg(hostname));
00134 found = FindDirs(m_groupname, "", &m_dirlist);
00135 if (found)
00136 {
00137 m_hostname = "";
00138 m_hostname.detach();
00139 }
00140 }
00141 if ((!found) && m_allowFallback && (group != "Default"))
00142 {
00143 LOG(VB_FILE, LOG_NOTICE, LOC +
00144 QString("Unable to find storage group '%1', trying "
00145 "'Default' group!").arg(group));
00146 found = FindDirs("Default", m_hostname, &m_dirlist);
00147 if(found)
00148 {
00149 m_groupname = "Default";
00150 m_groupname.detach();
00151 }
00152 else if (!hostname.isEmpty())
00153 {
00154 LOG(VB_FILE, LOG_NOTICE, LOC +
00155 QString("Unable to find any directories for the local "
00156 "Default storage group on '%1', trying directories "
00157 "in all Default groups!").arg(hostname));
00158 found = FindDirs("Default", "", &m_dirlist);
00159 if(found)
00160 {
00161 m_groupname = "Default";
00162 m_hostname = "";
00163 m_groupname.detach();
00164 m_hostname.detach();
00165 }
00166 }
00167 }
00168
00169 if (allowFallback && !m_dirlist.size())
00170 {
00171 QString msg = "Unable to find any Storage Group Directories. ";
00172 QString tmpDir = gCoreContext->GetSetting("RecordFilePrefix");
00173 if (tmpDir != "")
00174 {
00175 msg += QString("Using old 'RecordFilePrefix' value of '%1'")
00176 .arg(tmpDir);
00177 }
00178 else
00179 {
00180 tmpDir = kDefaultStorageDir;
00181 msg += QString("Using hardcoded default value of '%1'")
00182 .arg(kDefaultStorageDir);
00183 }
00184 LOG(VB_GENERAL, LOG_ERR, LOC + msg);
00185 m_dirlist << tmpDir;
00186 }
00187 }
00188
00189 QString StorageGroup::GetFirstDir(bool appendSlash) const
00190 {
00191 if (m_dirlist.isEmpty())
00192 return QString();
00193
00194 QString tmp = m_dirlist[0];
00195 tmp.detach();
00196
00197 if (appendSlash)
00198 tmp += "/";
00199
00200 return tmp;
00201 }
00202
00203 QStringList StorageGroup::GetDirFileList(QString dir, QString base,
00204 bool recursive)
00205 {
00206 QStringList files;
00207 QDir d(dir);
00208
00209 if (!d.exists())
00210 return files;
00211
00212 if (base.split("/").size() > 20)
00213 {
00214 LOG(VB_GENERAL, LOG_ERR, LOC + "GetDirFileList(), 20 levels deep, "
00215 "possible directory loop detected.");
00216 return files;
00217 }
00218
00219 if (!base.isEmpty())
00220 base += "/";
00221
00222 if (recursive)
00223 {
00224 QStringList list =
00225 d.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable);
00226
00227 for (QStringList::iterator p = list.begin(); p != list.end(); ++p)
00228 {
00229 LOG(VB_FILE, LOG_DEBUG, LOC +
00230 QString("GetDirFileList: Dir: %1/%2").arg(base).arg(*p));
00231 files << GetDirFileList(dir + "/" + *p, base + *p, true);
00232 }
00233 }
00234
00235 QStringList list = d.entryList(QDir::Files|QDir::Readable);
00236 for (QStringList::iterator p = list.begin(); p != list.end(); ++p)
00237 {
00238 LOG(VB_FILE, LOG_DEBUG, LOC +
00239 QString("GetDirFileList: File: %1%2").arg(base).arg(*p));
00240 if (recursive)
00241 files.append(base + *p);
00242 else
00243 files.append(*p);
00244 }
00245
00246 return files;
00247 }
00248
00249 QStringList StorageGroup::GetFileList(QString Path, bool recursive)
00250 {
00251 QStringList files;
00252 QString tmpDir;
00253 QDir d;
00254
00255 for (QStringList::Iterator it = m_dirlist.begin(); it != m_dirlist.end(); ++it)
00256 {
00257 tmpDir = *it + Path;
00258
00259 d.setPath(tmpDir);
00260 if (d.exists())
00261 files << GetDirFileList(tmpDir, Path, recursive);
00262 }
00263
00264 return files;
00265 }
00266
00267 QStringList StorageGroup::GetFileInfoList(QString Path)
00268 {
00269 QStringList files;
00270 QString relPath;
00271 bool badPath = true;
00272
00273 if (Path.isEmpty() || Path == "/")
00274 {
00275 for (QStringList::Iterator it = m_dirlist.begin(); it != m_dirlist.end(); ++it)
00276 files << QString("sgdir::%1").arg(*it);
00277
00278 return files;
00279 }
00280
00281 for (QStringList::Iterator it = m_dirlist.begin(); it != m_dirlist.end(); ++it)
00282 {
00283 if (Path.startsWith(*it))
00284 {
00285 relPath = Path;
00286 relPath.replace(*it,"");
00287 if (relPath.startsWith("/"))
00288 relPath.replace(0,1,"");
00289 badPath = false;
00290 }
00291 }
00292
00293 LOG(VB_FILE, LOG_INFO, LOC +
00294 QString("GetFileInfoList: Reading '%1'").arg(Path));
00295
00296 if (badPath)
00297 return files;
00298
00299 QDir d(Path);
00300 if (!d.exists())
00301 return files;
00302
00303 QFileInfoList list = d.entryInfoList();
00304 if (!list.size())
00305 return files;
00306
00307 for (QFileInfoList::iterator p = list.begin(); p != list.end(); ++p)
00308 {
00309 if (p->fileName() == "." ||
00310 p->fileName() == ".." ||
00311 p->fileName() == "Thumbs.db")
00312 {
00313 continue;
00314 }
00315
00316 QString tmp;
00317
00318 if (p->isDir())
00319 tmp = QString("dir::%1::0").arg(p->fileName());
00320 else
00321 tmp = QString("file::%1::%2::%3%4").arg(p->fileName()).arg(p->size())
00322 .arg(relPath).arg(p->fileName());
00323
00324 LOG(VB_FILE, LOG_DEBUG, LOC +
00325 QString("GetFileInfoList: (%1)").arg(tmp));
00326 files.append(tmp);
00327 }
00328
00329 return files;
00330 }
00331
00332 bool StorageGroup::FileExists(QString filename)
00333 {
00334 LOG(VB_FILE, LOG_DEBUG, LOC +
00335 QString("FileExist: Testing for '%1'").arg(filename));
00336 bool badPath = true;
00337
00338 if (filename.isEmpty())
00339 return false;
00340
00341 for (QStringList::Iterator it = m_dirlist.begin(); it != m_dirlist.end(); ++it)
00342 {
00343 if (filename.startsWith(*it))
00344 {
00345 badPath = false;
00346 }
00347 }
00348
00349 if (badPath)
00350 return false;
00351
00352 bool result = false;
00353
00354 QFile checkFile(filename);
00355 if (checkFile.exists(filename))
00356 result = true;
00357
00358 return result;
00359 }
00360
00361
00362
00363
00364 QStringList StorageGroup::GetFileInfo(QString filename)
00365 {
00366 LOG(VB_FILE, LOG_DEBUG, LOC +
00367 QString("GetFileInfo: For '%1'") .arg(filename));
00368
00369 QStringList details;
00370 bool searched = false;
00371
00372 if (!FileExists(filename))
00373 {
00374 searched = true;
00375 filename = FindFile(filename);
00376 }
00377
00378 if ((searched && !filename.isEmpty()) ||
00379 (FileExists(filename)))
00380 {
00381 QFileInfo fInfo(filename);
00382
00383 details << filename;
00384 details << QString("%1").arg(fInfo.lastModified().toTime_t());
00385 details << QString("%1").arg(fInfo.size());
00386 }
00387
00388 return details;
00389 }
00390
00399 QString StorageGroup::GetRelativePathname(const QString &filename)
00400 {
00401 QString result = filename;
00402 MSqlQuery query(MSqlQuery::InitCon());
00403
00404 LOG(VB_FILE, LOG_DEBUG,
00405 QString("StorageGroup::GetRelativePathname(%1)").arg(filename));
00406
00407 StaticInit();
00408
00409 if (filename.startsWith("myth://"))
00410 {
00411 QUrl qurl(filename);
00412
00413 if (qurl.hasFragment())
00414 result = qurl.path() + "#" + qurl.fragment();
00415 else
00416 result = qurl.path();
00417
00418 if (result.startsWith("/"))
00419 result.replace(0, 1, "");
00420
00421 return result;
00422 }
00423
00424 query.prepare("SELECT DISTINCT dirname FROM storagegroup "
00425 "ORDER BY dirname DESC;");
00426 if (query.exec())
00427 {
00428 QString dirname;
00429 while (query.next())
00430 {
00431
00432
00433
00434 dirname = QString::fromUtf8(query.value(0)
00435 .toByteArray().constData());
00436 if (filename.startsWith(dirname))
00437 {
00438 result = filename;
00439 result.replace(0, dirname.length(), "");
00440 if (result.startsWith("/"))
00441 result.replace(0, 1, "");
00442
00443 LOG(VB_FILE, LOG_DEBUG,
00444 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
00445 .arg(filename).arg(result));
00446 return result;
00447 }
00448 }
00449 }
00450
00451 query.prepare("SELECT DISTINCT data FROM settings WHERE "
00452 "value = 'VideoStartupDir';");
00453 if (query.exec())
00454 {
00455 while (query.next())
00456 {
00457 QString videostartupdir = query.value(0).toString();
00458 QStringList videodirs = videostartupdir.split(':',
00459 QString::SkipEmptyParts);
00460 QString directory;
00461 for (QStringList::Iterator it = videodirs.begin();
00462 it != videodirs.end(); ++it)
00463 {
00464 directory = *it;
00465 if (filename.startsWith(directory))
00466 {
00467 result = filename;
00468 result.replace(0, directory.length(), "");
00469 if (result.startsWith("/"))
00470 result.replace(0, 1, "");
00471
00472 LOG(VB_FILE, LOG_DEBUG,
00473 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
00474 .arg(filename).arg(result));
00475 return result;
00476 }
00477 }
00478 }
00479 }
00480
00481 QMap<QString, QString>::iterator it = m_builtinGroups.begin();
00482 for (; it != m_builtinGroups.end(); ++it)
00483 {
00484 QDir qdir(it.value());
00485 if (!qdir.exists())
00486 qdir.mkpath(it.value());
00487
00488 QString directory = it.value();
00489 if (filename.startsWith(directory))
00490 {
00491 result = filename;
00492 result.replace(0, directory.length(), "");
00493 if (result.startsWith("/"))
00494 result.replace(0, 1, "");
00495
00496 LOG(VB_FILE, LOG_DEBUG,
00497 QString("StorageGroup::GetRelativePathname(%1) = '%2'")
00498 .arg(filename).arg(result));
00499 return result;
00500 }
00501 }
00502
00503 return result;
00504 }
00505
00515 bool StorageGroup::FindDirs(const QString group, const QString hostname,
00516 QStringList *dirlist)
00517 {
00518 bool found = false;
00519 QString dirname;
00520 MSqlQuery query(MSqlQuery::InitCon());
00521
00522 StaticInit();
00523
00524 QString sql = "SELECT DISTINCT dirname "
00525 "FROM storagegroup ";
00526
00527 if (!group.isEmpty())
00528 {
00529 sql.append("WHERE groupname = :GROUP");
00530 if (!hostname.isEmpty())
00531 sql.append(" AND hostname = :HOSTNAME");
00532 }
00533
00534 query.prepare(sql);
00535 if (!group.isEmpty())
00536 {
00537 query.bindValue(":GROUP", group);
00538 if (!hostname.isEmpty())
00539 query.bindValue(":HOSTNAME", hostname);
00540 }
00541
00542 if (!query.exec() || !query.isActive())
00543 MythDB::DBError("StorageGroup::StorageGroup()", query);
00544 else if (query.next())
00545 {
00546 do
00547 {
00548
00549
00550
00551 dirname = QString::fromUtf8(query.value(0)
00552 .toByteArray().constData());
00553 dirname.replace(QRegExp("^\\s*"), "");
00554 dirname.replace(QRegExp("\\s*$"), "");
00555 if (dirname.right(1) == "/")
00556 dirname.remove(dirname.length() - 1, 1);
00557
00558 if (dirlist)
00559 (*dirlist) << dirname;
00560 else
00561 return true;
00562 }
00563 while (query.next());
00564 found = true;
00565 }
00566
00567 if (m_builtinGroups.contains(group))
00568 {
00569 QDir testdir(m_builtinGroups[group]);
00570 if (testdir.exists())
00571 {
00572 if (dirlist && !dirlist->contains(testdir.absolutePath()))
00573 (*dirlist) << testdir.absolutePath();
00574 found = true;
00575 }
00576 }
00577
00578 return found;
00579 }
00580
00581 QString StorageGroup::FindFile(QString filename)
00582 {
00583 LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindFile: Searching for '%1'")
00584 .arg(filename));
00585
00586 QString recDir = FindFileDir(filename);
00587 QString result = "";
00588
00589 if (!recDir.isEmpty())
00590 {
00591 result = recDir + "/" + filename;
00592 LOG(VB_FILE, LOG_DEBUG, LOC +
00593 QString("FindFile: Found '%1'") .arg(result));
00594 }
00595 else
00596 {
00597 LOG(VB_FILE, LOG_ERR, LOC +
00598 QString("FindFile: Unable to find '%1'!") .arg(filename));
00599 }
00600
00601 return result;
00602 }
00603
00604 QString StorageGroup::FindFileDir(QString filename)
00605 {
00606 QString result = "";
00607 QFileInfo checkFile("");
00608
00609 int curDir = 0;
00610 while (curDir < m_dirlist.size())
00611 {
00612 QString testFile = m_dirlist[curDir] + "/" + filename;
00613 LOG(VB_FILE, LOG_DEBUG, LOC +
00614 QString("FindFileDir: Checking '%1' for '%2'")
00615 .arg(m_dirlist[curDir]).arg(testFile));
00616 checkFile.setFile(testFile);
00617 if (checkFile.exists() || checkFile.isSymLink())
00618 {
00619 QString tmp = m_dirlist[curDir];
00620 tmp.detach();
00621 return tmp;
00622 }
00623
00624 curDir++;
00625 }
00626
00627 if (m_groupname.isEmpty() || (m_allowFallback == false))
00628 {
00629
00630 QString tmpFile =
00631 gCoreContext->GetSetting("RecordFilePrefix") + "/" + filename;
00632 checkFile.setFile(tmpFile);
00633 if (checkFile.exists() || checkFile.isSymLink())
00634 result = tmpFile;
00635 }
00636 else if (m_groupname != "Default")
00637 {
00638
00639 StorageGroup sgroup("Default");
00640 QString tmpFile = sgroup.FindFileDir(filename);
00641 result = (tmpFile.isEmpty()) ? result : tmpFile;
00642 }
00643 else
00644 {
00645
00646 StorageGroup sgroup;
00647 QString tmpFile = sgroup.FindFileDir(filename);
00648 result = (tmpFile.isEmpty()) ? result : tmpFile;
00649 }
00650
00651 result.detach();
00652 return result;
00653 }
00654
00655 QString StorageGroup::FindNextDirMostFree(void)
00656 {
00657 QString nextDir;
00658 int64_t nextDirFree = 0;
00659 int64_t thisDirTotal;
00660 int64_t thisDirUsed;
00661 int64_t thisDirFree;
00662
00663 LOG(VB_FILE, LOG_DEBUG, LOC + QString("FindNextDirMostFree: Starting"));
00664
00665 if (m_allowFallback)
00666 nextDir = kDefaultStorageDir;
00667
00668 if (m_dirlist.size())
00669 nextDir = m_dirlist[0];
00670
00671 QDir checkDir("");
00672 int curDir = 0;
00673 while (curDir < m_dirlist.size())
00674 {
00675 checkDir.setPath(m_dirlist[curDir]);
00676 if (!checkDir.exists())
00677 {
00678 LOG(VB_GENERAL, LOG_ERR, LOC +
00679 QString("FindNextDirMostFree: '%1' does not exist!")
00680 .arg(m_dirlist[curDir]));
00681 curDir++;
00682 continue;
00683 }
00684
00685 thisDirFree = getDiskSpace(m_dirlist[curDir], thisDirTotal,
00686 thisDirUsed);
00687 LOG(VB_FILE, LOG_DEBUG, LOC +
00688 QString("FindNextDirMostFree: '%1' has %2 KiB free")
00689 .arg(m_dirlist[curDir])
00690 .arg(QString::number(thisDirFree)));
00691
00692 if (thisDirFree > nextDirFree)
00693 {
00694 nextDir = m_dirlist[curDir];
00695 nextDirFree = thisDirFree;
00696 }
00697 curDir++;
00698 }
00699
00700 if (nextDir.isEmpty())
00701 LOG(VB_FILE, LOG_ERR, LOC +
00702 "FindNextDirMostFree: Unable to find any directories to use.");
00703 else
00704 LOG(VB_FILE, LOG_DEBUG, LOC +
00705 QString("FindNextDirMostFree: Using '%1'").arg(nextDir));
00706
00707 nextDir.detach();
00708 return nextDir;
00709 }
00710
00711 void StorageGroup::CheckAllStorageGroupDirs(void)
00712 {
00713 QString m_groupname;
00714 QString dirname;
00715 MSqlQuery query(MSqlQuery::InitCon());
00716
00717 query.prepare("SELECT groupname, dirname "
00718 "FROM storagegroup "
00719 "WHERE hostname = :HOSTNAME;");
00720 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
00721 if (!query.exec() || !query.isActive())
00722 {
00723 MythDB::DBError("StorageGroup::CheckAllStorageGroupDirs()", query);
00724 return;
00725 }
00726
00727 LOG(VB_FILE, LOG_DEBUG, LOC +
00728 "CheckAllStorageGroupDirs(): Checking All Storage Group directories");
00729
00730 QFile testFile("");
00731 QDir testDir("");
00732 while (query.next())
00733 {
00734 m_groupname = query.value(0).toString();
00735
00736
00737
00738 dirname = QString::fromUtf8(query.value(1)
00739 .toByteArray().constData());
00740
00741 dirname.replace(QRegExp("^\\s*"), "");
00742 dirname.replace(QRegExp("\\s*$"), "");
00743
00744 LOG(VB_FILE, LOG_DEBUG, LOC +
00745 QString("Checking directory '%1' in group '%2'.")
00746 .arg(dirname).arg(m_groupname));
00747
00748 testDir.setPath(dirname);
00749 if (!testDir.exists())
00750 {
00751 LOG(VB_FILE, LOG_WARNING, LOC +
00752 QString("Group '%1' references directory '%2' but this "
00753 "directory does not exist. This directory "
00754 "will not be used on this server.")
00755 .arg(m_groupname).arg(dirname));
00756 }
00757 else
00758 {
00759 testFile.setFileName(dirname + "/.test");
00760 if (testFile.open(QIODevice::WriteOnly))
00761 testFile.remove();
00762 else
00763 LOG(VB_GENERAL, LOG_ERR, LOC +
00764 QString("Group '%1' wants to use directory '%2', but "
00765 "this directory is not writeable.")
00766 .arg(m_groupname).arg(dirname));
00767 }
00768 }
00769 }
00770
00771 QStringList StorageGroup::getRecordingsGroups(void)
00772 {
00773 QStringList groups;
00774
00775 MSqlQuery query(MSqlQuery::InitCon());
00776
00777 QString sql = "SELECT DISTINCT groupname "
00778 "FROM storagegroup "
00779 "WHERE groupname NOT IN (";
00780 for (QStringList::const_iterator it = StorageGroup::kSpecialGroups.begin();
00781 it != StorageGroup::kSpecialGroups.end(); ++it)
00782 sql.append(QString(" '%1',").arg(*it));
00783 sql = sql.left(sql.length() - 1);
00784 sql.append(" );");
00785
00786 query.prepare(sql);
00787 if (query.exec() && query.isActive() && query.size() > 0)
00788 while (query.next())
00789 groups += query.value(0).toString();
00790
00791 groups.sort();
00792 groups.detach();
00793
00794 return groups;
00795 }
00796
00797 QStringList StorageGroup::getGroupDirs(QString groupname, QString host)
00798 {
00799 QStringList groups;
00800 QString addHost;
00801
00802 MSqlQuery query(MSqlQuery::InitCon());
00803
00804 if (!host.isEmpty())
00805 addHost = " AND hostname = :HOSTNAME";
00806 else
00807 addHost = "";
00808
00809 QString sql = QString("SELECT dirname,hostname "
00810 "FROM storagegroup "
00811 "WHERE groupname = :GROUPNAME %1").arg(addHost);
00812
00813 query.prepare(sql);
00814 query.bindValue(":GROUPNAME", groupname);
00815
00816 if (!host.isEmpty())
00817 query.bindValue(":HOSTNAME", host);
00818
00819 if (query.exec() && query.isActive() && query.size() > 0)
00820 {
00821 QString dirname;
00822 while (query.next())
00823 {
00824
00825
00826
00827 dirname = QString::fromUtf8(query.value(0)
00828 .toByteArray().constData());
00829 groups += gCoreContext->GenMythURL(query.value(1).toString(),
00830 0,
00831 dirname,
00832 groupname);
00833 }
00834 }
00835
00836 groups.sort();
00837 groups.detach();
00838
00839 return groups;
00840 }
00841
00842 void StorageGroup::ClearGroupToUseCache(void)
00843 {
00844 QMutexLocker locker(&s_groupToUseLock);
00845 s_groupToUseCache.clear();
00846 }
00847
00848 QString StorageGroup::GetGroupToUse(
00849 const QString &host, const QString &sgroup)
00850 {
00851 QString tmpGroup = sgroup;
00852 QString groupKey = QString("%1:%2").arg(sgroup).arg(host);
00853
00854 QMutexLocker locker(&s_groupToUseLock);
00855
00856 if (s_groupToUseCache.contains(groupKey))
00857 {
00858 tmpGroup = s_groupToUseCache[groupKey];
00859 }
00860 else
00861 {
00862 if (StorageGroup::FindDirs(sgroup, host))
00863 {
00864 s_groupToUseCache[groupKey] = sgroup;
00865 }
00866 else
00867 {
00868 LOG(VB_FILE, LOG_DEBUG,
00869 QString("GetGroupToUse(): "
00870 "falling back to Videos Storage Group for host %1 "
00871 "since it does not have a %2 Storage Group.")
00872 .arg(host).arg(sgroup));
00873
00874 tmpGroup = "Videos";
00875 s_groupToUseCache[groupKey] = tmpGroup;
00876 }
00877 }
00878
00879 return tmpGroup;
00880 }
00881
00882