bool CFileNFS::OpenForWrite(const CURL& url, bool bOverWrite) { int ret = 0; // we can't open files like nfs://file.f or nfs://server/file.f // if a file matches the if below return false, it can't exist on a nfs share. if (!IsValidFile(url.GetFileName())) return false; Close(); CSingleLock lock(gNfsConnection); CStdString filename = ""; if(!gNfsConnection.Connect(url,filename)) return false; if (bOverWrite) { CLog::Log(LOGWARNING, "FileNFS::OpenForWrite() called with overwriting enabled! - %s", filename.c_str()); //create file with proper permissions ret = gNfsConnection.GetImpl()->nfs_creat(gNfsConnection.GetNfsContext(), filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &m_pFileHandle); //if file was created the file handle isn't valid ... so close it and open later if(ret == 0) { gNfsConnection.GetImpl()->nfs_close(gNfsConnection.GetNfsContext(),m_pFileHandle); } } ret = gNfsConnection.GetImpl()->nfs_open(gNfsConnection.GetNfsContext(), filename.c_str(), O_RDWR, &m_pFileHandle); if (ret || m_pFileHandle == NULL) { // write error to logfile CLog::Log(LOGERROR, "CFileNFS::Open: Unable to open file : '%s' error : '%s'", filename.c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); return false; } m_url=url; #ifdef _LINUX struct __stat64 tmpBuffer = {0}; #else struct stat tmpBuffer = {0}; #endif //only stat if file was not created if(!bOverWrite) { if(Stat(&tmpBuffer)) { m_url.Reset(); Close(); return false; } m_fileSize = tmpBuffer.st_size;//cache filesize of this file } else//file was created - filesize is zero { m_fileSize = 0; } // We've successfully opened the file! return true; }
int64_t CNFSFile::GetPosition() { int ret = 0; uint64_t offset = 0; CSingleLock lock(gNfsConnection); if (gNfsConnection.GetNfsContext() == NULL || m_pFileHandle == NULL) return 0; ret = (int)gNfsConnection.GetImpl()->nfs_lseek(gNfsConnection.GetNfsContext(), m_pFileHandle, 0, SEEK_CUR, &offset); if (ret < 0) { CLog::Log(LOGERROR, "NFS: Failed to lseek(%s)",gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); } return offset; }
unsigned int CFileNFS::Read(void *lpBuf, int64_t uiBufSize) { int numberOfBytesRead = 0; CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || gNfsConnection.GetNfsContext()==NULL ) return 0; numberOfBytesRead = gNfsConnection.GetImpl()->nfs_read(gNfsConnection.GetNfsContext(), m_pFileHandle, uiBufSize, (char *)lpBuf); //something went wrong ... if (numberOfBytesRead < 0) { CLog::Log(LOGERROR, "%s - Error( %d, %s )", __FUNCTION__, numberOfBytesRead, gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); return 0; } return (unsigned int)numberOfBytesRead; }
bool CNFSFile::Delete(const CURL& url) { int ret = 0; CSingleLock lock(gNfsConnection); CStdString filename = ""; if(!gNfsConnection.Connect(url, filename)) return false; ret = gNfsConnection.GetImpl()->nfs_unlink(gNfsConnection.GetNfsContext(), filename.c_str()); if(ret != 0) { CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); } return (ret == 0); }
void CFileNFS::Close() { CSingleLock lock(gNfsConnection); if (m_pFileHandle != NULL && gNfsConnection.GetNfsContext()!=NULL) { int ret = 0; CLog::Log(LOGDEBUG,"CFileNFS::Close closing file %s", m_url.GetFileName().c_str()); ret = gNfsConnection.GetImpl()->nfs_close(gNfsConnection.GetNfsContext(), m_pFileHandle); if (ret < 0) { CLog::Log(LOGERROR, "Failed to close(%s) - %s\n", m_url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); } m_pFileHandle=NULL; m_fileSize = 0; } }
int CNFSFile::Stat(const CURL& url, struct __stat64* buffer) { int ret = 0; CSingleLock lock(gNfsConnection); CStdString filename = ""; if(!gNfsConnection.Connect(url,filename)) return -1; NFSSTAT tmpBuffer = {0}; ret = gNfsConnection.GetImpl()->nfs_stat(gNfsConnection.GetNfsContext(), filename.c_str(), &tmpBuffer); //if buffer == NULL we where called from Exists - in that case don't spam the log with errors if (ret != 0 && buffer != NULL) { CLog::Log(LOGERROR, "NFS: Failed to stat(%s) %s\n", url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); ret = -1; } else { if(buffer) { #if defined(TARGET_WINDOWS)// TODO get rid of this define after gotham memcpy(buffer, &tmpBuffer, sizeof(struct __stat64)); #else 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; #endif } } return ret; }
//this was a bitch! //for nfs write to work we have to write chunked //otherwise this could crash on big files ssize_t CNFSFile::Write(const void* lpBuf, size_t uiBufSize) { size_t numberOfBytesWritten = 0; int writtenBytes = 0; size_t leftBytes = uiBufSize; //clamp max write chunksize to 32kb - fixme - this might be superfluious with future libnfs versions size_t chunkSize = gNfsConnection.GetMaxWriteChunkSize() > 32768 ? 32768 : (size_t)gNfsConnection.GetMaxWriteChunkSize(); CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || m_pNfsContext == NULL) return -1; //write as long as some bytes are left to be written while( leftBytes ) { //the last chunk could be smalle than chunksize if(leftBytes < chunkSize) { chunkSize = leftBytes;//write last chunk with correct size } //write chunk writtenBytes = gNfsConnection.GetImpl()->nfs_write(m_pNfsContext, m_pFileHandle, chunkSize, (char *)lpBuf + numberOfBytesWritten); //decrease left bytes leftBytes-= writtenBytes; //increase overall written bytes numberOfBytesWritten += writtenBytes; //danger - something went wrong if (writtenBytes < 0) { CLog::Log(LOGERROR, "Failed to pwrite(%s) %s\n", m_url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); if (numberOfBytesWritten == 0) return -1; break; } } //return total number of written bytes return numberOfBytesWritten; }
bool CNFSFile::Rename(const CURL& url, const CURL& urlnew) { int ret = 0; CSingleLock lock(gNfsConnection); CStdString strFile = ""; if(!gNfsConnection.Connect(url,strFile)) return false; CStdString strFileNew; CStdString strDummy; gNfsConnection.splitUrlIntoExportAndPath(urlnew, strDummy, strFileNew); ret = gNfsConnection.GetImpl()->nfs_rename(gNfsConnection.GetNfsContext() , strFile.c_str(), strFileNew.c_str()); if(ret != 0) { CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); } return (ret == 0); }
void CNFSFile::Close() { CSingleLock lock(gNfsConnection); if (m_pFileHandle != NULL && m_pNfsContext != NULL) { int ret = 0; CLog::Log(LOGDEBUG,"CNFSFile::Close closing file %s", m_url.GetFileName().c_str()); ret = gNfsConnection.GetImpl()->nfs_close(m_pNfsContext, m_pFileHandle); gNfsConnection.removeFromKeepAliveList(m_pFileHandle); if (ret < 0) { CLog::Log(LOGERROR, "Failed to close(%s) - %s\n", m_url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); } m_pFileHandle = NULL; m_pNfsContext = NULL; m_fileSize = 0; m_exportPath.clear(); } }
unsigned int CNFSFile::Read(void *lpBuf, int64_t uiBufSize) { int numberOfBytesRead = 0; CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || m_pNfsContext == NULL ) return 0; numberOfBytesRead = gNfsConnection.GetImpl()->nfs_read(m_pNfsContext, m_pFileHandle, uiBufSize, (char *)lpBuf); lock.Leave();//no need to keep the connection lock after that gNfsConnection.resetKeepAlive(m_exportPath, m_pFileHandle);//triggers keep alive timer reset for this filehandle //something went wrong ... if (numberOfBytesRead < 0) { CLog::Log(LOGERROR, "%s - Error( %d, %s )", __FUNCTION__, numberOfBytesRead, gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); return 0; } return (unsigned int)numberOfBytesRead; }
//this was a bitch! //for nfs write to work we have to write chunked //otherwise this could crash on big files int CFileNFS::Write(const void* lpBuf, int64_t uiBufSize) { int numberOfBytesWritten = 0; int writtenBytes = 0; int leftBytes = uiBufSize; int chunkSize = gNfsConnection.GetMaxWriteChunkSize(); CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || gNfsConnection.GetNfsContext() == NULL) return -1; //write as long as some bytes are left to be written while( leftBytes ) { //the last chunk could be smalle than chunksize if(leftBytes < chunkSize) { chunkSize = leftBytes;//write last chunk with correct size } //write chunk writtenBytes = gNfsConnection.GetImpl()->nfs_write(gNfsConnection.GetNfsContext(), m_pFileHandle, (size_t)chunkSize, (char *)lpBuf + numberOfBytesWritten); //decrease left bytes leftBytes-= writtenBytes; //increase overall written bytes numberOfBytesWritten += writtenBytes; //danger - something went wrong if (writtenBytes < 0) { CLog::Log(LOGERROR, "Failed to pwrite(%s) %s\n", m_url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext())); break; } } //return total number of written bytes return numberOfBytesWritten; }
bool CNFSFile::Open(const CURL& url) { int ret = 0; Close(); // we can't open files like nfs://file.f or nfs://server/file.f // if a file matches the if below return false, it can't exist on a nfs share. if (!IsValidFile(url.GetFileName())) { CLog::Log(LOGNOTICE,"NFS: Bad URL : '%s'",url.GetFileName().c_str()); return false; } CStdString filename = ""; CSingleLock lock(gNfsConnection); if(!gNfsConnection.Connect(url, filename)) return false; m_pNfsContext = gNfsConnection.GetNfsContext(); m_exportPath = gNfsConnection.GetContextMapId(); ret = gNfsConnection.GetImpl()->nfs_open(m_pNfsContext, filename.c_str(), O_RDONLY, &m_pFileHandle); if (ret != 0) { CLog::Log(LOGINFO, "CNFSFile::Open: Unable to open file : '%s' error : '%s'", url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); m_pNfsContext = NULL; m_exportPath.clear(); return false; } CLog::Log(LOGDEBUG,"CNFSFile::Open - opened %s",url.GetFileName().c_str()); m_url=url; struct __stat64 tmpBuffer; if( Stat(&tmpBuffer) ) { m_url.Reset(); Close(); return false; } m_fileSize = tmpBuffer.st_size;//cache the size of this file // We've successfully opened the file! return true; }
int CNFSFile::Truncate(int64_t iSize) { int ret = 0; CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || m_pNfsContext == NULL) return -1; ret = (int)gNfsConnection.GetImpl()->nfs_ftruncate(m_pNfsContext, m_pFileHandle, iSize); if (ret < 0) { CLog::Log(LOGERROR, "%s - Error( ftruncate: %"PRId64", fsize: %"PRId64", %s)", __FUNCTION__, iSize, m_fileSize, gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); return -1; } return ret; }
int64_t CNFSFile::Seek(int64_t iFilePosition, int iWhence) { int ret = 0; uint64_t offset = 0; CSingleLock lock(gNfsConnection); if (m_pFileHandle == NULL || m_pNfsContext == NULL) return -1; ret = (int)gNfsConnection.GetImpl()->nfs_lseek(m_pNfsContext, m_pFileHandle, iFilePosition, iWhence, &offset); if (ret < 0) { CLog::Log(LOGERROR, "%s - Error( seekpos: %"PRId64", whence: %i, fsize: %"PRId64", %s)", __FUNCTION__, iFilePosition, iWhence, m_fileSize, gNfsConnection.GetImpl()->nfs_get_error(m_pNfsContext)); return -1; } return (int64_t)offset; }