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+
5660namespace
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
118132int 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
@@ -140,7 +159,13 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
140159 return -1 ;
141160
142161 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
162+ {
163+ #ifdef HAVE_SMBCLIENT
164+ if (stream->scheme == VFS_SCHEME_SMB)
165+ return retro_vfs_file_tell_smb (stream);
166+ #endif
143167 return _ftelli64 (stream->fp );
168+ }
144169 if (lseek (stream->fd , 0 , SEEK_CUR) < 0 )
145170 return -1 ;
146171
@@ -155,7 +180,13 @@ int64_t retro_vfs_file_seek_internal(
155180 return -1 ;
156181
157182 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
183+ {
184+ #ifdef HAVE_SMBCLIENT
185+ if (stream->scheme == VFS_SCHEME_SMB)
186+ return retro_vfs_file_seek_smb (stream, offset, whence);
187+ #endif
158188 return _fseeki64 (stream->fp , offset, whence);
189+ }
159190 if (lseek (stream->fd , (off_t )offset, whence) < 0 )
160191 return -1 ;
161192
@@ -171,25 +202,51 @@ int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
171202int64_t retro_vfs_file_read_impl (libretro_vfs_implementation_file* stream,
172203 void * s, uint64_t len)
173204{
174- if (!stream || (!stream-> fp && stream-> fh == INVALID_HANDLE_VALUE) || !s )
175- return -1 ;
205+ if (!stream)
206+ return -1 ;
176207
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- }
208+ #ifdef HAVE_SMBCLIENT
209+ if (stream->scheme == VFS_SCHEME_SMB)
210+ return retro_vfs_file_read_smb (stream, s, len);
211+ #endif
212+
213+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
214+ return -1 ;
215+
216+ if (stream->fh != INVALID_HANDLE_VALUE)
217+ {
218+ DWORD _bytes_read;
219+ ReadFile (stream->fh , (char *)s, len, &_bytes_read, NULL );
220+ return (int64_t )_bytes_read;
221+ }
183222
184223 if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 )
185- return fread (s, 1 , (size_t )len, stream->fp );
224+ return fread (s, 1 , (size_t )len, stream->fp );
186225 return read (stream->fd , s, (size_t )len);
187226}
188227
189228
190229int64_t retro_vfs_file_write_impl (libretro_vfs_implementation_file* stream, const void * s, uint64_t len)
191230{
192- if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
231+ if (!stream)
232+ return -1 ;
233+
234+ #ifdef HAVE_SMBCLIENT
235+ if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&
236+ stream->scheme == VFS_SCHEME_SMB)
237+ {
238+ int64_t pos = 0 ;
239+ ssize_t ret = -1 ;
240+
241+ pos = retro_vfs_file_tell_smb (stream);
242+ ret = retro_vfs_file_write_smb (stream, s, len);
243+ if (ret != -1 && pos + ret > stream->size )
244+ stream->size = pos + ret;
245+ return ret;
246+ }
247+ #endif
248+
249+ if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
193250 return -1 ;
194251
195252 if (stream->fh != INVALID_HANDLE_VALUE)
@@ -260,6 +317,9 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
260317 stream->mapsize = 0 ;
261318 stream->mapped = NULL ;
262319 stream->scheme = VFS_SCHEME_NONE;
320+ #ifdef HAVE_SMBCLIENT
321+ stream->smb_fh = 0 ;
322+ #endif
263323
264324#ifdef VFS_FRONTEND
265325 if ( path
@@ -276,6 +336,20 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
276336 path += sizeof (" vfsonly://" )-1 ;
277337#endif
278338
339+ #ifdef HAVE_SMBCLIENT
340+ if ( path
341+ && path[0 ] == ' s'
342+ && path[1 ] == ' m'
343+ && path[2 ] == ' b'
344+ && path[3 ] == ' :'
345+ && path[4 ] == ' /'
346+ && path[5 ] == ' /'
347+ && path[6 ] != ' \0 ' )
348+ {
349+ stream->scheme = VFS_SCHEME_SMB;
350+ }
351+ #endif
352+
279353 path_wide = utf8_to_utf16_string_alloc (path);
280354 windowsize_path (path_wide);
281355 path_wstring = path_wide;
@@ -340,6 +414,16 @@ libretro_vfs_implementation_file* retro_vfs_file_open_impl(
340414 ? OPEN_ALWAYS
341415 : CREATE_ALWAYS;
342416
417+ #ifdef HAVE_SMBCLIENT
418+ if (stream->scheme == VFS_SCHEME_SMB)
419+ {
420+ if (!retro_vfs_file_open_smb (stream, path, mode, hints))
421+ goto error;
422+
423+ return stream;
424+ }
425+ #endif
426+
343427 if ((file_handle = CreateFile2FromAppW (path_wstring.data (), desireAccess,
344428 FILE_SHARE_READ, creationDisposition, NULL )) == INVALID_HANDLE_VALUE)
345429 goto error;
@@ -654,6 +738,10 @@ struct libretro_vfs_implementation_dir
654738 HANDLE directory;
655739 bool next;
656740 char path[PATH_MAX_LENGTH];
741+ #ifdef HAVE_SMBCLIENT
742+ intptr_t smb_directory;
743+ char smb_path[PATH_MAX_LENGTH];
744+ #endif
657745};
658746
659747libretro_vfs_implementation_dir* retro_vfs_opendir_impl (
@@ -676,6 +764,23 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
676764
677765 _len = strlcpy (path_buf, name, sizeof (path_buf));
678766
767+ #ifdef HAVE_SMBCLIENT
768+ if (name[0 ]==' s' && name[1 ]==' m' && name[2 ]==' b' &&
769+ name[3 ]==' :' && name[4 ]==' /' && name[5 ]==' /' && name[6 ] != ' \0 ' )
770+ {
771+ intptr_t dh = retro_vfs_opendir_smb (name, include_hidden);
772+ if (dh < 0 )
773+ {
774+ free (rdir->orig_path );
775+ free (rdir);
776+ return NULL ;
777+ }
778+ rdir->smb_directory = dh;
779+ rdir->smb_path [0 ] = ' \0 ' ;
780+ return rdir;
781+ }
782+ #endif
783+
679784 /* Non-NT platforms don't like extra slashes in the path */
680785 if (path_buf[_len - 1 ] != ' \\ ' )
681786 path_buf[_len++] = ' \\ ' ;
@@ -705,6 +810,22 @@ libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
705810
706811bool retro_vfs_readdir_impl (libretro_vfs_implementation_dir* rdir)
707812{
813+ #ifdef HAVE_SMBCLIENT
814+ if (rdir->smb_directory != 0 )
815+ {
816+ struct smbc_dirent *de = retro_vfs_readdir_smb (rdir->smb_directory );
817+ if (!de)
818+ return false ;
819+ strlcpy (rdir->smb_path , de->name , sizeof (rdir->smb_path ));
820+ return true ;
821+ }
822+ /* If we opened an SMB path but failed, do not fall through to native readdir */
823+ if (rdir->orig_path &&
824+ rdir->orig_path [0 ]==' s' && rdir->orig_path [1 ]==' m' && rdir->orig_path [2 ]==' b' &&
825+ rdir->orig_path [3 ]==' :' && rdir->orig_path [4 ]==' /' && rdir->orig_path [5 ]==' /' )
826+ return false ;
827+ #endif
828+
708829 if (rdir->next )
709830 return (FindNextFileW (rdir->directory , &rdir->entry ) != 0 );
710831
@@ -714,6 +835,10 @@ bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
714835
715836const char * retro_vfs_dirent_get_name_impl (libretro_vfs_implementation_dir* rdir)
716837{
838+ #ifdef HAVE_SMBCLIENT
839+ if (rdir->smb_directory != 0 )
840+ return rdir->smb_path ;
841+ #endif
717842 char * name = utf16_to_utf8_string_alloc (rdir->entry .cFileName );
718843 memset (rdir->entry .cFileName , 0 , sizeof (rdir->entry .cFileName ));
719844 strlcpy ((char *)rdir->entry .cFileName , name, sizeof (rdir->entry .cFileName ));
@@ -724,6 +849,22 @@ const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir
724849
725850bool retro_vfs_dirent_is_dir_impl (libretro_vfs_implementation_dir* rdir)
726851{
852+ #ifdef HAVE_SMBCLIENT
853+ if (rdir->smb_directory != 0 )
854+ {
855+ char full[PATH_MAX_LENGTH];
856+ const char *name = retro_vfs_dirent_get_name_impl (rdir);
857+
858+ if (!name)
859+ return false ;
860+
861+ fill_pathname_join_special (full, rdir->orig_path , name, sizeof (full));
862+ int32_t sz = 0 ;
863+ int st = retro_vfs_stat_smb (full, &sz);
864+
865+ return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0 ;
866+ }
867+ #endif
727868 const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry ;
728869 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
729870}
@@ -733,6 +874,14 @@ int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
733874 if (!rdir)
734875 return -1 ;
735876
877+ #ifdef HAVE_SMBCLIENT
878+ if (rdir->smb_directory != 0 )
879+ {
880+ retro_vfs_closedir_smb (rdir->smb_directory );
881+ rdir->smb_directory = 0 ;
882+ }
883+ #endif
884+
736885 if (rdir->directory != INVALID_HANDLE_VALUE)
737886 FindClose (rdir->directory );
738887
0 commit comments