bool FileOps::CacheFile(void* destination, MythFile &source) { unsigned long long totalLength = source.Length(); unsigned long long totalRead = 0; const long buffersize = RCV_BUF_IMAGE_SIZE; char* buffer = new char[buffersize]; while (totalRead < totalLength) { int bytes_read = source.Read(buffer, buffersize); if (bytes_read <= 0) break; totalRead += bytes_read; char *p = buffer; while (bytes_read > 0) { int bytes_written = XBMC->WriteFile(destination, p, bytes_read); if (bytes_written <= 0) break; bytes_read -= bytes_written; p += bytes_written; } } XBMC->CloseFile(destination); delete[] buffer; if (totalRead < totalLength) XBMC->Log(LOG_DEBUG, "%s: Failed to read all data: (%d/%d)", __FUNCTION__, totalRead, totalLength); return true; }
bool FileOps::CacheFile(const CStdString &localFilename, MythFile &source) { if (source.IsNull()) { XBMC->Log(LOG_ERROR,"%s: NULL file provided", __FUNCTION__); return false; } if (source.Length() == 0) { XBMC->Log(LOG_ERROR,"%s: Empty file provided", __FUNCTION__); return false; } // Try to open the file. If it fails, check if we need to create the directory first. // This way we avoid checking if the directory exists every time. void *file; if (!(file = XBMC->OpenFileForWrite(localFilename.c_str(), true))) { CStdString cacheDirectory = GetDirectoryName(localFilename); if (XBMC->DirectoryExists(cacheDirectory.c_str()) || XBMC->CreateDirectory(cacheDirectory.c_str())) { if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s: Created cache directory: %s", __FUNCTION__, cacheDirectory.c_str()); if (!(file = XBMC->OpenFileForWrite(localFilename.c_str(), true))) { XBMC->Log(LOG_ERROR, "%s: Failed to create cache file: %s", __FUNCTION__, localFilename.c_str()); return false; } } else { XBMC->Log(LOG_ERROR, "%s: Failed to create cache directory: %s", __FUNCTION__, cacheDirectory.c_str()); return false; } } unsigned long long totalLength = source.Length(); unsigned long long totalRead = 0; const long buffersize = RCV_BUF_IMAGE_SIZE; char* buffer = new char[buffersize]; while (totalRead < totalLength) { int bytes_read = source.Read(buffer, buffersize); if (bytes_read <= 0) break; totalRead += bytes_read; char *p = buffer; while (bytes_read > 0) { int bytes_written = XBMC->WriteFile(file, p, bytes_read); if (bytes_written <= 0) break; bytes_read -= bytes_written; p += bytes_written; } } XBMC->CloseFile(file); delete[] buffer; if (totalRead < totalLength) { XBMC->Log(LOG_DEBUG, "%s: Failed to read all data: %s (%d/%d)", __FUNCTION__, localFilename.c_str(), totalRead, totalLength); } return true; }
void* FileOps::Process() { XBMC->Log(LOG_DEBUG, "%s FileOps Thread Started", __FUNCTION__); std::list<FileOps::JobItem> jobQueueDelayed; while (!IsStopped()) { // Wake this thread from time to time to clean the cache and recache empty files (delayed queue) // For caching new files, the tread is woken up by m_queueContent.Signal(); m_queueContent.Wait(c_timeoutProcess * 1000); while (!m_jobQueue.empty() && !IsStopped()) { Lock(); FileOps::JobItem job = m_jobQueue.front(); m_jobQueue.pop_front(); Unlock(); if (g_bExtraDebug) XBMC->Log(LOG_DEBUG,"%s Job fetched: local: %s, remote: %s, storagegroup: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); // Connect to the file and cache it to the local addon cache MythFile file = m_con.ConnectPath(job.m_remoteFilename, job.m_storageGroup); if (!file.IsNull() && file.Length() > 0) { if (CacheFile(job.m_localFilename.c_str(), file)) { if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s File Cached: local: %s, remote: %s, type: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); } else { XBMC->Log(LOG_DEBUG, "%s Caching file failed: local: %s, remote: %s, type: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); if (XBMC->FileExists(job.m_localFilename.c_str(), true)) { XBMC->DeleteFile(job.m_localFilename.c_str()); } } } else { // Failed to open file for reading. Unfortunately it cannot be determined if this is a permanent or a temporary problem (new recording's preview hasn't been generated yet). // Increase the error count and retry to cache the file a few times if (file.IsNull()) { XBMC->Log(LOG_ERROR, "%s Failed to read file: local: %s, remote: %s, type: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); job.m_errorCount += 1; } // File was empty (this happens usually for new recordings where the preview image hasn't been generated yet) // This is not an error, always try to recache the file else if (file.Length() == 0) { XBMC->Log(LOG_DEBUG, "%s File is empty: local: %s, remote: %s, type: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); } // Recache the file if it hasn't exceeded the maximum number of allowed attempts if (job.m_errorCount <= c_maximumAttemptsOnReadError) { XBMC->Log(LOG_DEBUG, "%s Delayed recache file: local: %s, remote: %s, type: %s", __FUNCTION__, job.m_localFilename.c_str(), job.m_remoteFilename.c_str(), job.m_storageGroup.c_str()); jobQueueDelayed.push_back(job); } } } // Try to recache the currently empty files Lock(); m_jobQueue.insert(m_jobQueue.end(), jobQueueDelayed.begin(), jobQueueDelayed.end()); jobQueueDelayed.clear(); Unlock(); } XBMC->Log(LOG_DEBUG, "%s FileOps Thread Stopped", __FUNCTION__); return NULL; }
CStdString fileOps::GetFileFromBackend ( CStdString filenameToGet, CStdString fromStorageGroup ) { XBMC->Log(LOG_DEBUG,"%s - Getting File via Myth Protocol - %s", __FUNCTION__,filenameToGet.c_str()); if (filenameToGet.Left(1).compare("/") != 0) { filenameToGet = "/" + filenameToGet; } MythFile theFile; if (fromStorageGroup.CompareNoCase("channels")==0) { CStdString chanFilename = "/channels" + filenameToGet; CStdString chanSG = "c"; theFile=mythConP.ConnectPath((char*)chanFilename.c_str(),(char*)chanSG.c_str()); } else { theFile=mythConP.ConnectPath((char*)filenameToGet.c_str(),(char*)fromStorageGroup.c_str()); } if (theFile.IsNull()) { return ""; } int theFilesLength = theFile.Duration(); if (theFilesLength <= 0) { return ""; } CStdString writeFilePath = baseLocalCachepath + fromStorageGroup + filenameToGet; checkDirectory(writeFilePath,true); XFILE::CFile writeFile; if (writeFile.OpenForWrite(writeFilePath)) { //char* theFileBuff = new char[theFilesLength]; int totalRead = 0; while (totalRead < theFilesLength) { char* theFileTmpBuff = new char[theFilesLength]; int readData = theFile.Read(theFileTmpBuff,theFilesLength-totalRead); if (readData <= 0) { break; } writeFile.Write((const void*)theFileTmpBuff,readData); /*char *filePntr = theFileBuff; if (totalRead > 0) { filePntr += (totalRead); } if (readData > (theFilesLength-totalRead)) { readData = (theFilesLength-totalRead); } memcpy((void*)filePntr,(void*)theFileTmpBuff,readData); */ totalRead += readData; } writeFile.Close(); if (totalRead < theFilesLength) { XBMC->Log(LOG_DEBUG,"%s - Did not Read all data - %s - %d - %d", __FUNCTION__,filenameToGet.c_str(),totalRead,theFilesLength); } return writeFilePath; } else { return ""; } }