Skip to content

Commit df68941

Browse files
committed
Improve FreeBSD support:
- include posix_openpt() usage patch - add workaround for readdir() issue: #211 - fix few warnings
1 parent c91eb9a commit df68941

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

sshfs.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
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+
605613
static 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)
22002220
static 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,
22782299
static 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;

sshfs.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ Options
120120
:buflimit: Work around OpenSSH "buffer fillup" bug.
121121
:createmode: Work around broken servers that produce an error when passing a
122122
non-zero mode to create, by always passing a mode of 0.
123+
:readdir: Work around file manager used that keeps dir open while
124+
user add/remove files/dirs, that produce an error - all dirs
125+
become empty for a while or until remount.
126+
This happen because handle cached after opendir() but readdir()
127+
does not use offset.
128+
Workaround converts readdir() into "getdir()": opendir() and
129+
releasedir() not exported to fuse; offset set to 0.
123130

124131
-o idmap=TYPE
125132
How to map remote UID/GIDs to local values. Possible values are:

0 commit comments

Comments
 (0)