*/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
|
||||
- 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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user