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 ;
@@ -543,6 +545,7 @@ static struct fuse_opt workaround_opts[] = {
543545 SSHFS_OPT ("none" , truncate_workaround , 0 ),
544546 SSHFS_OPT ("none" , buflimit_workaround , 0 ),
545547 SSHFS_OPT ("none" , fstat_workaround , 0 ),
548+ SSHFS_OPT ("none" , readdir_workaround , 0 ),
546549 SSHFS_OPT ("rename" , rename_workaround , 1 ),
547550 SSHFS_OPT ("norename" , rename_workaround , 0 ),
548551 SSHFS_OPT ("renamexdev" , renamexdev_workaround , 1 ),
@@ -555,6 +558,8 @@ static struct fuse_opt workaround_opts[] = {
555558 SSHFS_OPT ("nofstat" , fstat_workaround , 0 ),
556559 SSHFS_OPT ("createmode" , createmode_workaround , 1 ),
557560 SSHFS_OPT ("nocreatemode" , createmode_workaround , 0 ),
561+ SSHFS_OPT ("readdir" , readdir_workaround , 1 ),
562+ SSHFS_OPT ("noreaddir" , readdir_workaround , 0 ),
558563 FUSE_OPT_END
559564};
560565
@@ -602,6 +607,9 @@ static const char *type_name(uint8_t type)
602607#define list_entry (ptr , type , member ) \
603608 container_of(ptr, type, member)
604609
610+ static int sshfs_releasedir (const char * path , struct fuse_file_info * fi );
611+
612+
605613static void list_init (struct list_head * head )
606614{
607615 head -> next = head ;
@@ -1108,7 +1116,11 @@ static int pty_master(char **name)
11081116{
11091117 int mfd ;
11101118
1119+ #ifdef __FreeBSD__
1120+ mfd = posix_openpt (O_RDWR | O_NOCTTY );
1121+ #else
11111122 mfd = open ("/dev/ptmx" , O_RDWR | O_NOCTTY );
1123+ #endif
11121124 if (mfd == -1 ) {
11131125 perror ("failed to open pty" );
11141126 return -1 ;
@@ -1891,12 +1903,20 @@ static void *sshfs_init(struct fuse_conn_info *conn,
18911903 if (conn -> capable & FUSE_CAP_ASYNC_READ )
18921904 sshfs .sync_read = 1 ;
18931905
1894- // These workarounds require the "path" argument.
1895- cfg -> nullpath_ok = !(sshfs .truncate_workaround || sshfs .fstat_workaround );
1896-
1897- // When using multiple connections, release() needs to know the path
1898- if (sshfs .max_conns > 1 )
1906+ /* These workarounds require the "path" argument:
1907+ * - truncate_workaround
1908+ * - fstat_workaround
1909+ * - readdir_workaround
1910+ * Also it required when using multiple connections: release()
1911+ * needs to know the path.
1912+ */
1913+ if (sshfs .truncate_workaround ||
1914+ sshfs .fstat_workaround ||
1915+ sshfs .readdir_workaround ||
1916+ sshfs .max_conns > 1 )
18991917 cfg -> nullpath_ok = 0 ;
1918+ else
1919+ cfg -> nullpath_ok = 1 ;
19001920
19011921 // Lookup of . and .. is supported
19021922 conn -> capable |= FUSE_CAP_EXPORT_SUPPORT ;
@@ -2200,6 +2220,7 @@ static int sshfs_req_pending(struct request *req)
22002220static int sftp_readdir_async (struct conn * conn , struct buffer * handle ,
22012221 void * buf , off_t offset , fuse_fill_dir_t filler )
22022222{
2223+ (void ) offset ;
22032224 int err = 0 ;
22042225 int outstanding = 0 ;
22052226 int max = READDIR_START ;
@@ -2278,6 +2299,7 @@ static int sftp_readdir_async(struct conn *conn, struct buffer *handle,
22782299static int sftp_readdir_sync (struct conn * conn , struct buffer * handle ,
22792300 void * buf , off_t offset , fuse_fill_dir_t filler )
22802301{
2302+ (void ) offset ;
22812303 int err ;
22822304 assert (offset == 0 );
22832305 do {
@@ -2327,10 +2349,19 @@ static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
23272349 off_t offset , struct fuse_file_info * fi ,
23282350 enum fuse_readdir_flags flags )
23292351{
2330- (void ) path ; ( void ) flags ;
2352+ (void ) flags ;
23312353 int err ;
23322354 struct dir_handle * handle ;
23332355
2356+ if (sshfs .readdir_workaround ) {
2357+ if (path == NULL )
2358+ return - EIO ;
2359+ err = sshfs_opendir (path , fi );
2360+ if (err )
2361+ return err ;
2362+ offset = 0 ;
2363+ }
2364+
23342365 handle = (struct dir_handle * ) fi -> fh ;
23352366
23362367 if (sshfs .sync_readdir )
@@ -2340,6 +2371,9 @@ static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
23402371 err = sftp_readdir_async (handle -> conn , & handle -> buf , dbuf ,
23412372 offset , filler );
23422373
2374+ if (sshfs .readdir_workaround )
2375+ sshfs_releasedir (path , fi );
2376+
23432377 return err ;
23442378}
23452379
@@ -3625,6 +3659,7 @@ static void usage(const char *progname)
36253659" [no]buflimit fix buffer fillup bug in server (default: off)\n"
36263660" [no]fstat always use stat() instead of fstat() (default: off)\n"
36273661" [no]createmode always pass mode 0 to create (default: off)\n"
3662+ " [no]readdir always open/read/close dir on readdir (default: on)\n"
36283663" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
36293664" none no translation of the ID space\n"
36303665" user only translate UID/GID of connecting user\n"
@@ -4182,6 +4217,7 @@ int main(int argc, char *argv[])
41824217 sshfs .truncate_workaround = 0 ;
41834218 sshfs .buflimit_workaround = 0 ;
41844219 sshfs .createmode_workaround = 0 ;
4220+ sshfs .readdir_workaround = 1 ;
41854221 sshfs .ssh_ver = 2 ;
41864222 sshfs .progname = argv [0 ];
41874223 sshfs .max_conns = 1 ;
0 commit comments