*/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:
parent
697531a948
commit
f6dc9bcad6
1
NEWS
1
NEWS
@ -12,6 +12,7 @@ ver 0.22 (not yet released)
|
|||||||
- curl: support "charset" parameter in URI fragment
|
- curl: support "charset" parameter in URI fragment
|
||||||
- ffmpeg: allow partial reads
|
- ffmpeg: allow partial reads
|
||||||
- io_uring: new plugin for local files on Linux (using liburing)
|
- io_uring: new plugin for local files on Linux (using liburing)
|
||||||
|
- smbclient: close unused SMB/CIFS connections
|
||||||
* archive
|
* archive
|
||||||
- iso9660: support seeking
|
- iso9660: support seeking
|
||||||
* database
|
* database
|
||||||
|
@ -31,15 +31,15 @@
|
|||||||
|
|
||||||
class SmbclientInputStream final : public InputStream {
|
class SmbclientInputStream final : public InputStream {
|
||||||
SmbclientContext ctx;
|
SmbclientContext ctx;
|
||||||
int fd;
|
SMBCFILE *const handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SmbclientInputStream(const char *_uri,
|
SmbclientInputStream(const char *_uri,
|
||||||
Mutex &_mutex,
|
Mutex &_mutex,
|
||||||
SmbclientContext &&_ctx,
|
SmbclientContext &&_ctx,
|
||||||
int _fd, const struct stat &st)
|
SMBCFILE *_handle, const struct stat &st)
|
||||||
:InputStream(_uri, _mutex),
|
:InputStream(_uri, _mutex),
|
||||||
ctx(std::move(_ctx)), fd(_fd)
|
ctx(std::move(_ctx)), handle(_handle)
|
||||||
{
|
{
|
||||||
seekable = true;
|
seekable = true;
|
||||||
size = st.st_size;
|
size = st.st_size;
|
||||||
@ -48,7 +48,7 @@ public:
|
|||||||
|
|
||||||
~SmbclientInputStream() override {
|
~SmbclientInputStream() override {
|
||||||
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
||||||
smbc_close(fd);
|
ctx.Close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
@ -89,18 +89,18 @@ input_smbclient_open(const char *uri,
|
|||||||
|
|
||||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
||||||
|
|
||||||
int fd = smbc_open(uri, O_RDONLY, 0);
|
SMBCFILE *handle = ctx.OpenReadOnly(uri);
|
||||||
if (fd < 0)
|
if (handle == nullptr)
|
||||||
throw MakeErrno("smbc_open() failed");
|
throw MakeErrno("smbc_open() failed");
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (smbc_fstat(fd, &st) < 0)
|
if (ctx.Stat(handle, st) < 0)
|
||||||
throw MakeErrno("smbc_fstat() failed");
|
throw MakeErrno("smbc_fstat() failed");
|
||||||
|
|
||||||
return std::make_unique<MaybeBufferedInputStream>
|
return std::make_unique<MaybeBufferedInputStream>
|
||||||
(std::make_unique<SmbclientInputStream>(uri, mutex,
|
(std::make_unique<SmbclientInputStream>(uri, mutex,
|
||||||
std::move(ctx),
|
std::move(ctx),
|
||||||
fd, st));
|
handle, st));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@ -112,7 +112,7 @@ SmbclientInputStream::Read(std::unique_lock<Mutex> &,
|
|||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
const std::lock_guard<Mutex> lock(smbclient_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)
|
if (nbytes < 0)
|
||||||
@ -131,7 +131,7 @@ SmbclientInputStream::Seek(std::unique_lock<Mutex> &,
|
|||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
const std::lock_guard<Mutex> lock(smbclient_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)
|
if (result < 0)
|
||||||
|
@ -54,6 +54,46 @@ public:
|
|||||||
* Throws on error.
|
* Throws on error.
|
||||||
*/
|
*/
|
||||||
static SmbclientContext New();
|
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
|
#endif
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "SmbclientNeighborPlugin.hxx"
|
#include "SmbclientNeighborPlugin.hxx"
|
||||||
#include "lib/smbclient/Init.hxx"
|
#include "lib/smbclient/Init.hxx"
|
||||||
|
#include "lib/smbclient/Context.hxx"
|
||||||
#include "lib/smbclient/Domain.hxx"
|
#include "lib/smbclient/Domain.hxx"
|
||||||
#include "lib/smbclient/Mutex.hxx"
|
#include "lib/smbclient/Mutex.hxx"
|
||||||
#include "neighbor/NeighborPlugin.hxx"
|
#include "neighbor/NeighborPlugin.hxx"
|
||||||
@ -56,6 +57,8 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SmbclientContext ctx = SmbclientContext::New();
|
||||||
|
|
||||||
Thread thread;
|
Thread thread;
|
||||||
|
|
||||||
mutable Mutex mutex;
|
mutable Mutex mutex;
|
||||||
@ -66,7 +69,7 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
|
|||||||
bool quit;
|
bool quit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SmbclientNeighborExplorer(NeighborListener &_listener) noexcept
|
explicit SmbclientNeighborExplorer(NeighborListener &_listener)
|
||||||
:NeighborExplorer(_listener),
|
:NeighborExplorer(_listener),
|
||||||
thread(BIND_THIS_METHOD(ThreadFunc)) {}
|
thread(BIND_THIS_METHOD(ThreadFunc)) {}
|
||||||
|
|
||||||
@ -125,21 +128,24 @@ ReadServer(NeighborExplorer::List &list, const smbc_dirent &e) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ReadServers(NeighborExplorer::List &list, const char *uri) noexcept;
|
ReadServers(SmbclientContext &ctx, const char *uri,
|
||||||
|
NeighborExplorer::List &list) noexcept;
|
||||||
|
|
||||||
static void
|
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;
|
std::string uri = "smb://" + name;
|
||||||
ReadServers(list, uri.c_str());
|
ReadServers(ctx, uri.c_str(), list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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) {
|
switch (e.smbc_type) {
|
||||||
case SMBC_WORKGROUP:
|
case SMBC_WORKGROUP:
|
||||||
ReadWorkgroup(list, std::string(e.name, e.namelen));
|
ReadWorkgroup(ctx, std::string(e.name, e.namelen), list);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SMBC_SERVER:
|
case SMBC_SERVER:
|
||||||
@ -149,20 +155,21 @@ ReadEntry(NeighborExplorer::List &list, const smbc_dirent &e) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ReadServers(NeighborExplorer::List &list, int fd) noexcept
|
ReadServers(SmbclientContext &ctx, SMBCFILE *handle,
|
||||||
|
NeighborExplorer::List &list) noexcept
|
||||||
{
|
{
|
||||||
smbc_dirent *e;
|
while (auto e = ctx.ReadDirectory(handle))
|
||||||
while ((e = smbc_readdir(fd)) != nullptr)
|
ReadEntry(ctx, *e, list);
|
||||||
ReadEntry(list, *e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
SMBCFILE *handle = ctx.OpenDirectory(uri);
|
||||||
if (fd >= 0) {
|
if (handle != nullptr) {
|
||||||
ReadServers(list, fd);
|
ReadServers(ctx, handle, list);
|
||||||
smbc_closedir(fd);
|
ctx.CloseDirectory(handle);
|
||||||
} else
|
} else
|
||||||
FormatErrno(smbclient_domain, "smbc_opendir('%s') failed",
|
FormatErrno(smbclient_domain, "smbc_opendir('%s') failed",
|
||||||
uri);
|
uri);
|
||||||
@ -170,11 +177,11 @@ ReadServers(NeighborExplorer::List &list, const char *uri) noexcept
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static NeighborExplorer::List
|
static NeighborExplorer::List
|
||||||
DetectServers() noexcept
|
DetectServers(SmbclientContext &ctx) noexcept
|
||||||
{
|
{
|
||||||
NeighborExplorer::List list;
|
NeighborExplorer::List list;
|
||||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
||||||
ReadServers(list, "smb://");
|
ReadServers(ctx, "smb://", list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +205,7 @@ SmbclientNeighborExplorer::Run() noexcept
|
|||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
found = DetectServers();
|
found = DetectServers(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto found_before_begin = found.before_begin();
|
const auto found_before_begin = found.before_begin();
|
||||||
|
@ -34,14 +34,17 @@
|
|||||||
#include <libsmbclient.h>
|
#include <libsmbclient.h>
|
||||||
|
|
||||||
class SmbclientDirectoryReader final : public StorageDirectoryReader {
|
class SmbclientDirectoryReader final : public StorageDirectoryReader {
|
||||||
|
SmbclientContext &ctx;
|
||||||
const std::string base;
|
const std::string base;
|
||||||
const unsigned handle;
|
SMBCFILE *const handle;
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SmbclientDirectoryReader(std::string &&_base, unsigned _handle)
|
SmbclientDirectoryReader(SmbclientContext &_ctx,
|
||||||
:base(std::move(_base)), handle(_handle) {}
|
std::string &&_base,
|
||||||
|
SMBCFILE *_handle) noexcept
|
||||||
|
:ctx(_ctx), base(std::move(_base)), handle(_handle) {}
|
||||||
|
|
||||||
~SmbclientDirectoryReader() override;
|
~SmbclientDirectoryReader() override;
|
||||||
|
|
||||||
@ -85,13 +88,13 @@ SmbclientStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static StorageFileInfo
|
static StorageFileInfo
|
||||||
GetInfo(const char *path)
|
GetInfo(SmbclientContext &ctx, const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
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");
|
throw MakeErrno("Failed to access file");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +117,7 @@ StorageFileInfo
|
|||||||
SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow)
|
SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow)
|
||||||
{
|
{
|
||||||
const std::string mapped = MapUTF8(uri_utf8);
|
const std::string mapped = MapUTF8(uri_utf8);
|
||||||
return ::GetInfo(mapped.c_str());
|
return ::GetInfo(ctx, mapped.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<StorageDirectoryReader>
|
std::unique_ptr<StorageDirectoryReader>
|
||||||
@ -122,16 +125,17 @@ SmbclientStorage::OpenDirectory(std::string_view uri_utf8)
|
|||||||
{
|
{
|
||||||
std::string mapped = MapUTF8(uri_utf8);
|
std::string mapped = MapUTF8(uri_utf8);
|
||||||
|
|
||||||
int handle;
|
SMBCFILE *handle;
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
||||||
handle = smbc_opendir(mapped.c_str());
|
handle = ctx.OpenDirectory(mapped.c_str());
|
||||||
if (handle < 0)
|
if (handle == nullptr)
|
||||||
throw MakeErrno("Failed to open directory");
|
throw MakeErrno("Failed to open directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<SmbclientDirectoryReader>(std::move(mapped),
|
return std::make_unique<SmbclientDirectoryReader>(ctx,
|
||||||
|
std::move(mapped),
|
||||||
handle);
|
handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +151,7 @@ SkipNameFS(const char *name) noexcept
|
|||||||
SmbclientDirectoryReader::~SmbclientDirectoryReader()
|
SmbclientDirectoryReader::~SmbclientDirectoryReader()
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
const std::lock_guard<Mutex> lock(smbclient_mutex);
|
||||||
smbc_close(handle);
|
ctx.CloseDirectory(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@ -155,8 +159,7 @@ SmbclientDirectoryReader::Read() noexcept
|
|||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
||||||
|
|
||||||
struct smbc_dirent *e;
|
while (auto e = ctx.ReadDirectory(handle)) {
|
||||||
while ((e = smbc_readdir(handle)) != nullptr) {
|
|
||||||
name = e->name;
|
name = e->name;
|
||||||
if (!SkipNameFS(name))
|
if (!SkipNameFS(name))
|
||||||
return name;
|
return name;
|
||||||
@ -169,7 +172,7 @@ StorageFileInfo
|
|||||||
SmbclientDirectoryReader::GetInfo([[maybe_unused]] bool follow)
|
SmbclientDirectoryReader::GetInfo([[maybe_unused]] bool follow)
|
||||||
{
|
{
|
||||||
const std::string path = PathTraitsUTF8::Build(base, name);
|
const std::string path = PathTraitsUTF8::Build(base, name);
|
||||||
return ::GetInfo(path.c_str());
|
return ::GetInfo(ctx, path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Storage>
|
static std::unique_ptr<Storage>
|
||||||
|
Loading…
Reference in New Issue
Block a user