mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Large file support for psftp and pscp on both Windows and Unix. On Unix
we set _FILE_OFFSET_BITS to 64 on the compiler command line (via mkfiles.pl), and on Windows we use SetFilePointer and GetFileSize to cope with 64-bit sizes where possible. Not tested on Win9x. [originally from svn r6783]
This commit is contained in:
parent
3d522cfd08
commit
33b7caa590
@ -927,7 +927,8 @@ if (defined $makefiles{'gtk'}) {
|
||||
"\n".
|
||||
&splitline("CFLAGS = -O2 -Wall -Werror -g " .
|
||||
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
|
||||
" `gtk-config --cflags`")."\n".
|
||||
" `gtk-config --cflags`").
|
||||
" -D _FILE_OFFSET_BITS=64\n".
|
||||
"XLDFLAGS = `gtk-config --libs`\n".
|
||||
"ULDFLAGS =#\n".
|
||||
"INSTALL=install\n",
|
||||
|
147
pscp.c
147
pscp.c
@ -25,6 +25,7 @@
|
||||
#include "ssh.h"
|
||||
#include "sftp.h"
|
||||
#include "storage.h"
|
||||
#include "int64.h"
|
||||
|
||||
static int list = 0;
|
||||
static int verbose = 0;
|
||||
@ -35,7 +36,6 @@ static int statistics = 1;
|
||||
static int prev_stats_len = 0;
|
||||
static int scp_unsafe_mode = 0;
|
||||
static int errs = 0;
|
||||
static int gui_mode = 0;
|
||||
static int try_scp = 1;
|
||||
static int try_sftp = 1;
|
||||
static int main_cmd_is_sftp = 0;
|
||||
@ -69,10 +69,7 @@ void ldisc_send(void *handle, char *buf, int len, int interactive)
|
||||
|
||||
static void tell_char(FILE * stream, char c)
|
||||
{
|
||||
if (!gui_mode)
|
||||
fputc(c, stream);
|
||||
else
|
||||
gui_send_char(stream == stderr, c);
|
||||
fputc(c, stream);
|
||||
}
|
||||
|
||||
static void tell_str(FILE * stream, char *str)
|
||||
@ -112,9 +109,6 @@ void fatalbox(char *fmt, ...)
|
||||
sfree(str2);
|
||||
errs++;
|
||||
|
||||
if (gui_mode)
|
||||
gui_send_errcount(list, errs);
|
||||
|
||||
cleanup_exit(1);
|
||||
}
|
||||
void modalfatalbox(char *fmt, ...)
|
||||
@ -130,9 +124,6 @@ void modalfatalbox(char *fmt, ...)
|
||||
sfree(str2);
|
||||
errs++;
|
||||
|
||||
if (gui_mode)
|
||||
gui_send_errcount(list, errs);
|
||||
|
||||
cleanup_exit(1);
|
||||
}
|
||||
void connection_fatal(void *frontend, char *fmt, ...)
|
||||
@ -148,9 +139,6 @@ void connection_fatal(void *frontend, char *fmt, ...)
|
||||
sfree(str2);
|
||||
errs++;
|
||||
|
||||
if (gui_mode)
|
||||
gui_send_errcount(list, errs);
|
||||
|
||||
cleanup_exit(1);
|
||||
}
|
||||
|
||||
@ -310,9 +298,6 @@ static void bump(char *fmt, ...)
|
||||
ssh_scp_recv((unsigned char *) &ch, 1);
|
||||
}
|
||||
|
||||
if (gui_mode)
|
||||
gui_send_errcount(list, errs);
|
||||
|
||||
cleanup_exit(1);
|
||||
}
|
||||
|
||||
@ -495,7 +480,7 @@ static void do_cmd(char *host, char *user, char *cmd)
|
||||
/*
|
||||
* Update statistic information about current file.
|
||||
*/
|
||||
static void print_stats(char *name, unsigned long size, unsigned long done,
|
||||
static void print_stats(char *name, uint64 size, uint64 done,
|
||||
time_t start, time_t now)
|
||||
{
|
||||
float ratebs;
|
||||
@ -504,34 +489,42 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
|
||||
int pct;
|
||||
int len;
|
||||
int elap;
|
||||
double donedbl;
|
||||
double sizedbl;
|
||||
|
||||
elap = (unsigned long) difftime(now, start);
|
||||
|
||||
if (now > start)
|
||||
ratebs = (float) done / elap;
|
||||
ratebs = (float) (uint64_to_double(done) / elap);
|
||||
else
|
||||
ratebs = (float) done;
|
||||
ratebs = (float) uint64_to_double(done);
|
||||
|
||||
if (ratebs < 1.0)
|
||||
eta = size - done;
|
||||
else
|
||||
eta = (unsigned long) ((size - done) / ratebs);
|
||||
eta = (unsigned long) (uint64_to_double(uint64_subtract(size, done)));
|
||||
else {
|
||||
eta = (unsigned long)
|
||||
((uint64_to_double(uint64_subtract(size, done)) / ratebs));
|
||||
}
|
||||
|
||||
etastr = dupprintf("%02ld:%02ld:%02ld",
|
||||
eta / 3600, (eta % 3600) / 60, eta % 60);
|
||||
|
||||
pct = (int) (100 * (done * 1.0 / size));
|
||||
donedbl = uint64_to_double(done);
|
||||
sizedbl = uint64_to_double(size);
|
||||
pct = (int) (100 * (donedbl * 1.0 / sizedbl));
|
||||
|
||||
if (gui_mode) {
|
||||
gui_update_stats(name, size, pct, elap, done, eta,
|
||||
(unsigned long) ratebs);
|
||||
} else {
|
||||
len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
|
||||
name, done / 1024, ratebs / 1024.0, etastr, pct);
|
||||
{
|
||||
char donekb[40];
|
||||
/* divide by 1024 to provide kB */
|
||||
uint64_decimal(uint64_shift_right(done, 10), donekb);
|
||||
len = printf("\r%-25.25s | %s kB | %5.1f kB/s | ETA: %8s | %3d%%",
|
||||
name,
|
||||
donekb, ratebs / 1024.0, etastr, pct);
|
||||
if (len < prev_stats_len)
|
||||
printf("%*s", prev_stats_len - len, "");
|
||||
prev_stats_len = len;
|
||||
|
||||
if (done == size)
|
||||
if (uint64_compare(done, size) == 0)
|
||||
printf("\n");
|
||||
|
||||
fflush(stdout);
|
||||
@ -822,7 +815,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime)
|
||||
}
|
||||
}
|
||||
|
||||
int scp_send_filename(char *name, unsigned long size, int modes)
|
||||
int scp_send_filename(char *name, uint64 size, int modes)
|
||||
{
|
||||
if (using_sftp) {
|
||||
char *fullname;
|
||||
@ -854,7 +847,9 @@ int scp_send_filename(char *name, unsigned long size, int modes)
|
||||
return 0;
|
||||
} else {
|
||||
char buf[40];
|
||||
sprintf(buf, "C%04o %lu ", modes, size);
|
||||
char sizestr[40];
|
||||
uint64_decimal(size, sizestr);
|
||||
sprintf(buf, "C%04o %s ", modes, sizestr);
|
||||
back->send(backhandle, buf, strlen(buf));
|
||||
back->send(backhandle, name, strlen(name));
|
||||
back->send(backhandle, "\n", 1);
|
||||
@ -1135,7 +1130,7 @@ struct scp_sink_action {
|
||||
char *buf; /* will need freeing after use */
|
||||
char *name; /* filename or dirname (not ENDDIR) */
|
||||
int mode; /* access mode (not ENDDIR) */
|
||||
unsigned long size; /* file size (not ENDDIR) */
|
||||
uint64 size; /* file size (not ENDDIR) */
|
||||
int settime; /* 1 if atime and mtime are filled */
|
||||
unsigned long atime, mtime; /* access times for the file */
|
||||
};
|
||||
@ -1359,7 +1354,7 @@ int scp_get_sink_action(struct scp_sink_action *act)
|
||||
act->action = SCP_SINK_DIR;
|
||||
act->buf = dupstr(stripslashes(fname, 0));
|
||||
act->name = act->buf;
|
||||
act->size = 0; /* duhh, it's a directory */
|
||||
act->size = uint64_make(0,0); /* duhh, it's a directory */
|
||||
act->mode = 07777 & attrs.permissions;
|
||||
if (scp_sftp_preserve &&
|
||||
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
|
||||
@ -1379,13 +1374,9 @@ int scp_get_sink_action(struct scp_sink_action *act)
|
||||
act->buf = dupstr(stripslashes(fname, 0));
|
||||
act->name = act->buf;
|
||||
if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
|
||||
if (uint64_compare(attrs.size,
|
||||
uint64_make(0, ULONG_MAX)) > 0) {
|
||||
act->size = ULONG_MAX; /* *boggle* */
|
||||
} else
|
||||
act->size = attrs.size.lo;
|
||||
act->size = attrs.size;
|
||||
} else
|
||||
act->size = ULONG_MAX; /* no idea */
|
||||
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
|
||||
act->mode = 07777 & attrs.permissions;
|
||||
if (scp_sftp_preserve &&
|
||||
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
|
||||
@ -1465,10 +1456,15 @@ int scp_get_sink_action(struct scp_sink_action *act)
|
||||
* If we get here, we must have seen SCP_SINK_FILE or
|
||||
* SCP_SINK_DIR.
|
||||
*/
|
||||
if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2)
|
||||
bump("Protocol error: Illegal file descriptor format");
|
||||
act->name = act->buf + i;
|
||||
return 0;
|
||||
{
|
||||
char sizestr[40];
|
||||
|
||||
if (sscanf(act->buf, "%o %s %n", &act->mode, sizestr, &i) != 2)
|
||||
bump("Protocol error: Illegal file descriptor format");
|
||||
act->size = uint64_from_decimal(sizestr);
|
||||
act->name = act->buf + i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1596,13 +1592,13 @@ static void run_err(const char *fmt, ...)
|
||||
*/
|
||||
static void source(char *src)
|
||||
{
|
||||
unsigned long size;
|
||||
uint64 size;
|
||||
unsigned long mtime, atime;
|
||||
char *last;
|
||||
RFile *f;
|
||||
int attr;
|
||||
unsigned long i;
|
||||
unsigned long stat_bytes;
|
||||
uint64 i;
|
||||
uint64 stat_bytes;
|
||||
time_t stat_starttime, stat_lasttime;
|
||||
|
||||
attr = file_type(src);
|
||||
@ -1655,21 +1651,26 @@ static void source(char *src)
|
||||
return;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
tell_user(stderr, "Sending file %s, size=%lu", last, size);
|
||||
if (verbose) {
|
||||
char sizestr[40];
|
||||
uint64_decimal(size, sizestr);
|
||||
tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
|
||||
}
|
||||
if (scp_send_filename(last, size, 0644))
|
||||
return;
|
||||
|
||||
stat_bytes = 0;
|
||||
stat_bytes = uint64_make(0,0);
|
||||
stat_starttime = time(NULL);
|
||||
stat_lasttime = 0;
|
||||
|
||||
for (i = 0; i < size; i += 4096) {
|
||||
for (i = uint64_make(0,0);
|
||||
uint64_compare(i,size) < 0;
|
||||
i = uint64_add32(i,4096)) {
|
||||
char transbuf[4096];
|
||||
int j, k = 4096;
|
||||
|
||||
if (i + k > size)
|
||||
k = size - i;
|
||||
if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */
|
||||
k = (uint64_subtract(size, i)).lo; /* k = size - i; */
|
||||
if ((j = read_from_file(f, transbuf, k)) != k) {
|
||||
if (statistics)
|
||||
printf("\n");
|
||||
@ -1679,8 +1680,9 @@ static void source(char *src)
|
||||
bump("%s: Network error occurred", src);
|
||||
|
||||
if (statistics) {
|
||||
stat_bytes += k;
|
||||
if (time(NULL) != stat_lasttime || i + k == size) {
|
||||
stat_bytes = uint64_add32(stat_bytes, k);
|
||||
if (time(NULL) != stat_lasttime ||
|
||||
(uint64_compare(uint64_add32(i, k), size) == 0)) {
|
||||
stat_lasttime = time(NULL);
|
||||
print_stats(last, size, stat_bytes,
|
||||
stat_starttime, stat_lasttime);
|
||||
@ -1747,9 +1749,9 @@ static void sink(char *targ, char *src)
|
||||
int exists;
|
||||
int attr;
|
||||
WFile *f;
|
||||
unsigned long received;
|
||||
uint64 received;
|
||||
int wrerror = 0;
|
||||
unsigned long stat_bytes;
|
||||
uint64 stat_bytes;
|
||||
time_t stat_starttime, stat_lasttime;
|
||||
char *stat_name;
|
||||
|
||||
@ -1880,20 +1882,20 @@ static void sink(char *targ, char *src)
|
||||
if (scp_accept_filexfer())
|
||||
return;
|
||||
|
||||
stat_bytes = 0;
|
||||
stat_bytes = uint64_make(0, 0);
|
||||
stat_starttime = time(NULL);
|
||||
stat_lasttime = 0;
|
||||
stat_name = stripslashes(destfname, 1);
|
||||
|
||||
received = 0;
|
||||
while (received < act.size) {
|
||||
received = uint64_make(0, 0);
|
||||
while (uint64_compare(received,act.size) < 0) {
|
||||
char transbuf[32768];
|
||||
unsigned long blksize;
|
||||
uint64 blksize;
|
||||
int read;
|
||||
blksize = 32768;
|
||||
if (blksize > (act.size - received))
|
||||
blksize = act.size - received;
|
||||
read = scp_recv_filedata(transbuf, (int)blksize);
|
||||
blksize = uint64_make(0, 32768);
|
||||
if (uint64_compare(blksize,uint64_subtract(act.size,received)) > 0)
|
||||
blksize = uint64_subtract(act.size,received);
|
||||
read = scp_recv_filedata(transbuf, (int)blksize.lo);
|
||||
if (read <= 0)
|
||||
bump("Lost connection");
|
||||
if (wrerror)
|
||||
@ -1908,15 +1910,15 @@ static void sink(char *targ, char *src)
|
||||
continue;
|
||||
}
|
||||
if (statistics) {
|
||||
stat_bytes += read;
|
||||
stat_bytes = uint64_add32(stat_bytes,read);
|
||||
if (time(NULL) > stat_lasttime ||
|
||||
received + read == act.size) {
|
||||
uint64_compare(uint64_add32(received, read), act.size) == 0) {
|
||||
stat_lasttime = time(NULL);
|
||||
print_stats(stat_name, act.size, stat_bytes,
|
||||
stat_starttime, stat_lasttime);
|
||||
}
|
||||
}
|
||||
received += read;
|
||||
received = uint64_add32(received, read);
|
||||
}
|
||||
if (act.settime) {
|
||||
set_file_times(f, act.mtime, act.atime);
|
||||
@ -2244,10 +2246,6 @@ int psftp_main(int argc, char *argv[])
|
||||
usage();
|
||||
} else if (strcmp(argv[i], "-V") == 0) {
|
||||
version();
|
||||
} else if (strcmp(argv[i], "-gui") == 0 && i + 1 < argc) {
|
||||
gui_enable(argv[++i]);
|
||||
gui_mode = 1;
|
||||
console_batch_mode = TRUE;
|
||||
} else if (strcmp(argv[i], "-ls") == 0) {
|
||||
list = 1;
|
||||
} else if (strcmp(argv[i], "-batch") == 0) {
|
||||
@ -2294,9 +2292,6 @@ int psftp_main(int argc, char *argv[])
|
||||
}
|
||||
random_save_seed();
|
||||
|
||||
if (gui_mode)
|
||||
gui_send_errcount(list, errs);
|
||||
|
||||
cmdline_cleanup();
|
||||
console_provide_logctx(NULL);
|
||||
back->free(backhandle);
|
||||
|
51
psftp.c
51
psftp.c
@ -204,7 +204,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
||||
struct sftp_request *req, *rreq;
|
||||
struct fxp_xfer *xfer;
|
||||
uint64 offset;
|
||||
FILE *fp;
|
||||
WFile *file;
|
||||
int ret, shown_err = FALSE;
|
||||
|
||||
/*
|
||||
@ -386,12 +386,12 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
||||
}
|
||||
|
||||
if (restart) {
|
||||
fp = fopen(outfname, "rb+");
|
||||
file = open_existing_wfile(outfname, NULL);
|
||||
} else {
|
||||
fp = fopen(outfname, "wb");
|
||||
file = open_new_file(outfname);
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
if (!file) {
|
||||
printf("local: unable to open %s\n", outfname);
|
||||
|
||||
sftp_register(req = fxp_close_send(fh));
|
||||
@ -403,11 +403,21 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
||||
}
|
||||
|
||||
if (restart) {
|
||||
long posn;
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
posn = ftell(fp);
|
||||
printf("reget: restarting at file position %ld\n", posn);
|
||||
offset = uint64_make(0, posn);
|
||||
char decbuf[30];
|
||||
if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) {
|
||||
printf("reget: cannot restart %s - file too large\n",
|
||||
outfname);
|
||||
sftp_register(req = fxp_close_send(fh));
|
||||
rreq = sftp_find_request(pktin = sftp_recv());
|
||||
assert(rreq == req);
|
||||
fxp_close_recv(pktin, rreq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = get_file_posn(file);
|
||||
uint64_decimal(offset, decbuf);
|
||||
printf("reget: restarting at file position %s\n", decbuf);
|
||||
} else {
|
||||
offset = uint64_make(0, 0);
|
||||
}
|
||||
@ -442,7 +452,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
||||
|
||||
wpos = 0;
|
||||
while (wpos < len) {
|
||||
wlen = fwrite(buf + wpos, 1, len - wpos, fp);
|
||||
wlen = write_to_file(file, buf + wpos, len - wpos);
|
||||
if (wlen <= 0) {
|
||||
printf("error while writing local file\n");
|
||||
ret = 0;
|
||||
@ -461,7 +471,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
||||
|
||||
xfer_cleanup(xfer);
|
||||
|
||||
fclose(fp);
|
||||
close_wfile(file);
|
||||
|
||||
sftp_register(req = fxp_close_send(fh));
|
||||
rreq = sftp_find_request(pktin = sftp_recv());
|
||||
@ -478,7 +488,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
||||
struct sftp_packet *pktin;
|
||||
struct sftp_request *req, *rreq;
|
||||
uint64 offset;
|
||||
FILE *fp;
|
||||
RFile *file;
|
||||
int ret, err, eof;
|
||||
|
||||
/*
|
||||
@ -608,8 +618,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fopen(fname, "rb");
|
||||
if (!fp) {
|
||||
file = open_existing_file(fname, NULL, NULL, NULL);
|
||||
if (!file) {
|
||||
printf("local: unable to open %s\n", fname);
|
||||
return 0;
|
||||
}
|
||||
@ -649,12 +659,9 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
||||
offset = attrs.size;
|
||||
uint64_decimal(offset, decbuf);
|
||||
printf("reput: restarting at file position %s\n", decbuf);
|
||||
if (uint64_compare(offset, uint64_make(0, LONG_MAX)) > 0) {
|
||||
printf("reput: remote file is larger than we can deal with\n");
|
||||
return 0;
|
||||
}
|
||||
if (fseek(fp, offset.lo, SEEK_SET) != 0)
|
||||
fseek(fp, 0, SEEK_END); /* *shrug* */
|
||||
|
||||
if (seek_file((WFile *)file, offset, FROM_START) != 0)
|
||||
seek_file((WFile *)file, uint64_make(0,0), FROM_END); /* *shrug* */
|
||||
} else {
|
||||
offset = uint64_make(0, 0);
|
||||
}
|
||||
@ -673,7 +680,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
||||
int len, ret;
|
||||
|
||||
while (xfer_upload_ready(xfer) && !err && !eof) {
|
||||
len = fread(buffer, 1, sizeof(buffer), fp);
|
||||
len = read_from_file(file, buffer, sizeof(buffer));
|
||||
if (len == -1) {
|
||||
printf("error while reading local file\n");
|
||||
err = 1;
|
||||
@ -701,7 +708,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
||||
assert(rreq == req);
|
||||
fxp_close_recv(pktin, rreq);
|
||||
|
||||
fclose(fp);
|
||||
close_rfile(file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
17
psftp.h
17
psftp.h
@ -3,6 +3,8 @@
|
||||
* platform-specific SFTP module.
|
||||
*/
|
||||
|
||||
#include "int64.h"
|
||||
|
||||
#ifndef PUTTY_PSFTP_H
|
||||
#define PUTTY_PSFTP_H
|
||||
|
||||
@ -78,16 +80,15 @@ void gui_enable(char *arg);
|
||||
* the times when saving a new file.
|
||||
*
|
||||
* On the other hand, the abstraction is pretty simple: it supports
|
||||
* only opening a file and reading it, or creating a file and
|
||||
* writing it. (FIXME: to use this in PSFTP it will also need to
|
||||
* support seeking to a starting point for restarted transfers.)
|
||||
* None of this read-and-write, seeking-back-and-forth stuff.
|
||||
* only opening a file and reading it, or creating a file and writing
|
||||
* it. None of this read-and-write, seeking-back-and-forth stuff.
|
||||
*/
|
||||
typedef struct RFile RFile;
|
||||
typedef struct WFile WFile;
|
||||
/* Output params size, mtime and atime can all be NULL if desired */
|
||||
RFile *open_existing_file(char *name, unsigned long *size,
|
||||
RFile *open_existing_file(char *name, uint64 *size,
|
||||
unsigned long *mtime, unsigned long *atime);
|
||||
WFile *open_existing_wfile(char *name, uint64 *size);
|
||||
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
|
||||
int read_from_file(RFile *f, void *buffer, int length);
|
||||
/* Closes and frees the RFile */
|
||||
@ -98,7 +99,11 @@ int write_to_file(WFile *f, void *buffer, int length);
|
||||
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);
|
||||
/* Closes and frees the WFile */
|
||||
void close_wfile(WFile *f);
|
||||
|
||||
/* Seek offset bytes through file */
|
||||
enum { FROM_START, FROM_CURRENT, FROM_END };
|
||||
int seek_file(WFile *f, uint64 offset, int whence);
|
||||
/* Get file position */
|
||||
uint64 get_file_posn(WFile *f);
|
||||
/*
|
||||
* Determine the type of a file: nonexistent, file, directory or
|
||||
* weird. `weird' covers anything else - named pipes, Unix sockets,
|
||||
|
105
unix/uxsftp.c
105
unix/uxsftp.c
@ -19,6 +19,7 @@
|
||||
|
||||
#include "putty.h"
|
||||
#include "psftp.h"
|
||||
#include "int64.h"
|
||||
|
||||
/*
|
||||
* In PSFTP our selects are synchronous, so these functions are
|
||||
@ -79,18 +80,6 @@ int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stubs for the GUI feedback mechanism in Windows PSCP.
|
||||
*/
|
||||
void gui_update_stats(char *name, unsigned long size,
|
||||
int percentage, unsigned long elapsed,
|
||||
unsigned long done, unsigned long eta,
|
||||
unsigned long ratebs) {}
|
||||
void gui_send_errcount(int list, int errs) {}
|
||||
void gui_send_char(int is_stderr, int c) {}
|
||||
void gui_enable(char *arg) {}
|
||||
|
||||
|
||||
/*
|
||||
* Set local current directory. Returns NULL on success, or else an
|
||||
* error message which must be freed after printing.
|
||||
@ -134,7 +123,7 @@ struct RFile {
|
||||
int fd;
|
||||
};
|
||||
|
||||
RFile *open_existing_file(char *name, unsigned long *size,
|
||||
RFile *open_existing_file(char *name, uint64 *size,
|
||||
unsigned long *mtime, unsigned long *atime)
|
||||
{
|
||||
int fd;
|
||||
@ -154,9 +143,15 @@ RFile *open_existing_file(char *name, unsigned long *size,
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = statbuf.st_size;
|
||||
|
||||
if (size) {
|
||||
if (sizeof(statbuf.st_size) == 8) {
|
||||
size->hi = statbuf.st_size >> 32;
|
||||
size->lo = (long) statbuf.st_size;
|
||||
} else {
|
||||
*size = uint64_make(0, statbuf.st_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (mtime)
|
||||
*mtime = statbuf.st_mtime;
|
||||
|
||||
@ -199,6 +194,37 @@ WFile *open_new_file(char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
WFile *open_existing_wfile(char *name, uint64 *size)
|
||||
{
|
||||
int fd;
|
||||
WFile *ret;
|
||||
|
||||
fd = open(name, O_APPEND | O_WRONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
ret = snew(WFile);
|
||||
ret->fd = fd;
|
||||
|
||||
if (size) {
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) < 0) {
|
||||
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
}
|
||||
|
||||
if (sizeof(statbuf.st_size) == 8) {
|
||||
size->hi = statbuf.st_size >> 32;
|
||||
size->lo = (long) statbuf.st_size;
|
||||
} else {
|
||||
*size = uint64_make(0, statbuf.st_size);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_to_file(WFile *f, void *buffer, int length)
|
||||
{
|
||||
char *p = (char *)buffer;
|
||||
@ -240,6 +266,53 @@ void close_wfile(WFile *f)
|
||||
sfree(f);
|
||||
}
|
||||
|
||||
/* Seek offset bytes through file, from whence, where whence is
|
||||
FROM_START, FROM_CURRENT, or FROM_END */
|
||||
int seek_file(WFile *f, uint64 offset, int whence)
|
||||
{
|
||||
off_t fileofft;
|
||||
int lseek_whence;
|
||||
|
||||
if (sizeof(off_t) == 8) {
|
||||
fileofft = ((off_t) offset.hi << 32) + offset.lo;
|
||||
} else {
|
||||
fileofft = offset.lo;
|
||||
}
|
||||
|
||||
switch (whence) {
|
||||
case FROM_START:
|
||||
lseek_whence = SEEK_SET;
|
||||
break;
|
||||
case FROM_CURRENT:
|
||||
lseek_whence = SEEK_CUR;
|
||||
break;
|
||||
case FROM_END:
|
||||
lseek_whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return lseek(f->fd, fileofft, lseek_whence) >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
uint64 get_file_posn(WFile *f)
|
||||
{
|
||||
off_t fileofft;
|
||||
uint64 ret;
|
||||
|
||||
fileofft = lseek(f->fd, (off_t) 0, SEEK_CUR);
|
||||
|
||||
if (sizeof(off_t) == 8) {
|
||||
ret.hi = fileofft >> 32;
|
||||
ret.lo = (long) fileofft;
|
||||
} else {
|
||||
ret = uint64_make(0, fileofft);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_type(char *name)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
@ -6,124 +6,7 @@
|
||||
|
||||
#include "putty.h"
|
||||
#include "psftp.h"
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Interface to GUI driver program.
|
||||
*/
|
||||
|
||||
/* This is just a base value from which the main message numbers are
|
||||
* derived. */
|
||||
#define WM_APP_BASE 0x8000
|
||||
|
||||
/* These two pass a single character value in wParam. They represent
|
||||
* the visible output from PSCP. */
|
||||
#define WM_STD_OUT_CHAR ( WM_APP_BASE+400 )
|
||||
#define WM_STD_ERR_CHAR ( WM_APP_BASE+401 )
|
||||
|
||||
/* These pass a transfer status update. WM_STATS_CHAR passes a single
|
||||
* character in wParam, and is called repeatedly to pass the name of
|
||||
* the file, terminated with "\n". WM_STATS_SIZE passes the size of
|
||||
* the file being transferred in wParam. WM_STATS_ELAPSED is called
|
||||
* to pass the elapsed time (in seconds) in wParam, and
|
||||
* WM_STATS_PERCENT passes the percentage of the transfer which is
|
||||
* complete, also in wParam. */
|
||||
#define WM_STATS_CHAR ( WM_APP_BASE+402 )
|
||||
#define WM_STATS_SIZE ( WM_APP_BASE+403 )
|
||||
#define WM_STATS_PERCENT ( WM_APP_BASE+404 )
|
||||
#define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
|
||||
|
||||
/* These are used at the end of a run to pass an error code in
|
||||
* wParam: zero means success, nonzero means failure. WM_RET_ERR_CNT
|
||||
* is used after a copy, and WM_LS_RET_ERR_CNT is used after a file
|
||||
* list operation. */
|
||||
#define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
|
||||
#define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
|
||||
|
||||
/* More transfer status update messages. WM_STATS_DONE passes the
|
||||
* number of bytes sent so far in wParam. WM_STATS_ETA passes the
|
||||
* estimated time to completion (in seconds). WM_STATS_RATEBS passes
|
||||
* the average transfer rate (in bytes per second). */
|
||||
#define WM_STATS_DONE ( WM_APP_BASE+408 )
|
||||
#define WM_STATS_ETA ( WM_APP_BASE+409 )
|
||||
#define WM_STATS_RATEBS ( WM_APP_BASE+410 )
|
||||
|
||||
#define NAME_STR_MAX 2048
|
||||
static char statname[NAME_STR_MAX + 1];
|
||||
static unsigned long statsize = 0;
|
||||
static unsigned long statdone = 0;
|
||||
static unsigned long stateta = 0;
|
||||
static unsigned long statratebs = 0;
|
||||
static int statperct = 0;
|
||||
static unsigned long statelapsed = 0;
|
||||
|
||||
static HWND gui_hwnd = NULL;
|
||||
|
||||
static void send_msg(HWND h, UINT message, WPARAM wParam)
|
||||
{
|
||||
while (!PostMessage(h, message, wParam, 0))
|
||||
SleepEx(1000, TRUE);
|
||||
}
|
||||
|
||||
void gui_send_char(int is_stderr, int c)
|
||||
{
|
||||
unsigned int msg_id = WM_STD_OUT_CHAR;
|
||||
if (is_stderr)
|
||||
msg_id = WM_STD_ERR_CHAR;
|
||||
send_msg(gui_hwnd, msg_id, (WPARAM) c);
|
||||
}
|
||||
|
||||
void gui_send_errcount(int list, int errs)
|
||||
{
|
||||
unsigned int msg_id = WM_RET_ERR_CNT;
|
||||
if (list)
|
||||
msg_id = WM_LS_RET_ERR_CNT;
|
||||
while (!PostMessage(gui_hwnd, msg_id, (WPARAM) errs, 0))
|
||||
SleepEx(1000, TRUE);
|
||||
}
|
||||
|
||||
void gui_update_stats(char *name, unsigned long size,
|
||||
int percentage, unsigned long elapsed,
|
||||
unsigned long done, unsigned long eta,
|
||||
unsigned long ratebs)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (strcmp(name, statname) != 0) {
|
||||
for (i = 0; i < strlen(name); ++i)
|
||||
send_msg(gui_hwnd, WM_STATS_CHAR, (WPARAM) name[i]);
|
||||
send_msg(gui_hwnd, WM_STATS_CHAR, (WPARAM) '\n');
|
||||
strcpy(statname, name);
|
||||
}
|
||||
if (statsize != size) {
|
||||
send_msg(gui_hwnd, WM_STATS_SIZE, (WPARAM) size);
|
||||
statsize = size;
|
||||
}
|
||||
if (statdone != done) {
|
||||
send_msg(gui_hwnd, WM_STATS_DONE, (WPARAM) done);
|
||||
statdone = done;
|
||||
}
|
||||
if (stateta != eta) {
|
||||
send_msg(gui_hwnd, WM_STATS_ETA, (WPARAM) eta);
|
||||
stateta = eta;
|
||||
}
|
||||
if (statratebs != ratebs) {
|
||||
send_msg(gui_hwnd, WM_STATS_RATEBS, (WPARAM) ratebs);
|
||||
statratebs = ratebs;
|
||||
}
|
||||
if (statelapsed != elapsed) {
|
||||
send_msg(gui_hwnd, WM_STATS_ELAPSED, (WPARAM) elapsed);
|
||||
statelapsed = elapsed;
|
||||
}
|
||||
if (statperct != percentage) {
|
||||
send_msg(gui_hwnd, WM_STATS_PERCENT, (WPARAM) percentage);
|
||||
statperct = percentage;
|
||||
}
|
||||
}
|
||||
|
||||
void gui_enable(char *arg)
|
||||
{
|
||||
gui_hwnd = (HWND) atoi(arg);
|
||||
}
|
||||
#include "int64.h"
|
||||
|
||||
char *get_ttymode(void *frontend, const char *mode) { return NULL; }
|
||||
|
||||
@ -188,7 +71,7 @@ struct RFile {
|
||||
HANDLE h;
|
||||
};
|
||||
|
||||
RFile *open_existing_file(char *name, unsigned long *size,
|
||||
RFile *open_existing_file(char *name, uint64 *size,
|
||||
unsigned long *mtime, unsigned long *atime)
|
||||
{
|
||||
HANDLE h;
|
||||
@ -203,7 +86,7 @@ RFile *open_existing_file(char *name, unsigned long *size,
|
||||
ret->h = h;
|
||||
|
||||
if (size)
|
||||
*size = GetFileSize(h, NULL);
|
||||
size->lo=GetFileSize(h, &(size->hi));
|
||||
|
||||
if (mtime || atime) {
|
||||
FILETIME actime, wrtime;
|
||||
@ -253,6 +136,25 @@ WFile *open_new_file(char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
WFile *open_existing_wfile(char *name, uint64 *size)
|
||||
{
|
||||
HANDLE h;
|
||||
WFile *ret;
|
||||
|
||||
h = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, 0, 0);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
ret = snew(WFile);
|
||||
ret->h = h;
|
||||
|
||||
if (size)
|
||||
size->lo=GetFileSize(h, &(size->hi));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_to_file(WFile *f, void *buffer, int length)
|
||||
{
|
||||
int ret, written;
|
||||
@ -277,6 +179,44 @@ void close_wfile(WFile *f)
|
||||
sfree(f);
|
||||
}
|
||||
|
||||
/* Seek offset bytes through file, from whence, where whence is
|
||||
FROM_START, FROM_CURRENT, or FROM_END */
|
||||
int seek_file(WFile *f, uint64 offset, int whence)
|
||||
{
|
||||
DWORD movemethod;
|
||||
|
||||
switch (whence) {
|
||||
case FROM_START:
|
||||
movemethod = FILE_BEGIN;
|
||||
break;
|
||||
case FROM_CURRENT:
|
||||
movemethod = FILE_CURRENT;
|
||||
break;
|
||||
case FROM_END:
|
||||
movemethod = FILE_END;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetFilePointer(f->h, offset.lo, &(offset.hi), movemethod);
|
||||
|
||||
if (GetLastError() != NO_ERROR)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 get_file_posn(WFile *f)
|
||||
{
|
||||
uint64 ret;
|
||||
|
||||
ret.hi = 0L;
|
||||
ret.lo = SetFilePointer(f->h, 0L, &(ret.hi), FILE_CURRENT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int file_type(char *name)
|
||||
{
|
||||
DWORD attr;
|
||||
|
Loading…
Reference in New Issue
Block a user