#include "tree234.h"
#include "sftp.h"
-#define GET_32BIT(cp) \
- (((unsigned long)(unsigned char)(cp)[0] << 24) | \
- ((unsigned long)(unsigned char)(cp)[1] << 16) | \
- ((unsigned long)(unsigned char)(cp)[2] << 8) | \
- ((unsigned long)(unsigned char)(cp)[3]))
-
-#define PUT_32BIT(cp, value) { \
- (cp)[0] = (unsigned char)((value) >> 24); \
- (cp)[1] = (unsigned char)((value) >> 16); \
- (cp)[2] = (unsigned char)((value) >> 8); \
- (cp)[3] = (unsigned char)(value); }
-
struct sftp_packet {
char *data;
unsigned length, maxlen;
static const char *fxp_error_message;
static int fxp_errtype;
-static void fxp_internal_error(char *msg);
+static void fxp_internal_error(const char *msg);
/* ----------------------------------------------------------------------
* SFTP packet construction functions.
*/
static void sftp_pkt_ensure(struct sftp_packet *pkt, int length)
{
- if (pkt->maxlen < length) {
+ if ((int)pkt->maxlen < length) {
pkt->maxlen = length + 256;
pkt->data = sresize(pkt->data, pkt->maxlen, char);
}
}
-static void sftp_pkt_adddata(struct sftp_packet *pkt, void *data, int len)
+static void sftp_pkt_adddata(struct sftp_packet *pkt,
+ const void *data, int len)
{
pkt->length += len;
sftp_pkt_ensure(pkt, pkt->length);
{
sftp_pkt_adddata(pkt, &byte, 1);
}
+static void sftp_pkt_adduint32(struct sftp_packet *pkt,
+ unsigned long value)
+{
+ unsigned char x[4];
+ PUT_32BIT(x, value);
+ sftp_pkt_adddata(pkt, x, 4);
+}
static struct sftp_packet *sftp_pkt_init(int pkt_type)
{
struct sftp_packet *pkt;
pkt->savedpos = -1;
pkt->length = 0;
pkt->maxlen = 0;
+ sftp_pkt_adduint32(pkt, 0); /* length field will be filled in later */
sftp_pkt_addbyte(pkt, (unsigned char) pkt_type);
return pkt;
}
sftp_pkt_adddata(pkt, &value, 1);
}
*/
-static void sftp_pkt_adduint32(struct sftp_packet *pkt,
- unsigned long value)
-{
- unsigned char x[4];
- PUT_32BIT(x, value);
- sftp_pkt_adddata(pkt, x, 4);
-}
static void sftp_pkt_adduint64(struct sftp_packet *pkt, uint64 value)
{
unsigned char x[8];
sftp_pkt_adduint32(pkt, 0);
pkt->savedpos = pkt->length;
}
-static void sftp_pkt_addstring_str(struct sftp_packet *pkt, char *data)
+static void sftp_pkt_addstring_str(struct sftp_packet *pkt, const char *data)
{
sftp_pkt_adddata(pkt, data, strlen(data));
PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
}
static void sftp_pkt_addstring_data(struct sftp_packet *pkt,
- char *data, int len)
+ const char *data, int len)
{
sftp_pkt_adddata(pkt, data, len);
PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
}
-static void sftp_pkt_addstring(struct sftp_packet *pkt, char *data)
+static void sftp_pkt_addstring(struct sftp_packet *pkt, const char *data)
{
sftp_pkt_addstring_start(pkt);
sftp_pkt_addstring_str(pkt, data);
*p = NULL;
if (pkt->length - pkt->savedpos < 4)
return 0;
- *length = GET_32BIT(pkt->data + pkt->savedpos);
+ *length = toint(GET_32BIT(pkt->data + pkt->savedpos));
pkt->savedpos += 4;
- if (pkt->length - pkt->savedpos < *length || *length < 0) {
+ if ((int)(pkt->length - pkt->savedpos) < *length || *length < 0) {
*length = 0;
return 0;
}
int sftp_send(struct sftp_packet *pkt)
{
int ret;
- char x[4];
- PUT_32BIT(x, pkt->length);
- ret = (sftp_senddata(x, 4) && sftp_senddata(pkt->data, pkt->length));
+ PUT_32BIT(pkt->data, pkt->length - 4);
+ ret = sftp_senddata(pkt->data, pkt->length);
sftp_pkt_free(pkt);
return ret;
}
struct sftp_request *sftp_find_request(struct sftp_packet *pktin)
{
unsigned long id;
+ unsigned fid;
struct sftp_request *req;
if (!pktin) {
fxp_internal_error("did not receive a valid SFTP packet\n");
return NULL;
}
- req = find234(sftp_requests, &id, sftp_reqfind);
+ fid = (unsigned)id;
+ req = find234(sftp_requests, &fid, sftp_reqfind);
if (!req || !req->registered) {
fxp_internal_error("request ID mismatch\n");
- sftp_pkt_free(pktin);
return NULL;
}
return -1;
}
-static void fxp_internal_error(char *msg)
+static void fxp_internal_error(const char *msg)
{
fxp_error_message = msg;
fxp_errtype = -1;
/*
* Canonify a pathname.
*/
-struct sftp_request *fxp_realpath_send(char *path)
+struct sftp_request *fxp_realpath_send(const char *path)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
/*
* Open a file.
*/
-struct sftp_request *fxp_open_send(char *path, int type)
+struct sftp_request *fxp_open_send(const char *path, int type,
+ struct fxp_attrs *attrs)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
sftp_pkt_adduint32(pktout, req->id);
sftp_pkt_addstring(pktout, path);
sftp_pkt_adduint32(pktout, type);
- sftp_pkt_adduint32(pktout, 0); /* (FIXME) empty ATTRS structure */
+ if (attrs)
+ sftp_pkt_addattrs(pktout, *attrs);
+ else
+ sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
sftp_send(pktout);
return req;
/*
* Open a directory.
*/
-struct sftp_request *fxp_opendir_send(char *path)
+struct sftp_request *fxp_opendir_send(const char *path)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
return req;
}
-void fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req)
+int fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req)
{
sfree(req);
fxp_got_status(pktin);
sftp_pkt_free(pktin);
+ return fxp_errtype == SSH_FX_OK;
}
-struct sftp_request *fxp_mkdir_send(char *path)
+struct sftp_request *fxp_mkdir_send(const char *path)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
return 1;
}
-struct sftp_request *fxp_rmdir_send(char *path)
+struct sftp_request *fxp_rmdir_send(const char *path)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
return 1;
}
-struct sftp_request *fxp_remove_send(char *fname)
+struct sftp_request *fxp_remove_send(const char *fname)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
return 1;
}
-struct sftp_request *fxp_rename_send(char *srcfname, char *dstfname)
+struct sftp_request *fxp_rename_send(const char *srcfname,
+ const char *dstfname)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
* Retrieve the attributes of a file. We have fxp_stat which works
* on filenames, and fxp_fstat which works on open file handles.
*/
-struct sftp_request *fxp_stat_send(char *fname)
+struct sftp_request *fxp_stat_send(const char *fname)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
/*
* Set the attributes of a file.
*/
-struct sftp_request *fxp_setstat_send(char *fname, struct fxp_attrs attrs)
+struct sftp_request *fxp_setstat_send(const char *fname,
+ struct fxp_attrs attrs)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
ret = snew(struct fxp_names);
ret->nnames = i;
ret->names = snewn(ret->nnames, struct fxp_name);
- for (i = 0; i < ret->nnames; i++) {
+ for (i = 0; i < (unsigned long)ret->nnames; i++) {
char *str1, *str2;
int len1, len2;
if (!sftp_pkt_getstring(pktin, &str1, &len1) ||
xfer->offset = offset;
xfer->head = xfer->tail = NULL;
xfer->req_totalsize = 0;
- xfer->req_maxsize = 16384;
+ xfer->req_maxsize = 1048576;
xfer->err = 0;
xfer->filesize = uint64_make(ULONG_MAX, ULONG_MAX);
xfer->furthestdata = uint64_make(0, 0);
xfer->tail = rr;
rr->next = NULL;
- rr->len = 4096;
+ rr->len = 32768;
rr->buffer = snewn(rr->len, char);
sftp_register(req = fxp_read_send(xfer->fh, rr->offset, rr->len));
fxp_set_userdata(req, rr);
return xfer;
}
+/*
+ * Returns INT_MIN to indicate that it didn't even get as far as
+ * fxp_read_recv and hence has not freed pktin.
+ */
int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
{
struct sftp_request *rreq;
struct req *rr;
rreq = sftp_find_request(pktin);
+ if (!rreq)
+ return INT_MIN; /* this packet doesn't even make sense */
rr = (struct req *)fxp_get_userdata(rreq);
- if (!rr)
- return 0; /* this packet isn't ours */
+ if (!rr) {
+ fxp_internal_error("request ID is not part of the current download");
+ return INT_MIN; /* this packet isn't ours */
+ }
rr->retlen = fxp_read_recv(pktin, rreq, rr->buffer, rr->len);
#ifdef DEBUG_DOWNLOAD
printf("read request %p has returned [%d]\n", rr, rr->retlen);
int xfer_upload_ready(struct fxp_xfer *xfer)
{
- if (xfer->req_totalsize < xfer->req_maxsize)
+ if (sftp_sendbuffer() == 0)
return 1;
else
return 0;
#endif
}
+/*
+ * Returns INT_MIN to indicate that it didn't even get as far as
+ * fxp_write_recv and hence has not freed pktin.
+ */
int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin)
{
struct sftp_request *rreq;
int ret;
rreq = sftp_find_request(pktin);
+ if (!rreq)
+ return INT_MIN; /* this packet doesn't even make sense */
rr = (struct req *)fxp_get_userdata(rreq);
- if (!rr)
- return 0; /* this packet isn't ours */
+ if (!rr) {
+ fxp_internal_error("request ID is not part of the current upload");
+ return INT_MIN; /* this packet isn't ours */
+ }
ret = fxp_write_recv(pktin, rreq);
#ifdef DEBUG_UPLOAD
printf("write request %p has returned [%d]\n", rr, ret);