4949#include < retro_environment.h>
5050#include < uwp/std_filesystem_compat.h>
5151
52+ #ifdef HAVE_SMBCLIENT
53+ #include " vfs_implementation_smb.h"
54+ #endif
55+
5256namespace
5357{
5458 /* UWP deals with paths containing / instead of
@@ -76,6 +80,13 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
7680 if (!stream)
7781 return -1 ;
7882
83+ #ifdef HAVE_SMBCLIENT
84+ if (stream->scheme == VFS_SCHEME_SMB)
85+ {
86+ retro_vfs_file_close_smb (stream);
87+ }
88+ #endif
89+
7990 if (stream->fp )
8091 fclose (stream->fp );
8192
@@ -94,6 +105,11 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
94105
95106int retro_vfs_file_error_impl (libretro_vfs_implementation_file* stream)
96107{
108+ #ifdef HAVE_SMBCLIENT
109+ if (stream->scheme == VFS_SCHEME_SMB)
110+ return retro_vfs_file_error_smb (stream);
111+ #endif
112+
97113 return ferror (stream->fp );
98114}
99115
@@ -117,7 +133,13 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
117133 return -1 ;
118134
119135 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
136+ {
137+ #ifdef HAVE_SMBCLIENT
138+ if (stream->scheme == VFS_SCHEME_SMB)
139+ return retro_vfs_file_tell_smb (stream);
140+ #endif
120141 return _ftelli64 (stream->fp );
142+ }
121143 if (lseek (stream->fd , 0 , SEEK_CUR) < 0 )
122144 return -1 ;
123145
@@ -132,7 +154,13 @@ int64_t retro_vfs_file_seek_internal(
132154 return -1 ;
133155
134156 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
157+ {
158+ #ifdef HAVE_SMBCLIENT
159+ if (stream->scheme == VFS_SCHEME_SMB)
160+ return retro_vfs_file_seek_smb (stream, offset, whence);
161+ #endif
135162 return _fseeki64 (stream->fp , offset, whence);
163+ }
136164 if (lseek (stream->fd , (off_t )offset, whence) < 0 )
137165 return -1 ;
138166
@@ -148,25 +176,51 @@ int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
148176int64_t retro_vfs_file_read_impl (libretro_vfs_implementation_file* stream,
149177 void * s, uint64_t len)
150178{
151- if (!stream || (!stream-> fp && stream-> fh == INVALID_HANDLE_VALUE) || !s )
152- return -1 ;
179+ if (!stream)
180+ return -1 ;
153181
154- if (stream->fh != INVALID_HANDLE_VALUE)
155- {
156- DWORD _bytes_read;
157- ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
158- return (int64_t )_bytes_read;
159- }
182+ #ifdef HAVE_SMBCLIENT
183+ if (stream->scheme == VFS_SCHEME_SMB)
184+ return retro_vfs_file_read_smb (stream, s, len);
185+ #endif
186+
187+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
188+ return -1 ;
189+
190+ if (stream->fh != INVALID_HANDLE_VALUE)
191+ {
192+ DWORD _bytes_read;
193+ ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
194+ return (int64_t )_bytes_read;
195+ }
160196
161197 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
162- return fread (s, 1 , (size_t )len, stream->fp );
198+ return fread (s, 1 , (size_t )len, stream->fp );
163199 return read (stream->fd , s, (size_t )len);
164200}
165201
166202
167203int64_t retro_vfs_file_write_impl (libretro_vfs_implementation_file* stream, const void * s, uint64_t len)
168204{
169- if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
205+ if (!stream)
206+ return -1 ;
207+
208+ #ifdef HAVE_SMBCLIENT
209+ if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&
210+ stream->scheme == VFS_SCHEME_SMB)
211+ {
212+ int64_t pos = 0 ;
213+ ssize_t ret = -1 ;
214+
215+ pos = retro_vfs_file_tell_smb (stream);
216+ ret = retro_vfs_file_write_smb (stream, s, len);
217+ if (ret != -1 && pos + ret > stream->size )
218+ stream->size = pos + ret;
219+ return ret;
220+ }
221+ #endif
222+
223+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
170224 return -1 ;
171225
172226 if (stream->fh != INVALID_HANDLE_VALUE)
@@ -237,6 +291,9 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
237291 stream->mapsize = 0 ;
238292 stream->mapped = NULL ;
239293 stream->scheme = VFS_SCHEME_NONE;
294+ #ifdef HAVE_SMBCLIENT
295+ stream->smb_fh = 0 ;
296+ #endif
240297
241298#ifdef VFS_FRONTEND
242299 if ( path
@@ -253,6 +310,20 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
253310 path += sizeof (" vfsonly://" )-1 ;
254311#endif
255312
313+ #ifdef HAVE_SMBCLIENT
314+ if ( path
315+ && path[0 ] == ' s'
316+ && path[1 ] == ' m'
317+ && path[2 ] == ' b'
318+ && path[3 ] == ' :'
319+ && path[4 ] == ' /'
320+ && path[5 ] == ' /'
321+ && path[6 ] != ' \0 ' )
322+ {
323+ stream->scheme = VFS_SCHEME_SMB;
324+ }
325+ #endif
326+
256327 path_wide = utf8_to_utf16_string_alloc (path);
257328 windowsize_path (path_wide);
258329 path_wstring = path_wide;
@@ -317,6 +388,16 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
317388 ? OPEN_ALWAYS
318389 : CREATE_ALWAYS;
319390
391+ #ifdef HAVE_SMBCLIENT
392+ if (stream->scheme == VFS_SCHEME_SMB)
393+ {
394+ if (!retro_vfs_file_open_smb (stream, path, mode, hints))
395+ goto error;
396+
397+ return stream;
398+ }
399+ #endif
400+
320401 if ((file_handle = CreateFile2FromAppW (path_wstring.data (), desireAccess,
321402 FILE_SHARE_READ, creationDisposition, NULL )) == INVALID_HANDLE_VALUE)
322403 goto error;
@@ -631,6 +712,10 @@ struct libretro_vfs_implementation_dir
631712 HANDLE directory;
632713 bool next;
633714 char path[PATH_MAX_LENGTH];
715+ #ifdef HAVE_SMBCLIENT
716+ intptr_t smb_directory;
717+ char smb_path[PATH_MAX_LENGTH];
718+ #endif
634719};
635720
636721libretro_vfs_implementation_dir* retro_vfs_opendir_impl (
@@ -653,6 +738,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
653738
654739 _len = strlcpy (path_buf, name, sizeof (path_buf));
655740
741+ #ifdef HAVE_SMBCLIENT
742+ if (name[0 ]==' s' && name[1 ]==' m' && name[2 ]==' b' &&
743+ name[3 ]==' :' && name[4 ]==' /' && name[5 ]==' /' && name[6 ] != ' \0 ' )
744+ {
745+ intptr_t dh = retro_vfs_opendir_smb (name, include_hidden);
746+ if (dh < 0 )
747+ {
748+ free (rdir->orig_path );
749+ free (rdir);
750+ return NULL ;
751+ }
752+ rdir->smb_directory = dh;
753+ rdir->smb_path [0 ] = ' \0 ' ;
754+ return rdir;
755+ }
756+ #endif
757+
656758 /* Non-NT platforms don't like extra slashes in the path */
657759 if (path_buf[_len - 1 ] != ' \\ ' )
658760 path_buf[_len++] = ' \\ ' ;
@@ -682,6 +784,22 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
682784
683785bool retro_vfs_readdir_impl (libretro_vfs_implementation_dir* rdir)
684786{
787+ #ifdef HAVE_SMBCLIENT
788+ if (rdir->smb_directory != 0 )
789+ {
790+ struct smbc_dirent *de = retro_vfs_readdir_smb (rdir->smb_directory );
791+ if (!de)
792+ return false ;
793+ strlcpy (rdir->smb_path , de->name , sizeof (rdir->smb_path ));
794+ return true ;
795+ }
796+ /* If we opened an SMB path but failed, do not fall through to native readdir */
797+ if (rdir->orig_path &&
798+ rdir->orig_path [0 ]==' s' && rdir->orig_path [1 ]==' m' && rdir->orig_path [2 ]==' b' &&
799+ rdir->orig_path [3 ]==' :' && rdir->orig_path [4 ]==' /' && rdir->orig_path [5 ]==' /' )
800+ return false ;
801+ #endif
802+
685803 if (rdir->next )
686804 return (FindNextFileW (rdir->directory , &rdir->entry ) != 0 );
687805
@@ -691,6 +809,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
691809
692810const char * retro_vfs_dirent_get_name_impl (libretro_vfs_implementation_dir* rdir)
693811{
812+ #ifdef HAVE_SMBCLIENT
813+ if (rdir->smb_directory != 0 )
814+ return rdir->smb_path ;
815+ #endif
694816 char * name = utf16_to_utf8_string_alloc (rdir->entry .cFileName );
695817 memset (rdir->entry .cFileName , 0 , sizeof (rdir->entry .cFileName ));
696818 strlcpy ((char *)rdir->entry .cFileName , name, sizeof (rdir->entry .cFileName ));
@@ -701,6 +823,22 @@ const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir
701823
702824bool retro_vfs_dirent_is_dir_impl (libretro_vfs_implementation_dir* rdir)
703825{
826+ #ifdef HAVE_SMBCLIENT
827+ if (rdir->smb_directory != 0 )
828+ {
829+ char full[PATH_MAX_LENGTH];
830+ const char *name = retro_vfs_dirent_get_name_impl (rdir);
831+
832+ if (!name)
833+ return false ;
834+
835+ fill_pathname_join_special (full, rdir->orig_path , name, sizeof (full));
836+ int32_t sz = 0 ;
837+ int st = retro_vfs_stat_smb (full, &sz);
838+
839+ return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0 ;
840+ }
841+ #endif
704842 const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry ;
705843 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
706844}
@@ -710,7 +848,15 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
710848 if (!rdir)
711849 return -1 ;
712850
713- if (rdir->directory != INVALID_HANDLE_VALUE)
851+ #ifdef HAVE_SMBCLIENT
852+ if (rdir->smb_directory != 0 )
853+ {
854+ retro_vfs_closedir_smb (rdir->smb_directory );
855+ rdir->smb_directory = 0 ;
856+ }
857+ #endif
858+
859+ if (rdir->directory && rdir->directory != INVALID_HANDLE_VALUE)
714860 FindClose (rdir->directory );
715861
716862 if (rdir->orig_path )
0 commit comments