/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ /* * know bugs: * - when opening a server for the first time with ip address and the second time * with server name, access to the server is denied. * - when browsing entire network, user can't go back one step * share = smb://, user selects a workgroup, user selects a server. * doing ".." will go back to smb:// (entire network) and not to workgroup list. * * debugging is set to a max of 10 for release builds (see local.h) */ #include "SMBDirectory.h" #include "FileItem.h" #include "PasswordManager.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/XTimeUtils.h" #include "utils/log.h" #include "platform/posix/filesystem/SMBWSDiscovery.h" #include #include struct CachedDirEntry { unsigned int type; std::string name; }; using namespace XFILE; CSMBDirectory::CSMBDirectory(void) { smb.AddActiveConnection(); } CSMBDirectory::~CSMBDirectory(void) { smb.AddIdleConnection(); } bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) { // We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] /* samba isn't thread safe with old interface, always lock */ std::unique_lock lock(smb); smb.Init(); //Separate roots for the authentication and the containing items to allow browsing to work correctly std::string strRoot = url.Get(); std::string strAuth; lock.unlock(); // OpenDir is locked // if url provided does not having anything except smb protocol // Do a WS-Discovery search to find possible smb servers to mimic smbv1 behaviour if (strRoot == "smb://") { auto settingsComponent = CServiceBroker::GetSettingsComponent(); if (!settingsComponent) return false; auto settings = CServiceBroker::GetSettingsComponent()->GetSettings(); if (!settings) return false; // Check WS-Discovery daemon enabled, if not return as smb:// cant be handled further if (settings->GetBool(CSettings::SETTING_SERVICES_WSDISCOVERY)) { WSDiscovery::CWSDiscoveryPosix& WSInstance = dynamic_cast(CServiceBroker::GetWSDiscovery()); return WSInstance.GetServerList(items); } else { return false; } } int fd = OpenDir(url, strAuth); if (fd < 0) return false; URIUtils::AddSlashAtEnd(strRoot); URIUtils::AddSlashAtEnd(strAuth); std::string strFile; // need to keep the samba lock for as short as possible. // so we first cache all directory entries and then go over them again asking for stat // "stat" is locked each time. that way the lock is freed between stat requests std::vector vecEntries; struct smbc_dirent* dirEnt; lock.lock(); if (!smb.IsSmbValid()) return false; while ((dirEnt = smbc_readdir(fd))) { CachedDirEntry aDir; aDir.type = dirEnt->smbc_type; aDir.name = dirEnt->name; vecEntries.push_back(aDir); } smbc_closedir(fd); lock.unlock(); for (size_t i=0; i