bool CSMBFile::OpenForWrite(const CURL& url, bool bOverWrite) { m_fileSize = 0; 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())) return false; std::string strFileName = GetAuthenticatedPath(url); CSingleLock lock(smb); if (bOverWrite) { CLog::Log(LOGWARNING, "SMBFile::OpenForWrite() called with overwriting enabled! - %s", strFileName.c_str()); m_fd = smb.GetImpl()->smbc_creat(strFileName.c_str(), 0); } else { m_fd = smb.GetImpl()->smbc_open(strFileName.c_str(), O_RDWR, 0); } if (m_fd == -1) { // write error to logfile CLog::Log(LOGERROR, "SMBFile->Open: Unable to open file : '%s'\nunix_err:'%x' error : '%s'", strFileName.c_str(), errno, strerror(errno)); return false; } // We've successfully opened the file! return true; }
CSMBFile::CSMBFile() { smb.Init(); m_fd = -1; smb.AddActiveConnection(); m_allowRetry = true; }
CSmbFile::CSmbFile() { smb.Init(); m_fd = -1; #ifdef TARGET_POSIX smb.AddActiveConnection(); #endif }
CFileSMB::CFileSMB() { smb.Init(); m_fd = -1; #ifdef _LINUX smb.AddActiveConnection(); #endif }
int CSMBFile::Stat(const CURL& url, struct __stat64* buffer) { smb.Init(); std::string strFileName = GetAuthenticatedPath(url); CSingleLock lock(smb); struct stat tmpBuffer = {0}; int iResult = smb.GetImpl()->smbc_stat(strFileName.c_str(), &tmpBuffer); CUtil::StatToStat64(buffer, &tmpBuffer); return iResult; }
bool CSMBFile::Delete(const CURL& url) { smb.Init(); std::string strFile = GetAuthenticatedPath(url); CSingleLock lock(smb); int result = smb.GetImpl()->smbc_unlink(strFile.c_str()); if (result != 0) CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, strerror(errno)); return (result == 0); }
int CFileSMB::OpenFile(const CURL &url, CStdString& strAuth) { int fd = -1; smb.Init(); strAuth = GetAuthenticatedPath(url); CStdString strPath = strAuth; { CSingleLock lock(smb); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } // file open failed, try to open the directory to force authentication #ifndef _LINUX if (fd < 0 && smb.ConvertUnixToNT(errno) == NT_STATUS_ACCESS_DENIED) #else if (fd < 0 && errno == EACCES) #endif { CURL urlshare(url); /* just replace the filename with the sharename */ urlshare.SetFileName(url.GetShareName()); CSMBDirectory smbDir; // TODO: Currently we always allow prompting on files. This may need to // change in the future as background scanners are more prolific. smbDir.SetAllowPrompting(true); fd = smbDir.Open(urlshare); // directory open worked, try opening the file again if (fd >= 0) { CSingleLock lock(smb); // close current directory filehandle // dont need to purge since its the same server and share smbc_closedir(fd); // set up new filehandle (as CFileSMB::Open does) strPath = GetAuthenticatedPath(url); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } } if (fd >= 0) strAuth = strPath; return fd; }
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.GetFileName().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.GetFileName().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 (smb.GetImpl()->smbc_stat(strFileName.c_str(), &tmpBuffer) < 0) { smb.GetImpl()->smbc_close(m_fd); m_fd = -1; return false; } m_fileSize = tmpBuffer.st_size; int64_t ret = smb.GetImpl()->smbc_lseek(m_fd, 0, SEEK_SET); if (ret < 0) { smb.GetImpl()->smbc_close(m_fd); m_fd = -1; return false; } // We've successfully opened the file! return true; }
unsigned int CSMBFile::Read(void *lpBuf, int64_t uiBufSize) { if (m_fd == -1) return 0; CSingleLock lock(smb); // Init not called since it has to be "inited" by now smb.SetActivityTime(); /* work around stupid bug in samba */ /* some samba servers has a bug in it where the */ /* 17th bit will be ignored in a request of data */ /* this can lead to a very small return of data */ /* also worse, a request of exactly 64k will return */ /* as if eof, client has a workaround for windows */ /* thou it seems other servers are affected too */ if( uiBufSize >= 64*1024-2 ) uiBufSize = 64*1024-2; int bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize); if ( bytesRead < 0 && errno == EINVAL ) { CLog::Log(LOGERROR, "%s - Error( %d, %d, %s ) - Retrying", __FUNCTION__, bytesRead, errno, strerror(errno)); bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize); } if ( bytesRead < 0 ) { CLog::Log(LOGERROR, "%s - Error( %d, %d, %s )", __FUNCTION__, bytesRead, errno, strerror(errno)); return 0; } return (unsigned int)bytesRead; }
int CFileSMB::Stat(const CURL& url, struct __stat64* buffer) { smb.Init(); CStdString strFileName = GetAuthenticatedPath(url); CSingleLock lock(smb); #ifndef _LINUX struct __stat64 tmpBuffer = {0}; #else struct stat tmpBuffer = {0}; #endif int iResult = smbc_stat(strFileName, &tmpBuffer); memset(buffer, 0, sizeof(struct __stat64)); buffer->st_dev = tmpBuffer.st_dev; buffer->st_ino = tmpBuffer.st_ino; buffer->st_mode = tmpBuffer.st_mode; buffer->st_nlink = tmpBuffer.st_nlink; buffer->st_uid = tmpBuffer.st_uid; buffer->st_gid = tmpBuffer.st_gid; buffer->st_rdev = tmpBuffer.st_rdev; buffer->st_size = tmpBuffer.st_size; buffer->st_atime = tmpBuffer.st_atime; buffer->st_mtime = tmpBuffer.st_mtime; buffer->st_ctime = tmpBuffer.st_ctime; return iResult; }
CFileSMB::~CFileSMB() { Close(); #ifdef _LINUX smb.AddIdleConnection(); #endif }
int64_t CSMBFile::GetPosition() { if (m_fd == -1) return -1; CSingleLock lock(smb); return smb.GetImpl()->smbc_lseek(m_fd, 0, SEEK_CUR); }
ssize_t CSMBFile::Read(void *lpBuf, size_t uiBufSize) { if (uiBufSize > SSIZE_MAX) uiBufSize = SSIZE_MAX; if (m_fd == -1) return -1; // Some external libs (libass) use test read with zero size and // null buffer pointer to check whether file is readable, but // libsmbclient always return "-1" if called with null buffer // regardless of buffer size. // To overcome this, force return "0" in that case. if (uiBufSize == 0 && lpBuf == NULL) return 0; CSingleLock lock(smb); // Init not called since it has to be "inited" by now smb.SetActivityTime(); ssize_t bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize); if (m_allowRetry && bytesRead < 0 && errno == EINVAL ) { CLog::Log(LOGERROR, "%s - Error( %" PRIdS ", %d, %s ) - Retrying", __FUNCTION__, bytesRead, errno, strerror(errno)); bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize); } if ( bytesRead < 0 ) CLog::Log(LOGERROR, "%s - Error( %" PRIdS ", %d, %s )", __FUNCTION__, bytesRead, errno, strerror(errno)); return bytesRead; }
CSmbFile::~CSmbFile() { Close(); #ifdef TARGET_POSIX smb.AddIdleConnection(); #endif }
int CSMBFile::OpenFile(const CURL &url, std::string& strAuth) { smb.Init(); strAuth = GetAuthenticatedPath(url); std::string strPath = strAuth; int fd = -1; { CSingleLock lock(smb); fd = smb.GetImpl()->smbc_open(strPath.c_str(), O_RDONLY, 0); } if (fd >= 0) strAuth = strPath; return fd; }
bool CSMBFile::Exists(const CURL& url) { // 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())) return false; smb.Init(); std::string strFileName = GetAuthenticatedPath(url); CSingleLock lock(smb); struct stat info = {0}; int iResult = smb.GetImpl()->smbc_stat(strFileName.c_str(), &info); if (iResult < 0) return false; return true; }
int64_t CSMBFile::Seek(int64_t iFilePosition, int iWhence) { if (m_fd == -1) return -1; CSingleLock lock(smb); // Init not called since it has to be "inited" by now smb.SetActivityTime(); int64_t pos = smb.GetImpl()->smbc_lseek(m_fd, iFilePosition, iWhence); if (pos < 0) { CLog::Log(LOGERROR, "%s - Error( %" PRId64", %d, %s )", __FUNCTION__, pos, errno, strerror(errno)); return -1; } return (int64_t)pos; }
bool CFileSMB::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,"FileSmb->Open: Bad URL : '%s'",url.GetFileName().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. CStdString strFileName; m_fd = OpenFile(url, strFileName); CLog::Log(LOGDEBUG,"CFileSMB::Open - opened %s, fd=%d",url.GetFileName().c_str(), m_fd); if (m_fd == -1) { // write error to logfile #ifndef _LINUX int nt_error = smb.ConvertUnixToNT(errno); CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' nt_err : '%x' error : '%s'", strFileName.c_str(), errno, nt_error, get_friendly_nt_error_msg(nt_error)); #else CLog::Log(LOGINFO, "FileSmb->Open: Unable to open file : '%s'\nunix_err:'%x' error : '%s'", strFileName.c_str(), errno, strerror(errno)); #endif return false; } CSingleLock lock(smb); #ifndef _LINUX struct __stat64 tmpBuffer = {0}; #else struct stat tmpBuffer; #endif if (smbc_stat(strFileName, &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 CSmbFile::Delete(const CURL& url) { smb.Init(); CStdString strFile = GetAuthenticatedPath(url); CSingleLock lock(smb); int result = smbc_unlink(strFile.c_str()); if(result != 0) #ifdef TARGET_WINDOWS CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, get_friendly_nt_error_msg(smb.ConvertUnixToNT(errno))); #else CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, strerror(errno)); #endif return (result == 0); }
ssize_t CSMBFile::Read(void *lpBuf, size_t uiBufSize) { if (uiBufSize > SSIZE_MAX) uiBufSize = SSIZE_MAX; if (m_fd == -1) return -1; // Some external libs (libass) use test read with zero size and // null buffer pointer to check whether file is readable, but // libsmbclient always return "-1" if called with null buffer // regardless of buffer size. // To overcome this, force return "0" in that case. if (uiBufSize == 0 && lpBuf == NULL) return 0; CSingleLock lock(smb); // Init not called since it has to be "inited" by now smb.SetActivityTime(); /* work around stupid bug in samba */ /* some samba servers has a bug in it where the */ /* 17th bit will be ignored in a request of data */ /* this can lead to a very small return of data */ /* also worse, a request of exactly 64k will return */ /* as if eof, client has a workaround for windows */ /* thou it seems other servers are affected too */ // FIXME: does this workaround still required? ssize_t totalRead = 0; uint8_t* buf = (uint8_t*)lpBuf; do { const ssize_t readSize = (uiBufSize >= 64 * 1024 - 2) ? 64 * 1024 - 2 : uiBufSize; ssize_t r = smbc_read(m_fd, buf + totalRead, readSize); if (r < 0) { if (errno == EINVAL) { CLog::LogF(LOGWARNING, "Error %d: \"%s\" - Retrying", errno, strerror(errno)); r = smbc_read(m_fd, buf + totalRead, readSize); } if (r < 0) { CLog::LogF(LOGERROR, "Error %d: \"%s\"", errno, strerror(errno)); if (totalRead == 0) return -1; break; } } totalRead += r; uiBufSize -= r; if (r != readSize) break; } while (uiBufSize > 0); return totalRead; }
bool CFileSMB::Rename(const CURL& url, const CURL& urlnew) { smb.Init(); CStdString strFile = GetAuthenticatedPath(url); CStdString strFileNew = GetAuthenticatedPath(urlnew); CSingleLock lock(smb); int result = smbc_rename(strFile.c_str(), strFileNew.c_str()); if(result != 0) #ifndef _LINUX CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, get_friendly_nt_error_msg(smb.ConvertUnixToNT(errno))); #else CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, strerror(errno)); #endif return (result == 0); }
int64_t CSMBFile::GetPosition() { if (m_fd == -1) return 0; smb.Init(); CSingleLock lock(smb); int64_t pos = smbc_lseek(m_fd, 0, SEEK_CUR); if ( pos < 0 ) return 0; return pos; }
ssize_t CSMBFile::Write(const void* lpBuf, size_t uiBufSize) { if (m_fd == -1) return -1; // lpBuf can be safely casted to void* since xbmc_write will only read from it. smb.Init(); CSingleLock lock(smb); return smbc_write(m_fd, (void*)lpBuf, uiBufSize); }
void CSMBFile::Close() { if (m_fd != -1) { CLog::Log(LOGDEBUG,"CSMBFile::Close closing fd %d", m_fd); CSingleLock lock(smb); smb.GetImpl()->smbc_close(m_fd); m_fd = -1; } }
int64_t CFile::GetPosition() { if (m_fd == -1) return 0; smb.Init(); PLATFORM::CLockObject lock(smb); int64_t pos = smbc_lseek(m_fd, 0, SEEK_CUR); if ( pos < 0 ) return 0; return pos; }
ssize_t CSMBFile::Read(void *lpBuf, size_t uiBufSize) { if (uiBufSize > SSIZE_MAX) uiBufSize = SSIZE_MAX; if (m_fd == -1) return -1; // Some external libs (libass) use test read with zero size and // null buffer pointer to check whether file is readable, but // libsmbclient always return "-1" if called with null buffer // regardless of buffer size. // To overcome this, force return "0" in that case. if (uiBufSize == 0 && lpBuf == NULL) return 0; CSingleLock lock(smb); // Init not called since it has to be "inited" by now smb.SetActivityTime(); /* work around stupid bug in samba */ /* some samba servers has a bug in it where the */ /* 17th bit will be ignored in a request of data */ /* this can lead to a very small return of data */ /* also worse, a request of exactly 64k will return */ /* as if eof, client has a workaround for windows */ /* thou it seems other servers are affected too */ if (uiBufSize >= 64*1024-2) uiBufSize = 64*1024-2; ssize_t bytesRead = smb.GetImpl()->smbc_read(m_fd, lpBuf, (int)uiBufSize); if (bytesRead < 0 && errno == EINVAL) { CLog::Log(LOGERROR, "%s - Error( %" PRIdS ", %d, %s ) - Retrying", __FUNCTION__, bytesRead, errno, strerror(errno)); bytesRead = smb.GetImpl()->smbc_read(m_fd, lpBuf, (int)uiBufSize); } if (bytesRead < 0) CLog::Log(LOGERROR, "%s - Error( %" PRIdS ", %d, %s )", __FUNCTION__, bytesRead, errno, strerror(errno)); return bytesRead; }
int CSMBFile::Write(const void* lpBuf, int64_t uiBufSize) { if (m_fd == -1) return -1; DWORD dwNumberOfBytesWritten = 0; // lpBuf can be safely casted to void* since xbmc_write will only read from it. smb.Init(); CSingleLock lock(smb); dwNumberOfBytesWritten = smbc_write(m_fd, (void*)lpBuf, (DWORD)uiBufSize); return (int)dwNumberOfBytesWritten; }
int CSMBFile::Stat(struct __stat64* buffer) { if (m_fd == -1) return -1; CSingleLock lock(smb); struct stat tmpBuffer = {0}; int iResult = smb.GetImpl()->smbc_fstat(m_fd, &tmpBuffer); CUtil::StatToStat64(buffer, &tmpBuffer); return iResult; }
//int CFile::OpenFile(const CURL &url, CStdString& strAuth) int CFile::OpenFile() { int fd = -1; smb.Init(); //strAuth = GetAuthenticatedPath(url); //CStdString strPath = strAuth; CStdString strPath = m_fileName; { CLockObject lock(smb); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } // file open failed, try to open the directory to force authentication if (fd < 0 && errno == EACCES) { #if 0 CURL urlshare(url); /* just replace the filename with the sharename */ urlshare.SetFileName(url.GetShareName()); CSMBDirectory smbDir; // TODO: Currently we always allow prompting on files. This may need to // change in the future as background scanners are more prolific. smbDir.SetFlags(DIR_FLAG_ALLOW_PROMPT); fd = smbDir.Open(urlshare); // directory open worked, try opening the file again if (fd >= 0) { CLockObject lock(smb); // close current directory filehandle // dont need to purge since its the same server and share smbc_closedir(fd); // set up new filehandle (as CFile::Open does) strPath = GetAuthenticatedPath(url); fd = smbc_open(strPath.c_str(), O_RDONLY, 0); } #else XBMC->Log(LOG_ERROR, "%s: File open on %s failed\n", __FUNCTION__, strPath.c_str()); #endif } // if (fd >= 0) // strAuth = strPath; return fd; }
int64_t CSmbFile::Seek(int64_t iFilePosition, int iWhence) { if (m_fd == -1) return -1; CSingleLock lock(smb); // Init not called since it has to be "inited" by now #ifdef TARGET_POSIX smb.SetActivityTime(); #endif int64_t pos = smbc_lseek(m_fd, iFilePosition, iWhence); if ( pos < 0 ) { #ifdef TARGET_WINDOWS CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, get_friendly_nt_error_msg(smb.ConvertUnixToNT(errno))); #else CLog::Log(LOGERROR, "%s - Error( %"PRId64", %d, %s )", __FUNCTION__, pos, errno, strerror(errno)); #endif return -1; } return (int64_t)pos; }