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+
60+
5661namespace
5762{
5863 /* UWP deals with paths containing / instead of
@@ -90,6 +95,9 @@ struct libretro_vfs_implementation_file
9095 int fd;
9196 unsigned hints;
9297 enum vfs_scheme scheme;
98+ #ifdef HAVE_SMBCLIENT
99+ intptr_t smb_fh;
100+ #endif
93101};
94102
95103#define RFILE_HINT_UNBUFFERED (1 << 8 )
@@ -99,6 +107,13 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
99107 if (!stream)
100108 return -1 ;
101109
110+ #ifdef HAVE_SMBCLIENT
111+ if (stream->scheme == VFS_SCHEME_SMB)
112+ {
113+ retro_vfs_file_close_smb (stream);
114+ }
115+ #endif
116+
102117 if (stream->fp )
103118 fclose (stream->fp );
104119
@@ -117,6 +132,11 @@ int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
117132
118133int retro_vfs_file_error_impl (libretro_vfs_implementation_file* stream)
119134{
135+ #ifdef HAVE_SMBCLIENT
136+ if (stream->scheme == VFS_SCHEME_SMB)
137+ return retro_vfs_file_error_smb (stream);
138+ #endif
139+
120140 return ferror (stream->fp );
121141}
122142
@@ -140,7 +160,13 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
140160 return -1 ;
141161
142162 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
163+ {
164+ #ifdef HAVE_SMBCLIENT
165+ if (stream->scheme == VFS_SCHEME_SMB)
166+ return retro_vfs_file_tell_smb (stream);
167+ #endif
143168 return _ftelli64 (stream->fp );
169+ }
144170 if (lseek (stream->fd , 0 , SEEK_CUR) < 0 )
145171 return -1 ;
146172
@@ -155,7 +181,13 @@ int64_t retro_vfs_file_seek_internal(
155181 return -1 ;
156182
157183 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
184+ {
185+ #ifdef HAVE_SMBCLIENT
186+ if (stream->scheme == VFS_SCHEME_SMB)
187+ return retro_vfs_file_seek_smb (stream, offset, whence);
188+ #endif
158189 return _fseeki64 (stream->fp , offset, whence);
190+ }
159191 if (lseek (stream->fd , (off_t )offset, whence) < 0 )
160192 return -1 ;
161193
@@ -171,25 +203,51 @@ int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
171203int64_t retro_vfs_file_read_impl (libretro_vfs_implementation_file* stream,
172204 void * s, uint64_t len)
173205{
174- if (!stream || (!stream-> fp && stream-> fh == INVALID_HANDLE_VALUE) || !s )
175- return -1 ;
206+ if (!stream)
207+ return -1 ;
176208
177- if (stream->fh != INVALID_HANDLE_VALUE)
178- {
179- DWORD _bytes_read;
180- ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
181- return (int64_t )_bytes_read;
182- }
209+ #ifdef HAVE_SMBCLIENT
210+ if (stream->scheme == VFS_SCHEME_SMB)
211+ return retro_vfs_file_read_smb (stream, s, len);
212+ #endif
213+
214+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
215+ return -1 ;
216+
217+ if (stream->fh != INVALID_HANDLE_VALUE)
218+ {
219+ DWORD _bytes_read;
220+ ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
221+ return (int64_t )_bytes_read;
222+ }
183223
184224 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
185- return fread (s, 1 , (size_t )len, stream->fp );
225+ return fread (s, 1 , (size_t )len, stream->fp );
186226 return read (stream->fd , s, (size_t )len);
187227}
188228
189229
190230int64_t retro_vfs_file_write_impl (libretro_vfs_implementation_file* stream, const void * s, uint64_t len)
191231{
192- if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
232+ if (!stream)
233+ return -1 ;
234+
235+ #ifdef HAVE_SMBCLIENT
236+ if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&
237+ stream->scheme == VFS_SCHEME_SMB)
238+ {
239+ int64_t pos = 0 ;
240+ ssize_t ret = -1 ;
241+
242+ pos = retro_vfs_file_tell_smb (stream);
243+ ret = retro_vfs_file_write_smb (stream, s, len);
244+ if (ret != -1 && pos + ret > stream->size )
245+ stream->size = pos + ret;
246+ return ret;
247+ }
248+ #endif
249+
250+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
193251 return -1 ;
194252
195253 if (stream->fh != INVALID_HANDLE_VALUE)
@@ -276,6 +334,20 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
276334 path += sizeof (" vfsonly://" )-1 ;
277335#endif
278336
337+ #ifdef HAVE_SMBCLIENT
338+ if ( path
339+ && path[0 ] == ' s'
340+ && path[1 ] == ' m'
341+ && path[2 ] == ' b'
342+ && path[3 ] == ' :'
343+ && path[4 ] == ' /'
344+ && path[5 ] == ' /'
345+ && path[6 ] != ' \0 ' )
346+ {
347+ stream->scheme = VFS_SCHEME_SMB;
348+ }
349+ #endif
350+
279351 path_wide = utf8_to_utf16_string_alloc (path);
280352 windowsize_path (path_wide);
281353 path_wstring = path_wide;
@@ -340,6 +412,16 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
340412 ? OPEN_ALWAYS
341413 : CREATE_ALWAYS;
342414
415+ #ifdef HAVE_SMBCLIENT
416+ if (stream->scheme == VFS_SCHEME_SMB)
417+ {
418+ if (!retro_vfs_file_open_smb (stream, path, mode, hints))
419+ goto error;
420+
421+ return stream;
422+ }
423+ #endif
424+
343425 if ((file_handle = CreateFile2FromAppW (path_wstring.data (), desireAccess,
344426 FILE_SHARE_READ, creationDisposition, NULL )) == INVALID_HANDLE_VALUE)
345427 goto error;
@@ -654,6 +736,10 @@ struct libretro_vfs_implementation_dir
654736 HANDLE directory;
655737 bool next;
656738 char path[PATH_MAX_LENGTH];
739+ #ifdef HAVE_SMBCLIENT
740+ intptr_t smb_directory;
741+ char smb_path[PATH_MAX_LENGTH];
742+ #endif
657743};
658744
659745libretro_vfs_implementation_dir* retro_vfs_opendir_impl (
@@ -676,6 +762,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
676762
677763 _len = strlcpy (path_buf, name, sizeof (path_buf));
678764
765+ #ifdef HAVE_SMBCLIENT
766+ if (name[0 ]==' s' && name[1 ]==' m' && name[2 ]==' b' &&
767+ name[3 ]==' :' && name[4 ]==' /' && name[5 ]==' /' && name[6 ] != ' \0 ' )
768+ {
769+ intptr_t dh = retro_vfs_opendir_smb (name, include_hidden);
770+ if (dh < 0 )
771+ {
772+ free (rdir->orig_path );
773+ free (rdir);
774+ return NULL ;
775+ }
776+ rdir->smb_directory = dh;
777+ rdir->smb_path [0 ] = ' \0 ' ;
778+ return rdir;
779+ }
780+ #endif
781+
679782 /* Non-NT platforms don't like extra slashes in the path */
680783 if (path_buf[_len - 1 ] != ' \\ ' )
681784 path_buf[_len++] = ' \\ ' ;
@@ -705,6 +808,22 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
705808
706809bool retro_vfs_readdir_impl (libretro_vfs_implementation_dir* rdir)
707810{
811+ #ifdef HAVE_SMBCLIENT
812+ if (rdir->smb_directory != 0 )
813+ {
814+ struct smbc_dirent *de = retro_vfs_readdir_smb (rdir->smb_directory );
815+ if (!de)
816+ return false ;
817+ strlcpy (rdir->smb_path , de->name , sizeof (rdir->smb_path ));
818+ return true ;
819+ }
820+ /* If we opened an SMB path but failed, do not fall through to native readdir */
821+ if (rdir->orig_path &&
822+ rdir->orig_path [0 ]==' s' && rdir->orig_path [1 ]==' m' && rdir->orig_path [2 ]==' b' &&
823+ rdir->orig_path [3 ]==' :' && rdir->orig_path [4 ]==' /' && rdir->orig_path [5 ]==' /' )
824+ return false ;
825+ #endif
826+
708827 if (rdir->next )
709828 return (FindNextFileW (rdir->directory , &rdir->entry ) != 0 );
710829
@@ -714,6 +833,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
714833
715834const char * retro_vfs_dirent_get_name_impl (libretro_vfs_implementation_dir* rdir)
716835{
836+ #ifdef HAVE_SMBCLIENT
837+ if (rdir->smb_directory != 0 )
838+ return rdir->smb_path ;
839+ #endif
717840 char * name = utf16_to_utf8_string_alloc (rdir->entry .cFileName );
718841 memset (rdir->entry .cFileName , 0 , sizeof (rdir->entry .cFileName ));
719842 strlcpy ((char *)rdir->entry .cFileName , name, sizeof (rdir->entry .cFileName ));
@@ -724,6 +847,22 @@ const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir
724847
725848bool retro_vfs_dirent_is_dir_impl (libretro_vfs_implementation_dir* rdir)
726849{
850+ #ifdef HAVE_SMBCLIENT
851+ if (rdir->smb_directory != 0 )
852+ {
853+ char full[PATH_MAX_LENGTH];
854+ const char *name = retro_vfs_dirent_get_name_impl (rdir);
855+
856+ if (!name)
857+ return false ;
858+
859+ fill_pathname_join_special (full, rdir->orig_path , name, sizeof (full));
860+ int32_t sz = 0 ;
861+ int st = retro_vfs_stat_smb (full, &sz);
862+
863+ return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0 ;
864+ }
865+ #endif
727866 const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry ;
728867 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
729868}
@@ -733,6 +872,14 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
733872 if (!rdir)
734873 return -1 ;
735874
875+ #ifdef HAVE_SMBCLIENT
876+ if (rdir->smb_directory != 0 )
877+ {
878+ retro_vfs_closedir_smb (rdir->smb_directory );
879+ rdir->smb_directory = 0 ;
880+ }
881+ #endif
882+
736883 if (rdir->directory != INVALID_HANDLE_VALUE)
737884 FindClose (rdir->directory );
738885
0 commit comments