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
@@ -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,
175206int64_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
194233int64_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
663751libretro_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
710815bool 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
719840const 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
729854bool 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