Compare commits

..

8 Commits

Author SHA1 Message Date
Miklos Szeredi 666119d285 fix 2006-03-09 20:03:16 +00:00
Miklos Szeredi f3e8d58bd7 new release 2006-03-09 19:43:13 +00:00
Miklos Szeredi 326ff7f97e fix 2006-03-09 11:25:15 +00:00
Miklos Szeredi 7f4eaea507 fix 2006-03-08 14:32:16 +00:00
Miklos Szeredi 57fc3f4b6a fix 2006-02-24 11:42:40 +00:00
Miklos Szeredi b436754a11 fix 2006-02-23 21:31:41 +00:00
Miklos Szeredi e277fe1ca2 fix 2006-02-23 16:20:55 +00:00
Miklos Szeredi c9c9e9dfbd fix 2006-02-22 16:23:42 +00:00
5 changed files with 243 additions and 75 deletions
+28
View File
@@ -1,3 +1,31 @@
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.6
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Fix segfault if remote host is down and reconnection is enabled
2006-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug in symlink transformation. Reported by Ralf Hoffmann
2006-02-24 Miklos Szeredi <miklos@szeredi.hu>
* Add workaround for broken truncate on old sftp servers. Can be
enabled with '-oworkaround=truncate'. Patch from Joseph M Link
2006-02-23 Miklos Szeredi <miklos@szeredi.hu>
* Avoid double memcpy on writes. Patch by Joseph M Link
* More memory copy avoidance
2006-02-22 Miklos Szeredi <miklos@szeredi.hu>
* Add -fPIC to the comile flags of sshnodelay.so. Reported by
Anthony Kolasny
2006-02-20 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.5
+1 -1
View File
@@ -24,4 +24,4 @@ uninstall-local:
rm -f "$(DESTDIR)$(libdir)/sshnodelay.so"
sshnodelay.so:
$(CC) -Wall -W -s --shared $(sshnodelay_libs) sshnodelay.c -o sshnodelay.so
$(CC) -Wall -W -s --shared -fPIC $(sshnodelay_libs) sshnodelay.c -o sshnodelay.so
+7
View File
@@ -1,3 +1,10 @@
What is new in 1.6
------------------
* Workaround for missing truncate operation on old sftp servers
* Bug fixes
What is new in 1.5
------------------
+1 -1
View File
@@ -1,4 +1,4 @@
AC_INIT(sshfs-fuse, 1.5)
AC_INIT(sshfs-fuse, 1.6)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
+206 -73
View File
@@ -157,6 +157,7 @@ struct sshfs {
char *workarounds;
int rename_workaround;
int nodelay_workaround;
int truncate_workaround;
int transform_symlinks;
int detect_uid;
unsigned max_read;
@@ -266,12 +267,16 @@ static struct fuse_opt sshfs_opts[] = {
static struct fuse_opt workaround_opts[] = {
SSHFS_OPT("none", rename_workaround, 0),
SSHFS_OPT("none", nodelay_workaround, 0),
SSHFS_OPT("none", truncate_workaround, 0),
SSHFS_OPT("all", rename_workaround, 1),
SSHFS_OPT("all", nodelay_workaround, 1),
SSHFS_OPT("all", truncate_workaround, 1),
SSHFS_OPT("rename", rename_workaround, 1),
SSHFS_OPT("norename", rename_workaround, 0),
SSHFS_OPT("nodelay", nodelay_workaround, 1),
SSHFS_OPT("nonodelay", nodelay_workaround, 0),
SSHFS_OPT("truncate", truncate_workaround, 1),
SSHFS_OPT("notruncate", truncate_workaround, 0),
FUSE_OPT_END
};
@@ -791,26 +796,45 @@ static uint32_t sftp_get_id(void)
return idctr++;
}
static void buf_to_iov(struct buffer *buf, struct iovec *iov)
static void buf_to_iov(const struct buffer *buf, struct iovec *iov)
{
iov->iov_base = buf->p;
iov->iov_len = buf->len;
}
static int sftp_send(uint8_t type, struct buffer *buf)
static size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
{
unsigned long seg;
size_t ret = 0;
for (seg = 0; seg < nr_segs; seg++)
ret += iov[seg].iov_len;
return ret;
}
#define SFTP_MAX_IOV 3
static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[],
size_t count)
{
int res;
struct buffer buf2;
struct iovec iov[2];
buf_init(&buf2, 5);
buf_add_uint32(&buf2, buf->len + 1);
buf_add_uint8(&buf2, type);
buf_to_iov(&buf2, &iov[0]);
buf_to_iov(buf, &iov[1]);
struct buffer buf;
struct iovec iovout[SFTP_MAX_IOV];
unsigned i;
unsigned nout = 0;
assert(count <= SFTP_MAX_IOV - 1);
buf_init(&buf, 5);
buf_add_uint32(&buf, iov_length(iov, count) + 5);
buf_add_uint8(&buf, type);
buf_add_uint32(&buf, id);
buf_to_iov(&buf, &iovout[nout++]);
for (i = 0; i < count; i++)
iovout[nout++] = iov[i];
pthread_mutex_lock(&sshfs.lock_write);
res = do_write(iov, 2);
res = do_write(iovout, nout);
pthread_mutex_unlock(&sshfs.lock_write);
buf_free(&buf2);
buf_free(&buf);
return res;
}
@@ -975,11 +999,9 @@ static int sftp_init()
uint8_t type;
uint32_t version;
struct buffer buf;
buf_init(&buf, 4);
buf_add_uint32(&buf, PROTO_VERSION);
if (sftp_send(SSH_FXP_INIT, &buf) == -1)
buf_init(&buf, 0);
if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1)
goto out;
buf_clear(&buf);
if (sftp_read(&type, &buf) == -1)
goto out;
if (type != SSH_FXP_VERSION) {
@@ -1009,11 +1031,12 @@ static void sftp_detect_uid()
uint8_t type;
struct buffer buf;
struct stat stbuf;
struct iovec iov[1];
buf_init(&buf, 9);
buf_add_uint32(&buf, id);
buf_init(&buf, 5);
buf_add_string(&buf, ".");
if (sftp_send(SSH_FXP_STAT, &buf) == -1)
buf_to_iov(&buf, &iov[0]);
if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
goto out;
buf_clear(&buf);
if (sftp_read(&type, &buf) == -1)
@@ -1183,13 +1206,12 @@ static int sftp_request_wait(struct request *req, uint8_t type,
return err;
}
static int sftp_request_send(uint8_t type, const struct buffer *buf,
static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
request_func begin_func, request_func end_func,
int want_reply, void *data,
struct request **reqp)
{
int err;
struct buffer buf2;
uint32_t id;
struct request *req = g_new0(struct request, 1);
@@ -1198,13 +1220,10 @@ static int sftp_request_send(uint8_t type, const struct buffer *buf,
req->data = data;
sem_init(&req->ready, 0, 0);
buf_init(&req->reply, 0);
buf_init(&buf2, buf->len + 4);
pthread_mutex_lock(&sshfs.lock);
if (begin_func)
begin_func(req);
id = sftp_get_id();
buf_add_uint32(&buf2, id);
buf_add_mem(&buf2, buf->p, buf->len);
err = start_processing_thread();
if (err) {
pthread_mutex_unlock(&sshfs.lock);
@@ -1216,37 +1235,33 @@ static int sftp_request_send(uint8_t type, const struct buffer *buf,
pthread_mutex_unlock(&sshfs.lock);
err = -EIO;
if (sftp_send(type, &buf2) == -1) {
if (sftp_send_iov(type, id, iov, count) == -1) {
pthread_mutex_lock(&sshfs.lock);
g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
pthread_mutex_unlock(&sshfs.lock);
goto out;
}
buf_free(&buf2);
if (want_reply)
*reqp = req;
return 0;
out:
buf_free(&buf2);
req->error = err;
if (!want_reply)
sftp_request_wait(req, type, 0, NULL);
else
*reqp = req;
return err;
}
static int sftp_request_common(uint8_t type, const struct buffer *buf,
uint8_t expect_type, struct buffer *outbuf,
request_func begin_func, request_func end_func,
void *data)
static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count,
uint8_t expect_type, struct buffer *outbuf)
{
struct request *req;
sftp_request_send(type, buf, begin_func, end_func, expect_type, data,
&req);
sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL, &req);
if (expect_type == 0)
return 0;
@@ -1256,15 +1271,10 @@ static int sftp_request_common(uint8_t type, const struct buffer *buf,
static int sftp_request(uint8_t type, const struct buffer *buf,
uint8_t expect_type, struct buffer *outbuf)
{
return sftp_request_common(type, buf, expect_type, outbuf, NULL, NULL,
NULL);
}
struct iovec iov;
static int sftp_request_async(uint8_t type, const struct buffer *buf,
request_func begin_func, request_func end_func,
void *data)
{
return sftp_request_send(type, buf, begin_func, end_func, 0, data, NULL);
buf_to_iov(buf, &iov);
return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
}
static int sshfs_getattr(const char *path, struct stat *stbuf)
@@ -1331,7 +1341,7 @@ static void transform_symlink(const char *path, char **linkp)
return;
dotdots--;
newlink = malloc(dotdots * 3 + l ? strlen(l) : 1 + 10);
newlink = malloc(dotdots * 3 + strlen(l) + 2);
if (!newlink) {
fprintf(stderr, "sshfs: memory allocation failed\n");
exit(1);
@@ -1568,34 +1578,23 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
return err;
}
static int sshfs_truncate_workaround(const char *path, off_t size,
struct fuse_file_info *fi);
static int sshfs_truncate(const char *path, off_t size)
{
int err;
struct buffer buf;
sshfs.modifver ++;
if (size == 0 || sshfs.truncate_workaround)
return sshfs_truncate_workaround(path, size, NULL);
buf_init(&buf, 0);
buf_add_path(&buf, path);
if (size == 0) {
/* If size is zero, use open(..., O_TRUNC), to work around
broken sftp servers */
struct buffer handle;
buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_TRUNC);
buf_add_uint32(&buf, 0);
err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
if (!err) {
int err2;
buf_finish(&handle);
err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
if (!err)
err = err2;
buf_free(&handle);
}
} else {
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
buf_add_uint64(&buf, size);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
}
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
buf_add_uint64(&buf, size);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
buf_free(&buf);
return err;
}
@@ -1630,6 +1629,8 @@ static int sshfs_open_common(const char *path, mode_t mode,
struct sshfs_file *sf;
struct request *open_req;
uint32_t pflags = 0;
struct iovec iov;
if ((fi->flags & O_ACCMODE) == O_RDONLY)
pflags = SSH_FXF_READ;
else if((fi->flags & O_ACCMODE) == O_WRONLY)
@@ -1661,7 +1662,8 @@ static int sshfs_open_common(const char *path, mode_t mode,
buf_add_uint32(&buf, pflags);
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
buf_add_uint32(&buf, mode);
sftp_request_send(SSH_FXP_OPEN, &buf, NULL, NULL, 1, NULL, &open_req);
buf_to_iov(&buf, &iov);
sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL, &open_req);
buf_clear(&buf);
buf_add_path(&buf, path);
err2 = sftp_request(SSH_FXP_LSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
@@ -1823,12 +1825,15 @@ static void sshfs_send_async_read(struct sshfs_file *sf,
{
struct buffer buf;
struct buffer *handle = &sf->handle;
struct iovec iov;
buf_init(&buf, 0);
buf_add_buf(&buf, handle);
buf_add_uint64(&buf, chunk->offset);
buf_add_uint32(&buf, chunk->size);
sftp_request_async(SSH_FXP_READ, &buf, sshfs_read_begin, sshfs_read_end,
chunk);
buf_to_iov(&buf, &iov);
sftp_request_send(SSH_FXP_READ, &iov, 1, sshfs_read_begin, sshfs_read_end,
0, chunk, NULL);
buf_free(&buf);
}
@@ -1971,9 +1976,9 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
{
int err;
struct buffer buf;
struct buffer data;
struct sshfs_file *sf = get_sshfs_file(fi);
struct buffer *handle = &sf->handle;
struct iovec iov[2];
(void) path;
@@ -1981,17 +1986,18 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
return -EIO;
sshfs.modifver ++;
data.p = (uint8_t *) wbuf;
data.len = size;
buf_init(&buf, 0);
buf_add_buf(&buf, handle);
buf_add_uint64(&buf, offset);
buf_add_data(&buf, &data);
buf_add_uint32(&buf, size);
buf_to_iov(&buf, &iov[0]);
iov[1].iov_base = (void *) wbuf;
iov[1].iov_len = size;
if (!sshfs.sync_write && !sf->write_error)
err = sftp_request_async(SSH_FXP_WRITE, &buf, sshfs_write_begin,
sshfs_write_end, sf);
err = sftp_request_send(SSH_FXP_WRITE, iov, 2, sshfs_write_begin,
sshfs_write_end, 0, sf, NULL);
else
err = sftp_request(SSH_FXP_WRITE, &buf, SSH_FXP_STATUS, NULL);
err = sftp_request_iov(SSH_FXP_WRITE, iov, 2, SSH_FXP_STATUS, NULL);
buf_free(&buf);
return err ? err : (int) size;
}
@@ -2047,6 +2053,9 @@ static int sshfs_ftruncate(const char *path, off_t size,
return -EIO;
sshfs.modifver ++;
if (sshfs.truncate_workaround)
return sshfs_truncate_workaround(path, size, fi);
buf_init(&buf, 0);
buf_add_buf(&buf, &sf->handle);
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
@@ -2056,6 +2065,7 @@ static int sshfs_ftruncate(const char *path, off_t size,
return err;
}
#endif
static int sshfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
@@ -2081,7 +2091,128 @@ static int sshfs_fgetattr(const char *path, struct stat *stbuf,
buf_free(&buf);
return err;
}
#endif
static int sshfs_truncate_zero(const char *path)
{
int err;
struct fuse_file_info fi;
fi.flags = O_WRONLY | O_TRUNC;
err = sshfs_open(path, &fi);
if (!err)
sshfs_release(path, &fi);
return err;
}
static size_t calc_buf_size(off_t size, off_t offset)
{
return offset + sshfs.max_read < size ? sshfs.max_read : size - offset;
}
static int sshfs_truncate_shrink(const char *path, off_t size)
{
int res;
char *data;
off_t offset;
struct fuse_file_info fi;
data = calloc(size, 1);
if (!data)
return -ENOMEM;
fi.flags = O_RDONLY;
res = sshfs_open(path, &fi);
if (res)
goto out;
for (offset = 0; offset < size; offset += res) {
size_t bufsize = calc_buf_size(size, offset);
res = sshfs_read(path, data + offset, bufsize, offset, &fi);
if (res <= 0)
break;
}
sshfs_release(path, &fi);
if (res < 0)
goto out;
fi.flags = O_WRONLY | O_TRUNC;
res = sshfs_open(path, &fi);
if (res)
goto out;
for (offset = 0; offset < size; offset += res) {
size_t bufsize = calc_buf_size(size, offset);
res = sshfs_write(path, data + offset, bufsize, offset, &fi);
if (res < 0)
break;
}
if (res >= 0)
res = sshfs_flush(path, &fi);
sshfs_release(path, &fi);
out:
free(data);
return res;
}
static int sshfs_truncate_extend(const char *path, off_t size,
struct fuse_file_info *fi)
{
int res;
char c = 0;
struct fuse_file_info tmpfi;
struct fuse_file_info *openfi = fi;
if (!fi) {
openfi = &tmpfi;
openfi->flags = O_WRONLY;
res = sshfs_open(path, openfi);
if (res)
return res;
}
res = sshfs_write(path, &c, 1, size - 1, openfi);
if (res == 1)
res = sshfs_flush(path, openfi);
if (!fi)
sshfs_release(path, openfi);
return res;
}
/*
* Work around broken sftp servers which don't handle
* SSH_FILEXFER_ATTR_SIZE in SETSTAT request.
*
* If new size is zero, just open the file with O_TRUNC.
*
* If new size is smaller than current size, then copy file locally,
* then open/trunc and send it back.
*
* If new size is greater than current size, then write a zero byte to
* the new end of the file.
*/
static int sshfs_truncate_workaround(const char *path, off_t size,
struct fuse_file_info *fi)
{
if (size == 0)
return sshfs_truncate_zero(path);
else {
struct stat stbuf;
int err;
if (fi)
err = sshfs_fgetattr(path, &stbuf, fi);
else
err = sshfs_getattr(path, &stbuf);
if (err)
return err;
if (stbuf.st_size == size)
return 0;
else if (stbuf.st_size > size)
return sshfs_truncate_shrink(path, size);
else
return sshfs_truncate_extend(path, size, fi);
}
}
static int processing_init(void)
{
@@ -2154,6 +2285,7 @@ static void usage(const char *progname)
" all all workarounds enabled\n"
" [no]rename fix renaming to existing file (default: off)\n"
" [no]nodelay set nodelay tcp flag in ssh (default: on)\n"
" [no]truncate fix truncate for old servers (default: off)\n"
" -o idmap=TYPE user/group ID mapping, possible types are:\n"
" none no translation of the ID space (default)\n"
" user only translate UID of connecting user\n"
@@ -2300,6 +2432,7 @@ int main(int argc, char *argv[])
sshfs.max_read = 65536;
sshfs.nodelay_workaround = 1;
sshfs.rename_workaround = 0;
sshfs.truncate_workaround = 0;
sshfs.ssh_ver = 2;
sshfs.progname = argv[0];
ssh_add_arg("ssh");