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,11 @@ 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+ retro_vfs_file_close_smb (stream);
86+ #endif
87+
7988 if (stream->fp )
8089 fclose (stream->fp );
8190
@@ -94,6 +103,11 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
94103
95104int retro_vfs_file_error_impl (libretro_vfs_implementation_file* stream)
96105{
106+ #ifdef HAVE_SMBCLIENT
107+ if (stream->scheme == VFS_SCHEME_SMB)
108+ return retro_vfs_file_error_smb (stream);
109+ #endif
110+
97111 return ferror (stream->fp );
98112}
99113
@@ -117,7 +131,13 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
117131 return -1 ;
118132
119133 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
134+ {
135+ #ifdef HAVE_SMBCLIENT
136+ if (stream->scheme == VFS_SCHEME_SMB)
137+ return retro_vfs_file_tell_smb (stream);
138+ #endif
120139 return _ftelli64 (stream->fp );
140+ }
121141 if (lseek (stream->fd , 0 , SEEK_CUR) < 0 )
122142 return -1 ;
123143
@@ -132,7 +152,13 @@ int64_t retro_vfs_file_seek_internal(
132152 return -1 ;
133153
134154 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
155+ {
156+ #ifdef HAVE_SMBCLIENT
157+ if (stream->scheme == VFS_SCHEME_SMB)
158+ return retro_vfs_file_seek_smb (stream, offset, whence);
159+ #endif
135160 return _fseeki64 (stream->fp , offset, whence);
161+ }
136162 if (lseek (stream->fd , (off_t )offset, whence) < 0 )
137163 return -1 ;
138164
@@ -148,25 +174,51 @@ int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
148174int64_t retro_vfs_file_read_impl (libretro_vfs_implementation_file* stream,
149175 void * s, uint64_t len)
150176{
151- if (!stream || (!stream-> fp && stream-> fh == INVALID_HANDLE_VALUE) || !s )
152- return -1 ;
177+ if (!stream)
178+ return -1 ;
153179
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- }
180+ #ifdef HAVE_SMBCLIENT
181+ if (stream->scheme == VFS_SCHEME_SMB)
182+ return retro_vfs_file_read_smb (stream, s, len);
183+ #endif
184+
185+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
186+ return -1 ;
187+
188+ if (stream->fh != INVALID_HANDLE_VALUE)
189+ {
190+ DWORD _bytes_read;
191+ ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
192+ return (int64_t )_bytes_read;
193+ }
160194
161195 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
162- return fread (s, 1 , (size_t )len, stream->fp );
196+ return fread (s, 1 , (size_t )len, stream->fp );
163197 return read (stream->fd , s, (size_t )len);
164198}
165199
166200
167201int64_t retro_vfs_file_write_impl (libretro_vfs_implementation_file* stream, const void * s, uint64_t len)
168202{
169- if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
203+ if (!stream)
204+ return -1 ;
205+
206+ #ifdef HAVE_SMBCLIENT
207+ if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&
208+ stream->scheme == VFS_SCHEME_SMB)
209+ {
210+ int64_t pos = 0 ;
211+ ssize_t ret = -1 ;
212+
213+ pos = retro_vfs_file_tell_smb (stream);
214+ ret = retro_vfs_file_write_smb (stream, s, len);
215+ if (ret != -1 && pos + ret > stream->size )
216+ stream->size = pos + ret;
217+ return ret;
218+ }
219+ #endif
220+
221+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
170222 return -1 ;
171223
172224 if (stream->fh != INVALID_HANDLE_VALUE)
@@ -237,6 +289,9 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
237289 stream->mapsize = 0 ;
238290 stream->mapped = NULL ;
239291 stream->scheme = VFS_SCHEME_NONE;
292+ #ifdef HAVE_SMBCLIENT
293+ stream->smb_fh = 0 ;
294+ #endif
240295
241296#ifdef VFS_FRONTEND
242297 if ( path
@@ -253,6 +308,20 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
253308 path += sizeof (" vfsonly://" )-1 ;
254309#endif
255310
311+ #ifdef HAVE_SMBCLIENT
312+ if ( path
313+ && path[0 ] == ' s'
314+ && path[1 ] == ' m'
315+ && path[2 ] == ' b'
316+ && path[3 ] == ' :'
317+ && path[4 ] == ' /'
318+ && path[5 ] == ' /'
319+ && path[6 ] != ' \0 ' )
320+ {
321+ stream->scheme = VFS_SCHEME_SMB;
322+ }
323+ #endif
324+
256325 path_wide = utf8_to_utf16_string_alloc (path);
257326 windowsize_path (path_wide);
258327 path_wstring = path_wide;
@@ -317,6 +386,16 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
317386 ? OPEN_ALWAYS
318387 : CREATE_ALWAYS;
319388
389+ #ifdef HAVE_SMBCLIENT
390+ if (stream->scheme == VFS_SCHEME_SMB)
391+ {
392+ if (!retro_vfs_file_open_smb (stream, path, mode, hints))
393+ goto error;
394+
395+ return stream;
396+ }
397+ #endif
398+
320399 if ((file_handle = CreateFile2FromAppW (path_wstring.data (), desireAccess,
321400 FILE_SHARE_READ, creationDisposition, NULL )) == INVALID_HANDLE_VALUE)
322401 goto error;
@@ -631,6 +710,10 @@ struct libretro_vfs_implementation_dir
631710 HANDLE directory;
632711 bool next;
633712 char path[PATH_MAX_LENGTH];
713+ #ifdef HAVE_SMBCLIENT
714+ intptr_t smb_directory;
715+ char smb_path[PATH_MAX_LENGTH];
716+ #endif
634717};
635718
636719libretro_vfs_implementation_dir* retro_vfs_opendir_impl (
@@ -653,6 +736,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
653736
654737 _len = strlcpy (path_buf, name, sizeof (path_buf));
655738
739+ #ifdef HAVE_SMBCLIENT
740+ if (name[0 ]==' s' && name[1 ]==' m' && name[2 ]==' b' &&
741+ name[3 ]==' :' && name[4 ]==' /' && name[5 ]==' /' && name[6 ] != ' \0 ' )
742+ {
743+ intptr_t dh = retro_vfs_opendir_smb (name, include_hidden);
744+ if (dh <= 0 )
745+ {
746+ free (rdir->orig_path );
747+ free (rdir);
748+ return NULL ;
749+ }
750+ rdir->smb_directory = dh;
751+ rdir->smb_path [0 ] = ' \0 ' ;
752+ return rdir;
753+ }
754+ #endif
755+
656756 /* Non-NT platforms don't like extra slashes in the path */
657757 if (path_buf[_len - 1 ] != ' \\ ' )
658758 path_buf[_len++] = ' \\ ' ;
@@ -682,6 +782,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
682782
683783bool retro_vfs_readdir_impl (libretro_vfs_implementation_dir* rdir)
684784{
785+ #ifdef HAVE_SMBCLIENT
786+ if (rdir && rdir->smb_directory != 0 )
787+ {
788+ struct smbc_dirent *de = retro_vfs_readdir_smb (rdir->smb_directory );
789+ if (!de)
790+ return false ;
791+
792+ strlcpy (rdir->smb_path , de->name , sizeof (rdir->smb_path ));
793+ return true ;
794+ }
795+ /* If we opened an SMB path but failed, do not fall through to native readdir */
796+ if (rdir->orig_path &&
797+ rdir->orig_path [0 ] == ' s' && rdir->orig_path [1 ] == ' m' && rdir->orig_path [2 ] == ' b' &&
798+ rdir->orig_path [3 ] == ' :' && rdir->orig_path [4 ] == ' /' && rdir->orig_path [5 ] == ' /' )
799+ return false ;
800+ #endif
801+
685802 if (rdir->next )
686803 return (FindNextFileW (rdir->directory , &rdir->entry ) != 0 );
687804
@@ -691,6 +808,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
691808
692809const char * retro_vfs_dirent_get_name_impl (libretro_vfs_implementation_dir* rdir)
693810{
811+ #ifdef HAVE_SMBCLIENT
812+ if (rdir && rdir->smb_directory != 0 )
813+ return rdir->smb_path ;
814+ #endif
694815 char * name = utf16_to_utf8_string_alloc (rdir->entry .cFileName );
695816 memset (rdir->entry .cFileName , 0 , sizeof (rdir->entry .cFileName ));
696817 strlcpy ((char *)rdir->entry .cFileName , name, sizeof (rdir->entry .cFileName ));
@@ -701,6 +822,22 @@ const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir
701822
702823bool retro_vfs_dirent_is_dir_impl (libretro_vfs_implementation_dir* rdir)
703824{
825+ #ifdef HAVE_SMBCLIENT
826+ if (rdir && rdir->smb_directory != 0 )
827+ {
828+ char full[PATH_MAX_LENGTH];
829+ const char *name = retro_vfs_dirent_get_name_impl (rdir);
830+
831+ if (!name)
832+ return false ;
833+
834+ fill_pathname_join_special (full, rdir->orig_path , name, sizeof (full));
835+ int32_t sz = 0 ;
836+ int st = retro_vfs_stat_smb (full, &sz);
837+
838+ return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0 ;
839+ }
840+ #endif
704841 const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry ;
705842 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
706843}
@@ -710,7 +847,15 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
710847 if (!rdir)
711848 return -1 ;
712849
713- if (rdir->directory != INVALID_HANDLE_VALUE)
850+ #ifdef HAVE_SMBCLIENT
851+ if (rdir->smb_directory != 0 )
852+ {
853+ retro_vfs_closedir_smb (rdir->smb_directory );
854+ rdir->smb_directory = 0 ;
855+ }
856+ #endif
857+
858+ if (rdir->directory && rdir->directory != INVALID_HANDLE_VALUE)
714859 FindClose (rdir->directory );
715860
716861 if (rdir->orig_path )
0 commit comments