bool CFile::OpenForWrite(const CURL& file, bool bOverWrite) { try { CURL url = URIUtils::SubstitutePath(file); CURL authUrl = url; if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrl); m_pFile = CFileFactory::CreateLoader(url); if (m_pFile && m_pFile->OpenForWrite(authUrl, bOverWrite)) { // add this file to our directory cache (if it's stored) g_directoryCache.AddFile(url.Get()); return true; } return false; } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception opening %s", __FUNCTION__, file.GetRedacted().c_str()); } CLog::Log(LOGERROR, "%s - Error opening %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
bool CFile::Exists(const CURL& file, bool bUseCache /* = true */) { CURL url(URIUtils::SubstitutePath(file)); try { if (bUseCache) { bool bPathInCache; if (g_directoryCache.FileExists(url.Get(), bPathInCache)) return true; if (bPathInCache) return false; } std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; return pFile->Exists(url); } XBMCCOMMONS_HANDLE_UNCHECKED catch (CRedirectException *pRedirectEx) { // the file implementation decided this item should use a different implementation. // the exception will contain the new implementation and optional a redirected URL. CLog::Log(LOGDEBUG,"File::Exists - redirecting implementation for %s", file.GetRedacted().c_str()); if (pRedirectEx && pRedirectEx->m_pNewFileImp) { std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp); std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl); delete pRedirectEx; if (pImp.get()) { if (pNewUrl.get()) { if (bUseCache) { bool bPathInCache; if (g_directoryCache.FileExists(pNewUrl->Get(), bPathInCache)) return true; if (bPathInCache) return false; } return pImp->Exists(*pNewUrl); } else return pImp->Exists(url); } } } catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error checking for %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
int CFile::Stat(const CURL& file, struct __stat64* buffer) { if (!buffer) return -1; CURL url(URIUtils::SubstitutePath(file)); CURL authUrl = url; if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrl); try { std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return -1; return pFile->Stat(authUrl, buffer); } XBMCCOMMONS_HANDLE_UNCHECKED catch (CRedirectException *pRedirectEx) { // the file implementation decided this item should use a different implementation. // the exception will contain the new implementation and optional a redirected URL. CLog::Log(LOGDEBUG,"File::Stat - redirecting implementation for %s", file.GetRedacted().c_str()); if (pRedirectEx && pRedirectEx->m_pNewFileImp) { std::unique_ptr<IFile> pImp(pRedirectEx->m_pNewFileImp); std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl); delete pRedirectEx; if (pNewUrl.get()) { if (pImp.get()) { CURL newAuthUrl = *pNewUrl; if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl); if (!pImp->Stat(newAuthUrl, buffer)) { return 0; } } } else { if (pImp.get() && !pImp->Stat(authUrl, buffer)) { return 0; } } } } catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error statting %s", __FUNCTION__, file.GetRedacted().c_str()); return -1; }
bool CFileCache::Open(const CURL& url) { Close(); XR::CSingleLock lock(m_sync); LOGDEBUG("CFileCache::Open - opening <%s> using cache", url.GetRedacted().c_str()); if (!m_pCache) { LOGERR("CFileCache::Open - no cache strategy defined"); return false; } m_sourcePath = url.Get(); // open cache strategy if (m_pCache->Open() != CACHE_RC_OK) { LOGERR("CFileCache::Open - failed to open cache"); Close(); return false; } // opening the source file. if (!m_source.Open(m_sourcePath, READ_NO_CACHE | READ_TRUNCATED | READ_CHUNKED)) { LOGERR("Failed to open source <%s>", url.GetRedacted().c_str()); Close(); return false; } m_source.IoControl(IOCTRL_SET_CACHE, this); // check if source can seek m_seekPossible = m_source.IoControl(IOCTRL_SEEK_POSSIBLE, NULL); m_chunkSize = CFile::GetChunkSize(m_source.GetChunkSize(), READ_CACHE_CHUNK_SIZE); m_readPos = 0; m_writePos = 0; m_writeRate = 1024 * 1024; m_writeRateActual = 0; m_cacheFull = false; m_seekEvent.Reset(); m_seekEnded.Reset(); CThread::Create(false); return true; }
bool CSMBFile::Open(const CURL& url) { Close(); // we can't open files like smb://file.f or smb://server/file.f // if a file matches the if below return false, it can't exist on a samba share. if (!IsValidFile(url.GetFileName())) { CLog::Log(LOGNOTICE,"SMBFile->Open: Bad URL : '%s'",url.GetRedacted().c_str()); return false; } m_url = url; // opening a file to another computer share will create a new session // when opening smb://server xbms will try to find folder.jpg in all shares // listed, which will create lot's of open sessions. std::string strFileName; m_fd = OpenFile(url, strFileName); CLog::Log(LOGDEBUG,"CSMBFile::Open - opened %s, fd=%d",url.GetRedacted().c_str(), m_fd); if (m_fd == -1) { // write error to logfile CLog::Log(LOGINFO, "SMBFile->Open: Unable to open file : '%s'\nunix_err:'%x' error : '%s'", CURL::GetRedacted(strFileName).c_str(), errno, strerror(errno)); return false; } CSingleLock lock(smb); struct stat tmpBuffer; if (smbc_stat(strFileName.c_str(), &tmpBuffer) < 0) { smbc_close(m_fd); m_fd = -1; return false; } m_fileSize = tmpBuffer.st_size; int64_t ret = smbc_lseek(m_fd, 0, SEEK_SET); if ( ret < 0 ) { smbc_close(m_fd); m_fd = -1; return false; } // We've successfully opened the file! return true; }
bool CDAVFile::Rename(const CURL& url, const CURL& urlnew) { if (m_opened) return false; CDAVFile dav; CURL url2(urlnew); std::string strProtocol = url2.GetTranslatedProtocol(); url2.SetProtocol(strProtocol); std::string strRequest = "MOVE"; dav.SetCustomRequest(strRequest); dav.SetRequestHeader("Destination", url2.GetWithoutUserDetails()); CLog::Log(LOGDEBUG, "CDAVFile::Rename - Execute MOVE (%s -> %s)", url.GetRedacted().c_str(), url2.GetRedacted().c_str()); if (!dav.Execute(url)) { CLog::Log(LOGERROR, "CDAVFile::Rename - Unable to rename dav resource (%s -> %s)", url.GetRedacted().c_str(), url2.GetRedacted().c_str()); return false; } dav.Close(); return true; }
bool CFile::Delete(const CURL& file) { try { CURL url(URIUtils::SubstitutePath(file)); unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; if(pFile->Delete(url)) { g_directoryCache.ClearFile(url.Get()); return true; } } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } if (Exists(file)) CLog::Log(LOGERROR, "%s - Error deleting file %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
StorageFolder CWinLibraryDirectory::GetFolder(const CURL& url) { StorageFolder rootFolder = GetRootFolder(url); if (!rootFolder) return nullptr; // find inner folder std::string folderPath = URIUtils::FixSlashesAndDups(url.GetFileName(), '\\'); if (!folderPath.empty()) { try { std::wstring wStrPath = ToW(folderPath); auto item = Wait(rootFolder.TryGetItemAsync(wStrPath)); if (item && item.IsOfType(StorageItemTypes::Folder)) return item.as<StorageFolder>(); return nullptr; } catch (const winrt::hresult_error& ex) { std::string error = FromW(ex.message().c_str()); CLog::LogF(LOGERROR, "unable to get folder '%s' with error", url.GetRedacted().c_str(), error.c_str()); } return nullptr; } return rootFolder; }
bool CFile::Rename(const CURL& file, const CURL& newFile) { try { CURL url(URIUtils::SubstitutePath(file)); CURL urlnew(URIUtils::SubstitutePath(newFile)); CURL authUrl = url; if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrl); CURL authUrlNew = urlnew; if (CPasswordManager::GetInstance().IsURLSupported(authUrlNew) && authUrlNew.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrlNew); std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; if(pFile->Rename(authUrl, authUrlNew)) { g_directoryCache.ClearFile(url.Get()); g_directoryCache.AddFile(urlnew.Get()); return true; } } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception ", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error renaming file %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
bool CDirectory::Exists(const CURL& url, bool bUseCache /* = true */) { try { CURL realURL = URIUtils::SubstitutePath(url); if (bUseCache) { bool bPathInCache; std::string realPath(realURL.Get()); URIUtils::AddSlashAtEnd(realPath); if (g_directoryCache.FileExists(realPath, bPathInCache)) return true; if (bPathInCache) return false; } unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL)); if (pDirectory.get()) return pDirectory->Exists(realURL); } XBMCCOMMONS_HANDLE_UNCHECKED catch (...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error checking for %s", __FUNCTION__, url.GetRedacted().c_str()); return false; }
bool CFile::Rename(const CURL& file, const CURL& newFile) { try { CURL url(URIUtils::SubstitutePath(file)); CURL urlnew(URIUtils::SubstitutePath(newFile)); std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; if(pFile->Rename(url, urlnew)) { g_directoryCache.ClearFile(url.Get()); g_directoryCache.AddFile(urlnew.Get()); return true; } } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception ", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error renaming file %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
int CDAVFile::Stat(const CURL& url, struct __stat64* buffer) { CDAVFile dav; std::string strRequest = "PROPFIND"; dav.SetCustomRequest(strRequest); dav.SetRequestHeader("depth", 0); dav.SetMimeType("text/xml; charset=\"utf-8\""); if (buffer) { CLog::Log(LOGDEBUG, "CDAVFile::Stat - Execute STAT (%s)", url.GetRedacted().c_str()); dav.SetPostData( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" " <D:propfind xmlns:D=\"DAV:\">" " <D:prop>" " <D:resourcetype/>" " <D:getcontentlength/>" " <D:getlastmodified/>" " <D:creationdate/>" " <D:displayname/>" " </D:prop>" " </D:propfind>"); } else { dav.SetPostData( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"); } if (!dav.Execute(url)) { if (buffer) CLog::Log(LOGERROR, "CDAVFile::Stat - Unable to stat resource (%s) with code %i", url.GetRedacted().c_str(), m_lastResponseCode); return -1; } dav.Close(); // Iterate over all responses for (TiXmlNode *pChild = m_davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { if (CDAVCommon::ValueWithoutNamespace(pChild, "response")) { if (ParseResponse(pChild->ToElement(), buffer)) return 0; else return -1; } } return -1; }
bool CDAVFile::Delete(const CURL& url) { if (m_opened) return false; CDAVFile dav; std::string strRequest = "DELETE"; dav.SetCustomRequest(strRequest); CLog::Log(LOGDEBUG, "CDAVFile::Delete - Execute DELETE (%s)", url.GetRedacted().c_str()); if (!dav.Execute(url)) { CLog::Log(LOGERROR, "CDAVFile::Delete - Unable to delete dav resource (%s)", url.GetRedacted().c_str()); return false; } dav.Close(); return true; }
bool CFile::OpenForWrite(const CURL& file, bool bOverWrite) { try { CURL url = URIUtils::SubstitutePath(file); m_pFile = CFileFactory::CreateLoader(url); if (m_pFile && m_pFile->OpenForWrite(url, bOverWrite)) { // add this file to our directory cache (if it's stored) g_directoryCache.AddFile(url.Get()); return true; } return false; } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception opening %s", __FUNCTION__, file.GetRedacted().c_str()); } CLog::Log(LOGERROR, "%s - Error opening %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
bool CMultiPathDirectory::Exists(const CURL& url) { CLog::Log(LOGDEBUG,"Testing Existence (%s)", url.GetRedacted().c_str()); std::vector<std::string> vecPaths; if (!GetPaths(url, vecPaths)) return false; for (unsigned int i = 0; i < vecPaths.size(); ++i) { CLog::Log(LOGDEBUG,"Testing Existence (%s)", vecPaths[i].c_str()); if (CDirectory::Exists(vecPaths[i])) return true; } return false; }
StorageFolder^ CWinLibraryDirectory::GetFolder(const CURL& url) { StorageFolder^ rootFolder = GetRootFolder(url); if (!rootFolder) return nullptr; // find inner folder std::string folderPath = URIUtils::FixSlashesAndDups(url.GetFileName(), '\\'); if (url.GetHostName() == "removable") { // here path has the form e\path where first segment is drive letter // we should make path form like regular e:\path auto index = folderPath.find('\\'); if (index != std::string::npos) { folderPath = folderPath.insert(index, 1, ':'); } // win-lib://removable/F -> folderPath contains only drive letter else if (index == std::string::npos && folderPath.length() == 1) { folderPath += ":\\"; } else { return nullptr; } } if (!folderPath.empty()) { try { std::wstring wStrPath = ToW(folderPath); Platform::String^ pPath = ref new Platform::String(wStrPath.c_str()); return Wait(rootFolder->GetFolderAsync(pPath)); } catch (Platform::Exception^ ex) { std::string error = FromW(std::wstring(ex->Message->Data())); CLog::LogF(LOGERROR, "unable to get folder '%s' with error", url.GetRedacted().c_str(), error.c_str()); } return nullptr; } return rootFolder; }
bool CDirectory::Create(const CURL& url) { try { CURL realURL = URIUtils::SubstitutePath(url); unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL)); if (pDirectory.get()) if(pDirectory->Create(realURL)) return true; } XBMCCOMMONS_HANDLE_UNCHECKED catch (...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error creating %s", __FUNCTION__, url.GetRedacted().c_str()); return false; }
bool CFile::SetHidden(const CURL& file, bool hidden) { try { CURL url(URIUtils::SubstitutePath(file)); std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; return pFile->SetHidden(url, hidden); } catch(...) { CLog::Log(LOGERROR, "%s(%s) - Unhandled exception", __FUNCTION__, file.GetRedacted().c_str()); } return false; }
bool CFile::SetHidden(const CURL& file, bool hidden) { try { CURL url(URIUtils::SubstitutePath(file)); CURL authUrl = url; if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrl); std::unique_ptr<IFile> pFile(CFileFactory::CreateLoader(url)); if (!pFile.get()) return false; return pFile->SetHidden(authUrl, hidden); } catch(...) { CLog::Log(LOGERROR, "%s(%s) - Unhandled exception", __FUNCTION__, file.GetRedacted().c_str()); } return false; }
CVFSURLWrapper(const CURL& url2) { m_strings.push_back(url2.Get()); m_strings.push_back(url2.GetDomain()); m_strings.push_back(url2.GetHostName()); m_strings.push_back(url2.GetFileName()); m_strings.push_back(url2.GetOptions()); m_strings.push_back(url2.GetUserName()); m_strings.push_back(url2.GetPassWord()); m_strings.push_back(url2.GetRedacted()); m_strings.push_back(url2.GetShareName()); url.url = m_strings[0].c_str(); url.domain = m_strings[1].c_str(); url.hostname = m_strings[2].c_str(); url.filename = m_strings[3].c_str(); url.port = url2.GetPort(); url.options = m_strings[4].c_str(); url.username = m_strings[5].c_str(); url.password = m_strings[6].c_str(); url.redacted = m_strings[7].c_str(); url.sharename = m_strings[8].c_str(); }
bool CFileCache::Open(const CURL& url) { Close(); CSingleLock lock(m_sync); CLog::Log(LOGDEBUG,"CFileCache::Open - opening <%s> using cache", url.GetFileName().c_str()); m_sourcePath = url.Get(); // opening the source file. if (!m_source.Open(m_sourcePath, READ_NO_CACHE | READ_TRUNCATED | READ_CHUNKED)) { CLog::Log(LOGERROR,"%s - failed to open source <%s>", __FUNCTION__, url.GetRedacted().c_str()); Close(); return false; } m_source.IoControl(IOCTRL_SET_CACHE, this); bool retry = false; m_source.IoControl(IOCTRL_SET_RETRY, &retry); // We already handle retrying ourselves // check if source can seek m_seekPossible = m_source.IoControl(IOCTRL_SEEK_POSSIBLE, NULL); m_chunkSize = CFile::GetChunkSize(m_source.GetChunkSize(), READ_CACHE_CHUNK_SIZE); m_fileSize = m_source.GetLength(); if (!m_pCache) { if (g_advancedSettings.m_cacheMemBufferSize == 0) { // Use cache on disk m_pCache = new CSimpleFileCache(); m_forwardCacheSize = 0; } else { size_t cacheSize; if (m_fileSize > 0 && m_fileSize < g_advancedSettings.m_cacheMemBufferSize && !(m_flags & READ_AUDIO_VIDEO)) { // NOTE: We don't need to take into account READ_MULTI_STREAM here as it's only used for audio/video cacheSize = m_fileSize; } else { cacheSize = g_advancedSettings.m_cacheMemBufferSize; } size_t back = cacheSize / 4; size_t front = cacheSize - back; if (m_flags & READ_MULTI_STREAM) { // READ_MULTI_STREAM requires double buffering, so use half the amount of memory for each buffer front /= 2; back /= 2; } m_pCache = new CCircularCache(front, back); m_forwardCacheSize = front; } if (m_flags & READ_MULTI_STREAM) { // If READ_MULTI_STREAM flag is set: Double buffering is required m_pCache = new CDoubleCache(m_pCache); } } // open cache strategy if (!m_pCache || m_pCache->Open() != CACHE_RC_OK) { CLog::Log(LOGERROR,"CFileCache::Open - failed to open cache"); Close(); return false; } m_readPos = 0; m_writePos = 0; m_writeRate = 1024 * 1024; m_writeRateActual = 0; m_seekEvent.Reset(); m_seekEnded.Reset(); CThread::Create(false); return true; }
bool CFile::Open(const CURL& file, const unsigned int flags) { if (m_pFile) { if ((flags & READ_REOPEN) == 0) { CLog::Log(LOGERROR, "File::Open - already open: %s", file.GetRedacted().c_str()); return false; } else { return m_pFile->ReOpen(URIUtils::SubstitutePath(file)); } } m_flags = flags; try { bool bPathInCache; CURL url(URIUtils::SubstitutePath(file)), url2(url); if (url2.IsProtocol("apk") || url2.IsProtocol("zip") ) url2.SetOptions(""); if (!g_directoryCache.FileExists(url2.Get(), bPathInCache) ) { if (bPathInCache) return false; } if (!(m_flags & READ_NO_CACHE)) { const std::string pathToUrl(url.Get()); if (URIUtils::IsInternetStream(url, true) && !CUtil::IsPicture(pathToUrl) ) m_flags |= READ_CACHED; if (m_flags & READ_CACHED) { // for internet stream, if it contains multiple stream, file cache need handle it specially. m_pFile = new CFileCache(m_flags); if (!m_pFile) return false; return m_pFile->Open(url); } } m_pFile = CFileFactory::CreateLoader(url); if (!m_pFile) return false; CURL authUrl(url); if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(authUrl); try { if (!m_pFile->Open(authUrl)) { SAFE_DELETE(m_pFile); return false; } } catch (CRedirectException *pRedirectEx) { // the file implementation decided this item should use a different implementation. // the exception will contain the new implementation. CLog::Log(LOGDEBUG,"File::Open - redirecting implementation for %s", file.GetRedacted().c_str()); SAFE_DELETE(m_pFile); if (pRedirectEx && pRedirectEx->m_pNewFileImp) { std::unique_ptr<CURL> pNewUrl(pRedirectEx->m_pNewUrl); m_pFile = pRedirectEx->m_pNewFileImp; delete pRedirectEx; if (pNewUrl.get()) { CURL newAuthUrl(*pNewUrl); if (CPasswordManager::GetInstance().IsURLSupported(newAuthUrl) && newAuthUrl.GetUserName().empty()) CPasswordManager::GetInstance().AuthenticateURL(newAuthUrl); if (!m_pFile->Open(newAuthUrl)) { SAFE_DELETE(m_pFile); return false; } } else { if (!m_pFile->Open(authUrl)) { SAFE_DELETE(m_pFile); return false; } } } } catch (...) { CLog::Log(LOGERROR, "File::Open - unknown exception when opening %s", file.GetRedacted().c_str()); SAFE_DELETE(m_pFile); return false; } if (m_pFile->GetChunkSize() && !(m_flags & READ_CHUNKED)) { m_pBuffer = new CFileStreamBuffer(0); m_pBuffer->Attach(m_pFile); } if (m_flags & READ_BITRATE) { m_bitStreamStats = new BitstreamStats(); m_bitStreamStats->Start(); } return true; } XBMCCOMMONS_HANDLE_UNCHECKED catch(...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error opening %s", __FUNCTION__, file.GetRedacted().c_str()); return false; }
bool CFile::Copy(const CURL& url2, const CURL& dest, XFILE::IFileCallback* pCallback, void* pContext) { CFile file; const std::string pathToUrl(dest.Get()); if (pathToUrl.empty()) return false; // special case for zips - ignore caching CURL url(url2); if (URIUtils::IsInZIP(url.Get()) || URIUtils::IsInAPK(url.Get())) url.SetOptions("?cache=no"); if (file.Open(url.Get(), READ_TRUNCATED | READ_CHUNKED)) { CFile newFile; if (URIUtils::IsHD(pathToUrl)) // create possible missing dirs { std::vector<std::string> tokens; std::string strDirectory = URIUtils::GetDirectory(pathToUrl); URIUtils::RemoveSlashAtEnd(strDirectory); // for the test below if (!(strDirectory.size() == 2 && strDirectory[1] == ':')) { CURL url(strDirectory); std::string pathsep; #ifndef TARGET_POSIX pathsep = "\\"; #else pathsep = "/"; #endif // Try to use the recursive creation first, if it fails // it might not be implemented for that subsystem so let's // fall back to the old method in that case if (!CDirectory::Create(url)) { StringUtils::Tokenize(url.GetFileName(), tokens, pathsep.c_str()); std::string strCurrPath; // Handle special if (!url.GetProtocol().empty()) { pathsep = "/"; strCurrPath += url.GetProtocol() + "://"; } // If the directory has a / at the beginning, don't forget it else if (strDirectory[0] == pathsep[0]) strCurrPath += pathsep; for (std::vector<std::string>::iterator iter = tokens.begin(); iter != tokens.end(); ++iter) { strCurrPath += *iter + pathsep; CDirectory::Create(strCurrPath); } } } } if (CFile::Exists(dest)) CFile::Delete(dest); if (!newFile.OpenForWrite(dest, true)) // overwrite always { file.Close(); return false; } int iBufferSize = GetChunkSize(file.GetChunkSize(), 128 * 1024); auto_buffer buffer(iBufferSize); ssize_t iRead, iWrite; unsigned long long llFileSize = file.GetLength(); unsigned long long llPos = 0; CStopWatch timer; timer.StartZero(); float start = 0.0f; while (true) { g_application.ResetScreenSaver(); iRead = file.Read(buffer.get(), iBufferSize); if (iRead == 0) break; else if (iRead < 0) { CLog::Log(LOGERROR, "%s - Failed read from file %s", __FUNCTION__, url.GetRedacted().c_str()); llFileSize = (uint64_t)-1; break; } /* write data and make sure we managed to write it all */ iWrite = 0; while(iWrite < iRead) { ssize_t iWrite2 = newFile.Write(buffer.get() + iWrite, iRead - iWrite); if(iWrite2 <=0) break; iWrite+=iWrite2; } if (iWrite != iRead) { CLog::Log(LOGERROR, "%s - Failed write to file %s", __FUNCTION__, dest.GetRedacted().c_str()); llFileSize = (uint64_t)-1; break; } llPos += iRead; // calculate the current and average speeds float end = timer.GetElapsedSeconds(); if (pCallback && end - start > 0.5 && end) { start = end; float averageSpeed = llPos / end; int ipercent = 0; if(llFileSize) ipercent = 100 * llPos / llFileSize; if(!pCallback->OnFileCallback(pContext, ipercent, averageSpeed)) { CLog::Log(LOGERROR, "%s - User aborted copy", __FUNCTION__); llFileSize = (uint64_t)-1; break; } } } /* close both files */ newFile.Close(); file.Close(); /* verify that we managed to completed the file */ if (llFileSize && llPos != llFileSize) { CFile::Delete(dest); return false; } return true; } return false; }
bool CDirectory::GetDirectory(const CURL& url, CFileItemList &items, const CHints &hints, bool allowThreads) { try { CURL realURL = URIUtils::SubstitutePath(url); std::shared_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL)); if (!pDirectory.get()) return false; // check our cache for this path if (g_directoryCache.GetDirectory(realURL.Get(), items, (hints.flags & DIR_FLAG_READ_CACHE) == DIR_FLAG_READ_CACHE)) items.SetURL(url); else { // need to clear the cache (in case the directory fetch fails) // and (re)fetch the folder if (!(hints.flags & DIR_FLAG_BYPASS_CACHE)) g_directoryCache.ClearDirectory(realURL.Get()); pDirectory->SetFlags(hints.flags); bool result = false, cancel = false; while (!result && !cancel) { const std::string pathToUrl(url.Get()); if (g_application.IsCurrentThread() && allowThreads && !URIUtils::IsSpecial(pathToUrl)) { CSingleExit ex(g_graphicsContext); CGetDirectory get(pDirectory, realURL, url); if(!get.Wait(TIME_TO_BUSY_DIALOG)) { CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY); if (dialog) { dialog->Open(); while(!get.Wait(10)) { CSingleLock lock(g_graphicsContext); // update progress float progress = pDirectory->GetProgress(); if (progress > 0) dialog->SetProgress(progress); if (dialog->IsCanceled()) { cancel = true; pDirectory->CancelDirectory(); break; } lock.Leave(); // prevent an occasional deadlock on exit g_windowManager.ProcessRenderLoop(false); } dialog->Close(); } } result = get.GetDirectory(items); } else { items.SetURL(url); result = pDirectory->GetDirectory(realURL, items); } if (!result) { if (!cancel && g_application.IsCurrentThread() && pDirectory->ProcessRequirements()) continue; CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, url.GetRedacted().c_str()); return false; } } // cache the directory, if necessary if (!(hints.flags & DIR_FLAG_BYPASS_CACHE)) g_directoryCache.SetDirectory(realURL.Get(), items, pDirectory->GetCacheType(url)); } // now filter for allowed files if (!pDirectory->AllowAll()) { pDirectory->SetMask(hints.mask); for (int i = 0; i < items.Size(); ++i) { CFileItemPtr item = items[i]; if (!item->m_bIsFolder && !pDirectory->IsAllowed(item->GetURL())) { items.Remove(i); i--; // don't confuse loop } } } // filter hidden files // TODO: we shouldn't be checking the gui setting here, callers should use getHidden instead if (!CSettings::Get().GetBool("filelists.showhidden") && !(hints.flags & DIR_FLAG_GET_HIDDEN)) { for (int i = 0; i < items.Size(); ++i) { if (items[i]->GetProperty("file:hidden").asBoolean()) { items.Remove(i); i--; // don't confuse loop } } } // Should any of the files we read be treated as a directory? // Disable for database folders, as they already contain the extracted items if (!(hints.flags & DIR_FLAG_NO_FILE_DIRS) && !items.IsMusicDb() && !items.IsVideoDb() && !items.IsSmartPlayList()) FilterFileDirectories(items, hints.mask); // Correct items for path substitution const std::string pathToUrl(url.Get()); const std::string pathToUrl2(realURL.Get()); if (pathToUrl != pathToUrl2) { for (int i = 0; i < items.Size(); ++i) { CFileItemPtr item = items[i]; item->SetPath(URIUtils::SubstitutePath(item->GetPath(), true)); } } return true; } XBMCCOMMONS_HANDLE_UNCHECKED catch (...) { CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__); } CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, url.GetRedacted().c_str()); return false; }
bool CDAVDirectory::Remove(const CURL& url) { CDAVFile dav; std::string strRequest = "DELETE"; dav.SetCustomRequest(strRequest); if (!dav.Execute(url)) { CLog::Log(LOGERROR, "%s - Unable to delete dav directory (%s) - %d", __FUNCTION__, url.GetRedacted().c_str(), dav.GetLastResponseCode()); return false; } dav.Close(); return true; }
bool CDAVDirectory::GetDirectory(const CURL& url, CFileItemList &items) { CCurlFile dav; std::string strRequest = "PROPFIND"; dav.SetCustomRequest(strRequest); dav.SetMimeType("text/xml; charset=\"utf-8\""); dav.SetRequestHeader("depth", 1); dav.SetPostData( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" " <D:propfind xmlns:D=\"DAV:\">" " <D:prop>" " <D:resourcetype/>" " <D:getcontentlength/>" " <D:getlastmodified/>" " <D:creationdate/>" " <D:displayname/>" " </D:prop>" " </D:propfind>"); if (!dav.Open(url)) { CLog::Log(LOGERROR, "%s - Unable to get dav directory (%s)", __FUNCTION__, url.GetRedacted().c_str()); return false; } std::string strResponse; dav.ReadData(strResponse); std::string fileCharset(dav.GetProperty(XFILE::FILE_PROPERTY_CONTENT_CHARSET)); CXBMCTinyXML davResponse; davResponse.Parse(strResponse, fileCharset); if (!davResponse.Parse(strResponse)) { CLog::Log(LOGERROR, "%s - Unable to process dav directory (%s)", __FUNCTION__, url.GetRedacted().c_str()); dav.Close(); return false; } TiXmlNode *pChild; // Iterate over all responses for (pChild = davResponse.RootElement()->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { if (CDAVCommon::ValueWithoutNamespace(pChild, "response")) { CFileItem item; ParseResponse(pChild->ToElement(), item); CURL url2(url); CURL url3(item.GetPath()); std::string itemPath(URIUtils::AddFileToFolder(url2.GetWithoutFilename(), url3.GetFileName())); if (item.GetLabel().empty()) { std::string name(itemPath); URIUtils::RemoveSlashAtEnd(name); item.SetLabel(CURL::Decode(URIUtils::GetFileName(name))); } if (item.m_bIsFolder) URIUtils::AddSlashAtEnd(itemPath); // Add back protocol options if (!url2.GetProtocolOptions().empty()) itemPath += "|" + url2.GetProtocolOptions(); item.SetPath(itemPath); if (!item.IsURL(url)) { CFileItemPtr pItem(new CFileItem(item)); items.Add(pItem); } } } dav.Close(); return true; }
bool CDAVFile::Exists(const CURL& url) { if (Stat(url, NULL) != 0) { if (m_lastResponseCode >= 400 && m_lastResponseCode != 404) CLog::Log(LOGERROR, "CDAVFile::Exists - Unable to stat resource (%s) with code %i", url.GetRedacted().c_str(), m_lastResponseCode); return false; } return true; }
bool CMultiPathDirectory::GetDirectory(const CURL& url, CFileItemList &items) { CLog::Log(LOGDEBUG,"CMultiPathDirectory::GetDirectory(%s)", url.GetRedacted().c_str()); std::vector<std::string> vecPaths; if (!GetPaths(url, vecPaths)) return false; XbmcThreads::EndTime progressTime(3000); // 3 seconds before showing progress bar CGUIDialogProgress* dlgProgress = NULL; unsigned int iFailures = 0; for (unsigned int i = 0; i < vecPaths.size(); ++i) { // show the progress dialog if we have passed our time limit if (progressTime.IsTimePast() && !dlgProgress) { dlgProgress = g_windowManager.GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS); if (dlgProgress) { dlgProgress->SetHeading(CVariant{15310}); dlgProgress->SetLine(0, CVariant{15311}); dlgProgress->SetLine(1, CVariant{""}); dlgProgress->SetLine(2, CVariant{""}); dlgProgress->Open(); dlgProgress->ShowProgressBar(true); dlgProgress->SetProgressMax((int)vecPaths.size()*2); dlgProgress->Progress(); } } if (dlgProgress) { CURL url(vecPaths[i]); dlgProgress->SetLine(1, CVariant{url.GetWithoutUserDetails()}); dlgProgress->SetProgressAdvance(); dlgProgress->Progress(); } CFileItemList tempItems; CLog::Log(LOGDEBUG,"Getting Directory (%s)", vecPaths[i].c_str()); if (CDirectory::GetDirectory(vecPaths[i], tempItems, m_strFileMask, m_flags)) items.Append(tempItems); else { CLog::Log(LOGERROR,"Error Getting Directory (%s)", vecPaths[i].c_str()); iFailures++; } if (dlgProgress) { dlgProgress->SetProgressAdvance(); dlgProgress->Progress(); } } if (dlgProgress) dlgProgress->Close(); if (iFailures == vecPaths.size()) return false; // merge like-named folders into a sub multipath:// style url MergeItems(items); return true; }
bool CZipManager::GetZipList(const CURL& url, vector<SZipEntry>& items) { CLog::Log(LOGDEBUG, "%s - Processing %s", __FUNCTION__, url.GetRedacted().c_str()); struct __stat64 m_StatData = {}; std::string strFile = url.GetHostName(); if (CFile::Stat(strFile,&m_StatData)) { CLog::Log(LOGDEBUG,"CZipManager::GetZipList: failed to stat file %s", url.GetRedacted().c_str()); return false; } map<std::string,vector<SZipEntry> >::iterator it = mZipMap.find(strFile); if (it != mZipMap.end()) // already listed, just return it if not changed, else release and reread { map<std::string,int64_t>::iterator it2=mZipDate.find(strFile); CLog::Log(LOGDEBUG,"statdata: %" PRId64" new: %" PRIu64, it2->second, (uint64_t)m_StatData.st_mtime); if (m_StatData.st_mtime == it2->second) { items = it->second; return true; } mZipMap.erase(it); mZipDate.erase(it2); } CFile mFile; if (!mFile.Open(strFile)) { CLog::Log(LOGDEBUG,"ZipManager: unable to open file %s!",strFile.c_str()); return false; } unsigned int hdr; if (mFile.Read(&hdr, 4)!=4 || (Endian_SwapLE32(hdr) != ZIP_LOCAL_HEADER && Endian_SwapLE32(hdr) != ZIP_DATA_RECORD_HEADER && Endian_SwapLE32(hdr) != ZIP_SPLIT_ARCHIVE_HEADER)) { CLog::Log(LOGDEBUG,"ZipManager: not a zip file!"); mFile.Close(); return false; } if (Endian_SwapLE32(hdr) == ZIP_SPLIT_ARCHIVE_HEADER) CLog::LogF(LOGWARNING, "ZIP split archive header found. Trying to process as a single archive.."); // push date for update detection mZipDate.insert(make_pair(strFile,m_StatData.st_mtime)); // Look for end of central directory record // Zipfile comment may be up to 65535 bytes // End of central directory record is 22 bytes (ECDREC_SIZE) // -> need to check the last 65557 bytes int64_t fileSize = mFile.GetLength(); // Don't need to look in the last 18 bytes (ECDREC_SIZE-4) // But as we need to do overlapping between blocks (3 bytes), // we start the search at ECDREC_SIZE-1 from the end of file int searchSize = (int) min(65557, fileSize-ECDREC_SIZE+1); int blockSize = (int) min(1024, searchSize); int nbBlock = searchSize / blockSize; int extraBlockSize = searchSize % blockSize; // Signature is on 4 bytes // It could be between 2 blocks, so we need to read 3 extra bytes auto_buffer buffer(blockSize + 3); bool found = false; // Loop through blocks starting at the end of the file (minus ECDREC_SIZE-1) for (int nb=1; !found && (nb <= nbBlock); nb++) { mFile.Seek(fileSize-ECDREC_SIZE+1-(blockSize*nb),SEEK_SET); if (mFile.Read(buffer.get(), blockSize + 3) != blockSize + 3) return false; for (int i=blockSize-1; !found && (i >= 0); i--) { if ( Endian_SwapLE32(*((unsigned int*)(buffer.get()+i))) == ZIP_END_CENTRAL_HEADER ) { // Set current position to start of end of central directory mFile.Seek(fileSize-ECDREC_SIZE+1-(blockSize*nb)+i,SEEK_SET); found = true; } } } // If not found, look in the last block left... if ( !found && (extraBlockSize > 0) ) { mFile.Seek(fileSize-ECDREC_SIZE+1-searchSize,SEEK_SET); if (mFile.Read(buffer.get(), extraBlockSize + 3) != extraBlockSize + 3) return false; for (int i=extraBlockSize-1; !found && (i >= 0); i--) { if ( Endian_SwapLE32(*((unsigned int*)(buffer.get()+i))) == ZIP_END_CENTRAL_HEADER ) { // Set current position to start of end of central directory mFile.Seek(fileSize-ECDREC_SIZE+1-searchSize+i,SEEK_SET); found = true; } } } buffer.clear(); if ( !found ) { CLog::Log(LOGDEBUG,"ZipManager: broken file %s!",strFile.c_str()); mFile.Close(); return false; } unsigned int cdirOffset, cdirSize; // Get size of the central directory mFile.Seek(12,SEEK_CUR); if (mFile.Read(&cdirSize, 4) != 4) return false; cdirSize = Endian_SwapLE32(cdirSize); // Get Offset of start of central directory with respect to the starting disk number if (mFile.Read(&cdirOffset, 4) != 4) return false; cdirOffset = Endian_SwapLE32(cdirOffset); // Go to the start of central directory mFile.Seek(cdirOffset,SEEK_SET); char temp[CHDR_SIZE]; while (mFile.GetPosition() < cdirOffset + cdirSize) { SZipEntry ze; if (mFile.Read(temp, CHDR_SIZE) != CHDR_SIZE) return false; readCHeader(temp, ze); if (ze.header != ZIP_CENTRAL_HEADER) { CLog::Log(LOGDEBUG,"ZipManager: broken file %s!",strFile.c_str()); mFile.Close(); return false; } // Get the filename just after the central file header auto_buffer bufName(ze.flength); if (mFile.Read(bufName.get(), ze.flength) != ze.flength) return false; std::string strName(bufName.get(), bufName.size()); bufName.clear(); g_charsetConverter.unknownToUTF8(strName); ZeroMemory(ze.name, 255); strncpy(ze.name, strName.c_str(), strName.size()>254 ? 254 : strName.size()); // Jump after central file header extra field and file comment mFile.Seek(ze.eclength + ze.clength,SEEK_CUR); items.push_back(ze); } /* go through list and figure out file header lengths */ for(vector<SZipEntry>::iterator it = items.begin(); it != items.end(); ++it) { SZipEntry& ze = *it; // Go to the local file header to get the extra field length // !! local header extra field length != central file header extra field length !! mFile.Seek(ze.lhdrOffset+28,SEEK_SET); if (mFile.Read(&(ze.elength), 2) != 2) return false; ze.elength = Endian_SwapLE16(ze.elength); // Compressed data offset = local header offset + size of local header + filename length + local file header extra field length ze.offset = ze.lhdrOffset + LHDR_SIZE + ze.flength + ze.elength; } mZipMap.insert(make_pair(strFile,items)); mFile.Close(); return true; }