[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / platform / posix / filesystem / SMBFile.cpp
blob5e5dd58939d33f7d730bb50bf091350f51299703
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 // SMBFile.cpp: implementation of the CSMBFile class.
11 //////////////////////////////////////////////////////////////////////
13 #include "SMBFile.h"
15 #include "PasswordManager.h"
16 #include "SMBDirectory.h"
17 #include "ServiceBroker.h"
18 #include "Util.h"
19 #include "commons/Exception.h"
20 #include "filesystem/SpecialProtocol.h"
21 #include "network/DNSNameCache.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/Settings.h"
24 #include "settings/SettingsComponent.h"
25 #include "utils/StringUtils.h"
26 #include "utils/TimeUtils.h"
27 #include "utils/URIUtils.h"
28 #include "utils/log.h"
30 #include <cstring>
31 #include <inttypes.h>
32 #include <mutex>
33 #include <regex>
35 #include <libsmbclient.h>
37 using namespace XFILE;
39 void xb_smbc_log(void* private_ptr, int level, const char* msg)
41 const int logLevel = [level]()
43 switch (level)
45 case 0:
46 return LOGWARNING;
47 case 1:
48 return LOGINFO;
49 default:
50 return LOGDEBUG;
52 }();
54 if (std::strchr(msg, '@'))
56 // redact User/pass in URLs
57 static const std::regex redact("(\\w+://)\\S+:\\S+@");
58 CLog::Log(logLevel, "smb: {}", std::regex_replace(msg, redact, "$1USERNAME:PASSWORD@"));
60 else
61 CLog::Log(logLevel, "smb: {}", msg);
64 void xb_smbc_auth(const char *srv, const char *shr, char *wg, int wglen,
65 char *un, int unlen, char *pw, int pwlen)
69 // WTF is this ?, we get the original server cache only
70 // to set the server cache to this function which call the
71 // original one anyway. Seems quite silly.
72 smbc_get_cached_srv_fn orig_cache;
73 SMBCSRV* xb_smbc_cache(SMBCCTX* c, const char* server, const char* share, const char* workgroup, const char* username)
75 return orig_cache(c, server, share, workgroup, username);
78 bool CSMB::IsFirstInit = true;
80 CSMB::CSMB()
82 m_context = NULL;
83 m_OpenConnections = 0;
84 m_IdleTimeout = 0;
87 CSMB::~CSMB()
89 Deinit();
92 void CSMB::Deinit()
94 std::unique_lock<CCriticalSection> lock(*this);
96 /* samba goes loco if deinited while it has some files opened */
97 if (m_context)
99 smbc_set_context(NULL);
100 smbc_free_context(m_context, 1);
101 m_context = NULL;
105 void CSMB::Init()
107 std::unique_lock<CCriticalSection> lock(*this);
109 if (!m_context)
111 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
113 // force libsmbclient to use our own smb.conf by overriding HOME
114 std::string truehome(getenv("HOME"));
115 setenv("HOME", CSpecialProtocol::TranslatePath("special://home").c_str(), 1);
117 // Create ~/.kodi/.smb/smb.conf. This file is used by libsmbclient.
118 // http://us1.samba.org/samba/docs/man/manpages-3/libsmbclient.7.html
119 // http://us1.samba.org/samba/docs/man/manpages-3/smb.conf.5.html
120 std::string smb_conf;
121 std::string home(getenv("HOME"));
122 URIUtils::RemoveSlashAtEnd(home);
123 smb_conf = home + "/.smb";
124 int result = mkdir(smb_conf.c_str(), 0755);
125 if (result == 0 || (errno == EEXIST && IsFirstInit))
127 smb_conf += "/smb.conf";
128 FILE* f = fopen(smb_conf.c_str(), "w");
129 if (f != NULL)
131 fprintf(f, "[global]\n");
133 fprintf(f, "\tlock directory = %s/.smb/\n", home.c_str());
135 // set minimum smbclient protocol version
136 if (settings->GetInt(CSettings::SETTING_SMB_MINPROTOCOL) > 0)
138 if (settings->GetInt(CSettings::SETTING_SMB_MINPROTOCOL) == 1)
139 fprintf(f, "\tclient min protocol = NT1\n");
140 else
141 fprintf(f, "\tclient min protocol = SMB%d\n", settings->GetInt(CSettings::SETTING_SMB_MINPROTOCOL));
144 // set maximum smbclient protocol version
145 if (settings->GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) > 0)
147 if (settings->GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) == 1)
148 fprintf(f, "\tclient max protocol = NT1\n");
149 else
150 fprintf(f, "\tclient max protocol = SMB%d\n", settings->GetInt(CSettings::SETTING_SMB_MAXPROTOCOL));
153 // set legacy security options
154 if (settings->GetBool(CSettings::SETTING_SMB_LEGACYSECURITY) && (settings->GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) == 1))
156 fprintf(f, "\tclient NTLMv2 auth = no\n");
157 fprintf(f, "\tclient use spnego = no\n");
160 // set wins server if there's one. name resolve order defaults to 'lmhosts host wins bcast'.
161 // if no WINS server has been specified the wins method will be ignored.
162 if (settings->GetString(CSettings::SETTING_SMB_WINSSERVER).length() > 0 && !StringUtils::EqualsNoCase(settings->GetString(CSettings::SETTING_SMB_WINSSERVER), "0.0.0.0") )
164 fprintf(f, "\twins server = %s\n", settings->GetString(CSettings::SETTING_SMB_WINSSERVER).c_str());
165 fprintf(f, "\tname resolve order = bcast wins host\n");
167 else
168 fprintf(f, "\tname resolve order = bcast host\n");
170 // use user-configured charset. if no charset is specified,
171 // samba tries to use charset 850 but falls back to ASCII in case it is not available
172 if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambadoscodepage.length() > 0)
173 fprintf(f, "\tdos charset = %s\n", CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambadoscodepage.c_str());
175 // include users configuration if available
176 fprintf(f, "\tinclude = %s/.smb/user.conf\n", home.c_str());
178 fclose(f);
182 // reads smb.conf so this MUST be after we create smb.conf
183 // multiple smbc_init calls are ignored by libsmbclient.
184 // note: this is important as it initializes the smb old
185 // interface compatibility. Samba 3.4.0 or higher has the new interface.
186 // note: we leak the following here once, not sure why yet.
187 // 48 bytes -> smb_xmalloc_array
188 // 32 bytes -> set_param_opt
189 // 16 bytes -> set_param_opt
190 smbc_init(xb_smbc_auth, 0);
192 // setup our context
193 m_context = smbc_new_context();
195 // restore HOME
196 setenv("HOME", truehome.c_str(), 1);
198 #ifdef DEPRECATED_SMBC_INTERFACE
199 smbc_setDebug(m_context, CServiceBroker::GetLogging().CanLogComponent(LOGSAMBA) ? 10 : 0);
200 smbc_setLogCallback(m_context, this, xb_smbc_log);
201 smbc_setFunctionAuthData(m_context, xb_smbc_auth);
202 orig_cache = smbc_getFunctionGetCachedServer(m_context);
203 smbc_setFunctionGetCachedServer(m_context, xb_smbc_cache);
204 smbc_setOptionOneSharePerServer(m_context, false);
205 smbc_setOptionBrowseMaxLmbCount(m_context, 0);
206 smbc_setTimeout(m_context, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambaclienttimeout * 1000);
207 // we do not need to strdup these, smbc_setXXX below will make their own copies
208 if (settings->GetString(CSettings::SETTING_SMB_WORKGROUP).length() > 0)
209 //! @bug libsmbclient < 4.9 isn't const correct
210 smbc_setWorkgroup(m_context, const_cast<char*>(settings->GetString(CSettings::SETTING_SMB_WORKGROUP).c_str()));
211 std::string guest = "guest";
212 //! @bug libsmbclient < 4.8 isn't const correct
213 smbc_setUser(m_context, const_cast<char*>(guest.c_str()));
214 #else
215 m_context->debug = (CServiceBroker::GetLogging().CanLogComponent(LOGSAMBA) ? 10 : 0);
216 m_context->callbacks.auth_fn = xb_smbc_auth;
217 orig_cache = m_context->callbacks.get_cached_srv_fn;
218 m_context->callbacks.get_cached_srv_fn = xb_smbc_cache;
219 m_context->options.one_share_per_server = false;
220 m_context->options.browse_max_lmb_count = 0;
221 m_context->timeout = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambaclienttimeout * 1000;
222 // we need to strdup these, they will get free'd on smbc_free_context
223 if (settings->GetString(CSettings::SETTING_SMB_WORKGROUP).length() > 0)
224 m_context->workgroup = strdup(settings->GetString(CSettings::SETTING_SMB_WORKGROUP).c_str());
225 m_context->user = strdup("guest");
226 #endif
228 // initialize samba and do some hacking into the settings
229 if (smbc_init_context(m_context))
231 // setup context using the smb old interface compatibility
232 SMBCCTX *old_context = smbc_set_context(m_context);
233 // free previous context or we leak it, this comes from smbc_init above.
234 // there is a bug in smbclient (old interface), if we init/set a context
235 // then set(null)/free it in DeInit above, the next smbc_set_context
236 // return the already freed previous context, free again and bang, crash.
237 // so we setup a stic bool to track the first init so we can free the
238 // context associated with the initial smbc_init.
239 if (old_context && IsFirstInit)
241 smbc_free_context(old_context, 1);
242 IsFirstInit = false;
245 else
247 smbc_free_context(m_context, 1);
248 m_context = NULL;
251 m_IdleTimeout = 180;
254 std::string CSMB::URLEncode(const CURL &url)
256 /* due to smb wanting encoded urls we have to build it manually */
258 std::string flat = "smb://";
260 /* samba messes up of password is set but no username is set. don't know why yet */
261 /* probably the url parser that goes crazy */
262 if(url.GetUserName().length() > 0 /* || url.GetPassWord().length() > 0 */)
264 if(!url.GetDomain().empty())
266 flat += URLEncode(url.GetDomain());
267 flat += ";";
269 flat += URLEncode(url.GetUserName());
270 if(url.GetPassWord().length() > 0)
272 flat += ":";
273 flat += URLEncode(url.GetPassWord());
275 flat += "@";
277 flat += URLEncode(url.GetHostName());
279 if (url.HasPort())
281 flat += StringUtils::Format(":{}", url.GetPort());
284 /* okey sadly since a slash is an invalid name we have to tokenize */
285 std::vector<std::string> parts;
286 StringUtils::Tokenize(url.GetFileName(), parts, "/");
287 for (const std::string& it : parts)
289 flat += "/";
290 flat += URLEncode((it));
293 /* okey options should go here, thou current samba doesn't support any */
295 return flat;
298 std::string CSMB::URLEncode(const std::string &value)
300 return CURL::Encode(value);
303 /* This is called from CApplication::ProcessSlow() and is used to tell if smbclient have been idle for too long */
304 void CSMB::CheckIfIdle()
306 /* We check if there are open connections. This is done without a lock to not halt the mainthread. It should be thread safe as
307 worst case scenario is that m_OpenConnections could read 0 and then changed to 1 if this happens it will enter the if which will lead to another check, which is locked. */
308 if (m_OpenConnections == 0)
309 { /* I've set the the maximum IDLE time to be 1 min and 30 sec. */
310 std::unique_lock<CCriticalSection> lock(*this);
311 if (m_OpenConnections == 0 /* check again - when locked */ && m_context != NULL)
313 if (m_IdleTimeout > 0)
315 m_IdleTimeout--;
317 else
319 CLog::Log(LOGINFO, "Samba is idle. Closing the remaining connections");
320 smb.Deinit();
326 void CSMB::SetActivityTime()
328 /* Since we get called every 500ms from ProcessSlow we limit the tick count to 180 */
329 /* That means we have 2 ticks per second which equals 180/2 == 90 seconds */
330 m_IdleTimeout = 180;
333 /* The following two function is used to keep track on how many Opened files/directories there are.
334 This makes the idle timer not count if a movie is paused for example */
335 void CSMB::AddActiveConnection()
337 std::unique_lock<CCriticalSection> lock(*this);
338 m_OpenConnections++;
340 void CSMB::AddIdleConnection()
342 std::unique_lock<CCriticalSection> lock(*this);
343 m_OpenConnections--;
344 /* If we close a file we reset the idle timer so that we don't have any weird behaviours if a user
345 leaves the movie paused for a long while and then press stop */
346 m_IdleTimeout = 180;
349 CURL CSMB::GetResolvedUrl(const CURL& url)
351 CURL tmpUrl(url);
352 std::string resolvedHostName;
354 if (CDNSNameCache::Lookup(tmpUrl.GetHostName(), resolvedHostName))
355 tmpUrl.SetHostName(resolvedHostName);
357 return tmpUrl;
360 CSMB smb;
362 CSMBFile::CSMBFile()
364 smb.Init();
365 m_fd = -1;
366 smb.AddActiveConnection();
367 m_allowRetry = true;
370 CSMBFile::~CSMBFile()
372 Close();
373 smb.AddIdleConnection();
376 int64_t CSMBFile::GetPosition()
378 if (m_fd == -1)
379 return -1;
380 std::unique_lock<CCriticalSection> lock(smb);
381 if (!smb.IsSmbValid())
382 return -1;
383 return smbc_lseek(m_fd, 0, SEEK_CUR);
386 int64_t CSMBFile::GetLength()
388 if (m_fd == -1)
389 return -1;
390 return m_fileSize;
393 bool CSMBFile::Open(const CURL& url)
395 Close();
397 // we can't open files like smb://file.f or smb://server/file.f
398 // if a file matches the if below return false, it can't exist on a samba share.
399 if (!IsValidFile(url.GetFileName()))
401 CLog::Log(LOGINFO, "SMBFile->Open: Bad URL : '{}'", url.GetRedacted());
402 return false;
404 m_url = url;
406 // opening a file to another computer share will create a new session
407 // when opening smb://server xbms will try to find folder.jpg in all shares
408 // listed, which will create lot's of open sessions.
410 std::string strFileName;
411 m_fd = OpenFile(url, strFileName);
413 CLog::Log(LOGDEBUG, "CSMBFile::Open - opened {}, fd={}", url.GetRedacted(), m_fd);
414 if (m_fd == -1)
416 // write error to logfile
417 CLog::Log(LOGERROR, "SMBFile->Open: Unable to open file : '{}'\nunix_err:'{:x}' error : '{}'",
418 CURL::GetRedacted(strFileName), errno, strerror(errno));
419 return false;
422 std::unique_lock<CCriticalSection> lock(smb);
423 if (!smb.IsSmbValid())
424 return false;
425 struct stat tmpBuffer;
426 if (smbc_stat(strFileName.c_str(), &tmpBuffer) < 0)
428 smbc_close(m_fd);
429 m_fd = -1;
430 return false;
433 m_fileSize = tmpBuffer.st_size;
435 int64_t ret = smbc_lseek(m_fd, 0, SEEK_SET);
436 if ( ret < 0 )
438 smbc_close(m_fd);
439 m_fd = -1;
440 return false;
442 // We've successfully opened the file!
443 return true;
447 /// \brief Checks authentication against SAMBA share. Reads password cache created in CSMBDirectory::OpenDir().
448 /// \param strAuth The SMB style path
449 /// \return SMB file descriptor
451 int CSMBFile::OpenFile(std::string& strAuth)
453 int fd = -1;
455 std::string strPath = g_passwordManager.GetSMBAuthFilename(strAuth);
457 fd = smbc_open(strPath.c_str(), O_RDONLY, 0);
458 //! @todo Run a loop here that prompts for our username/password as appropriate?
459 //! We have the ability to run a file (eg from a button action) without browsing to
460 //! the directory first. In the case of a password protected share that we do
461 //! not have the authentication information for, the above smbc_open() will have
462 //! returned negative, and the file will not be opened. While this is not a particular
463 //! likely scenario, we might want to implement prompting for the password in this case.
464 //! The code from SMBDirectory can be used for this.
465 if(fd >= 0)
466 strAuth = strPath;
468 return fd;
472 int CSMBFile::OpenFile(const CURL &url, std::string& strAuth)
474 int fd = -1;
475 smb.Init();
477 strAuth = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
478 std::string strPath = strAuth;
481 std::unique_lock<CCriticalSection> lock(smb);
482 if (smb.IsSmbValid())
483 fd = smbc_open(strPath.c_str(), O_RDONLY, 0);
486 if (fd >= 0)
487 strAuth = strPath;
489 return fd;
492 bool CSMBFile::Exists(const CURL& url)
494 // we can't open files like smb://file.f or smb://server/file.f
495 // if a file matches the if below return false, it can't exist on a samba share.
496 if (!IsValidFile(url.GetFileName())) return false;
498 smb.Init();
499 std::string strFileName = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
501 struct stat info;
503 std::unique_lock<CCriticalSection> lock(smb);
504 if (!smb.IsSmbValid())
505 return false;
506 int iResult = smbc_stat(strFileName.c_str(), &info);
508 if (iResult < 0) return false;
509 return true;
512 int CSMBFile::Stat(struct __stat64* buffer)
514 if (m_fd == -1)
515 return -1;
517 struct stat tmpBuffer = {};
519 std::unique_lock<CCriticalSection> lock(smb);
520 if (!smb.IsSmbValid())
521 return -1;
522 int iResult = smbc_fstat(m_fd, &tmpBuffer);
523 CUtil::StatToStat64(buffer, &tmpBuffer);
524 return iResult;
527 int CSMBFile::Stat(const CURL& url, struct __stat64* buffer)
529 smb.Init();
530 std::string strFileName = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
531 std::unique_lock<CCriticalSection> lock(smb);
533 if (!smb.IsSmbValid())
534 return -1;
535 struct stat tmpBuffer = {};
536 int iResult = smbc_stat(strFileName.c_str(), &tmpBuffer);
537 CUtil::StatToStat64(buffer, &tmpBuffer);
538 return iResult;
541 int CSMBFile::Truncate(int64_t size)
543 if (m_fd == -1) return 0;
545 * This would force us to be dependant on SMBv3.2 which is GPLv3
546 * This is only used by the TagLib writers, which are not currently in use
547 * So log and warn until we implement TagLib writing & can re-implement this better.
548 std::unique_lock<CCriticalSection> lock(smb); // Init not called since it has to be "inited" by now
550 #if defined(TARGET_ANDROID)
551 int iResult = 0;
552 #else
553 int iResult = smbc_ftruncate(m_fd, size);
554 #endif
556 CLog::Log(LOGWARNING, "{} - Warning(smbc_ftruncate called and not implemented)", __FUNCTION__);
557 return 0;
560 ssize_t CSMBFile::Read(void *lpBuf, size_t uiBufSize)
562 if (uiBufSize > SSIZE_MAX)
563 uiBufSize = SSIZE_MAX;
565 if (m_fd == -1)
566 return -1;
568 // Some external libs (libass) use test read with zero size and
569 // null buffer pointer to check whether file is readable, but
570 // libsmbclient always return "-1" if called with null buffer
571 // regardless of buffer size.
572 // To overcome this, force return "0" in that case.
573 if (uiBufSize == 0 && lpBuf == NULL)
574 return 0;
576 std::unique_lock<CCriticalSection> lock(
577 smb); // Init not called since it has to be "inited" by now
578 if (!smb.IsSmbValid())
579 return -1;
580 smb.SetActivityTime();
582 ssize_t bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize);
584 if (m_allowRetry && bytesRead < 0 && errno == EINVAL )
586 CLog::Log(LOGERROR, "{} - Error( {}, {}, {} ) - Retrying", __FUNCTION__, bytesRead, errno,
587 strerror(errno));
588 bytesRead = smbc_read(m_fd, lpBuf, (int)uiBufSize);
591 if ( bytesRead < 0 )
592 CLog::Log(LOGERROR, "{} - Error( {}, {}, {} )", __FUNCTION__, bytesRead, errno,
593 strerror(errno));
595 return bytesRead;
598 int64_t CSMBFile::Seek(int64_t iFilePosition, int iWhence)
600 if (m_fd == -1) return -1;
602 std::unique_lock<CCriticalSection> lock(
603 smb); // Init not called since it has to be "inited" by now
604 if (!smb.IsSmbValid())
605 return -1;
606 smb.SetActivityTime();
607 int64_t pos = smbc_lseek(m_fd, iFilePosition, iWhence);
609 if ( pos < 0 )
611 CLog::Log(LOGERROR, "{} - Error( {}, {}, {} )", __FUNCTION__, pos, errno, strerror(errno));
612 return -1;
615 return pos;
618 void CSMBFile::Close()
620 if (m_fd != -1)
622 CLog::Log(LOGDEBUG, "CSMBFile::Close closing fd {}", m_fd);
623 std::unique_lock<CCriticalSection> lock(smb);
624 if (!smb.IsSmbValid())
625 return;
626 smbc_close(m_fd);
628 m_fd = -1;
631 ssize_t CSMBFile::Write(const void* lpBuf, size_t uiBufSize)
633 if (m_fd == -1) return -1;
635 // lpBuf can be safely casted to void* since xbmc_write will only read from it.
636 std::unique_lock<CCriticalSection> lock(smb);
637 if (!smb.IsSmbValid())
638 return -1;
640 return smbc_write(m_fd, lpBuf, uiBufSize);
643 bool CSMBFile::Delete(const CURL& url)
645 smb.Init();
646 std::string strFile = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
648 std::unique_lock<CCriticalSection> lock(smb);
649 if (!smb.IsSmbValid())
650 return false;
652 int result = smbc_unlink(strFile.c_str());
654 if(result != 0)
655 CLog::Log(LOGERROR, "{} - Error( {} )", __FUNCTION__, strerror(errno));
657 return (result == 0);
660 bool CSMBFile::Rename(const CURL& url, const CURL& urlnew)
662 smb.Init();
663 std::string strFile = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
664 std::string strFileNew = GetAuthenticatedPath(CSMB::GetResolvedUrl(urlnew));
665 std::unique_lock<CCriticalSection> lock(smb);
666 if (!smb.IsSmbValid())
667 return false;
669 int result = smbc_rename(strFile.c_str(), strFileNew.c_str());
671 if(result != 0)
672 CLog::Log(LOGERROR, "{} - Error( {} )", __FUNCTION__, strerror(errno));
674 return (result == 0);
677 bool CSMBFile::OpenForWrite(const CURL& url, bool bOverWrite)
679 m_fileSize = 0;
681 Close();
683 // we can't open files like smb://file.f or smb://server/file.f
684 // if a file matches the if below return false, it can't exist on a samba share.
685 if (!IsValidFile(url.GetFileName())) return false;
687 std::string strFileName = GetAuthenticatedPath(CSMB::GetResolvedUrl(url));
688 std::unique_lock<CCriticalSection> lock(smb);
689 if (!smb.IsSmbValid())
690 return false;
692 if (bOverWrite)
694 CLog::Log(LOGWARNING, "SMBFile::OpenForWrite() called with overwriting enabled! - {}",
695 CURL::GetRedacted(strFileName));
696 m_fd = smbc_creat(strFileName.c_str(), 0);
698 else
700 m_fd = smbc_open(strFileName.c_str(), O_RDWR, 0);
703 if (m_fd == -1)
705 // write error to logfile
706 CLog::Log(LOGERROR, "SMBFile->Open: Unable to open file : '{}'\nunix_err:'{:x}' error : '{}'",
707 CURL::GetRedacted(strFileName), errno, strerror(errno));
708 return false;
711 // We've successfully opened the file!
712 return true;
715 bool CSMBFile::IsValidFile(const std::string& strFileName)
717 if (strFileName.find('/') == std::string::npos || /* doesn't have sharename */
718 StringUtils::EndsWith(strFileName, "/.") || /* not current folder */
719 StringUtils::EndsWith(strFileName, "/..")) /* not parent folder */
720 return false;
721 return true;
724 std::string CSMBFile::GetAuthenticatedPath(const CURL &url)
726 CURL authURL(CSMB::GetResolvedUrl(url));
727 CPasswordManager::GetInstance().AuthenticateURL(authURL);
728 return smb.URLEncode(authURL);
731 int CSMBFile::IoControl(EIoControl request, void* param)
733 if (request == IOCTRL_SEEK_POSSIBLE)
734 return 1;
736 if (request == IOCTRL_SET_RETRY)
738 m_allowRetry = *(bool*) param;
739 return 0;
742 return -1;
745 int CSMBFile::GetChunkSize()
747 const auto settings = CServiceBroker::GetSettingsComponent()->GetSettings();
749 if (!settings)
750 return (64 * 1024);
752 int chunkSize = settings->GetInt(CSettings::SETTING_SMB_CHUNKSIZE) * 1024;
754 if (settings->GetInt(CSettings::SETTING_SMB_MINPROTOCOL) == 1 &&
755 settings->GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) == 1)
757 if (chunkSize > 64 * 1024)
758 chunkSize = 64 * 1024;
761 return chunkSize;