Skip to content

Commit fbeb6f4

Browse files
committed
Add SMB implementation to UWP
1 parent 1b83f1a commit fbeb6f4

File tree

1 file changed

+159
-10
lines changed

1 file changed

+159
-10
lines changed

libretro-common/vfs/vfs_implementation_uwp.cpp

Lines changed: 159 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
#include <uwp/uwp_async.h>
5454
#include <uwp/std_filesystem_compat.h>
5555

56+
#ifdef HAVE_SMBCLIENT
57+
#include "vfs_implementation_smb.h"
58+
#endif
59+
5660
namespace
5761
{
5862
/* UWP deals with paths containing / instead of
@@ -90,6 +94,9 @@ struct libretro_vfs_implementation_file
9094
int fd;
9195
unsigned hints;
9296
enum vfs_scheme scheme;
97+
#ifdef HAVE_SMBCLIENT
98+
intptr_t smb_fh;
99+
#endif
93100
};
94101

95102
#define RFILE_HINT_UNBUFFERED (1 << 8)
@@ -99,6 +106,13 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
99106
if (!stream)
100107
return -1;
101108

109+
#ifdef HAVE_SMBCLIENT
110+
if (stream->scheme == VFS_SCHEME_SMB)
111+
{
112+
retro_vfs_file_close_smb(stream);
113+
}
114+
#endif
115+
102116
if (stream->fp)
103117
fclose(stream->fp);
104118

@@ -117,6 +131,11 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
117131

118132
int retro_vfs_file_error_impl(libretro_vfs_implementation_file* stream)
119133
{
134+
#ifdef HAVE_SMBCLIENT
135+
if (stream->scheme == VFS_SCHEME_SMB)
136+
return retro_vfs_file_error_smb(stream);
137+
#endif
138+
120139
return ferror(stream->fp);
121140
}
122141

@@ -142,7 +161,13 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
142161
return -1;
143162

144163
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
164+
{
165+
#ifdef HAVE_SMBCLIENT
166+
if (stream->scheme == VFS_SCHEME_SMB)
167+
return retro_vfs_file_tell_smb(stream);
168+
#endif
145169
return _ftelli64(stream->fp);
170+
}
146171
if ((val = lseek(stream->fd, 0, SEEK_CUR)) < 0)
147172
return -1;
148173

@@ -159,7 +184,13 @@ int64_t retro_vfs_file_seek_internal(
159184
return -1;
160185

161186
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
187+
{
188+
#ifdef HAVE_SMBCLIENT
189+
if (stream->scheme == VFS_SCHEME_SMB)
190+
return retro_vfs_file_seek_smb(stream, offset, whence);
191+
#endif
162192
return _fseeki64(stream->fp, offset, whence);
193+
}
163194
if ((val = lseek(stream->fd, (off_t)offset, whence)) < 0)
164195
return -1;
165196

@@ -175,25 +206,51 @@ int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
175206
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file* stream,
176207
void* s, uint64_t len)
177208
{
178-
if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
179-
return -1;
209+
if (!stream)
210+
return -1;
180211

181-
if (stream->fh != INVALID_HANDLE_VALUE)
182-
{
183-
DWORD _bytes_read;
184-
ReadFile(stream->fh, (char*)s, len, &_bytes_read, NULL);
185-
return (int64_t)_bytes_read;
186-
}
212+
#ifdef HAVE_SMBCLIENT
213+
if (stream->scheme == VFS_SCHEME_SMB)
214+
return retro_vfs_file_read_smb(stream, s, len);
215+
#endif
216+
217+
if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
218+
return -1;
219+
220+
if (stream->fh != INVALID_HANDLE_VALUE)
221+
{
222+
DWORD _bytes_read;
223+
ReadFile(stream->fh, (char*)s, len, &_bytes_read, NULL);
224+
return (int64_t)_bytes_read;
225+
}
187226

188227
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
189-
return fread(s, 1, (size_t)len, stream->fp);
228+
return fread(s, 1, (size_t)len, stream->fp);
190229
return read(stream->fd, s, (size_t)len);
191230
}
192231

193232

194233
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file* stream, const void* s, uint64_t len)
195234
{
196-
if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
235+
if (!stream)
236+
return -1;
237+
238+
#ifdef HAVE_SMBCLIENT
239+
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&
240+
stream->scheme == VFS_SCHEME_SMB)
241+
{
242+
int64_t pos = 0;
243+
ssize_t ret = -1;
244+
245+
pos = retro_vfs_file_tell_smb(stream);
246+
ret = retro_vfs_file_write_smb(stream, s, len);
247+
if (ret != -1 && pos + ret > stream->size)
248+
stream->size = pos + ret;
249+
return ret;
250+
}
251+
#endif
252+
253+
if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
197254
return -1;
198255

199256
if (stream->fh != INVALID_HANDLE_VALUE)
@@ -264,6 +321,9 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
264321
stream->mapsize = 0;
265322
stream->mapped = NULL;
266323
stream->scheme = VFS_SCHEME_NONE;
324+
#ifdef HAVE_SMBCLIENT
325+
stream->smb_fh = 0;
326+
#endif
267327

268328
#ifdef VFS_FRONTEND
269329
if ( path
@@ -280,6 +340,20 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
280340
path += sizeof("vfsonly://")-1;
281341
#endif
282342

343+
#ifdef HAVE_SMBCLIENT
344+
if ( path
345+
&& path[0] == 's'
346+
&& path[1] == 'm'
347+
&& path[2] == 'b'
348+
&& path[3] == ':'
349+
&& path[4] == '/'
350+
&& path[5] == '/'
351+
&& path[6] != '\0')
352+
{
353+
stream->scheme = VFS_SCHEME_SMB;
354+
}
355+
#endif
356+
283357
path_wide = utf8_to_utf16_string_alloc(path);
284358
windowsize_path(path_wide);
285359
path_wstring = path_wide;
@@ -344,6 +418,16 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
344418
? OPEN_ALWAYS
345419
: CREATE_ALWAYS;
346420

421+
#ifdef HAVE_SMBCLIENT
422+
if (stream->scheme == VFS_SCHEME_SMB)
423+
{
424+
if (!retro_vfs_file_open_smb(stream, path, mode, hints))
425+
goto error;
426+
427+
return stream;
428+
}
429+
#endif
430+
347431
if ((file_handle = CreateFile2FromAppW(path_wstring.data(), desireAccess,
348432
FILE_SHARE_READ, creationDisposition, NULL)) == INVALID_HANDLE_VALUE)
349433
goto error;
@@ -658,6 +742,10 @@ struct libretro_vfs_implementation_dir
658742
HANDLE directory;
659743
bool next;
660744
char path[PATH_MAX_LENGTH];
745+
#ifdef HAVE_SMBCLIENT
746+
intptr_t smb_directory;
747+
char smb_path[PATH_MAX_LENGTH];
748+
#endif
661749
};
662750

663751
libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
@@ -680,6 +768,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
680768

681769
_len = strlcpy(path_buf, name, sizeof(path_buf));
682770

771+
#ifdef HAVE_SMBCLIENT
772+
if (name[0]=='s' && name[1]=='m' && name[2]=='b' &&
773+
name[3]==':' && name[4]=='/' && name[5]=='/' && name[6] != '\0')
774+
{
775+
intptr_t dh = retro_vfs_opendir_smb(name, include_hidden);
776+
if (dh < 0)
777+
{
778+
free(rdir->orig_path);
779+
free(rdir);
780+
return NULL;
781+
}
782+
rdir->smb_directory = dh;
783+
rdir->smb_path[0] = '\0';
784+
return rdir;
785+
}
786+
#endif
787+
683788
/* Non-NT platforms don't like extra slashes in the path */
684789
if (path_buf[_len - 1] != '\\')
685790
path_buf[_len++] = '\\';
@@ -709,6 +814,22 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
709814

710815
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
711816
{
817+
#ifdef HAVE_SMBCLIENT
818+
if (rdir->smb_directory != 0)
819+
{
820+
struct smbc_dirent *de = retro_vfs_readdir_smb(rdir->smb_directory);
821+
if (!de)
822+
return false;
823+
strlcpy(rdir->smb_path, de->name, sizeof(rdir->smb_path));
824+
return true;
825+
}
826+
/* If we opened an SMB path but failed, do not fall through to native readdir */
827+
if (rdir->orig_path &&
828+
rdir->orig_path[0]=='s' && rdir->orig_path[1]=='m' && rdir->orig_path[2]=='b' &&
829+
rdir->orig_path[3]==':' && rdir->orig_path[4]=='/' && rdir->orig_path[5]=='/' )
830+
return false;
831+
#endif
832+
712833
if (rdir->next)
713834
return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
714835

@@ -718,6 +839,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
718839

719840
const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir)
720841
{
842+
#ifdef HAVE_SMBCLIENT
843+
if (rdir->smb_directory != 0)
844+
return rdir->smb_path;
845+
#endif
721846
char* name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
722847
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
723848
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
@@ -728,6 +853,22 @@ const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir
728853

729854
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir* rdir)
730855
{
856+
#ifdef HAVE_SMBCLIENT
857+
if (rdir->smb_directory != 0)
858+
{
859+
char full[PATH_MAX_LENGTH];
860+
const char *name = retro_vfs_dirent_get_name_impl(rdir);
861+
862+
if (!name)
863+
return false;
864+
865+
fill_pathname_join_special(full, rdir->orig_path, name, sizeof(full));
866+
int32_t sz = 0;
867+
int st = retro_vfs_stat_smb(full, &sz);
868+
869+
return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
870+
}
871+
#endif
731872
const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry;
732873
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
733874
}
@@ -737,6 +878,14 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
737878
if (!rdir)
738879
return -1;
739880

881+
#ifdef HAVE_SMBCLIENT
882+
if (rdir->smb_directory != 0)
883+
{
884+
retro_vfs_closedir_smb(rdir->smb_directory);
885+
rdir->smb_directory = 0;
886+
}
887+
#endif
888+
740889
if (rdir->directory != INVALID_HANDLE_VALUE)
741890
FindClose(rdir->directory);
742891

0 commit comments

Comments
 (0)