Browse files

Merge pull request #192 from Memphiz/libnfs5

Add nfs support - closes #3358 - needs libnfs at compiletime (osx/ios will build it when switched to darwin-depends - linux needs to make lib/libnfs and make install)
  • Loading branch information...
2 parents 9ed84f2 + dba3fc0 commit 5db9543ba15d82abd12285b52de0650b5afefa0b @Memphiz Memphiz committed Jun 18, 2011
View
12 XBMC-ATV2.xcodeproj/project.pbxproj
@@ -23,6 +23,8 @@
7C99B7AA134072CD00FC2B16 /* GUIDialogPlayEject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B7A8134072CD00FC2B16 /* GUIDialogPlayEject.cpp */; };
C807119F135DB842002F601B /* InputOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C807119D135DB842002F601B /* InputOperations.cpp */; };
C8EC5D51136954E400CCC10D /* XBMC_keytable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8EC5D4F136954E400CCC10D /* XBMC_keytable.cpp */; };
+ DF0DF16C13A3AF82008ED511 /* FileNFS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF16813A3AF82008ED511 /* FileNFS.cpp */; };
+ DF0DF16D13A3AF82008ED511 /* NFSDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF16A13A3AF82008ED511 /* NFSDirectory.cpp */; };
F54D9E0712B65FFF006870F9 /* libc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F54D9E0612B65FFF006870F9 /* libc.dylib */; };
F54D9E8E12B71457006870F9 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F54D9E8D12B71457006870F9 /* CoreAudio.framework */; };
F56B15FB12CD6922009B4C96 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F56B15FA12CD6922009B4C96 /* CoreVideo.framework */; };
@@ -958,6 +960,10 @@
C80711A0135DB848002F601B /* AnnouncementUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnnouncementUtils.h; sourceTree = "<group>"; };
C8EC5D4F136954E400CCC10D /* XBMC_keytable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMC_keytable.cpp; sourceTree = "<group>"; };
C8EC5D50136954E400CCC10D /* XBMC_keytable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMC_keytable.h; sourceTree = "<group>"; };
+ DF0DF16813A3AF82008ED511 /* FileNFS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileNFS.cpp; sourceTree = "<group>"; };
+ DF0DF16913A3AF82008ED511 /* FileNFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileNFS.h; sourceTree = "<group>"; };
+ DF0DF16A13A3AF82008ED511 /* NFSDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NFSDirectory.cpp; sourceTree = "<group>"; };
+ DF0DF16B13A3AF82008ED511 /* NFSDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NFSDirectory.h; sourceTree = "<group>"; };
F54D9E0612B65FFF006870F9 /* libc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc.dylib; path = usr/lib/libc.dylib; sourceTree = SDKROOT; };
F54D9E8D12B71457006870F9 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
F56B15FA12CD6922009B4C96 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
@@ -3922,6 +3928,10 @@
F56C7395131EC151000AD0F6 /* filesystem */ = {
isa = PBXGroup;
children = (
+ DF0DF16813A3AF82008ED511 /* FileNFS.cpp */,
+ DF0DF16913A3AF82008ED511 /* FileNFS.h */,
+ DF0DF16A13A3AF82008ED511 /* NFSDirectory.cpp */,
+ DF0DF16B13A3AF82008ED511 /* NFSDirectory.h */,
F57A1DBB1329FB0A00498CC7 /* SourcesDirectory.cpp */,
F57A1DBC1329FB0A00498CC7 /* SourcesDirectory.h */,
F56C7396131EC151000AD0F6 /* SpecialProtocol.cpp */,
@@ -6720,6 +6730,8 @@
7C0A7FC813A9E75400AFC2BD /* DirtyRegionSolvers.cpp in Sources */,
7C0A7FC913A9E75400AFC2BD /* DirtyRegionTracker.cpp in Sources */,
7C0A7FCC13A9E76E00AFC2BD /* GUIWindowDebugInfo.cpp in Sources */,
+ DF0DF16C13A3AF82008ED511 /* FileNFS.cpp in Sources */,
+ DF0DF16D13A3AF82008ED511 /* NFSDirectory.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
12 XBMC-IOS.xcodeproj/project.pbxproj
@@ -24,6 +24,8 @@
7C99B7BE1340730000FC2B16 /* GUIDialogPlayEject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B7BC1340730000FC2B16 /* GUIDialogPlayEject.cpp */; };
C80711AD135DB85F002F601B /* InputOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C80711AB135DB85F002F601B /* InputOperations.cpp */; };
C8EC5D26136953E100CCC10D /* XBMC_keytable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8EC5D24136953E100CCC10D /* XBMC_keytable.cpp */; };
+ DF0DF17F13A3AF9F008ED511 /* FileNFS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF17B13A3AF9F008ED511 /* FileNFS.cpp */; };
+ DF0DF18013A3AF9F008ED511 /* NFSDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF17D13A3AF9F008ED511 /* NFSDirectory.cpp */; };
F54D9E8112B713F8006870F9 /* libc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F54D9E8012B713F8006870F9 /* libc.dylib */; };
F56B143412CAF279009B4C96 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F56B143312CAF279009B4C96 /* CoreVideo.framework */; };
F56B14A512CAF523009B4C96 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F56B14A412CAF523009B4C96 /* AudioToolbox.framework */; };
@@ -958,6 +960,10 @@
C80711AE135DB865002F601B /* AnnouncementUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnnouncementUtils.h; sourceTree = "<group>"; };
C8EC5D24136953E100CCC10D /* XBMC_keytable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMC_keytable.cpp; sourceTree = "<group>"; };
C8EC5D25136953E100CCC10D /* XBMC_keytable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMC_keytable.h; sourceTree = "<group>"; };
+ DF0DF17B13A3AF9F008ED511 /* FileNFS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileNFS.cpp; sourceTree = "<group>"; };
+ DF0DF17C13A3AF9F008ED511 /* FileNFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileNFS.h; sourceTree = "<group>"; };
+ DF0DF17D13A3AF9F008ED511 /* NFSDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NFSDirectory.cpp; sourceTree = "<group>"; };
+ DF0DF17E13A3AF9F008ED511 /* NFSDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NFSDirectory.h; sourceTree = "<group>"; };
F54D9E8012B713F8006870F9 /* libc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libc.dylib; path = usr/lib/libc.dylib; sourceTree = SDKROOT; };
F56B143312CAF279009B4C96 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
F56B14A412CAF523009B4C96 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
@@ -4283,6 +4289,10 @@
F56C8378131F42E8000AD0F6 /* filesystem */ = {
isa = PBXGroup;
children = (
+ DF0DF17B13A3AF9F008ED511 /* FileNFS.cpp */,
+ DF0DF17C13A3AF9F008ED511 /* FileNFS.h */,
+ DF0DF17D13A3AF9F008ED511 /* NFSDirectory.cpp */,
+ DF0DF17E13A3AF9F008ED511 /* NFSDirectory.h */,
F57A1DB61329FAF700498CC7 /* SourcesDirectory.cpp */,
F57A1DB71329FAF700498CC7 /* SourcesDirectory.h */,
F56C8379131F42E8000AD0F6 /* SpecialProtocol.cpp */,
@@ -6737,6 +6747,8 @@
7C0A7F9D13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp in Sources */,
7C0A7FB213A9E72E00AFC2BD /* DirtyRegionSolvers.cpp in Sources */,
7C0A7FB313A9E72E00AFC2BD /* DirtyRegionTracker.cpp in Sources */,
+ DF0DF17F13A3AF9F008ED511 /* FileNFS.cpp in Sources */,
+ DF0DF18013A3AF9F008ED511 /* NFSDirectory.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
15 XBMC.xcodeproj/project.pbxproj
@@ -602,6 +602,8 @@
C8D0B2AF1265A9A800F0C0AC /* SystemGlobals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8D0B2AE1265A9A800F0C0AC /* SystemGlobals.cpp */; };
C8D0B2B01265A9A800F0C0AC /* SystemGlobals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8D0B2AE1265A9A800F0C0AC /* SystemGlobals.cpp */; };
C8EC5D0E1369519D00CCC10D /* XBMC_keytable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8EC5D0C1369519D00CCC10D /* XBMC_keytable.cpp */; };
+ DF0DF15B13A3ADA7008ED511 /* FileNFS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF15713A3ADA7008ED511 /* FileNFS.cpp */; };
+ DF0DF15C13A3ADA7008ED511 /* NFSDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF0DF15913A3ADA7008ED511 /* NFSDirectory.cpp */; };
E306D12E0DDF7B590052C2AD /* XBMCHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E306D12C0DDF7B590052C2AD /* XBMCHelper.cpp */; };
E33206380D5070AA00435CE3 /* DVDDemuxVobsub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E33206370D5070AA00435CE3 /* DVDDemuxVobsub.cpp */; };
E33466A60D2E5103005A65EC /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E33466A50D2E5103005A65EC /* IOKit.framework */; };
@@ -2518,6 +2520,10 @@
C8D0B2AE1265A9A800F0C0AC /* SystemGlobals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemGlobals.cpp; sourceTree = "<group>"; };
C8EC5D0C1369519D00CCC10D /* XBMC_keytable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMC_keytable.cpp; sourceTree = "<group>"; };
C8EC5D0D1369519D00CCC10D /* XBMC_keytable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMC_keytable.h; sourceTree = "<group>"; };
+ DF0DF15713A3ADA7008ED511 /* FileNFS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileNFS.cpp; sourceTree = "<group>"; };
+ DF0DF15813A3ADA7008ED511 /* FileNFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileNFS.h; sourceTree = "<group>"; };
+ DF0DF15913A3ADA7008ED511 /* NFSDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NFSDirectory.cpp; sourceTree = "<group>"; };
+ DF0DF15A13A3ADA7008ED511 /* NFSDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NFSDirectory.h; sourceTree = "<group>"; };
E306D12C0DDF7B590052C2AD /* XBMCHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XBMCHelper.cpp; sourceTree = "<group>"; };
E306D12D0DDF7B590052C2AD /* XBMCHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCHelper.h; sourceTree = "<group>"; };
E33206370D5070AA00435CE3 /* DVDDemuxVobsub.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DVDDemuxVobsub.cpp; sourceTree = "<group>"; };
@@ -5521,6 +5527,10 @@
E38E16940D25F9FA00618676 /* filesystem */ = {
isa = PBXGroup;
children = (
+ DF0DF15713A3ADA7008ED511 /* FileNFS.cpp */,
+ DF0DF15813A3ADA7008ED511 /* FileNFS.h */,
+ DF0DF15913A3ADA7008ED511 /* NFSDirectory.cpp */,
+ DF0DF15A13A3ADA7008ED511 /* NFSDirectory.h */,
7C84A59C12FA3C1600CD1714 /* SourcesDirectory.cpp */,
7C84A59D12FA3C1600CD1714 /* SourcesDirectory.h */,
7C2D6AE20F35453E00DD2E85 /* SpecialProtocol.cpp */,
@@ -8063,6 +8073,11 @@
F558F27B13ABD56600631E12 /* DirtyRegionSolvers.cpp in Sources */,
F558F27F13ABD57400631E12 /* DirtyRegionTracker.cpp in Sources */,
F558F29613ABD7DF00631E12 /* GUIWindowDebugInfo.cpp in Sources */,
+ 7C0A7F7C13A9E69A00AFC2BD /* DirtyRegionSolvers.cpp in Sources */,
+ 7C0A7F7D13A9E69A00AFC2BD /* DirtyRegionTracker.cpp in Sources */,
+ 7C0A7F8213A9E6C600AFC2BD /* GUIWindowDebugInfo.cpp in Sources */,
+ DF0DF15B13A3ADA7008ED511 /* FileNFS.cpp in Sources */,
+ DF0DF15C13A3ADA7008ED511 /* NFSDirectory.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
4 configure.in
@@ -830,6 +830,7 @@ if test "$use_libnfs" != "no"; then
AC_CHECK_HEADERS([nfsc/libnfs.h],,
[if test "$use_libnfs" = "yes"; then
AC_MSG_ERROR($libnfs_not_found)
+ USE_LIBNFS=0
elif test "$use_libnfs" != "no"; then
AC_MSG_NOTICE($libnfs_not_found)
use_libnfs="no"
@@ -840,8 +841,10 @@ if test "$use_libnfs" != "no"; then
fi
if test "$use_libnfs" != "no"; then
AC_DEFINE([HAVE_LIBNFS], [1], [Whether to use libnfs library.])
+ USE_LIBNFS=1
fi
else
+ USE_LIBNFS=0
AC_MSG_NOTICE($libnfs_disabled)
fi
@@ -1490,6 +1493,7 @@ AC_SUBST(USE_OPENGLES)
AC_SUBST(USE_VDPAU)
AC_SUBST(USE_VAAPI)
AC_SUBST(USE_CRYSTALHD)
+AC_SUBST(USE_LIBNFS)
AC_SUBST(USE_VDA)
AC_SUBST(USE_OPENMAX)
AC_SUBST(USE_PULSE)
View
7 xbmc/Application.cpp
@@ -99,6 +99,9 @@
#if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
#include "filesystem/SMBDirectory.h"
#endif
+#ifdef HAS_FILESYSTEM_NFS
+#include "filesystem/FileNFS.h"
+#endif
#ifdef HAS_FILESYSTEM_SFTP
#include "filesystem/FileSFTP.h"
#endif
@@ -4796,6 +4799,10 @@ void CApplication::ProcessSlow()
#if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
smb.CheckIfIdle();
#endif
+
+#ifdef HAS_FILESYSTEM_NFS
+ gNfsConnection.CheckIfIdle();
+#endif
#ifdef HAS_FILESYSTEM_SFTP
CSFTPSessionManager::ClearOutIdleSessions();
View
6 xbmc/FileItem.cpp
@@ -759,6 +759,11 @@ bool CFileItem::IsOnDVD() const
return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
}
+bool CFileItem::IsNfs() const
+{
+ return URIUtils::IsNfs(m_strPath);
+}
+
bool CFileItem::IsOnLAN() const
{
return URIUtils::IsOnLAN(m_strPath);
@@ -1999,6 +2004,7 @@ void CFileItemList::Stack()
// 1. rars and zips may be on slow sources? is this supposed to be allowed?
if( !item->IsRemote()
|| item->IsSmb()
+ || item->IsNfs()
|| URIUtils::IsInRAR(item->m_strPath)
|| URIUtils::IsInZIP(item->m_strPath)
)
View
1 xbmc/FileItem.h
@@ -116,6 +116,7 @@ class CFileItem :
bool IsOnDVD() const;
bool IsOnLAN() const;
bool IsHD() const;
+ bool IsNfs() const;
bool IsRemote() const;
bool IsSmb() const;
bool IsURL() const;
View
8 xbmc/Util.cpp
@@ -1145,8 +1145,8 @@ bool CUtil::CreateDirectoryEx(const CStdString& strPath)
// return true if directory already exist
if (CDirectory::Exists(strPath)) return true;
- // we currently only allow HD and smb paths
- if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath))
+ // we currently only allow HD and smb and nfs paths
+ if (!URIUtils::IsHD(strPath) && !URIUtils::IsSmb(strPath) && !URIUtils::IsNfs(strPath))
{
CLog::Log(LOGERROR,"%s called with an unsupported path: %s", __FUNCTION__, strPath.c_str());
return false;
@@ -1865,11 +1865,13 @@ bool CUtil::MakeShortenPath(CStdString StrInput, CStdString& StrOutput, int iTex
bool CUtil::SupportsFileOperations(const CStdString& strPath)
{
- // currently only hd and smb support delete and rename
+ // currently only hd, smb and nfs support delete and rename
if (URIUtils::IsHD(strPath))
return true;
if (URIUtils::IsSmb(strPath))
return true;
+ if (URIUtils::IsNfs(strPath))
+ return true;
if (URIUtils::IsMythTV(strPath))
{
/*
View
7 xbmc/filesystem/FactoryDirectory.cpp
@@ -93,6 +93,9 @@
#ifdef HAS_FILESYSTEM_SFTP
#include "SFTPDirectory.h"
#endif
+#ifdef HAS_FILESYSTEM_NFS
+#include "NFSDirectory.h"
+#endif
using namespace XFILE;
@@ -184,6 +187,10 @@ IDirectory* CFactoryDirectory::Create(const CStdString& strPath)
#ifdef HAS_ZEROCONF
if (strProtocol == "zeroconf") return new CZeroconfDirectory();
#endif
+#ifdef HAS_FILESYSTEM_NFS
+ if (strProtocol == "nfs") return new CNFSDirectory();
+#endif
+
}
CLog::Log(LOGWARNING, "%s - Unsupported protocol(%s) in %s", __FUNCTION__, strProtocol.c_str(), url.Get().c_str() );
View
8 xbmc/filesystem/FileFactory.cpp
@@ -62,6 +62,10 @@
#ifdef HAS_FILESYSTEM_SFTP
#include "FileSFTP.h"
#endif
+#ifdef HAS_FILESYSTEM_NFS
+#include "FileNFS.h"
+#endif
+
#include "FileMusicDatabase.h"
#include "FileSpecialProtocol.h"
#include "MultiPathFile.h"
@@ -154,6 +158,10 @@ IFile* CFileFactory::CreateLoader(const CURL& url)
#ifdef HAS_FILESYSTEM_VTP
else if (strProtocol == "vtp") return new CVTPFile();
#endif
+#ifdef HAS_FILESYSTEM_NFS
+ else if (strProtocol == "nfs") return new CFileNFS();
+#endif
+
}
CLog::Log(LOGWARNING, "%s - Unsupported protocol(%s) in %s", __FUNCTION__, strProtocol.c_str(), url.Get().c_str() );
View
541 xbmc/filesystem/FileNFS.cpp
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+// FileNFS.cpp: implementation of the CFileNFS class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "system.h"
+
+#ifdef HAS_FILESYSTEM_NFS
+#include "DllLibNfs.h"
+#include "FileNFS.h"
+#include "threads/SingleLock.h"
+#include "utils/log.h"
+#include "utils/URIUtils.h"
+
+using namespace XFILE;
+
+CNfsConnection::CNfsConnection()
+: m_pNfsContext(NULL)
+, m_shareName("")
+, m_readChunkSize(0)
+, m_writeChunkSize(0)
+, m_OpenConnections(0)
+, m_IdleTimeout(0)
+, m_pLibNfs(new DllLibNfs())
+{
+}
+
+CNfsConnection::~CNfsConnection()
+{
+ delete m_pLibNfs;
+}
+
+void CNfsConnection::resetContext()
+{
+
+ if(!m_pLibNfs->IsLoaded())
+ {
+ if(!m_pLibNfs->Load())
+ {
+ CLog::Log(LOGERROR,"NFS: Error loading libnfs (%s).",__FUNCTION__);
+ return;//FATAL!
+ }
+ }
+
+ if(m_pNfsContext)
+ {
+ m_pLibNfs->nfs_destroy_context(m_pNfsContext);
+ }
+
+ m_pNfsContext = m_pLibNfs->nfs_init_context();
+
+ if (!m_pNfsContext)
+ {
+ CLog::Log(LOGERROR,"NFS: Error initcontext in resetContext.");
+ }
+ m_writeChunkSize = 0;
+ m_readChunkSize = 0;
+ m_shareName.clear();
+ m_hostName.clear();
+}
+
+bool CNfsConnection::Connect(const CURL& url)
+{
+ CSingleLock lock(*this);
+ int ret = 0;
+ CStdString share;
+ URIUtils::GetDirectory(url.GetFileName(),share);
+ share = "/" + share;
+
+ if(!share.Equals(m_shareName,true) || !url.GetHostName().Equals(m_hostName,false) )
+ {
+ resetContext();//we need a new context because sharename or hostname has changed - old context will be freed
+
+ //we connect to the directory of the path. This will be the "root" path of this connection then.
+ //So all fileoperations are relative to this mountpoint...
+ ret = m_pLibNfs->nfs_mount_sync(m_pNfsContext, url.GetHostName().c_str(), share.c_str());
+
+ if (ret != 0)
+ {
+ CLog::Log(LOGERROR,"NFS: Failed to mount nfs share: %s\n", m_pLibNfs->nfs_get_error(m_pNfsContext));
+ return false;
+ }
+ m_shareName = share;
+ m_hostName = url.GetHostName();
+ m_readChunkSize = m_pLibNfs->nfs_get_readmax(m_pNfsContext);
+ m_writeChunkSize = m_pLibNfs->nfs_get_writemax(m_pNfsContext);
+ CLog::Log(LOGDEBUG,"NFS: Connected to server %s and export %s (chunks: r/w %i/%i)\n", url.GetHostName().c_str(), url.GetShareName().c_str(),(int)m_readChunkSize,(int)m_writeChunkSize);
+ }
+
+ return true;
+}
+
+void CNfsConnection::Deinit()
+{
+ if(m_pNfsContext)
+ {
+ m_pLibNfs->nfs_destroy_context(m_pNfsContext);
+ }
+ m_pNfsContext = NULL;
+ m_shareName.clear();
+ m_hostName.clear();
+ m_pLibNfs->Unload();
+}
+
+/* This is called from CApplication::ProcessSlow() and is used to tell if nfs have been idle for too long */
+void CNfsConnection::CheckIfIdle()
+{
+ /* We check if there are open connections. This is done without a lock to not halt the mainthread. It should be thread safe as
+ worst case scenario is that m_OpenConnections could read 0 and then changed to 1 if this happens it will enter the if wich will lead to another check, wich is locked. */
+ if (m_OpenConnections == 0 && m_pNfsContext != NULL)
+ { /* I've set the the maxiumum IDLE time to be 1 min and 30 sec. */
+ CSingleLock lock(*this);
+ if (m_OpenConnections == 0 /* check again - when locked */)
+ {
+ if (m_IdleTimeout > 0)
+ {
+ m_IdleTimeout--;
+ }
+ else
+ {
+ CLog::Log(LOGNOTICE, "NFS is idle. Closing the remaining connections.");
+ gNfsConnection.Deinit();
+ }
+ }
+ }
+}
+
+void CNfsConnection::SetActivityTime()
+{
+ /* Since we get called every 500ms from ProcessSlow we limit the tick count to 180 */
+ /* That means we have 2 ticks per second which equals 180/2 == 90 seconds */
+ m_IdleTimeout = 180;
+}
+
+
+/* The following two function is used to keep track on how many Opened files/directories there are.
+needed for unloading the dylib*/
+void CNfsConnection::AddActiveConnection()
+{
+ CSingleLock lock(*this);
+ m_OpenConnections++;
+}
+
+void CNfsConnection::AddIdleConnection()
+{
+ CSingleLock lock(*this);
+ m_OpenConnections--;
+ /* If we close a file we reset the idle timer so that we don't have any wierd behaviours if a user
+ leaves the movie paused for a long while and then press stop */
+ m_IdleTimeout = 180;
+}
+
+
+CNfsConnection gNfsConnection;
+
+CFileNFS::CFileNFS()
+: m_fileSize(0)
+, m_pFileHandle(NULL)
+{
+ gNfsConnection.AddActiveConnection();
+}
+
+CFileNFS::~CFileNFS()
+{
+ Close();
+ gNfsConnection.AddIdleConnection();
+}
+
+int64_t CFileNFS::GetPosition()
+{
+ int ret = 0;
+ off_t offset = 0;
+ CSingleLock lock(gNfsConnection);
+
+ if (gNfsConnection.GetNfsContext() == NULL || m_pFileHandle == NULL) return 0;
+
+ ret = (int)gNfsConnection.GetImpl()->nfs_lseek_sync(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;
+}
+
+int64_t CFileNFS::GetLength()
+{
+ if (m_pFileHandle == NULL) return 0;
+ return m_fileSize;
+}
+
+bool CFileNFS::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 = "//" + URIUtils::GetFileName(url.GetFileName());
+
+ CSingleLock lock(gNfsConnection);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ ret = gNfsConnection.GetImpl()->nfs_open_sync(gNfsConnection.GetNfsContext(), filename.c_str(), O_RDONLY, &m_pFileHandle);
+
+ if (ret != 0)
+ {
+ CLog::Log(LOGINFO, "CFileNFS::Open: Unable to open file : '%s' error : '%s'", url.GetFileName().c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+ return false;
+ }
+
+ CLog::Log(LOGDEBUG,"CFileNFS::Open - opened %s",url.GetFileName().c_str());
+ m_url=url;
+
+#ifdef _LINUX
+ struct __stat64 tmpBuffer;
+#else
+ struct stat tmpBuffer;
+#endif
+ 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;
+}
+
+
+bool CFileNFS::Exists(const CURL& url)
+{
+ return Stat(url,NULL) == 0;
+}
+
+int CFileNFS::Stat(struct __stat64* buffer)
+{
+ return Stat(m_url,buffer);
+}
+
+
+int CFileNFS::Stat(const CURL& url, struct __stat64* buffer)
+{
+ int ret = 0;
+ CSingleLock lock(gNfsConnection);
+
+ if(!gNfsConnection.Connect(url))
+ return -1;
+
+ CStdString filename = "//" + URIUtils::GetFileName(url.GetFileName());
+
+ struct stat tmpBuffer = {0};
+
+ ret = gNfsConnection.GetImpl()->nfs_stat_sync(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)
+ {
+ 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 ret;
+}
+
+unsigned int CFileNFS::Read(void *lpBuf, int64_t uiBufSize)
+{
+ int numberOfBytesRead = 0;
+ int bytesLeft = uiBufSize;
+ int bytesRead = 0;
+ int chunkSize = gNfsConnection.GetMaxReadChunkSize();
+ CSingleLock lock(gNfsConnection);
+
+ if (m_pFileHandle == NULL || gNfsConnection.GetNfsContext()==NULL ) return 0;
+
+ //read chunked since nfs will only give server specific packet sizes at once
+ while(bytesLeft)
+ {
+ //last chunk could be smaller then chunk size
+ if(bytesLeft < chunkSize)
+ {
+ chunkSize = bytesLeft;
+ }
+
+ bytesRead = gNfsConnection.GetImpl()->nfs_read_sync(gNfsConnection.GetNfsContext(), m_pFileHandle, chunkSize, (char *)lpBuf+numberOfBytesRead);
+ bytesLeft -= bytesRead;
+ numberOfBytesRead += bytesRead;
+
+ if(bytesRead == 0)
+ {
+ break; //EOF
+ }
+
+ //something went wrong ...
+ if (bytesRead < 0)
+ {
+ CLog::Log(LOGERROR, "%s - Error( %d, %s )", __FUNCTION__, bytesRead, gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+ return 0;
+ }
+
+ }
+ return (unsigned int)numberOfBytesRead;
+}
+
+int64_t CFileNFS::Seek(int64_t iFilePosition, int iWhence)
+{
+ int ret = 0;
+ off_t offset = 0;
+
+ CSingleLock lock(gNfsConnection);
+ if (m_pFileHandle == NULL || gNfsConnection.GetNfsContext()==NULL) return -1;
+
+
+ ret = (int)gNfsConnection.GetImpl()->nfs_lseek_sync(gNfsConnection.GetNfsContext(), 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(gNfsConnection.GetNfsContext()));
+ return -1;
+ }
+ return (int64_t)offset;
+}
+
+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_sync(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;
+ }
+}
+
+//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_sync(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 CFileNFS::Delete(const CURL& url)
+{
+ int ret = 0;
+ CSingleLock lock(gNfsConnection);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ CStdString filename = "//" + URIUtils::GetFileName(url.GetFileName());
+
+ ret = gNfsConnection.GetImpl()->nfs_unlink_sync(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);
+}
+
+bool CFileNFS::Rename(const CURL& url, const CURL& urlnew)
+{
+ int ret = 0;
+ CSingleLock lock(gNfsConnection);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ CStdString strFile = "//" + URIUtils::GetFileName(url.GetFileName());
+ CStdString strFileNew = "//" + URIUtils::GetFileName(urlnew.GetFileName());
+
+ ret = gNfsConnection.GetImpl()->nfs_rename_sync(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);
+}
+
+bool CFileNFS::OpenForWrite(const CURL& url, bool bOverWrite)
+{
+ int ret = 0;
+
+ Close();
+ CSingleLock lock(gNfsConnection);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ // 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;
+
+ CStdString filename = "//" + URIUtils::GetFileName(url.GetFileName());
+
+ 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_sync(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_sync(gNfsConnection.GetNfsContext(),m_pFileHandle);
+ }
+ }
+
+ ret = gNfsConnection.GetImpl()->nfs_open_sync(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;
+}
+
+bool CFileNFS::IsValidFile(const CStdString& strFileName)
+{
+ if (strFileName.Find('/') == -1 || /* doesn't have sharename */
+ strFileName.Right(2) == "/." || /* not current folder */
+ strFileName.Right(3) == "/..") /* not parent folder */
+ return false;
+ return true;
+}
+#endif//HAS_FILESYSTEM_NFS
View
77 xbmc/filesystem/FileNFS.h
@@ -0,0 +1,77 @@
+
+// FileNFS.h: interface for the CFileNFS class.
+#ifndef FILENFS_H_
+#define FILENFS_H_
+
+#include "IFile.h"
+#include "URL.h"
+#include "threads/CriticalSection.h"
+
+class DllLibNfs;
+
+class CNfsConnection : public CCriticalSection
+{
+public:
+
+ CNfsConnection();
+ ~CNfsConnection();
+ bool Connect(const CURL &url);
+ struct nfs_context *GetNfsContext(){return m_pNfsContext;}
+ size_t GetMaxReadChunkSize(){return m_readChunkSize;}
+ size_t GetMaxWriteChunkSize(){return m_writeChunkSize;}
+ DllLibNfs *GetImpl(){return m_pLibNfs;}
+
+ void AddActiveConnection();
+ void AddIdleConnection();
+ void CheckIfIdle();
+ void SetActivityTime();
+ void Deinit();
+
+private:
+ struct nfs_context *m_pNfsContext;
+ CStdString m_shareName;
+ CStdString m_hostName;
+ size_t m_readChunkSize;
+ size_t m_writeChunkSize;
+ int m_OpenConnections;
+ unsigned int m_IdleTimeout;
+ DllLibNfs *m_pLibNfs;
+ void resetContext();
+};
+
+extern CNfsConnection gNfsConnection;
+
+namespace XFILE
+{
+ class CFileNFS : public IFile
+ {
+ public:
+ CFileNFS();
+ virtual ~CFileNFS();
+ virtual void Close();
+ virtual int64_t Seek(int64_t iFilePosition, int iWhence = SEEK_SET);
+ virtual unsigned int Read(void* lpBuf, int64_t uiBufSize);
+ virtual bool Open(const CURL& url);
+ virtual bool Exists(const CURL& url);
+ virtual int Stat(const CURL& url, struct __stat64* buffer);
+ virtual int Stat(struct __stat64* buffer);
+ virtual int64_t GetLength();
+ virtual int64_t GetPosition();
+ virtual int Write(const void* lpBuf, int64_t uiBufSize);
+ //implement iocontrol for seek_possible for preventing the stat in File class for
+ //getting this info ...
+ virtual int IoControl(EIoControl request, void* param){ if(request == IOCTRL_SEEK_POSSIBLE) return 1;return -1;};
+ virtual int GetChunkSize() {return 1;}
+
+ virtual bool OpenForWrite(const CURL& url, bool bOverWrite = false);
+ virtual bool Delete(const CURL& url);
+ virtual bool Rename(const CURL& url, const CURL& urlnew);
+ protected:
+ CURL m_url;
+ bool IsValidFile(const CStdString& strFileName);
+ int64_t m_fileSize;
+ struct nfsfh *m_pFileHandle;
+ };
+}
+#endif // FILENFS_H_
+
View
5 xbmc/filesystem/Makefile.in
@@ -93,6 +93,11 @@ SRCS+=FileRar.cpp \
RarManager.cpp \
endif
+ifeq (@USE_LIBNFS@,1)
+SRCS+=FileNFS.cpp \
+ NFSDirectory.cpp \
+
+endif
INCLUDES+=-I@abs_top_srcdir@/lib/libUPnP/Platinum/Source/Core \
-I@abs_top_srcdir@/lib/libUPnP/Platinum/Source/Platinum \
View
206 xbmc/filesystem/NFSDirectory.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#ifdef HAS_FILESYSTEM_NFS
+#include "DllLibNfs.h"
+#include "NFSDirectory.h"
+#include "FileItem.h"
+#include "utils/log.h"
+#include "utils/URIUtils.h"
+#include "threads/SingleLock.h"
+
+using namespace XFILE;
+using namespace std;
+
+CNFSDirectory::CNFSDirectory(void)
+{
+ gNfsConnection.AddActiveConnection();
+}
+
+CNFSDirectory::~CNFSDirectory(void)
+{
+ gNfsConnection.AddIdleConnection();
+}
+
+bool CNFSDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
+{
+ // We accept nfs://server/path[/file]]]]
+ int ret = 0;
+ FILETIME fileTime, localTime;
+ CSingleLock lock(gNfsConnection);
+
+ CURL url(strPath);
+
+ if(!gNfsConnection.Connect(url))
+ {
+ return false;
+ }
+
+ CStdString strDirName="//";//relative to the strPath we connected - we want to get the "/" directory then
+
+ vector<CStdString> vecEntries;
+ struct nfsdir *nfsdir = NULL;
+ struct nfsdirent *nfsdirent = NULL;
+
+ ret = gNfsConnection.GetImpl()->nfs_opendir_sync(gNfsConnection.GetNfsContext(), strDirName.c_str(), &nfsdir);
+
+ if(ret != 0)
+ {
+ CLog::Log(LOGERROR, "Failed to open(%s) %s\n", strDirName.c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+ return false;
+ }
+ lock.Leave();
+
+ while((nfsdirent = gNfsConnection.GetImpl()->nfs_readdir(gNfsConnection.GetNfsContext(), nfsdir)) != NULL)
+ {
+ vecEntries.push_back(nfsdirent->name);
+ }
+
+ lock.Enter();
+ gNfsConnection.GetImpl()->nfs_closedir(gNfsConnection.GetNfsContext(), nfsdir);//close the dir
+ lock.Leave();
+
+ for (size_t i=0; i<vecEntries.size(); i++)
+ {
+ CStdString strName = vecEntries[i];
+
+ if (!strName.Equals(".") && !strName.Equals("..")
+ && !strName.Equals("lost+found"))
+ {
+ int64_t iSize = 0;
+ bool bIsDir = false;
+ int64_t lTimeDate = 0;
+ struct stat info = {0};
+
+ CStdString strFullName = strDirName + strName;
+
+ lock.Enter();
+ ret = gNfsConnection.GetImpl()->nfs_stat_sync(gNfsConnection.GetNfsContext(), strFullName.c_str(), &info);
+ lock.Leave();
+
+ if( ret == 0 )
+ {
+ bIsDir = (info.st_mode & S_IFDIR) ? true : false;
+ lTimeDate = info.st_mtime;
+ if(lTimeDate == 0) // if modification date is missing, use create date
+ lTimeDate = info.st_ctime;
+ iSize = info.st_size;
+ }
+ else
+ CLog::Log(LOGERROR, "NFS; Failed to stat(%s) %s\n", strFullName.c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+
+ LONGLONG ll = Int32x32To64(lTimeDate & 0xffffffff, 10000000) + 116444736000000000ll;
+ fileTime.dwLowDateTime = (DWORD) (ll & 0xffffffff);
+ fileTime.dwHighDateTime = (DWORD)(ll >> 32);
+ FileTimeToLocalFileTime(&fileTime, &localTime);
+
+ CFileItemPtr pItem(new CFileItem(strName));
+ pItem->m_strPath = strPath + strName;
+ pItem->m_dateTime=localTime;
+
+ if (bIsDir)
+ {
+ URIUtils::AddSlashAtEnd(pItem->m_strPath);
+ pItem->m_bIsFolder = true;
+ }
+ else
+ {
+ pItem->m_bIsFolder = false;
+ pItem->m_dwSize = iSize;
+ }
+ items.Add(pItem);
+ }
+ }
+ return true;
+}
+
+bool CNFSDirectory::Create(const char* strPath)
+{
+ int ret = 0;
+
+ CSingleLock lock(gNfsConnection);
+ CStdString folderName(strPath);
+ URIUtils::RemoveSlashAtEnd(folderName);//mkdir fails if a slash is at the end!!!
+
+ CURL url(folderName);
+ folderName = "//" + URIUtils::GetFileName(folderName);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ ret = gNfsConnection.GetImpl()->nfs_mkdir_sync(gNfsConnection.GetNfsContext(), folderName.c_str());
+
+ if(ret != 0)
+ CLog::Log(LOGERROR, "NFS: Failed to create(%s) %s\n", folderName.c_str(), gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+ return (ret == 0 || EEXIST == ret);
+}
+
+bool CNFSDirectory::Remove(const char* strPath)
+{
+ int ret = 0;
+
+ CSingleLock lock(gNfsConnection);
+ CStdString folderName(strPath);
+ URIUtils::RemoveSlashAtEnd(folderName);//rmdir fails if a slash is at the end!!!
+
+ CURL url(folderName);
+ folderName = "//" + URIUtils::GetFileName(folderName);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ ret = gNfsConnection.GetImpl()->nfs_rmdir_sync(gNfsConnection.GetNfsContext(), folderName.c_str());
+
+ if(ret != 0 && errno != ENOENT)
+ {
+ CLog::Log(LOGERROR, "%s - Error( %s )", __FUNCTION__, gNfsConnection.GetImpl()->nfs_get_error(gNfsConnection.GetNfsContext()));
+ return false;
+ }
+ return true;
+}
+
+bool CNFSDirectory::Exists(const char* strPath)
+{
+ int ret = 0;
+
+ CSingleLock lock(gNfsConnection);
+ CStdString folderName(strPath);
+ URIUtils::RemoveSlashAtEnd(folderName);//remove slash at end or URIUtils::GetFileName won't return what we want...
+
+ CURL url(folderName);
+ folderName = "//" + URIUtils::GetFileName(folderName);
+
+ if(!gNfsConnection.Connect(url))
+ return false;
+
+ struct stat info;
+ ret = gNfsConnection.GetImpl()->nfs_stat_sync(gNfsConnection.GetNfsContext(), folderName.c_str(), &info);
+
+ if (ret != 0)
+ {
+ return false;
+ }
+ return (info.st_mode & S_IFDIR) ? true : false;
+}
+
+#endif
View
40 xbmc/filesystem/NFSDirectory.h
@@ -0,0 +1,40 @@
+#pragma once
+/*
+ * Copyright (C) 2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "IDirectory.h"
+#include "FileNFS.h"
+
+namespace XFILE
+{
+ class CNFSDirectory : public IDirectory
+ {
+ public:
+ CNFSDirectory(void);
+ virtual ~CNFSDirectory(void);
+ virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items);
+ virtual DIR_CACHE_TYPE GetCacheType(const CStdString &strPath) const { return DIR_CACHE_ONCE; };
+ virtual bool Create(const char* strPath);
+ virtual bool Exists(const char* strPath);
+ virtual bool Remove(const char* strPath);
+ };
+}
+
View
5 xbmc/system.h
@@ -64,6 +64,11 @@
#define HAS_FILESYSTEM_VTP
#define HAS_FILESYSTEM_HTSP
+#ifdef HAVE_LIBNFS
+ #define HAS_FILESYSTEM_NFS
+#endif
+
+
/**********************
* Non-free Components
**********************/
View
11 xbmc/utils/URIUtils.cpp
@@ -683,6 +683,17 @@ bool URIUtils::IsMusicDb(const CStdString& strFile)
return strFile.Left(8).Equals("musicdb:");
}
+bool URIUtils::IsNfs(const CStdString& strFile)
+{
+ CStdString strFile2(strFile);
+
+ if (IsStack(strFile))
+ strFile2 = CStackDirectory::GetFirstStackedFile(strFile);
+
+ return strFile2.Left(4).Equals("nfs:");
+}
+
+
bool URIUtils::IsVideoDb(const CStdString& strFile)
{
return strFile.Left(8).Equals("videodb:");
View
1 xbmc/utils/URIUtils.h
@@ -68,6 +68,7 @@ class URIUtils
static bool IsMultiPath(const CStdString& strPath);
static bool IsMusicDb(const CStdString& strFile);
static bool IsMythTV(const CStdString& strFile);
+ static bool IsNfs(const CStdString& strFile);
static bool IsOnDVD(const CStdString& strFile);
static bool IsOnLAN(const CStdString& strFile);
static bool IsPlugin(const CStdString& strFile);

0 comments on commit 5db9543

Please sign in to comment.