20#include <sys/iosupport.h>
22#include <smb2/libsmb2.h>
24#include "OgcSmbDriver.h"
28#include "gamecube/GameCubeNetwork.h"
30#include "wii/WiiNetwork.h"
33smb2_context * OgcSmbDriver::ctx =
nullptr;
36static const char *
const smbDeviceName =
"smb";
41static char lastError[256] =
"";
43static void CaptureSmb2Error(
const char * context)
47 if(detail && detail[0])
48 snprintf(lastError,
sizeof(lastError),
"%s: %s", context, detail);
50 snprintf(lastError,
sizeof(lastError),
"%s", context);
56static const char * RelativePath(
const char * path)
61 const char * colon = strchr(path,
':');
70static int SetErrnoFromSmb2(
int smb2Result)
73 errno = (smb2Result < 0) ? -smb2Result : EIO;
77static void FillStatFromSmb2(
struct stat * st,
const smb2_stat_64 & src)
79 memset(st, 0,
sizeof(
struct stat));
80 st->st_size = (off_t)src.smb2_size;
81 st->st_mode = (src.smb2_type == SMB2_TYPE_DIRECTORY) ? (S_IFDIR | 0777) : (S_IFREG | 0666);
82 st->st_nlink = src.smb2_nlink ? src.smb2_nlink : 1;
83 st->st_mtime = (time_t)src.smb2_mtime;
84 st->st_atime = (time_t)src.smb2_atime;
85 st->st_ctime = (time_t)src.smb2_ctime;
101static int smb_open_r(
struct _reent *,
void * fileStruct,
const char * path,
int flags,
int)
109 bool append = (flags & O_APPEND) != 0;
113 CaptureSmb2Error(
"open");
114 return SetErrnoFromSmb2(-EIO);
124 state->
offset = st.smb2_size;
130static int smb_close_r(
struct _reent *,
void * fileStruct)
137static ssize_t smb_write_r(
struct _reent *,
void * fileStruct,
const char * ptr,
size_t len)
142 return SetErrnoFromSmb2(written);
148static ssize_t smb_read_r(
struct _reent *,
void * fileStruct,
char * ptr,
size_t len)
153 return SetErrnoFromSmb2(bytesRead);
155 state->
offset += bytesRead;
159static off_t smb_seek_r(
struct _reent *,
void * fileStruct, off_t pos,
int dir)
166 else if(dir == SEEK_END)
170 return SetErrnoFromSmb2(-EIO);
175 state->
offset = base + pos;
176 return (off_t)state->
offset;
179static int smb_fstat_r(
struct _reent *,
void * fileStruct,
struct stat * st)
186 CaptureSmb2Error(
"fstat");
187 return SetErrnoFromSmb2(result);
190 FillStatFromSmb2(st, s);
194static int smb_stat_r(
struct _reent *,
const char * path,
struct stat * st)
200 CaptureSmb2Error(
"stat");
201 return SetErrnoFromSmb2(result);
204 FillStatFromSmb2(st, s);
208static int smb_unlink_r(
struct _reent *,
const char * path)
211 return (result < 0) ? SetErrnoFromSmb2(result) : 0;
214static int smb_mkdir_r(
struct _reent *,
const char * path,
int)
217 return (result < 0) ? SetErrnoFromSmb2(result) : 0;
220static int smb_rmdir_r(
struct _reent *,
const char * path)
223 return (result < 0) ? SetErrnoFromSmb2(result) : 0;
235static DIR_ITER * smb_diropen_r(
struct _reent *, DIR_ITER * dirState,
const char * path)
237 const char * relPath = RelativePath(path);
242 snprintf(context,
sizeof(context),
"opendir '%s'", relPath[0] ? relPath :
"(root)");
243 CaptureSmb2Error(context);
244 SetErrnoFromSmb2(-ENOENT);
252static int smb_dirreset_r(
struct _reent *, DIR_ITER * dirState)
258static int smb_dirnext_r(
struct _reent *, DIR_ITER * dirState,
char * filename,
struct stat * filestat)
260 smb2dir * dir = ((
SmbDirState *)dirState->dirStruct)->dir;
268 strncpy(filename, entry->name, NAME_MAX);
269 filename[NAME_MAX] =
'\0';
270 FillStatFromSmb2(filestat, entry->st);
274static int smb_dirclose_r(
struct _reent *, DIR_ITER * dirState)
283static devoptab_t BuildSmbDevoptab()
285 devoptab_t dotab = {};
287 dotab.name = smbDeviceName;
289 dotab.open_r = smb_open_r;
290 dotab.close_r = smb_close_r;
291 dotab.write_r = smb_write_r;
292 dotab.read_r = smb_read_r;
293 dotab.seek_r = smb_seek_r;
294 dotab.fstat_r = smb_fstat_r;
295 dotab.stat_r = smb_stat_r;
296 dotab.unlink_r = smb_unlink_r;
297 dotab.mkdir_r = smb_mkdir_r;
298 dotab.rmdir_r = smb_rmdir_r;
300 dotab.diropen_r = smb_diropen_r;
301 dotab.dirreset_r = smb_dirreset_r;
302 dotab.dirnext_r = smb_dirnext_r;
303 dotab.dirclose_r = smb_dirclose_r;
343 snprintf(lastError,
sizeof(lastError),
"Network unavailable");
351 if(info.
host[0] ==
'\0' || info.
share[0] ==
'\0')
354 if(ctx && strcmp(current.host, info.
host) == 0 && strcmp(current.share, info.
share) == 0 && strcmp(current.user, info.
user) == 0)
355 return SmbConnectResult::Success;
361 ctx = smb2_init_context();
364 snprintf(lastError,
sizeof(lastError),
"Connection failed");
368 smb2_set_security_mode(ctx, SMB2_NEGOTIATE_SIGNING_ENABLED);
369 smb2_set_version(ctx, SMB2_VERSION_ANY2);
370 smb2_set_timeout(ctx, 30);
371 if(info.
user[0] !=
'\0')
372 smb2_set_user(ctx, info.
user);
373 smb2_set_password(ctx, info.
password);
382 int connectResult = smb2_connect_share(ctx, info.
host, info.
share, info.
user[0] ? info.
user :
nullptr);
383 if(connectResult != 0)
385 CaptureSmb2Error(
"connect_share");
386 smb2_destroy_context(ctx);
391 static devoptab_t smbDevoptab = BuildSmbDevoptab();
392 int devnum = AddDevice(&smbDevoptab);
396 snprintf(lastError,
sizeof(lastError),
"Add device failed");
397 smb2_disconnect_share(ctx);
398 smb2_destroy_context(ctx);
402 devoptabAdded =
true;
405 return SmbConnectResult::Success;
412 RemoveDevice(
"smb:");
413 devoptabAdded =
false;
418 smb2_disconnect_share(ctx);
419 smb2_destroy_context(ctx);
423 memset(¤t, 0,
sizeof(current));
430 case SmbConnectResult::Success:
return "Connected.";
434 default:
return "Unknown network share error.";
static void shutdown()
No-op on GameCube.
static bool isUp()
Non-blocking: true if the console currently has a usable IP.
static bool ensureUp()
Brings the network interface up if it isn't already, or confirms it's still alive if it is.
void shutdown() override
Disconnects if connected and releases whatever init() set up.
bool ensureNetworkUp() override
Ensures the network is up via the platform's network helper (WiiNetwork or GameCubeNetwork).
SmbConnectResult connect(const SmbShareInfo &info) override
Attempts to connect and mount in one call.
const char * connectResultMessage(SmbConnectResult result) const override
Short, user-displayable reason for a non-Success SmbConnectResult.
void disconnect() override
Unmounts and drops the connection.
static smb2_context * getContext()
The active context, used by the free-function devoptab callbacks in OgcSmbDriver.cpp.
void init() override
One-time setup.
bool isNetworkUp() const override
True if the network is already up, i.e.
const char * getLastError() const override
Raw, implementation-specific detail behind the last failure.
static void shutdown()
Stops and joins the background bring-up thread.
static bool isUp()
Non-blocking: true if the console currently has a usable IP.
static bool ensureUp(bool(*cancel)(void)=nullptr)
Brings the network interface up if it isn't already, or confirms it's still alive if it is.
SmbConnectResult
Result of a single connect() attempt.
@ ConnectFailed
network's up but the server/share/credentials didn't work
@ InvalidSettings
host or share is empty - nothing to try
@ NetworkUnavailable
no usable network connection at all
Per-open-directory state for the smb: devoptab directory callbacks.
smb2dir * dir
libsmb2 handle of the directory being iterated
Per-open-file state for the smb: devoptab file callbacks.
smb2fh * fh
libsmb2 handle of the open file
uint64_t offset
Current read/write position, passed explicitly to smb2_pread/smb2_pwrite.
Credentials/target for a single SMB share.
char share[64]
share name, eg.
char password[32]
"" for guest/anonymous
char user[32]
"" for guest/anonymous
char host[64]
server IP or hostname