|
MythTV
0.26-pre
|
00001 00002 using namespace std; 00003 00004 #include <QString> 00005 #include <QWriteLocker> 00006 #include <QReadLocker> 00007 00008 #include "mythmiscutil.h" 00009 #include "mythdb.h" 00010 #include "ringbuffer.h" 00011 #include "mythsocket.h" 00012 #include "mythlogging.h" 00013 #include "programinfo.h" 00014 #include "storagegroup.h" 00015 #include "mythcorecontext.h" 00016 #include "mythdownloadmanager.h" 00017 00018 #include "sockethandler/filetransfer.h" 00019 #include "requesthandler/deletethread.h" 00020 #include "requesthandler/fileserverhandler.h" 00021 #include "requesthandler/fileserverutil.h" 00022 00023 DeleteThread *deletethread = NULL; 00024 00025 void FileServerHandler::connectionClosed(MythSocket *socket) 00026 { 00027 // iterate through transfer list and close if 00028 // socket matches connected transfer 00029 { 00030 QWriteLocker wlock(&m_ftLock); 00031 QMap<int, FileTransfer*>::iterator i; 00032 for (i = m_ftMap.begin(); i != m_ftMap.end(); ++i) 00033 { 00034 if ((*i)->GetSocket() == socket) 00035 { 00036 (*i)->DownRef(); 00037 m_ftMap.remove(i.key()); 00038 return; 00039 } 00040 } 00041 } 00042 00043 // iterate through file server list and close 00044 // if socket matched connected server 00045 { 00046 QWriteLocker wlock(&m_fsLock); 00047 QMap<QString, SocketHandler*>::iterator i; 00048 for (i = m_fsMap.begin(); i != m_fsMap.end(); ++i) 00049 { 00050 if ((*i)->GetSocket() == socket) 00051 { 00052 (*i)->DownRef(); 00053 m_fsMap.remove(i.key()); 00054 return; 00055 } 00056 } 00057 } 00058 } 00059 00060 QString FileServerHandler::LocalFilePath(const QUrl &url, 00061 const QString &wantgroup) 00062 { 00063 QString lpath = url.path(); 00064 00065 if (lpath.section('/', -2, -2) == "channels") 00066 { 00067 // This must be an icon request. Check channel.icon to be safe. 00068 QString querytext; 00069 00070 QString file = lpath.section('/', -1); 00071 lpath = ""; 00072 00073 MSqlQuery query(MSqlQuery::InitCon()); 00074 query.prepare("SELECT icon FROM channel WHERE icon LIKE :FILENAME ;"); 00075 query.bindValue(":FILENAME", QString("%/") + file); 00076 00077 if (query.exec() && query.next()) 00078 { 00079 lpath = query.value(0).toString(); 00080 } 00081 else 00082 { 00083 MythDB::DBError("Icon path", query); 00084 } 00085 } 00086 else 00087 { 00088 lpath = lpath.section('/', -1); 00089 00090 QString fpath = lpath; 00091 if (fpath.right(4) == ".png") 00092 fpath = fpath.left(fpath.length() - 4); 00093 00094 ProgramInfo pginfo(fpath); 00095 if (pginfo.GetChanID()) 00096 { 00097 QString pburl = GetPlaybackURL(&pginfo); 00098 if (pburl.left(1) == "/") 00099 { 00100 lpath = pburl.section('/', 0, -2) + "/" + lpath; 00101 LOG(VB_FILE, LOG_INFO, 00102 QString("Local file path: %1").arg(lpath)); 00103 } 00104 else 00105 { 00106 LOG(VB_GENERAL, LOG_ERR, 00107 QString("LocalFilePath unable to find local " 00108 "path for '%1', found '%2' instead.") 00109 .arg(lpath).arg(pburl)); 00110 lpath = ""; 00111 } 00112 } 00113 else if (!lpath.isEmpty()) 00114 { 00115 // For securities sake, make sure filename is really the pathless. 00116 QString opath = lpath; 00117 StorageGroup sgroup; 00118 00119 if (!wantgroup.isEmpty()) 00120 { 00121 sgroup.Init(wantgroup); 00122 lpath = url.toString(); 00123 } 00124 else 00125 { 00126 lpath = QFileInfo(lpath).fileName(); 00127 } 00128 00129 QString tmpFile = sgroup.FindFile(lpath); 00130 if (!tmpFile.isEmpty()) 00131 { 00132 lpath = tmpFile; 00133 LOG(VB_FILE, LOG_INFO, 00134 QString("LocalFilePath(%1 '%2'), found through " 00135 "exhaustive search at '%3'") 00136 .arg(url.toString()).arg(opath).arg(lpath)); 00137 } 00138 else 00139 { 00140 LOG(VB_GENERAL, LOG_ERR, QString("LocalFilePath unable to " 00141 "find local path for '%1'.") 00142 .arg(opath)); 00143 lpath = ""; 00144 } 00145 00146 } 00147 else 00148 { 00149 lpath = ""; 00150 } 00151 } 00152 00153 return lpath; 00154 } 00155 00156 void FileServerHandler::RunDeleteThread(void) 00157 { 00158 if (deletethread != NULL) 00159 { 00160 if (deletethread->isRunning()) 00161 return 00162 00163 delete deletethread; 00164 deletethread = NULL; 00165 } 00166 00167 deletethread = new DeleteThread(); 00168 deletethread->start(); 00169 } 00170 00171 bool FileServerHandler::HandleAnnounce(MythSocket *socket, 00172 QStringList &commands, QStringList &slist) 00173 { 00174 if (commands[1] == "FileServer") 00175 { 00176 if (slist.size() >= 3) 00177 { 00178 SocketHandler *handler = 00179 new SocketHandler(socket, m_parent, commands[2]); 00180 00181 handler->BlockShutdown(true); 00182 handler->AllowStandardEvents(true); 00183 handler->AllowSystemEvents(true); 00184 00185 QWriteLocker wlock(&m_fsLock); 00186 m_fsMap.insert(commands[2], handler); 00187 m_parent->AddSocketHandler(handler); 00188 00189 slist.clear(); 00190 slist << "OK"; 00191 handler->SendStringList(slist); 00192 return true; 00193 } 00194 return false; 00195 } 00196 00197 if (commands[1] != "FileTransfer") 00198 return false; 00199 00200 if (slist.size() < 3) 00201 return false; 00202 00203 if ((commands.size() < 3) || (commands.size() > 6)) 00204 return false; 00205 00206 FileTransfer *ft = NULL; 00207 QString hostname = ""; 00208 QString filename = ""; 00209 bool writemode = false; 00210 bool usereadahead = true; 00211 int timeout_ms = 2000; 00212 switch (commands.size()) 00213 { 00214 case 6: 00215 timeout_ms = commands[5].toInt(); 00216 case 5: 00217 usereadahead = commands[4].toInt(); 00218 case 4: 00219 writemode = commands[3].toInt(); 00220 default: 00221 hostname = commands[2]; 00222 } 00223 00224 QStringList::const_iterator it = slist.begin(); 00225 QUrl qurl = *(++it); 00226 QString wantgroup = *(++it); 00227 00228 QStringList checkfiles; 00229 while (++it != slist.end()) 00230 checkfiles += *(it); 00231 00232 slist.clear(); 00233 00234 LOG(VB_GENERAL, LOG_DEBUG, "FileServerHandler::HandleAnnounce"); 00235 LOG(VB_GENERAL, LOG_INFO, QString("adding: %1 as remote file transfer") 00236 .arg(hostname)); 00237 00238 if (writemode) 00239 { 00240 if (wantgroup.isEmpty()) 00241 wantgroup = "Default"; 00242 00243 StorageGroup sgroup(wantgroup, gCoreContext->GetHostName(), false); 00244 QString dir = sgroup.FindNextDirMostFree(); 00245 if (dir.isEmpty()) 00246 { 00247 LOG(VB_GENERAL, LOG_ERR, "Unable to determine directory " 00248 "to write to in FileTransfer write command"); 00249 00250 slist << "ERROR" << "filetransfer_directory_not_found"; 00251 socket->writeStringList(slist); 00252 return true; 00253 } 00254 00255 QString basename = qurl.path(); 00256 if (basename.isEmpty()) 00257 { 00258 LOG(VB_GENERAL, LOG_ERR, QString("FileTransfer write " 00259 "filename is empty in url '%1'.") 00260 .arg(qurl.toString())); 00261 00262 slist << "ERROR" << "filetransfer_filename_empty"; 00263 socket->writeStringList(slist); 00264 return true; 00265 } 00266 00267 if ((basename.contains("/../")) || 00268 (basename.startsWith("../"))) 00269 { 00270 LOG(VB_GENERAL, LOG_ERR, QString("FileTransfer write " 00271 "filename '%1' does not pass sanity checks.") 00272 .arg(basename)); 00273 00274 slist << "ERROR" << "filetransfer_filename_dangerous"; 00275 socket->writeStringList(slist); 00276 return true; 00277 } 00278 00279 filename = dir + "/" + basename; 00280 } 00281 else 00282 filename = LocalFilePath(qurl, wantgroup); 00283 00284 QFileInfo finfo(filename); 00285 if (finfo.isDir()) 00286 { 00287 LOG(VB_GENERAL, LOG_ERR, QString("FileTransfer filename " 00288 "'%1' is actually a directory, cannot transfer.") 00289 .arg(filename)); 00290 00291 slist << "ERROR" << "filetransfer_filename_is_a_directory"; 00292 socket->writeStringList(slist); 00293 return true; 00294 } 00295 00296 if (writemode) 00297 { 00298 QString dirPath = finfo.absolutePath(); 00299 QDir qdir(dirPath); 00300 if (!qdir.exists()) 00301 { 00302 if (!qdir.mkpath(dirPath)) 00303 { 00304 LOG(VB_GENERAL, LOG_ERR, QString("FileTransfer " 00305 "filename '%1' is in a subdirectory which does " 00306 "not exist, but can not be created.") 00307 .arg(filename)); 00308 00309 slist << "ERROR" << "filetransfer_unable_to_create_subdirectory"; 00310 socket->writeStringList(slist); 00311 return true; 00312 } 00313 } 00314 00315 ft = new FileTransfer(filename, socket, m_parent, writemode); 00316 } 00317 else 00318 ft = new FileTransfer(filename, socket, m_parent, usereadahead, timeout_ms); 00319 00320 ft->BlockShutdown(true); 00321 00322 { 00323 QWriteLocker wlock(&m_ftLock); 00324 m_ftMap.insert(socket->socket(), ft); 00325 } 00326 00327 slist << "OK" 00328 << QString::number(socket->socket()) 00329 << QString::number(ft->GetFileSize()); 00330 00331 if (checkfiles.size()) 00332 { 00333 QFileInfo fi(filename); 00334 QDir dir = fi.absoluteDir(); 00335 for (it = checkfiles.begin(); it != checkfiles.end(); ++it) 00336 { 00337 if (dir.exists(*it) && 00338 QFileInfo(dir, *it).size() >= kReadTestSize) 00339 slist << *it; 00340 } 00341 } 00342 00343 socket->writeStringList(slist); 00344 m_parent->AddSocketHandler(ft); 00345 return true; 00346 } 00347 00348 void FileServerHandler::connectionAnnounced(MythSocket *socket, 00349 QStringList &commands, QStringList &slist) 00350 { 00351 if (commands[1] == "SlaveBackend") 00352 { 00353 // were not going to handle these, but we still want to track them 00354 // for commands that need access to these sockets 00355 if (slist.size() >= 3) 00356 { 00357 SocketHandler *handler = m_parent->GetConnectionBySocket(socket); 00358 if (handler == NULL) 00359 return; 00360 00361 QWriteLocker wlock(&m_fsLock); 00362 m_fsMap.insert(commands[2], handler); 00363 } 00364 } 00365 00366 } 00367 00368 bool FileServerHandler::HandleQuery(SocketHandler *socket, QStringList &commands, 00369 QStringList &slist) 00370 { 00371 bool handled = false; 00372 QString command = commands[0]; 00373 00374 if (command == "QUERY_FREE_SPACE") 00375 handled = HandleQueryFreeSpace(socket); 00376 else if (command == "QUERY_FREE_SPACE_LIST") 00377 handled = HandleQueryFreeSpaceList(socket); 00378 else if (command == "QUERY_FREE_SPACE_SUMMARY") 00379 handled = HandleQueryFreeSpaceSummary(socket); 00380 else if (command == "QUERY_FILE_EXISTS") 00381 handled = HandleQueryFileExists(socket, slist); 00382 else if (command == "QUERY_FILE_HASH") 00383 handled = HandleQueryFileHash(socket, slist); 00384 else if (command == "DELETE_FILE") 00385 handled = HandleDeleteFile(socket, slist); 00386 else if (command == "QUERY_SG_GETFILELIST") 00387 handled = HandleGetFileList(socket, slist); 00388 else if (command == "QUERY_SG_FILEQUERY") 00389 handled = HandleFileQuery(socket, slist); 00390 else if (command == "QUERY_FILETRANSFER") 00391 handled = HandleQueryFileTransfer(socket, commands, slist); 00392 else if (command == "DOWNLOAD_FILE" || command == "DOWNLOAD_FILE_NOW") 00393 handled = HandleDownloadFile(socket, slist); 00394 return handled; 00395 } 00396 00397 bool FileServerHandler::HandleQueryFreeSpace(SocketHandler *socket) 00398 { 00399 QStringList res; 00400 00401 QList<FileSystemInfo> disks = QueryFileSystems(); 00402 QList<FileSystemInfo>::const_iterator i; 00403 for (i = disks.begin(); i != disks.end(); ++i) 00404 i->ToStringList(res); 00405 00406 socket->SendStringList(res); 00407 return true; 00408 } 00409 00410 bool FileServerHandler::HandleQueryFreeSpaceList(SocketHandler *socket) 00411 { 00412 QStringList res; 00413 QStringList hosts; 00414 00415 QList<FileSystemInfo> disks = QueryAllFileSystems(); 00416 QList<FileSystemInfo>::const_iterator i; 00417 for (i = disks.begin(); i != disks.end(); ++i) 00418 if (!hosts.contains(i->getHostname())) 00419 hosts << i->getHostname(); 00420 00421 // TODO: get max bitrate from encoderlink 00422 FileSystemInfo::Consolidate(disks, true, 14000); 00423 00424 long long total = 0; 00425 long long used = 0; 00426 for (i = disks.begin(); i != disks.end(); ++i) 00427 { 00428 i->ToStringList(res); 00429 total += i->getTotalSpace(); 00430 used += i->getUsedSpace(); 00431 } 00432 00433 res << hosts.join(",") 00434 << "TotalDiskSpace" 00435 << "0" 00436 << "-2" 00437 << "-2" 00438 << "0" 00439 << QString::number(total) 00440 << QString::number(used); 00441 00442 socket->SendStringList(res); 00443 return true; 00444 } 00445 00446 bool FileServerHandler::HandleQueryFreeSpaceSummary(SocketHandler *socket) 00447 { 00448 QStringList res; 00449 QList<FileSystemInfo> disks = QueryAllFileSystems(); 00450 // TODO: get max bitrate from encoderlink 00451 FileSystemInfo::Consolidate(disks, true, 14000); 00452 00453 QList<FileSystemInfo>::const_iterator i; 00454 long long total = 0; 00455 long long used = 0; 00456 for (i = disks.begin(); i != disks.end(); ++i) 00457 { 00458 total += i->getTotalSpace(); 00459 used += i->getUsedSpace(); 00460 } 00461 00462 res << QString::number(total) << QString::number(used); 00463 socket->SendStringList(res); 00464 return true; 00465 } 00466 00467 QList<FileSystemInfo> FileServerHandler::QueryFileSystems(void) 00468 { 00469 QStringList groups(StorageGroup::kSpecialGroups); 00470 groups.removeAll("LiveTV"); 00471 QString specialGroups = groups.join("', '"); 00472 00473 MSqlQuery query(MSqlQuery::InitCon()); 00474 query.prepare(QString("SELECT MIN(id),dirname " 00475 "FROM storagegroup " 00476 "WHERE hostname = :HOSTNAME " 00477 "AND groupname NOT IN ( '%1' ) " 00478 "GROUP BY dirname;").arg(specialGroups)); 00479 query.bindValue(":HOSTNAME", gCoreContext->GetHostName()); 00480 00481 QList<FileSystemInfo> disks; 00482 if (query.exec() && query.isActive()) 00483 { 00484 if (!query.size()) 00485 { 00486 query.prepare("SELECT MIN(id),dirname " 00487 "FROM storagegroup " 00488 "WHERE groupname = :GROUP " 00489 "GROUP BY dirname;"); 00490 query.bindValue(":GROUP", "Default"); 00491 if (!query.exec()) 00492 MythDB::DBError("BackendQueryFileSystems", query); 00493 } 00494 00495 QDir checkDir(""); 00496 QString currentDir; 00497 FileSystemInfo disk; 00498 QMap <QString, bool>foundDirs; 00499 00500 while (query.next()) 00501 { 00502 disk.clear(); 00503 disk.setHostname(gCoreContext->GetHostName()); 00504 disk.setLocal(); 00505 disk.setBlockSize(0); 00506 disk.setGroupID(query.value(0).toInt()); 00507 00508 /* The storagegroup.dirname column uses utf8_bin collation, so Qt 00509 * uses QString::fromAscii() for toString(). Explicitly convert the 00510 * value using QString::fromUtf8() to prevent corruption. */ 00511 currentDir = QString::fromUtf8(query.value(1) 00512 .toByteArray().constData()); 00513 disk.setPath(currentDir); 00514 00515 if (currentDir.right(1) == "/") 00516 currentDir.remove(currentDir.length() - 1, 1); 00517 00518 checkDir.setPath(currentDir); 00519 if (!foundDirs.contains(currentDir)) 00520 { 00521 if (checkDir.exists()) 00522 { 00523 disk.PopulateDiskSpace(); 00524 disk.PopulateFSProp(); 00525 disks << disk; 00526 00527 foundDirs[currentDir] = true; 00528 } 00529 else 00530 foundDirs[currentDir] = false; 00531 } 00532 } 00533 } 00534 00535 return disks; 00536 } 00537 00538 QList<FileSystemInfo> FileServerHandler::QueryAllFileSystems(void) 00539 { 00540 QList<FileSystemInfo> disks = QueryFileSystems(); 00541 00542 { 00543 QReadLocker rlock(&m_fsLock); 00544 00545 QMap<QString, SocketHandler*>::iterator i; 00546 for (i = m_fsMap.begin(); i != m_fsMap.end(); ++i) 00547 disks << FileSystemInfo::RemoteGetInfo((*i)->GetSocket()); 00548 } 00549 00550 return disks; 00551 } 00552 00557 bool FileServerHandler::HandleQueryFileExists(SocketHandler *socket, 00558 QStringList &slist) 00559 { 00560 QString storageGroup = "Default"; 00561 QStringList res; 00562 00563 if (slist.size() == 3) 00564 { 00565 if (!slist[2].isEmpty()) 00566 storageGroup = slist[2]; 00567 } 00568 else if (slist.size() != 2) 00569 return false; 00570 00571 QString filename = slist[1]; 00572 if ((filename.isEmpty()) || 00573 (filename.contains("/../")) || 00574 (filename.startsWith("../"))) 00575 { 00576 LOG(VB_GENERAL, LOG_ERR, 00577 QString("ERROR checking for file, filename '%1' " 00578 "fails sanity checks").arg(filename)); 00579 res << ""; 00580 socket->SendStringList(res); 00581 return true; 00582 } 00583 00584 StorageGroup sgroup(storageGroup, gCoreContext->GetHostName()); 00585 QString fullname = sgroup.FindFile(filename); 00586 00587 if (!fullname.isEmpty()) 00588 { 00589 res << "1" 00590 << fullname; 00591 00592 // TODO: convert me to QFile 00593 struct stat fileinfo; 00594 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0) 00595 { 00596 res << QString::number(fileinfo.st_dev) 00597 << QString::number(fileinfo.st_ino) 00598 << QString::number(fileinfo.st_mode) 00599 << QString::number(fileinfo.st_nlink) 00600 << QString::number(fileinfo.st_uid) 00601 << QString::number(fileinfo.st_gid) 00602 << QString::number(fileinfo.st_rdev) 00603 << QString::number(fileinfo.st_size) 00604 #ifdef USING_MINGW 00605 << "0" 00606 << "0" 00607 #else 00608 << QString::number(fileinfo.st_blksize) 00609 << QString::number(fileinfo.st_blocks) 00610 #endif 00611 << QString::number(fileinfo.st_atime) 00612 << QString::number(fileinfo.st_mtime) 00613 << QString::number(fileinfo.st_ctime); 00614 } 00615 } 00616 else 00617 res << "0"; 00618 00619 socket->SendStringList(res); 00620 return true; 00621 } 00622 00627 bool FileServerHandler::HandleQueryFileHash(SocketHandler *socket, 00628 QStringList &slist) 00629 { 00630 QString storageGroup = "Default"; 00631 QString hostname = gCoreContext->GetHostName(); 00632 QString filename = ""; 00633 QStringList res; 00634 00635 switch (slist.size()) { 00636 case 4: 00637 if (!slist[3].isEmpty()) 00638 hostname = slist[3]; 00639 case 3: 00640 if (!slist[2].isEmpty()) 00641 storageGroup = slist[2]; 00642 case 2: 00643 filename = slist[1]; 00644 if (filename.isEmpty() || 00645 filename.contains("/../") || 00646 filename.startsWith("../")) 00647 { 00648 LOG(VB_GENERAL, LOG_ERR, 00649 QString("ERROR checking for file, filename '%1' " 00650 "fails sanity checks").arg(filename)); 00651 res << ""; 00652 socket->SendStringList(res); 00653 return true; 00654 } 00655 break; 00656 default: 00657 return false; 00658 } 00659 00660 QString hash = ""; 00661 00662 if (hostname == gCoreContext->GetHostName()) 00663 { 00664 // looking for file on me, return directly 00665 StorageGroup sgroup(storageGroup, gCoreContext->GetHostName()); 00666 QString fullname = sgroup.FindFile(filename); 00667 hash = FileHash(fullname); 00668 } 00669 else 00670 { 00671 QReadLocker rlock(&m_fsLock); 00672 if (m_fsMap.contains(hostname)) 00673 { 00674 // looking for file on connected host, query from it 00675 if (m_fsMap[hostname]->SendReceiveStringList(slist)) 00676 hash = slist[0]; 00677 } 00678 else 00679 { 00680 // looking for file on unknown host 00681 // assume host is an IP address, and look for matching 00682 // entry in database 00683 MSqlQuery query(MSqlQuery::InitCon()); 00684 query.prepare("SELECT hostname FROM settings " 00685 "WHERE value='BackendServerIP' " 00686 " OR value='BackendServerIP6' " 00687 "AND data=:HOSTNAME;"); 00688 query.bindValue(":HOSTNAME", hostname); 00689 00690 if (query.exec() && query.next()) 00691 { 00692 // address matches an entry 00693 hostname = query.value(0).toString(); 00694 if (m_fsMap.contains(hostname)) 00695 { 00696 // entry matches a connection 00697 slist.clear(); 00698 slist << "QUERY_FILE_HASH" 00699 << filename 00700 << storageGroup; 00701 00702 if (m_fsMap[hostname]->SendReceiveStringList(slist)) 00703 hash = slist[0]; 00704 } 00705 } 00706 } 00707 } 00708 00709 00710 res << hash; 00711 socket->SendStringList(res); 00712 00713 return true; 00714 } 00715 00716 bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, 00717 QStringList &slist) 00718 { 00719 if (slist.size() != 3) 00720 return false; 00721 00722 return HandleDeleteFile(socket, slist[1], slist[2]); 00723 } 00724 00725 bool FileServerHandler::DeleteFile(QString filename, QString storagegroup) 00726 { 00727 return HandleDeleteFile( (SocketHandler *)NULL, filename, storagegroup); 00728 } 00729 00730 bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, 00731 QString filename, QString storagegroup) 00732 { 00733 StorageGroup sgroup(storagegroup, "", false); 00734 QStringList res; 00735 00736 if ((filename.isEmpty()) || 00737 (filename.contains("/../")) || 00738 (filename.startsWith("../"))) 00739 { 00740 LOG(VB_GENERAL, LOG_ERR, 00741 QString("ERROR deleting file, filename '%1' fails sanity checks") 00742 .arg(filename)); 00743 if (socket) 00744 { 00745 res << "0"; 00746 socket->SendStringList(res); 00747 return true; 00748 } 00749 return false; 00750 } 00751 00752 QString fullfile = sgroup.FindFile(filename); 00753 00754 if (fullfile.isEmpty()) 00755 { 00756 LOG(VB_GENERAL, LOG_ERR, 00757 QString("Unable to find %1 in HandleDeleteFile()") .arg(filename)); 00758 if (socket) 00759 { 00760 res << "0"; 00761 socket->SendStringList(res); 00762 return true; 00763 } 00764 return false; 00765 } 00766 00767 QFile checkFile(fullfile); 00768 if (checkFile.exists()) 00769 { 00770 if (socket) 00771 { 00772 res << "1"; 00773 socket->SendStringList(res); 00774 } 00775 RunDeleteThread(); 00776 deletethread->AddFile(fullfile); 00777 } 00778 else 00779 { 00780 LOG(VB_GENERAL, LOG_ERR, QString("Error deleting file: '%1'") 00781 .arg(fullfile)); 00782 if (socket) 00783 { 00784 res << "0"; 00785 socket->SendStringList(res); 00786 } 00787 } 00788 00789 return true; 00790 } 00791 00792 bool FileServerHandler::HandleDeleteFile(DeleteHandler *handler) 00793 { 00794 RunDeleteThread(); 00795 return deletethread->AddFile(handler); 00796 } 00797 00798 bool FileServerHandler::HandleGetFileList(SocketHandler *socket, 00799 QStringList &slist) 00800 { 00801 QStringList res; 00802 00803 bool fileNamesOnly = false; 00804 if (slist.size() == 5) 00805 fileNamesOnly = slist[4].toInt(); 00806 else if (slist.size() != 4) 00807 { 00808 LOG(VB_GENERAL, LOG_ERR, QString("Invalid Request. %1") 00809 .arg(slist.join("[]:[]"))); 00810 res << "EMPTY LIST"; 00811 socket->SendStringList(res); 00812 return true; 00813 } 00814 00815 QString host = gCoreContext->GetHostName(); 00816 QString wantHost = slist[1]; 00817 QString groupname = slist[2]; 00818 QString path = slist[3]; 00819 00820 LOG(VB_FILE, LOG_INFO, 00821 QString("HandleSGGetFileList: group = %1 host = %2 " 00822 "path = %3 wanthost = %4") 00823 .arg(groupname).arg(host).arg(path).arg(wantHost)); 00824 00825 if ((host.toLower() == wantHost.toLower()) || 00826 gCoreContext->IsThisHost(wantHost)) 00827 { 00828 StorageGroup sg(groupname, host); 00829 LOG(VB_FILE, LOG_INFO, "Getting local info"); 00830 if (fileNamesOnly) 00831 res = sg.GetFileList(path); 00832 else 00833 res = sg.GetFileInfoList(path); 00834 00835 if (res.count() == 0) 00836 res << "EMPTY LIST"; 00837 } 00838 else 00839 { 00840 // handle request on remote server 00841 SocketHandler *remsock = NULL; 00842 { 00843 QReadLocker rlock(&m_fsLock); 00844 if (m_fsMap.contains(wantHost)) 00845 { 00846 remsock = m_fsMap[wantHost]; 00847 remsock->UpRef(); 00848 } 00849 } 00850 00851 if (remsock) 00852 { 00853 LOG(VB_FILE, LOG_INFO, "Getting remote info"); 00854 res << "QUERY_SG_GETFILELIST" << wantHost << groupname << path 00855 << QString::number(fileNamesOnly); 00856 remsock->SendReceiveStringList(res); 00857 remsock->DownRef(); 00858 } 00859 else 00860 { 00861 LOG(VB_FILE, LOG_ERR, QString("Failed to grab slave socket : %1 :") 00862 .arg(wantHost)); 00863 res << "SLAVE UNREACHABLE: " << wantHost; 00864 } 00865 } 00866 00867 socket->SendStringList(res); 00868 return true; 00869 } 00870 00871 bool FileServerHandler::HandleFileQuery(SocketHandler *socket, 00872 QStringList &slist) 00873 { 00874 QStringList res; 00875 00876 if (slist.size() != 4) 00877 { 00878 LOG(VB_GENERAL, LOG_ERR, QString("Invalid Request. %1") 00879 .arg(slist.join("[]:[]"))); 00880 res << "EMPTY LIST"; 00881 socket->SendStringList(res); 00882 return true; 00883 } 00884 00885 QString wantHost = slist[1]; 00886 QString groupname = slist[2]; 00887 QString filename = slist[3]; 00888 00889 LOG(VB_FILE, LOG_DEBUG, QString("HandleSGFileQuery: myth://%1@%2/%3") 00890 .arg(groupname).arg(wantHost).arg(filename)); 00891 00892 if ((wantHost.toLower() == gCoreContext->GetHostName().toLower()) || 00893 gCoreContext->IsThisHost(wantHost)) 00894 { 00895 // handle request locally 00896 LOG(VB_FILE, LOG_DEBUG, QString("Getting local info")); 00897 StorageGroup sg(groupname, gCoreContext->GetHostName()); 00898 res = sg.GetFileInfo(filename); 00899 00900 if (res.count() == 0) 00901 res << "EMPTY LIST"; 00902 } 00903 else 00904 { 00905 // handle request on remote server 00906 SocketHandler *remsock = NULL; 00907 { 00908 QReadLocker rlock(&m_fsLock); 00909 if (m_fsMap.contains(wantHost)) 00910 { 00911 remsock = m_fsMap[wantHost]; 00912 remsock->UpRef(); 00913 } 00914 } 00915 00916 if (remsock) 00917 { 00918 res << "QUERY_SG_FILEQUERY" << wantHost << groupname << filename; 00919 remsock->SendReceiveStringList(res); 00920 remsock->DownRef(); 00921 } 00922 else 00923 { 00924 res << "SLAVE UNREACHABLE: " << wantHost; 00925 } 00926 } 00927 00928 socket->SendStringList(res); 00929 return true; 00930 } 00931 00932 bool FileServerHandler::HandleQueryFileTransfer(SocketHandler *socket, 00933 QStringList &commands, QStringList &slist) 00934 { 00935 if (commands.size() != 2) 00936 return false; 00937 00938 if (slist.size() < 2) 00939 return false; 00940 00941 QStringList res; 00942 int recnum = commands[1].toInt(); 00943 FileTransfer *ft; 00944 00945 { 00946 QReadLocker rlock(&m_ftLock); 00947 if (!m_ftMap.contains(recnum)) 00948 { 00949 if (slist[1] == "DONE") 00950 res << "ok"; 00951 else 00952 { 00953 LOG(VB_GENERAL, LOG_ERR, 00954 QString("Unknown file transfer socket: %1").arg(recnum)); 00955 res << "ERROR" 00956 << "unknown_file_transfer_socket"; 00957 } 00958 00959 socket->SendStringList(res); 00960 return true; 00961 } 00962 00963 ft = m_ftMap[recnum]; 00964 ft->UpRef(); 00965 } 00966 00967 if (slist[1] == "IS_OPEN") 00968 { 00969 res << QString::number(ft->isOpen()); 00970 } 00971 else if (slist[1] == "DONE") 00972 { 00973 ft->Stop(); 00974 res << "ok"; 00975 } 00976 else if (slist[1] == "REQUEST_BLOCK") 00977 { 00978 if (slist.size() != 3) 00979 { 00980 LOG(VB_GENERAL, LOG_ERR, "Invalid QUERY_FILETRANSFER " 00981 "REQUEST_BLOCK call"); 00982 res << "ERROR" << "invalid_call"; 00983 } 00984 else 00985 { 00986 int size = slist[2].toInt(); 00987 res << QString::number(ft->RequestBlock(size)); 00988 } 00989 } 00990 else if (slist[1] == "WRITE_BLOCK") 00991 { 00992 if (slist.size() != 3) 00993 { 00994 LOG(VB_GENERAL, LOG_ERR, "Invalid QUERY_FILETRANSFER " 00995 "WRITE_BLOCK call"); 00996 res << "ERROR" << "invalid_call"; 00997 } 00998 else 00999 { 01000 int size = slist[2].toInt(); 01001 res << QString::number(ft->WriteBlock(size)); 01002 } 01003 } 01004 else if (slist[1] == "SEEK") 01005 { 01006 if (slist.size() != 5) 01007 { 01008 LOG(VB_GENERAL, LOG_ERR, "Invalid QUERY_FILETRANSFER SEEK call"); 01009 res << "ERROR" << "invalid_call"; 01010 } 01011 else 01012 { 01013 long long pos = slist[2].toLongLong(); 01014 int whence = slist[3].toInt(); 01015 long long curpos = slist[4].toLongLong(); 01016 01017 res << QString::number(ft->Seek(curpos, pos, whence)); 01018 } 01019 } 01020 else if (slist[1] == "SET_TIMEOUT") 01021 { 01022 if (slist.size() != 3) 01023 { 01024 LOG(VB_GENERAL, LOG_ERR, "Invalid QUERY_FILETRANSFER " 01025 "SET_TIMEOUT call"); 01026 res << "ERROR" << "invalid_call"; 01027 } 01028 else 01029 { 01030 bool fast = slist[2].toInt(); 01031 ft->SetTimeout(fast); 01032 res << "ok"; 01033 } 01034 } 01035 else 01036 { 01037 LOG(VB_GENERAL, LOG_ERR, "Invalid QUERY_FILETRANSFER call"); 01038 res << "ERROR" << "invalid_call"; 01039 } 01040 01041 ft->DownRef(); 01042 socket->SendStringList(res); 01043 return true; 01044 } 01045 01046 bool FileServerHandler::HandleDownloadFile(SocketHandler *socket, 01047 QStringList &slist) 01048 { 01049 QStringList res; 01050 01051 if (slist.size() != 4) 01052 { 01053 res << "ERROR" << QString("Bad %1 command").arg(slist[0]); 01054 socket->SendStringList(res); 01055 return true; 01056 } 01057 01058 bool synchronous = (slist[0] == "DOWNLOAD_FILE_NOW"); 01059 QString srcURL = slist[1]; 01060 QString storageGroup = slist[2]; 01061 QString filename = slist[3]; 01062 StorageGroup sgroup(storageGroup, gCoreContext->GetHostName(), false); 01063 QString outDir = sgroup.FindNextDirMostFree(); 01064 QString outFile; 01065 QStringList retlist; 01066 01067 if (filename.isEmpty()) 01068 { 01069 QFileInfo finfo(srcURL); 01070 filename = finfo.fileName(); 01071 } 01072 01073 if (outDir.isEmpty()) 01074 { 01075 LOG(VB_GENERAL, LOG_ERR, QString("Unable to determine directory " 01076 "to write to in %1 write command").arg(slist[0])); 01077 res << "ERROR" << "downloadfile_directory_not_found"; 01078 socket->SendStringList(res); 01079 return true; 01080 } 01081 01082 if ((filename.contains("/../")) || 01083 (filename.startsWith("../"))) 01084 { 01085 LOG(VB_GENERAL, LOG_ERR, QString("ERROR: %1 write " 01086 "filename '%2' does not pass sanity checks.") 01087 .arg(slist[0]).arg(filename)); 01088 res << "ERROR" << "downloadfile_filename_dangerous"; 01089 socket->SendStringList(res); 01090 return true; 01091 } 01092 01093 outFile = outDir + "/" + filename; 01094 01095 if (synchronous) 01096 { 01097 if (GetMythDownloadManager()->download(srcURL, outFile)) 01098 { 01099 res << "OK" 01100 << gCoreContext->GetMasterHostPrefix(storageGroup) 01101 + filename; 01102 } 01103 else 01104 res << "ERROR"; 01105 } 01106 else 01107 { 01108 QMutexLocker locker(&m_downloadURLsLock); 01109 m_downloadURLs[outFile] = 01110 gCoreContext->GetMasterHostPrefix(storageGroup) + 01111 StorageGroup::GetRelativePathname(outFile); 01112 01113 GetMythDownloadManager()->queueDownload(srcURL, outFile, this); 01114 res << "OK" 01115 << gCoreContext->GetMasterHostPrefix(storageGroup) + filename; 01116 } 01117 01118 socket->SendStringList(res); 01119 return true; 01120 } 01121
1.7.6.1