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; }
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 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); }
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); }
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; }
unsigned int CFileSMB::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 #ifdef _LINUX smb.SetActivityTime(); #endif /* 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 ) { #ifndef _LINUX CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, get_friendly_nt_error_msg(smb.ConvertUnixToNT(errno))); #else CLog::Log(LOGERROR, "%s - Error( %d, %d, %s )", __FUNCTION__, bytesRead, errno, strerror(errno)); #endif return 0; } return (unsigned int)bytesRead; }