Skip to content
This repository
Browse code

Override CSFTPDirectory::Exists() method to correctly report whether …

…an SFTP url represents a directory or not.

Fixes ticket #13784.

Refactored CSFTPSession::Exists() into FileExists() and DirectoryExists() methods, and have CSFTPFile and CSFTPDirectory classes use them.
This means that Exists() calls on these classes correctly only return true if the url refers to an item of the appropriate type (e.g. a file or a directory).
  • Loading branch information...
commit 6e28059b93220b1188461bfc99709cf7d27ae11c 1 parent 9e7d52f
Nigel Gilbert authored January 09, 2013
15  xbmc/filesystem/SFTPDirectory.cpp
@@ -20,6 +20,7 @@
20 20
 
21 21
 #include "SFTPDirectory.h"
22 22
 #ifdef HAS_FILESYSTEM_SFTP
  23
+#include "utils/log.h"
23 24
 #include "URL.h"
24 25
 
25 26
 using namespace XFILE;
@@ -39,4 +40,18 @@ bool CSFTPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &item
39 40
   CSFTPSessionPtr session = CSFTPSessionManager::CreateSession(url);
40 41
   return session->GetDirectory(url.GetWithoutFilename().c_str(), url.GetFileName().c_str(), items);
41 42
 }
  43
+
  44
+bool CSFTPDirectory::Exists(const char* strPath)
  45
+{
  46
+  CURL url(strPath);
  47
+
  48
+  CSFTPSessionPtr session = CSFTPSessionManager::CreateSession(url);
  49
+  if (session)
  50
+    return session->DirectoryExists(url.GetFileName().c_str());
  51
+  else
  52
+  {
  53
+    CLog::Log(LOGERROR, "SFTPDirectory: Failed to create session to check exists");
  54
+    return false;
  55
+  }
  56
+}
42 57
 #endif
1  xbmc/filesystem/SFTPDirectory.h
@@ -35,6 +35,7 @@ namespace XFILE
35 35
     CSFTPDirectory(void);
36 36
     virtual ~CSFTPDirectory(void);
37 37
     virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items);
  38
+    virtual bool Exists(const char* strPath);
38 39
   };
39 40
 }
40 41
 #endif
55  xbmc/filesystem/SFTPFile.cpp
@@ -35,6 +35,11 @@
35 35
 #pragma comment(lib, "ssh.lib")
36 36
 #endif
37 37
 
  38
+#ifdef TARGET_WINDOWS
  39
+#define S_ISDIR(m) ((m & _S_IFDIR) != 0)
  40
+#define S_ISREG(m) ((m & _S_IFREG) != 0)
  41
+#endif
  42
+
38 43
 #ifdef _MSC_VER
39 44
 #define O_RDONLY _O_RDONLY
40 45
 #endif
@@ -187,19 +192,20 @@ bool CSFTPSession::GetDirectory(const CStdString &base, const CStdString &folder
187 192
   return false;
188 193
 }
189 194
 
190  
-bool CSFTPSession::Exists(const char *path)
  195
+bool CSFTPSession::DirectoryExists(const char *path)
191 196
 {
192 197
   bool exists = false;
193  
-  CSingleLock lock(m_critSect);
194  
-  if(m_connected)
195  
-  {
196  
-    sftp_attributes attributes = sftp_stat(m_sftp_session, CorrectPath(path).c_str());
197  
-    exists = attributes != NULL;
  198
+  uint32_t permissions = 0;
  199
+  exists = GetItemPermissions(path, permissions);
  200
+  return exists && S_ISDIR(permissions);
  201
+}
198 202
 
199  
-    if (attributes)
200  
-      sftp_attributes_free(attributes);
201  
-  }
202  
-  return exists;
  203
+bool CSFTPSession::FileExists(const char *path)
  204
+{
  205
+  bool exists = false;
  206
+  uint32_t permissions = 0;
  207
+  exists = GetItemPermissions(path, permissions);
  208
+  return exists && S_ISREG(permissions);
203 209
 }
204 210
 
205 211
 int CSFTPSession::Stat(const char *path, struct __stat64* buffer)
@@ -422,6 +428,33 @@ void CSFTPSession::Disconnect()
422 428
   m_session = NULL;
423 429
 }
424 430
 
  431
+/*!
  432
+ \brief Gets POSIX compatible permissions information about the specified file or directory.
  433
+ \param path Remote SSH path to the file or directory.
  434
+ \param permissions POSIX compatible permissions information for the file or directory (if it exists). i.e. can use macros S_ISDIR() etc.
  435
+ \return Returns \e true, if it was possible to get permissions for the file or directory, \e false otherwise.
  436
+ */
  437
+bool CSFTPSession::GetItemPermissions(const char *path, uint32_t &permissions)
  438
+{
  439
+  bool gotPermissions = false;
  440
+  CSingleLock lock(m_critSect);
  441
+  if(m_connected)
  442
+  {
  443
+    sftp_attributes attributes = sftp_stat(m_sftp_session, CorrectPath(path).c_str());
  444
+    if (attributes)
  445
+    {
  446
+      if (attributes->flags & SSH_FILEXFER_ATTR_PERMISSIONS)
  447
+      {
  448
+        permissions = attributes->permissions;
  449
+        gotPermissions = true;
  450
+      }
  451
+
  452
+      sftp_attributes_free(attributes);
  453
+    }
  454
+  }
  455
+  return gotPermissions;
  456
+}
  457
+
425 458
 CCriticalSection CSFTPSessionManager::m_critSect;
426 459
 map<CStdString, CSFTPSessionPtr> CSFTPSessionManager::sessions;
427 460
 
@@ -554,7 +587,7 @@ bool CSFTPFile::Exists(const CURL& url)
554 587
 {
555 588
   CSFTPSessionPtr session = CSFTPSessionManager::CreateSession(url);
556 589
   if (session)
557  
-    return session->Exists(url.GetFileName().c_str());
  590
+    return session->FileExists(url.GetFileName().c_str());
558 591
   else
559 592
   {
560 593
     CLog::Log(LOGERROR, "SFTPFile: Failed to create session to check exists");
4  xbmc/filesystem/SFTPFile.h
@@ -58,7 +58,8 @@ class CSFTPSession
58 58
   sftp_file CreateFileHande(const CStdString &file);
59 59
   void CloseFileHandle(sftp_file handle);
60 60
   bool GetDirectory(const CStdString &base, const CStdString &folder, CFileItemList &items);
61  
-  bool Exists(const char *path);
  61
+  bool DirectoryExists(const char *path);
  62
+  bool FileExists(const char *path);
62 63
   int Stat(const char *path, struct __stat64* buffer);
63 64
   int Seek(sftp_file handle, uint64_t position);
64 65
   int Read(sftp_file handle, void *buffer, size_t length);
@@ -68,6 +69,7 @@ class CSFTPSession
68 69
   bool VerifyKnownHost(ssh_session session);
69 70
   bool Connect(const CStdString &host, unsigned int port, const CStdString &username, const CStdString &password);
70 71
   void Disconnect();
  72
+  bool GetItemPermissions(const char *path, uint32_t &permissions);
71 73
   CCriticalSection m_critSect;
72 74
 
73 75
   bool m_connected;

0 notes on commit 6e28059

Please sign in to comment.
Something went wrong with that request. Please try again.