*/smbclient: use the new API with SMBCCTX parameter

As a side effect, the input plugin closes the SMB/CIFS connection
after closing the file.

This solves one part of
https://github.com/MusicPlayerDaemon/MPD/issues/916
This commit is contained in:
Max Kellermann 2020-07-20 21:10:58 +02:00
parent 697531a948
commit f6dc9bcad6
5 changed files with 93 additions and 42 deletions

1
NEWS
View File

@ -12,6 +12,7 @@ ver 0.22 (not yet released)
- curl: support "charset" parameter in URI fragment
- ffmpeg: allow partial reads
- io_uring: new plugin for local files on Linux (using liburing)
- smbclient: close unused SMB/CIFS connections
* archive
- iso9660: support seeking
* database

View File

@ -31,15 +31,15 @@
class SmbclientInputStream final : public InputStream {
SmbclientContext ctx;
int fd;
SMBCFILE *const handle;
public:
SmbclientInputStream(const char *_uri,
Mutex &_mutex,
SmbclientContext &&_ctx,
int _fd, const struct stat &st)
SMBCFILE *_handle, const struct stat &st)
:InputStream(_uri, _mutex),
ctx(std::move(_ctx)), fd(_fd)
ctx(std::move(_ctx)), handle(_handle)
{
seekable = true;
size = st.st_size;
@ -48,7 +48,7 @@ public:
~SmbclientInputStream() override {
const std::lock_guard<Mutex> lock(smbclient_mutex);
smbc_close(fd);
ctx.Close(handle);
}
/* virtual methods from InputStream */
@ -89,18 +89,18 @@ input_smbclient_open(const char *uri,
const std::lock_guard<Mutex> protect(smbclient_mutex);
int fd = smbc_open(uri, O_RDONLY, 0);
if (fd < 0)
SMBCFILE *handle = ctx.OpenReadOnly(uri);
if (handle == nullptr)
throw MakeErrno("smbc_open() failed");
struct stat st;
if (smbc_fstat(fd, &st) < 0)
if (ctx.Stat(handle, st) < 0)
throw MakeErrno("smbc_fstat() failed");
return std::make_unique<MaybeBufferedInputStream>
(std::make_unique<SmbclientInputStream>(uri, mutex,
std::move(ctx),
fd, st));
handle, st));
}
size_t
@ -112,7 +112,7 @@ SmbclientInputStream::Read(std::unique_lock<Mutex> &,
{
const ScopeUnlock unlock(mutex);
const std::lock_guard<Mutex> lock(smbclient_mutex);
nbytes = smbc_read(fd, ptr, read_size);
nbytes = ctx.Read(handle, ptr, read_size);
}
if (nbytes < 0)
@ -131,7 +131,7 @@ SmbclientInputStream::Seek(std::unique_lock<Mutex> &,
{
const ScopeUnlock unlock(mutex);
const std::lock_guard<Mutex> lock(smbclient_mutex);
result = smbc_lseek(fd, new_offset, SEEK_SET);
result = ctx.Seek(handle, new_offset);
}
if (result < 0)

View File

@ -54,6 +54,46 @@ public:
* Throws on error.
*/
static SmbclientContext New();
SMBCFILE *Open(const char *fname, int flags, mode_t mode) noexcept {
return smbc_getFunctionOpen(ctx)(ctx, fname, flags, mode);
}
SMBCFILE *OpenReadOnly(const char *fname) noexcept {
return Open(fname, O_RDONLY, 0);
}
ssize_t Read(SMBCFILE *file, void *buf, size_t count) noexcept {
return smbc_getFunctionRead(ctx)(ctx, file, buf, count);
}
off_t Seek(SMBCFILE *file, off_t offset, int whence=SEEK_SET) noexcept {
return smbc_getFunctionLseek(ctx)(ctx, file, offset, whence);
}
int Stat(const char *fname, struct stat &st) noexcept {
return smbc_getFunctionStat(ctx)(ctx, fname, &st);
}
int Stat(SMBCFILE *file, struct stat &st) noexcept {
return smbc_getFunctionFstat(ctx)(ctx, file, &st);
}
void Close(SMBCFILE *file) noexcept {
smbc_getFunctionClose(ctx)(ctx, file);
}
SMBCFILE *OpenDirectory(const char *fname) noexcept {
return smbc_getFunctionOpendir(ctx)(ctx, fname);
}
void CloseDirectory(SMBCFILE *dir) noexcept {
smbc_getFunctionClosedir(ctx)(ctx, dir);
}
const struct smbc_dirent *ReadDirectory(SMBCFILE *dir) noexcept {
return smbc_getFunctionReaddir(ctx)(ctx, dir);
}
};
#endif

View File

@ -19,6 +19,7 @@
#include "SmbclientNeighborPlugin.hxx"
#include "lib/smbclient/Init.hxx"
#include "lib/smbclient/Context.hxx"
#include "lib/smbclient/Domain.hxx"
#include "lib/smbclient/Mutex.hxx"
#include "neighbor/NeighborPlugin.hxx"
@ -56,6 +57,8 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
}
};
SmbclientContext ctx = SmbclientContext::New();
Thread thread;
mutable Mutex mutex;
@ -66,7 +69,7 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
bool quit;
public:
explicit SmbclientNeighborExplorer(NeighborListener &_listener) noexcept
explicit SmbclientNeighborExplorer(NeighborListener &_listener)
:NeighborExplorer(_listener),
thread(BIND_THIS_METHOD(ThreadFunc)) {}
@ -125,21 +128,24 @@ ReadServer(NeighborExplorer::List &list, const smbc_dirent &e) noexcept
}
static void
ReadServers(NeighborExplorer::List &list, const char *uri) noexcept;
ReadServers(SmbclientContext &ctx, const char *uri,
NeighborExplorer::List &list) noexcept;
static void
ReadWorkgroup(NeighborExplorer::List &list, const std::string &name) noexcept
ReadWorkgroup(SmbclientContext &ctx, const std::string &name,
NeighborExplorer::List &list) noexcept
{
std::string uri = "smb://" + name;
ReadServers(list, uri.c_str());
ReadServers(ctx, uri.c_str(), list);
}
static void
ReadEntry(NeighborExplorer::List &list, const smbc_dirent &e) noexcept
ReadEntry(SmbclientContext &ctx, const smbc_dirent &e,
NeighborExplorer::List &list) noexcept
{
switch (e.smbc_type) {
case SMBC_WORKGROUP:
ReadWorkgroup(list, std::string(e.name, e.namelen));
ReadWorkgroup(ctx, std::string(e.name, e.namelen), list);
break;
case SMBC_SERVER:
@ -149,20 +155,21 @@ ReadEntry(NeighborExplorer::List &list, const smbc_dirent &e) noexcept
}
static void
ReadServers(NeighborExplorer::List &list, int fd) noexcept
ReadServers(SmbclientContext &ctx, SMBCFILE *handle,
NeighborExplorer::List &list) noexcept
{
smbc_dirent *e;
while ((e = smbc_readdir(fd)) != nullptr)
ReadEntry(list, *e);
while (auto e = ctx.ReadDirectory(handle))
ReadEntry(ctx, *e, list);
}
static void
ReadServers(NeighborExplorer::List &list, const char *uri) noexcept
ReadServers(SmbclientContext &ctx, const char *uri,
NeighborExplorer::List &list) noexcept
{
int fd = smbc_opendir(uri);
if (fd >= 0) {
ReadServers(list, fd);
smbc_closedir(fd);
SMBCFILE *handle = ctx.OpenDirectory(uri);
if (handle != nullptr) {
ReadServers(ctx, handle, list);
ctx.CloseDirectory(handle);
} else
FormatErrno(smbclient_domain, "smbc_opendir('%s') failed",
uri);
@ -170,11 +177,11 @@ ReadServers(NeighborExplorer::List &list, const char *uri) noexcept
gcc_pure
static NeighborExplorer::List
DetectServers() noexcept
DetectServers(SmbclientContext &ctx) noexcept
{
NeighborExplorer::List list;
const std::lock_guard<Mutex> protect(smbclient_mutex);
ReadServers(list, "smb://");
ReadServers(ctx, "smb://", list);
return list;
}
@ -198,7 +205,7 @@ SmbclientNeighborExplorer::Run() noexcept
{
const ScopeUnlock unlock(mutex);
found = DetectServers();
found = DetectServers(ctx);
}
const auto found_before_begin = found.before_begin();

View File

@ -34,14 +34,17 @@
#include <libsmbclient.h>
class SmbclientDirectoryReader final : public StorageDirectoryReader {
SmbclientContext &ctx;
const std::string base;
const unsigned handle;
SMBCFILE *const handle;
const char *name;
public:
SmbclientDirectoryReader(std::string &&_base, unsigned _handle)
:base(std::move(_base)), handle(_handle) {}
SmbclientDirectoryReader(SmbclientContext &_ctx,
std::string &&_base,
SMBCFILE *_handle) noexcept
:ctx(_ctx), base(std::move(_base)), handle(_handle) {}
~SmbclientDirectoryReader() override;
@ -85,13 +88,13 @@ SmbclientStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept
}
static StorageFileInfo
GetInfo(const char *path)
GetInfo(SmbclientContext &ctx, const char *path)
{
struct stat st;
{
const std::lock_guard<Mutex> protect(smbclient_mutex);
if (smbc_stat(path, &st) != 0)
if (ctx.Stat(path, st) != 0)
throw MakeErrno("Failed to access file");
}
@ -114,7 +117,7 @@ StorageFileInfo
SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow)
{
const std::string mapped = MapUTF8(uri_utf8);
return ::GetInfo(mapped.c_str());
return ::GetInfo(ctx, mapped.c_str());
}
std::unique_ptr<StorageDirectoryReader>
@ -122,16 +125,17 @@ SmbclientStorage::OpenDirectory(std::string_view uri_utf8)
{
std::string mapped = MapUTF8(uri_utf8);
int handle;
SMBCFILE *handle;
{
const std::lock_guard<Mutex> protect(smbclient_mutex);
handle = smbc_opendir(mapped.c_str());
if (handle < 0)
handle = ctx.OpenDirectory(mapped.c_str());
if (handle == nullptr)
throw MakeErrno("Failed to open directory");
}
return std::make_unique<SmbclientDirectoryReader>(std::move(mapped),
return std::make_unique<SmbclientDirectoryReader>(ctx,
std::move(mapped),
handle);
}
@ -147,7 +151,7 @@ SkipNameFS(const char *name) noexcept
SmbclientDirectoryReader::~SmbclientDirectoryReader()
{
const std::lock_guard<Mutex> lock(smbclient_mutex);
smbc_close(handle);
ctx.CloseDirectory(handle);
}
const char *
@ -155,8 +159,7 @@ SmbclientDirectoryReader::Read() noexcept
{
const std::lock_guard<Mutex> protect(smbclient_mutex);
struct smbc_dirent *e;
while ((e = smbc_readdir(handle)) != nullptr) {
while (auto e = ctx.ReadDirectory(handle)) {
name = e->name;
if (!SkipNameFS(name))
return name;
@ -169,7 +172,7 @@ StorageFileInfo
SmbclientDirectoryReader::GetInfo([[maybe_unused]] bool follow)
{
const std::string path = PathTraitsUTF8::Build(base, name);
return ::GetInfo(path.c_str());
return ::GetInfo(ctx, path.c_str());
}
static std::unique_ptr<Storage>