|
MythTV
0.26-pre
|
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 // << "Thumbnails" 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 // Returns a string list of details about the file 00363 // in the order EXISTS, DATE, SIZE 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 /* The storagegroup.dirname column uses utf8_bin collation, so Qt 00432 * uses QString::fromAscii() for toString(). Explicitly convert the 00433 * value using QString::fromUtf8() to prevent corruption. */ 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 /* The storagegroup.dirname column uses utf8_bin collation, so Qt 00549 * uses QString::fromAscii() for toString(). Explicitly convert the 00550 * value using QString::fromUtf8() to prevent corruption. */ 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 // Not found in any dir, so try RecordFilePrefix if it exists 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 // Not found in current group so try Default 00639 StorageGroup sgroup("Default"); 00640 QString tmpFile = sgroup.FindFileDir(filename); 00641 result = (tmpFile.isEmpty()) ? result : tmpFile; 00642 } 00643 else 00644 { 00645 // Not found in Default so try any dir 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 /* The storagegroup.dirname column uses utf8_bin collation, so Qt 00736 * uses QString::fromAscii() for toString(). Explicitly convert the 00737 * value using QString::fromUtf8() to prevent corruption. */ 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 /* The storagegroup.dirname column uses utf8_bin collation, so Qt 00825 * uses QString::fromAscii() for toString(). Explicitly convert the 00826 * value using QString::fromUtf8() to prevent corruption. */ 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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1