ssshfs is obsoleted by mount_psshfs

This commit is contained in:
pooka 2006-12-29 15:36:18 +00:00
parent c3ef8ea5d0
commit fb7890b666
4 changed files with 0 additions and 1540 deletions

View File

@ -1,19 +0,0 @@
# $NetBSD: Makefile,v 1.1 2006/11/21 00:54:06 pooka Exp $
NOMAN= 1
.include <bsd.own.mk>
SSHDIST= ${NETBSDSRCDIR}/crypto/dist/ssh
.PATH: ${SSHDIST}
PROG= ssshfs
SRCS= ssshfs.c sftp-getput.c sftp-connect.c sftp-client.c \
sftp-common.c sftp-glob.c misc.c
LDADD+= -lpuffs -lutil -lssh -lcrypto -lcrypt -lz
CPPFLAGS+= -I${SSHDIST}
DBG=-g -O0
WARNS= 0 # XXX: openssh code
.include <bsd.prog.mk>

View File

@ -1,292 +0,0 @@
/* $NetBSD: sftp-connect.c,v 1.2 2006/11/21 23:09:23 pooka Exp $ */
/* NetBSD: sftp.c,v 1.21 2006/09/28 21:22:15 christos Exp */
/* $OpenBSD: sftp.c,v 1.91 2006/08/03 03:34:42 deraadt Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
__RCSID("$NetBSD: sftp-connect.c,v 1.2 2006/11/21 23:09:23 pooka Exp $");
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <errno.h>
#include <glob.h>
#include <histedit.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "misc.h"
#include "sftp.h"
#include "buffer.h"
#include "sftp-common.h"
#include "sftp-client.h"
/* File to read commands from */
FILE* infile;
/* Are we in batchfile mode? */
int batchmode = 0;
/* Size of buffer used when copying files */
size_t copy_buffer_len = 32768;
/* Number of concurrent outstanding requests */
size_t num_requests = 16;
/* PID of ssh transport process */
static pid_t sshpid = -1;
/* This is set to 0 if the progressmeter is not desired. */
int showprogress = 1;
/* SIGINT received during command processing */
volatile sig_atomic_t interrupted = 0;
static void
killchild(int signo)
{
if (sshpid > 1) {
kill(sshpid, SIGTERM);
waitpid(sshpid, NULL, 0);
}
_exit(1);
}
static void
connect_to_server(char *path, char **args, int *in, int *out)
{
int c_in, c_out;
int inout[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
fatal("socketpair: %s", strerror(errno));
*in = *out = inout[0];
c_in = c_out = inout[1];
if ((sshpid = fork()) == -1)
fatal("fork: %s", strerror(errno));
else if (sshpid == 0) {
if ((dup2(c_in, STDIN_FILENO) == -1) ||
(dup2(c_out, STDOUT_FILENO) == -1)) {
fprintf(stderr, "dup2: %s\n", strerror(errno));
_exit(1);
}
close(*in);
close(*out);
close(c_in);
close(c_out);
/*
* The underlying ssh is in the same process group, so we must
* ignore SIGINT if we want to gracefully abort commands,
* otherwise the signal will make it to the ssh process and
* kill it too
*/
signal(SIGINT, SIG_IGN);
execvp(path, args);
fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
_exit(1);
}
signal(SIGTERM, killchild);
signal(SIGINT, killchild);
signal(SIGHUP, killchild);
close(c_in);
close(c_out);
}
static void
usage(void)
{
extern char *__progname;
fprintf(stderr,
"usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n"
" [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n"
" [-S program] [-s subsystem | sftp_server] host\n"
" %s [[user@]host[:file [file]]]\n"
" %s [[user@]host[:dir[/]]]\n"
" %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname);
exit(1);
}
int sftp_main(int, char *[]);
int
sftp_main(int argc, char **argv)
{
int ch;
extern int in, out;
char *host, *userhost, *cp, *file2 = NULL;
int debug_level = 0, sshver = 2;
char *sftp_server = NULL;
char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
LogLevel ll = SYSLOG_LEVEL_INFO;
arglist args;
extern int optind;
extern char *optarg;
extern char *argpath;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
memset(&args, '\0', sizeof(args));
args.list = NULL;
addargs(&args, "%s", ssh_program);
addargs(&args, "-oForwardX11 no");
addargs(&args, "-oForwardAgent no");
addargs(&args, "-oPermitLocalCommand no");
addargs(&args, "-oClearAllForwardings yes");
ll = SYSLOG_LEVEL_INFO;
infile = stdin;
while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) {
switch (ch) {
case 'C':
addargs(&args, "-C");
break;
case 'v':
if (debug_level < 3) {
addargs(&args, "-v");
ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
}
debug_level++;
break;
case 'F':
case 'o':
addargs(&args, "-%c%s", ch, optarg);
break;
case '1':
sshver = 1;
if (sftp_server == NULL)
sftp_server = _PATH_SFTP_SERVER;
break;
case 's':
sftp_server = optarg;
break;
case 'S':
ssh_program = optarg;
replacearg(&args, 0, "%s", ssh_program);
break;
case 'b':
if (batchmode)
fatal("Batch file already specified.");
/* Allow "-" as stdin */
if (strcmp(optarg, "-") != 0 &&
(infile = fopen(optarg, "r")) == NULL)
fatal("%s (%s).", strerror(errno), optarg);
showprogress = 0;
batchmode = 1;
addargs(&args, "-obatchmode yes");
break;
case 'P':
sftp_direct = optarg;
break;
case 'B':
copy_buffer_len = strtol(optarg, &cp, 10);
if (copy_buffer_len == 0 || *cp != '\0')
fatal("Invalid buffer size \"%s\"", optarg);
break;
case 'R':
num_requests = strtol(optarg, &cp, 10);
if (num_requests == 0 || *cp != '\0')
fatal("Invalid number of requests \"%s\"",
optarg);
break;
case 'h':
default:
break;
}
}
if (!isatty(STDERR_FILENO))
showprogress = 0;
log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
if (sftp_direct == NULL) {
#if 0
if (optind == argc || argc > (optind + 2))
usage();
#endif
userhost = xstrdup(argv[optind]);
file2 = argv[optind+1];
if ((host = strrchr(userhost, '@')) == NULL)
host = userhost;
else {
*host++ = '\0';
if (!userhost[0]) {
fprintf(stderr, "Missing username\n");
usage();
}
addargs(&args, "-l%s",userhost);
}
if ((cp = colon(host)) != NULL) {
*cp++ = '\0';
argpath = cp;
}
host = cleanhostname(host);
if (!*host) {
fprintf(stderr, "Missing hostname\n");
usage();
}
addargs(&args, "-oProtocol %d", sshver);
/* no subsystem if the server-spec contains a '/' */
if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
addargs(&args, "-s");
addargs(&args, "%s", host);
addargs(&args, "%s", (sftp_server != NULL ?
sftp_server : "sftp"));
if (!batchmode)
fprintf(stderr, "Connecting to %s...\n", host);
connect_to_server(ssh_program, args.list, &in, &out);
} else {
args.list = NULL;
addargs(&args, "sftp-server");
if (!batchmode)
fprintf(stderr, "Attaching to %s...\n", sftp_direct);
connect_to_server(sftp_direct, args.list, &in, &out);
}
freeargs(&args);
return 0;
}

View File

@ -1,580 +0,0 @@
/* $NetBSD: sftp-getput.c,v 1.3 2006/12/05 23:14:13 pooka Exp $ */
/* NetBSD: sftp-client.c,v 1.26 2006/09/28 21:22:15 christos Exp */
/* $OpenBSD: sftp-client.c,v 1.74 2006/08/03 03:34:42 deraadt Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* hacked, mangled & maimed for ssshfs by pooka */
/* XXX: memleaks */
/* XXX: signed vs unsigned */
/* XXX: remove all logging, only return status codes */
/* XXX: copy between two remote sites */
#include "includes.h"
__RCSID("$NetBSD: sftp-getput.c,v 1.3 2006/12/05 23:14:13 pooka Exp $");
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "buffer.h"
#include "log.h"
#include "atomicio.h"
#include "misc.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
extern volatile sig_atomic_t interrupted;
/* Minimum amount of data to read at a time */
#define MIN_READ_SIZE 512
struct sftp_conn {
int fd_in;
int fd_out;
u_int transfer_buflen;
u_int num_requests;
u_int version;
u_int msg_id;
};
static void
send_msg(int fd, Buffer *m)
{
u_char mlen[4];
struct iovec iov[2];
if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
fatal("Outbound message too long %u", buffer_len(m));
/* Send length first */
put_u32(mlen, buffer_len(m));
iov[0].iov_base = mlen;
iov[0].iov_len = sizeof(mlen);
iov[1].iov_base = buffer_ptr(m);
iov[1].iov_len = buffer_len(m);
if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen))
fatal("Couldn't send packet: %s", strerror(errno));
buffer_clear(m);
}
static void
get_msg(int fd, Buffer *m)
{
u_int msg_len;
buffer_append_space(m, 4);
if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
if (errno == EPIPE)
fatal("Connection closed");
else
fatal("Couldn't read packet: %s", strerror(errno));
}
msg_len = buffer_get_int(m);
if (msg_len > SFTP_MAX_MSG_LENGTH)
fatal("Received message too long %u", msg_len);
buffer_append_space(m, msg_len);
if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
if (errno == EPIPE)
fatal("Connection closed");
else
fatal("Read packet: %s", strerror(errno));
}
}
static u_int
get_status(int fd, u_int expected_id)
{
Buffer msg;
u_int type, id, status;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
SSH2_FXP_STATUS, type);
status = buffer_get_int(&msg);
buffer_free(&msg);
debug3("SSH2_FXP_STATUS %u", status);
return(status);
}
static char *
get_handle(int fd, u_int expected_id, u_int *len)
{
Buffer msg;
u_int type, id;
char *handle;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
error("Couldn't get handle: %s", fx2txt(status));
buffer_free(&msg);
return(NULL);
} else if (type != SSH2_FXP_HANDLE)
fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
SSH2_FXP_HANDLE, type);
handle = buffer_get_string(&msg, len);
buffer_free(&msg);
return(handle);
}
static Attrib *
get_decode_stat(int fd, u_int expected_id, int quiet)
{
Buffer msg;
u_int type, id;
Attrib *a;
buffer_init(&msg);
get_msg(fd, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received stat reply T:%u I:%u", type, id);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
if (quiet)
debug("Couldn't stat remote file: %s", fx2txt(status));
else
error("Couldn't stat remote file: %s", fx2txt(status));
buffer_free(&msg);
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
SSH2_FXP_ATTRS, type);
}
a = decode_attrib(&msg);
buffer_free(&msg);
return(a);
}
static void
send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
char *handle, u_int handle_len)
{
Buffer msg;
buffer_init(&msg);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_READ);
buffer_put_int(&msg, id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_int(&msg, len);
send_msg(fd_out, &msg);
buffer_free(&msg);
}
int
do_creatfile(struct sftp_conn *conn, const char *path, const Attrib *a)
{
Buffer msg;
char *handle;
u_int handle_len;
int id;
buffer_init(&msg);
id = conn->msg_id++;
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, path);
buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
encode_attrib(&msg, a);
send_msg(conn->fd_out, &msg);
handle = get_handle(conn->fd_in, id, &handle_len);
buffer_free(&msg);
if (handle == NULL)
return EIO;
do_close(conn, handle, handle_len);
return 0;
}
int
do_readfile(struct sftp_conn *conn, char *path, uint8_t *localbuf,
off_t getoff, size_t *getlen)
{
Attrib junk, *a;
Buffer msg;
char *handle;
int status = 0, write_error;
int read_error, write_errno;
u_int64_t offset, size;
u_int handle_len, mode, type, id, buflen, num_req, max_req;
struct request {
u_int id;
u_int len;
u_int64_t offset;
TAILQ_ENTRY(request) tq;
};
TAILQ_HEAD(reqhead, request) requests;
struct request *req;
status = -1;
TAILQ_INIT(&requests);
a = do_stat(conn, path, 0);
if (a == NULL)
return(-1);
/* XXX: should we preserve set[ug]id? */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
mode = a->perm & 0777;
else
mode = 0666;
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(!S_ISREG(a->perm))) {
error("Cannot download non-regular file: %s", path);
return(-1);
}
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
size = a->size;
else
size = 0;
buflen = conn->transfer_buflen;
buffer_init(&msg);
/* Send open request */
id = conn->msg_id++;
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, path);
buffer_put_int(&msg, SSH2_FXF_READ);
attrib_clear(&junk); /* Send empty attributes */
encode_attrib(&msg, &junk);
send_msg(conn->fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, path);
handle = get_handle(conn->fd_in, id, &handle_len);
if (handle == NULL) {
buffer_free(&msg);
return(-1);
}
/* Read from remote and write to local */
write_error = read_error = write_errno = num_req = 0;
offset = getoff;
max_req = 1;
while (num_req > 0 || max_req > 0) {
char *data;
u_int len;
/* Send some more requests */
while ((num_req < max_req) && (offset < getoff + *getlen)) {
req = xmalloc(sizeof(*req));
req->id = conn->msg_id++;
req->len = buflen;
req->offset = offset;
num_req++;
/* adjust for tail */
if ((req->len + req->offset) >= (getoff + *getlen)) {
req->len = getoff+*getlen - req->offset;
max_req = 0;
}
debug3("Request range %llu -> %llu (%d/%d)",
(unsigned long long)offset,
(unsigned long long)offset + req->len - 1,
num_req, max_req);
offset += req->len;
TAILQ_INSERT_TAIL(&requests, req, tq);
send_read_request(conn->fd_out, req->id, req->offset,
req->len, handle, handle_len);
}
buffer_clear(&msg);
get_msg(conn->fd_in, &msg);
type = buffer_get_char(&msg);
id = buffer_get_int(&msg);
debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
/* Find the request in our queue */
for (req = TAILQ_FIRST(&requests);
req != NULL && req->id != id;
req = TAILQ_NEXT(req, tq))
;
if (req == NULL)
fatal("Unexpected reply %u", id);
switch (type) {
case SSH2_FXP_STATUS:
status = buffer_get_int(&msg);
if (status != SSH2_FX_EOF)
read_error = 1;
max_req = 0;
TAILQ_REMOVE(&requests, req, tq);
xfree(req);
num_req--;
break;
case SSH2_FXP_DATA:
data = buffer_get_string(&msg, &len);
debug3("Received data %llu -> %llu",
(unsigned long long)req->offset,
(unsigned long long)req->offset + len - 1);
if (len > req->len)
fatal("Received more data than asked for "
"%u > %u", len, req->len);
memcpy(localbuf + (req->offset - getoff), data, len);
xfree(data);
if (len == req->len) {
TAILQ_REMOVE(&requests, req, tq);
xfree(req);
num_req--;
} else {
/* Resend the request for the missing data */
debug3("Short data block, re-requesting "
"%llu -> %llu (%2d)",
(unsigned long long)req->offset + len,
(unsigned long long)req->offset +
req->len - 1, num_req);
req->id = conn->msg_id++;
req->len -= len;
req->offset += len;
send_read_request(conn->fd_out, req->id,
req->offset, req->len, handle, handle_len);
/* Reduce the request size */
if (len < buflen)
buflen = MAX(MIN_READ_SIZE, len);
}
break;
default:
fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
SSH2_FXP_DATA, type);
}
}
/* Sanity check */
if (TAILQ_FIRST(&requests) != NULL)
fatal("Transfer complete, but requests still in queue");
if (read_error) {
error("Couldn't read from remote file \"%s\" : %s",
path, fx2txt(status));
do_close(conn, handle, handle_len);
} else {
status = do_close(conn, handle, handle_len);
}
*getlen -= (offset - getoff);
buffer_free(&msg);
xfree(handle);
return(status);
}
int
do_writefile(struct sftp_conn *conn, char *path, uint8_t *localbuf,
off_t putoff, size_t *putlen, int append)
{
int status;
u_int handle_len, id, type;
u_int64_t offset;
char *handle, *data;
Buffer msg;
Attrib a, savea;
Attrib *ap;
u_int32_t startid;
u_int32_t ackid;
struct outstanding_ack {
u_int id;
u_int len;
u_int64_t offset;
TAILQ_ENTRY(outstanding_ack) tq;
};
TAILQ_HEAD(ackhead, outstanding_ack) acks;
struct outstanding_ack *ack = NULL;
TAILQ_INIT(&acks);
/* XXX: temporarily set file permission to allow writing */
ap = do_stat(conn, path, 1);
if (!ap)
return -1;
if (append)
putoff = ap->size;
memcpy(&savea, ap, sizeof(Attrib));
savea.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
memset(&a, 0, sizeof(a));
a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
if (do_setstat(conn, path, &a)) {
printf("lossage\n");
return -1;
}
buffer_init(&msg);
/* Send open request */
id = conn->msg_id++;
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, path);
buffer_put_int(&msg, SSH2_FXF_WRITE | SSH2_FXF_CREAT);
encode_attrib(&msg, &a);
send_msg(conn->fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, path);
buffer_clear(&msg);
handle = get_handle(conn->fd_in, id, &handle_len);
if (handle == NULL) {
do_setstat(conn, path, &savea);
buffer_free(&msg);
return(-1);
}
startid = ackid = id + 1;
data = xmalloc(conn->transfer_buflen);
offset = putoff;
for (;;) {
size_t len;
len = conn->transfer_buflen;
if (offset + len > putoff + *putlen)
len = (putoff + *putlen) - offset;
if (len != 0) {
memcpy(data, localbuf + (offset - putoff), len);
ack = xmalloc(sizeof(*ack));
ack->id = ++id;
ack->offset = offset;
ack->len = len;
TAILQ_INSERT_TAIL(&acks, ack, tq);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_WRITE);
buffer_put_int(&msg, ack->id);
buffer_put_string(&msg, handle, handle_len);
buffer_put_int64(&msg, offset);
buffer_put_string(&msg, data, len);
send_msg(conn->fd_out, &msg);
debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
id, (unsigned long long)offset, len);
} else if (TAILQ_FIRST(&acks) == NULL)
break;
if (ack == NULL)
fatal("Unexpected ACK %u", id);
if (id == startid || len == 0 ||
id - ackid >= conn->num_requests) {
u_int r_id;
buffer_clear(&msg);
get_msg(conn->fd_in, &msg);
type = buffer_get_char(&msg);
r_id = buffer_get_int(&msg);
if (type != SSH2_FXP_STATUS)
fatal("Expected SSH2_FXP_STATUS(%d) packet, "
"got %d", SSH2_FXP_STATUS, type);
status = buffer_get_int(&msg);
debug3("SSH2_FXP_STATUS %d", status);
/* Find the request in our queue */
for (ack = TAILQ_FIRST(&acks);
ack != NULL && ack->id != r_id;
ack = TAILQ_NEXT(ack, tq))
;
if (ack == NULL)
fatal("Can't find request for ID %u", r_id);
TAILQ_REMOVE(&acks, ack, tq);
if (status != SSH2_FX_OK) {
error("Couldn't write to remote file \"%s\": %s",
path, fx2txt(status));
do_close(conn, handle, handle_len);
xfree(data);
xfree(ack);
goto done;
}
debug3("In write loop, ack for %u %u bytes at %llu",
ack->id, ack->len, (unsigned long long)ack->offset);
++ackid;
xfree(ack);
}
offset += len;
}
xfree(data);
status = do_close(conn, handle, handle_len);
*putlen -= (offset - putoff);
done:
do_setstat(conn, path, &savea);
xfree(handle);
buffer_free(&msg);
return(status);
}

View File

@ -1,649 +0,0 @@
/* $NetBSD: ssshfs.c,v 1.10 2006/12/07 10:54:29 pooka Exp $ */
/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* simple sshfs
* (silly sshfs? stupid sshfs? snappy sshfs? sucky sshfs? seven sshfs???)
* (sante sshfs? severed (dreams) sshfs? saucy sshfs? sauerkraut sshfs?)
*/
#include <sys/types.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <puffs.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#include <unistd.h>
#include "buffer.h"
#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
PUFFSOP_PROTOS(ssshfs)
struct ssshnode {
struct ssshnode *dotdot;
int childcount;
ino_t myid;
char name[MAXPATHLEN+1];
size_t namelen;
SFTP_DIRENT **ents;
int dcache;
struct vattr va;
};
#define DCACHE_EXISTS 0x1
#define DCACHE_CHANGED 0x2
static struct sftp_conn *sftpc;
int in, out;
static struct ssshnode rn;
static ino_t nextid = 3;
extern int sftp_main(int argc, char *argv[]);
char *argpath; /* XXX: arg passing nightmare */
/*
* uberquickhack one-person uidgid-mangler in case the target
* system doesn't have the same uids and gids
*/
static int mangle = 0;
static uid_t uidmangle_from = 1323, uidmangle_to = 5988;
static uid_t gidmangle_from = 100, gidmangle_to = 806;
int
main(int argc, char *argv[])
{
struct puffs_usermount *pu;
struct puffs_ops pops;
char *mountpath;
setprogname(argv[0]);
if (argc < 3)
errx(1, "usage: %s user@host:path mountpath", getprogname());
PUFFSOP_INIT(&pops);
PUFFSOP_SET(&pops, ssshfs, fs, mount);
PUFFSOP_SET(&pops, ssshfs, fs, unmount);
PUFFSOP_SETFSNOP(&pops, sync); /* XXX */
PUFFSOP_SETFSNOP(&pops, statvfs);
PUFFSOP_SET(&pops, ssshfs, node, lookup);
PUFFSOP_SET(&pops, ssshfs, node, getattr);
PUFFSOP_SET(&pops, ssshfs, node, setattr);
PUFFSOP_SET(&pops, ssshfs, node, readdir);
PUFFSOP_SET(&pops, ssshfs, node, symlink);
PUFFSOP_SET(&pops, ssshfs, node, readlink);
PUFFSOP_SET(&pops, ssshfs, node, remove);
PUFFSOP_SET(&pops, ssshfs, node, create);
PUFFSOP_SET(&pops, ssshfs, node, mkdir);
PUFFSOP_SET(&pops, ssshfs, node, rmdir);
PUFFSOP_SET(&pops, ssshfs, node, read);
PUFFSOP_SET(&pops, ssshfs, node, write);
PUFFSOP_SET(&pops, ssshfs, node, rename);
PUFFSOP_SET(&pops, ssshfs, node, reclaim);
mountpath = argv[--argc]; /* urgh */
sftp_main(argc, argv);
if ((pu = puffs_mount(&pops, mountpath, 0, "ssshfs",
PUFFS_KFLAG_NOCACHE, 0))==NULL)
err(1, "mount");
if (puffs_mainloop(pu, 0) == -1)
err(1, "mainloop");
return 0;
}
static void
buildpath(struct ssshnode *ssn, const struct ssshnode *ossn, const char *pcomp)
{
size_t clen = strlen(pcomp);
assert((ossn->namelen + clen + 1 + 1) <= MAXPATHLEN);
memcpy(ssn->name, ossn->name, ossn->namelen);
ssn->name[ossn->namelen] = '/';
strcat(ssn->name, pcomp);
ssn->namelen = ossn->namelen + clen + 1; /* not nil, but '/' */
ssn->name[ssn->namelen] = 0;
}
static void
buildvattr(struct ssshnode *ssn, const Attrib *a)
{
struct vattr *va = &ssn->va;
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
va->va_size = a->size;
va->va_bytes = a->size;
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
if (a->uid == uidmangle_to && mangle)
va->va_uid = uidmangle_from;
else
va->va_uid = a->uid;
if (a->gid == gidmangle_to && mangle)
va->va_gid = gidmangle_from;
else
va->va_gid = a->gid;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
va->va_mode = a->perm;
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
va->va_atime.tv_sec = a->atime;
va->va_mtime.tv_sec = a->mtime;
}
va->va_type = puffs_mode2vt(va->va_mode);
}
static Attrib *
vattrtoAttrib(const struct vattr *va)
{
static Attrib a; /* XXX, but sftp isn't threadsafe either */
memset(&a, 0, sizeof(a));
if (va->va_size != PUFFS_VNOVAL) {
a.size = va->va_size;
a.flags |= SSH2_FILEXFER_ATTR_SIZE;
}
if (va->va_uid != PUFFS_VNOVAL) {
if (va->va_uid == uidmangle_from && mangle)
a.uid = uidmangle_to;
else
a.uid = va->va_uid;
if (va->va_gid == gidmangle_from && mangle)
a.gid = gidmangle_to;
else
a.gid = va->va_gid;
a.flags |= SSH2_FILEXFER_ATTR_UIDGID;
}
if (va->va_mode != PUFFS_VNOVAL) {
a.perm = va->va_mode & 0777;
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
}
if (va->va_atime.tv_sec != PUFFS_VNOVAL) {
a.atime = va->va_atime.tv_sec;
a.mtime = va->va_mtime.tv_sec;
a.flags |= SSH2_FILEXFER_ATTR_ACMODTIME;
}
return &a;
}
static int
dircache(struct ssshnode *ssn)
{
assert(ssn->va.va_type == VDIR);
if ((ssn->dcache & DCACHE_EXISTS)
&& ((ssn->dcache & DCACHE_CHANGED) == 0))
return 0;
if (ssn->dcache & DCACHE_EXISTS)
free_sftp_dirents(ssn->ents);
ssn->dcache &= ~DCACHE_EXISTS;
if (do_readdir(sftpc, ssn->name, &ssn->ents) != 0)
return 1;
ssn->dcache |= DCACHE_EXISTS;
ssn->dcache &= ~DCACHE_CHANGED;
return 0;
}
static struct ssshnode *
makenewnode(struct ssshnode *ossn, const char *pcomp, const char *longname)
{
struct ssshnode *newssn;
int links;
newssn = emalloc(sizeof(struct ssshnode));
memset(newssn, 0, sizeof(struct ssshnode));
newssn->dotdot = ossn;
newssn->myid = nextid++;
buildpath(newssn, ossn, pcomp);
ossn->childcount++;
newssn->childcount = 0;
newssn->va.va_fileid = newssn->myid;
newssn->va.va_blocksize = 512;
newssn->va.va_size = 0;
newssn->va.va_bytes = 0;
/* XXX: only way I know how (didn't look into the protocol, though) */
if (longname && (sscanf(longname, "%*s%d", &links) == 1))
newssn->va.va_nlink = links;
else
newssn->va.va_nlink = 1;
return newssn;
}
int
ssshfs_fs_mount(struct puffs_usermount *pu, void **rootcookie)
{
sftpc = do_init(in, out, 1<<15, 1);
if (sftpc == NULL) {
printf("can't init sftpc\n");
return EBUSY;
}
rn.childcount = 1;
rn.myid = 2;
memset(rn.name, 0, sizeof(rn.name));
if (argpath)
strcpy(rn.name, argpath);
else {
char *dotpath;
dotpath = do_realpath(sftpc, ".");
if (!dotpath)
return ENOENT;
strcpy(rn.name, dotpath);
}
rn.namelen = strlen(rn.name);
rn.va.va_type = VDIR;
rn.va.va_mode = 0777;
rn.va.va_nlink = 1024; /* XXXX */
*rootcookie = &rn;
return 0;
}
int
ssshfs_fs_unmount(struct puffs_usermount *pu, int flags, pid_t pid)
{
close(in);
close(out);
return 0;
}
int
ssshfs_node_lookup(struct puffs_usermount *pu, void *opc, void **newnode,
enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
const struct puffs_cn *pcn)
{
struct ssshnode *ssn = opc;
struct ssshnode *newssn;
struct SFTP_DIRENT *de;
int i;
if (pcn->pcn_flags & PUFFS_ISDOTDOT) {
*newnode = ssn->dotdot;
*newtype = VDIR;
return 0;
}
dircache(ssn);
for (i = 0, de = ssn->ents[0]; de; de = ssn->ents[i++])
if (strcmp(de->filename, pcn->pcn_name) == 0)
break;
if (!de)
return ENOENT;
newssn = makenewnode(ssn, de->filename, de->longname);
buildvattr(newssn, &de->a);
*newnode = newssn;
*newtype = newssn->va.va_type;
*newsize = newssn->va.va_size;
return 0;
}
int
ssshfs_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *va,
const struct puffs_cred *pcr, pid_t pid)
{
struct ssshnode *ssn = opc;
memcpy(va, &ssn->va, sizeof(struct vattr));
return 0;
}
int
ssshfs_node_setattr(struct puffs_usermount *pu, void *opc,
const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
{
struct ssshnode *ssn = opc;
Attrib *a;
int rv;
puffs_setvattr(&ssn->va, va);
a = vattrtoAttrib(va);
/* XXX: compensate for lack of granulatity of SSH2_FILEXFER */
if ((a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)
&& (va->va_mtime.tv_sec == PUFFS_VNOVAL))
a->mtime = ssn->va.va_mtime.tv_sec;
rv = do_setstat(sftpc, ssn->name, a);
if (rv)
return EIO;
return 0;
}
int do_creatfile(struct sftp_conn *conn, char *path, Attrib *a); /* XXX */
int
ssshfs_node_create(struct puffs_usermount *pu, void *opc, void **newnode,
const struct puffs_cn *pcn, const struct vattr *va)
{
struct ssshnode *ssd = opc, *newssn;
Attrib *a;
int rv;
newssn = makenewnode(ssd, pcn->pcn_name, NULL);
puffs_setvattr(&newssn->va, va);
a = vattrtoAttrib(va);
if ((rv = do_creatfile(sftpc, newssn->name, a)) != 0) {
/* XXX: free newssn */
return EIO;
}
ssd->dcache |= DCACHE_CHANGED;
ssd->va.va_nlink++;
*newnode = newssn;
return 0;
}
int
ssshfs_node_readdir(struct puffs_usermount *pu, void *opc, struct dirent *dent,
const struct puffs_cred *pcr, off_t *readoff, size_t *reslen)
{
struct ssshnode *ssn = opc;
struct SFTP_DIRENT *de;
dircache(ssn);
for (de = ssn->ents[*readoff]; de; de = ssn->ents[++(*readoff)]) {
if (!puffs_nextdent(&dent, de->filename, nextid++,
puffs_vtype2dt(ssn->va.va_type), reslen))
return 0;
}
return 0;
}
int
ssshfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf,
off_t offset, size_t *resid, const struct puffs_cred *pcr,
int ioflag)
{
size_t x1, x2;
struct ssshnode *ssn = opc;
int rv;
if (offset > ssn->va.va_size)
return 0;
x1 = *resid;
if (offset + *resid > ssn->va.va_size)
x1 = ssn->va.va_size - offset;
if (x1 == 0)
return 0;
x2 = x1;
rv = do_readfile(sftpc, ssn->name, buf, offset, &x1);
if (rv)
return EIO;
*resid -= (x2 - x1);
return 0;
}
int
ssshfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
off_t offset, size_t *resid, const struct puffs_cred *cred,
int ioflag)
{
struct ssshnode *ssn = opc;
size_t origres;
int rv;
origres = *resid;
rv = do_writefile(sftpc, ssn->name, buf, offset, resid,
ioflag & PUFFS_IO_APPEND);
if (ioflag & PUFFS_IO_APPEND) {
ssn->va.va_size += origres - *resid;
} else {
if (offset + (origres - *resid) > ssn->va.va_size)
ssn->va.va_size = offset + (origres - *resid);
}
if (rv)
return EIO;
return 0;
}
int
ssshfs_node_readlink(struct puffs_usermount *pu, void *opc,
const struct puffs_cred *cred, char *linkvalue, size_t *linklen)
{
struct ssshnode *ssn = opc;
char *res;
if (sftp_proto_version(sftpc) < 3)
return EOPNOTSUPP;
res = do_readlink(sftpc, ssn->name);
if (!res)
return EIO;
*linklen = strlen(res);
memcpy(linkvalue, res, *linklen);
return 0;
}
int
ssshfs_node_remove(struct puffs_usermount *pu, void *opc, void *targ,
const struct puffs_cn *pcn)
{
struct ssshnode *ssn = targ, *ssd = opc;
int rv;
if (ssn->va.va_type == VDIR)
return EISDIR;
if ((rv = do_rm(sftpc, ssn->name)) != 0)
return EIO;
ssd->dcache |= DCACHE_CHANGED;
ssd->va.va_nlink--;
return 0;
}
int
ssshfs_node_mkdir(struct puffs_usermount *pu, void *opc, void **newnode,
const struct puffs_cn *pcn, const struct vattr *va)
{
struct ssshnode *ssd = opc, *newssn;
Attrib *a;
int rv;
newssn = makenewnode(ssd, pcn->pcn_name, NULL);
newssn->va.va_nlink++;
puffs_setvattr(&newssn->va, va);
a = vattrtoAttrib(va);
if ((rv = do_mkdir(sftpc, newssn->name, a)) != 0) {
/* XXX: free newssn */
return EIO;
}
ssd->dcache |= DCACHE_CHANGED;
ssd->va.va_nlink++;
*newnode = newssn;
return 0;
}
int
ssshfs_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ,
const struct puffs_cn *pcn)
{
struct ssshnode *ssn = targ, *ssd = opc;
int rv;
if (ssn->va.va_type != VDIR)
return ENOTDIR;
if ((rv = do_rmdir(sftpc, ssn->name)) != 0)
return EIO;
ssd->dcache |= DCACHE_CHANGED;
ssd->va.va_nlink--;
return 0;
}
int
ssshfs_node_symlink(struct puffs_usermount *pu, void *opc, void **newnode,
const struct puffs_cn *pcn, const struct vattr *va,
const char *link_target)
{
struct ssshnode *ssd = opc, *newssn;
char buf[MAXPATHLEN+1];
Attrib *a;
int rv;
if (sftp_proto_version(sftpc) < 3)
return EOPNOTSUPP;
if (*link_target == '/') {
strcpy(buf, link_target);
} else {
strcpy(buf, ssd->name);
strcat(buf, "/");
strcat(buf, link_target);
}
newssn = makenewnode(ssd, pcn->pcn_name, NULL);
puffs_setvattr(&newssn->va, va);
a = vattrtoAttrib(va);
if ((rv = do_symlink(sftpc, newssn->name, buf)) != 0)
return EIO;
ssd->dcache |= DCACHE_CHANGED;
ssd->va.va_nlink++;
*newnode = newssn;
return 0;
}
int
ssshfs_node_rename(struct puffs_usermount *pu, void *opc, void *src,
const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
const struct puffs_cn *pcn_targ)
{
struct ssshnode *ssd_src = opc, *ssd_dest = targ_dir;
struct ssshnode *ssn_file = src;
char newname[MAXPATHLEN+1];
strcpy(newname, ssd_dest->name);
strcat(newname, "/");
strcat(newname, pcn_targ->pcn_name);
if (targ)
if (do_rm(sftpc, newname))
return EIO;
if (do_rename(sftpc, ssn_file->name, newname))
return EIO;
/* ok, commit */
ssn_file->namelen = strlen(newname);
ssd_src->childcount--;
ssd_src->va.va_nlink--;
ssd_dest->childcount++;
ssd_dest->va.va_nlink++;
ssd_src->dcache |= DCACHE_CHANGED;
ssd_dest->dcache |= DCACHE_CHANGED;
return 0;
}
int
ssshfs_node_reclaim(struct puffs_usermount *pu, void *opc, pid_t pid)
{
struct ssshnode *ssn, *ssn_next;
for (ssn = opc; ssn != &rn; ssn = ssn_next) {
if (ssn->childcount == 0) {
if (ssn->dcache & DCACHE_EXISTS)
free_sftp_dirents(ssn->ents);
ssn_next = ssn->dotdot;
ssn_next->childcount--;
free(ssn);
} else
break;
}
return 0;
}