3232#include <netdb.h>
3333#include <signal.h>
3434#include <sys/uio.h>
35+ #include <sys/param.h>
3536#include <sys/types.h>
3637#include <sys/time.h>
3738#include <sys/wait.h>
@@ -311,6 +312,7 @@ struct sshfs {
311312 int unrel_append ;
312313 int fstat_workaround ;
313314 int createmode_workaround ;
315+ int readdir_workaround ;
314316 int transform_symlinks ;
315317 int follow_symlinks ;
316318 int no_check_root ;
@@ -542,6 +544,7 @@ static struct fuse_opt workaround_opts[] = {
542544 SSHFS_OPT ("none" , truncate_workaround , 0 ),
543545 SSHFS_OPT ("none" , buflimit_workaround , 0 ),
544546 SSHFS_OPT ("none" , fstat_workaround , 0 ),
547+ SSHFS_OPT ("none" , readdir_workaround , 0 ),
545548 SSHFS_OPT ("rename" , rename_workaround , 1 ),
546549 SSHFS_OPT ("norename" , rename_workaround , 0 ),
547550 SSHFS_OPT ("renamexdev" , renamexdev_workaround , 1 ),
@@ -554,6 +557,8 @@ static struct fuse_opt workaround_opts[] = {
554557 SSHFS_OPT ("nofstat" , fstat_workaround , 0 ),
555558 SSHFS_OPT ("createmode" , createmode_workaround , 1 ),
556559 SSHFS_OPT ("nocreatemode" , createmode_workaround , 0 ),
560+ SSHFS_OPT ("readdir" , readdir_workaround , 1 ),
561+ SSHFS_OPT ("noreaddir" , readdir_workaround , 0 ),
557562 FUSE_OPT_END
558563};
559564
@@ -1106,7 +1111,11 @@ static int pty_master(char **name)
11061111{
11071112 int mfd ;
11081113
1114+ #ifdef __FreeBSD__
1115+ mfd = posix_openpt (O_RDWR | O_NOCTTY );
1116+ #else
11091117 mfd = open ("/dev/ptmx" , O_RDWR | O_NOCTTY );
1118+ #endif
11101119 if (mfd == -1 ) {
11111120 perror ("failed to open pty" );
11121121 return -1 ;
@@ -1886,12 +1895,20 @@ static void *sshfs_init(struct fuse_conn_info *conn,
18861895 if (conn -> capable & FUSE_CAP_ASYNC_READ )
18871896 sshfs .sync_read = 1 ;
18881897
1889- // These workarounds require the "path" argument.
1890- cfg -> nullpath_ok = !(sshfs .truncate_workaround || sshfs .fstat_workaround );
1891-
1892- // When using multiple connections, release() needs to know the path
1893- if (sshfs .max_conns > 1 )
1898+ /* These workarounds require the "path" argument:
1899+ * - truncate_workaround
1900+ * - fstat_workaround
1901+ * - readdir_workaround
1902+ * Also it required when using multiple connections: release()
1903+ * needs to know the path.
1904+ */
1905+ if (sshfs .truncate_workaround ||
1906+ sshfs .fstat_workaround ||
1907+ sshfs .readdir_workaround ||
1908+ sshfs .max_conns > 1 )
18941909 cfg -> nullpath_ok = 0 ;
1910+ else
1911+ cfg -> nullpath_ok = 1 ;
18951912
18961913 // Lookup of . and .. is supported
18971914 conn -> capable |= FUSE_CAP_EXPORT_SUPPORT ;
@@ -2198,6 +2215,7 @@ static int sshfs_req_pending(struct request *req)
21982215static int sftp_readdir_async (struct conn * conn , struct buffer * handle ,
21992216 void * buf , off_t offset , fuse_fill_dir_t filler )
22002217{
2218+ (void ) offset ;
22012219 int err = 0 ;
22022220 int outstanding = 0 ;
22032221 int max = READDIR_START ;
@@ -2276,6 +2294,7 @@ static int sftp_readdir_async(struct conn *conn, struct buffer *handle,
22762294static int sftp_readdir_sync (struct conn * conn , struct buffer * handle ,
22772295 void * buf , off_t offset , fuse_fill_dir_t filler )
22782296{
2297+ (void ) offset ;
22792298 int err ;
22802299 assert (offset == 0 );
22812300 do {
@@ -2321,14 +2340,38 @@ static int sshfs_opendir(const char *path, struct fuse_file_info *fi)
23212340 return err ;
23222341}
23232342
2343+ static int sshfs_releasedir (const char * path , struct fuse_file_info * fi )
2344+ {
2345+ (void ) path ;
2346+ int err ;
2347+ struct dir_handle * handle ;
2348+
2349+ handle = (struct dir_handle * ) fi -> fh ;
2350+ err = sftp_request (handle -> conn , SSH_FXP_CLOSE , & handle -> buf , 0 , NULL );
2351+ pthread_mutex_lock (& sshfs .lock );
2352+ handle -> conn -> dir_count -- ;
2353+ pthread_mutex_unlock (& sshfs .lock );
2354+ buf_free (& handle -> buf );
2355+ g_free (handle );
2356+ return err ;
2357+ }
2358+
23242359static int sshfs_readdir (const char * path , void * dbuf , fuse_fill_dir_t filler ,
23252360 off_t offset , struct fuse_file_info * fi ,
23262361 enum fuse_readdir_flags flags )
23272362{
2328- (void ) path ; ( void ) flags ;
2363+ (void ) flags ;
23292364 int err ;
23302365 struct dir_handle * handle ;
23312366
2367+ if (sshfs .readdir_workaround ) {
2368+ if (path == NULL )
2369+ return - EIO ;
2370+ err = sshfs_opendir (path , fi );
2371+ if (err )
2372+ return err ;
2373+ }
2374+
23322375 handle = (struct dir_handle * ) fi -> fh ;
23332376
23342377 if (sshfs .sync_readdir )
@@ -2338,22 +2381,9 @@ static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
23382381 err = sftp_readdir_async (handle -> conn , & handle -> buf , dbuf ,
23392382 offset , filler );
23402383
2341- return err ;
2342- }
2384+ if ( sshfs . readdir_workaround )
2385+ err = sshfs_releasedir ( path , fi );
23432386
2344- static int sshfs_releasedir (const char * path , struct fuse_file_info * fi )
2345- {
2346- (void ) path ;
2347- int err ;
2348- struct dir_handle * handle ;
2349-
2350- handle = (struct dir_handle * ) fi -> fh ;
2351- err = sftp_request (handle -> conn , SSH_FXP_CLOSE , & handle -> buf , 0 , NULL );
2352- pthread_mutex_lock (& sshfs .lock );
2353- handle -> conn -> dir_count -- ;
2354- pthread_mutex_unlock (& sshfs .lock );
2355- buf_free (& handle -> buf );
2356- g_free (handle );
23572387 return err ;
23582388}
23592389
@@ -3616,6 +3646,7 @@ static void usage(const char *progname)
36163646" [no]buflimit fix buffer fillup bug in server (default: off)\n"
36173647" [no]fstat always use stat() instead of fstat() (default: off)\n"
36183648" [no]createmode always pass mode 0 to create (default: off)\n"
3649+ " [no]readdir always open/read/close dir on readdir (default: on for BSD)\n"
36193650" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
36203651" none no translation of the ID space\n"
36213652" user only translate UID/GID of connecting user\n"
@@ -4173,6 +4204,11 @@ int main(int argc, char *argv[])
41734204 sshfs .truncate_workaround = 0 ;
41744205 sshfs .buflimit_workaround = 0 ;
41754206 sshfs .createmode_workaround = 0 ;
4207+ #ifdef BSD
4208+ sshfs .readdir_workaround = 1 ;
4209+ #else
4210+ sshfs .readdir_workaround = 0 ;
4211+ #endif
41764212 sshfs .ssh_ver = 2 ;
41774213 sshfs .progname = argv [0 ];
41784214 sshfs .max_conns = 1 ;
0 commit comments