mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 01:02:24 +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".
|
"\n".
|
||||||
&splitline("CFLAGS = -O2 -Wall -Werror -g " .
|
&splitline("CFLAGS = -O2 -Wall -Werror -g " .
|
||||||
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
|
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
|
||||||
" `gtk-config --cflags`")."\n".
|
" `gtk-config --cflags`").
|
||||||
|
" -D _FILE_OFFSET_BITS=64\n".
|
||||||
"XLDFLAGS = `gtk-config --libs`\n".
|
"XLDFLAGS = `gtk-config --libs`\n".
|
||||||
"ULDFLAGS =#\n".
|
"ULDFLAGS =#\n".
|
||||||
"INSTALL=install\n",
|
"INSTALL=install\n",
|
||||||
|
147
pscp.c
147
pscp.c
@ -25,6 +25,7 @@
|
|||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "sftp.h"
|
#include "sftp.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "int64.h"
|
||||||
|
|
||||||
static int list = 0;
|
static int list = 0;
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
@ -35,7 +36,6 @@ static int statistics = 1;
|
|||||||
static int prev_stats_len = 0;
|
static int prev_stats_len = 0;
|
||||||
static int scp_unsafe_mode = 0;
|
static int scp_unsafe_mode = 0;
|
||||||
static int errs = 0;
|
static int errs = 0;
|
||||||
static int gui_mode = 0;
|
|
||||||
static int try_scp = 1;
|
static int try_scp = 1;
|
||||||
static int try_sftp = 1;
|
static int try_sftp = 1;
|
||||||
static int main_cmd_is_sftp = 0;
|
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)
|
static void tell_char(FILE * stream, char c)
|
||||||
{
|
{
|
||||||
if (!gui_mode)
|
fputc(c, stream);
|
||||||
fputc(c, stream);
|
|
||||||
else
|
|
||||||
gui_send_char(stream == stderr, c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tell_str(FILE * stream, char *str)
|
static void tell_str(FILE * stream, char *str)
|
||||||
@ -112,9 +109,6 @@ void fatalbox(char *fmt, ...)
|
|||||||
sfree(str2);
|
sfree(str2);
|
||||||
errs++;
|
errs++;
|
||||||
|
|
||||||
if (gui_mode)
|
|
||||||
gui_send_errcount(list, errs);
|
|
||||||
|
|
||||||
cleanup_exit(1);
|
cleanup_exit(1);
|
||||||
}
|
}
|
||||||
void modalfatalbox(char *fmt, ...)
|
void modalfatalbox(char *fmt, ...)
|
||||||
@ -130,9 +124,6 @@ void modalfatalbox(char *fmt, ...)
|
|||||||
sfree(str2);
|
sfree(str2);
|
||||||
errs++;
|
errs++;
|
||||||
|
|
||||||
if (gui_mode)
|
|
||||||
gui_send_errcount(list, errs);
|
|
||||||
|
|
||||||
cleanup_exit(1);
|
cleanup_exit(1);
|
||||||
}
|
}
|
||||||
void connection_fatal(void *frontend, char *fmt, ...)
|
void connection_fatal(void *frontend, char *fmt, ...)
|
||||||
@ -148,9 +139,6 @@ void connection_fatal(void *frontend, char *fmt, ...)
|
|||||||
sfree(str2);
|
sfree(str2);
|
||||||
errs++;
|
errs++;
|
||||||
|
|
||||||
if (gui_mode)
|
|
||||||
gui_send_errcount(list, errs);
|
|
||||||
|
|
||||||
cleanup_exit(1);
|
cleanup_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,9 +298,6 @@ static void bump(char *fmt, ...)
|
|||||||
ssh_scp_recv((unsigned char *) &ch, 1);
|
ssh_scp_recv((unsigned char *) &ch, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gui_mode)
|
|
||||||
gui_send_errcount(list, errs);
|
|
||||||
|
|
||||||
cleanup_exit(1);
|
cleanup_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +480,7 @@ static void do_cmd(char *host, char *user, char *cmd)
|
|||||||
/*
|
/*
|
||||||
* Update statistic information about current file.
|
* 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)
|
time_t start, time_t now)
|
||||||
{
|
{
|
||||||
float ratebs;
|
float ratebs;
|
||||||
@ -504,34 +489,42 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
|
|||||||
int pct;
|
int pct;
|
||||||
int len;
|
int len;
|
||||||
int elap;
|
int elap;
|
||||||
|
double donedbl;
|
||||||
|
double sizedbl;
|
||||||
|
|
||||||
elap = (unsigned long) difftime(now, start);
|
elap = (unsigned long) difftime(now, start);
|
||||||
|
|
||||||
if (now > start)
|
if (now > start)
|
||||||
ratebs = (float) done / elap;
|
ratebs = (float) (uint64_to_double(done) / elap);
|
||||||
else
|
else
|
||||||
ratebs = (float) done;
|
ratebs = (float) uint64_to_double(done);
|
||||||
|
|
||||||
if (ratebs < 1.0)
|
if (ratebs < 1.0)
|
||||||
eta = size - done;
|
eta = (unsigned long) (uint64_to_double(uint64_subtract(size, done)));
|
||||||
else
|
else {
|
||||||
eta = (unsigned long) ((size - done) / ratebs);
|
eta = (unsigned long)
|
||||||
|
((uint64_to_double(uint64_subtract(size, done)) / ratebs));
|
||||||
|
}
|
||||||
|
|
||||||
etastr = dupprintf("%02ld:%02ld:%02ld",
|
etastr = dupprintf("%02ld:%02ld:%02ld",
|
||||||
eta / 3600, (eta % 3600) / 60, eta % 60);
|
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,
|
char donekb[40];
|
||||||
(unsigned long) ratebs);
|
/* divide by 1024 to provide kB */
|
||||||
} else {
|
uint64_decimal(uint64_shift_right(done, 10), donekb);
|
||||||
len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
|
len = printf("\r%-25.25s | %s kB | %5.1f kB/s | ETA: %8s | %3d%%",
|
||||||
name, done / 1024, ratebs / 1024.0, etastr, pct);
|
name,
|
||||||
|
donekb, ratebs / 1024.0, etastr, pct);
|
||||||
if (len < prev_stats_len)
|
if (len < prev_stats_len)
|
||||||
printf("%*s", prev_stats_len - len, "");
|
printf("%*s", prev_stats_len - len, "");
|
||||||
prev_stats_len = len;
|
prev_stats_len = len;
|
||||||
|
|
||||||
if (done == size)
|
if (uint64_compare(done, size) == 0)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
fflush(stdout);
|
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) {
|
if (using_sftp) {
|
||||||
char *fullname;
|
char *fullname;
|
||||||
@ -854,7 +847,9 @@ int scp_send_filename(char *name, unsigned long size, int modes)
|
|||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
char buf[40];
|
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, buf, strlen(buf));
|
||||||
back->send(backhandle, name, strlen(name));
|
back->send(backhandle, name, strlen(name));
|
||||||
back->send(backhandle, "\n", 1);
|
back->send(backhandle, "\n", 1);
|
||||||
@ -1135,7 +1130,7 @@ struct scp_sink_action {
|
|||||||
char *buf; /* will need freeing after use */
|
char *buf; /* will need freeing after use */
|
||||||
char *name; /* filename or dirname (not ENDDIR) */
|
char *name; /* filename or dirname (not ENDDIR) */
|
||||||
int mode; /* access mode (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 */
|
int settime; /* 1 if atime and mtime are filled */
|
||||||
unsigned long atime, mtime; /* access times for the file */
|
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->action = SCP_SINK_DIR;
|
||||||
act->buf = dupstr(stripslashes(fname, 0));
|
act->buf = dupstr(stripslashes(fname, 0));
|
||||||
act->name = act->buf;
|
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;
|
act->mode = 07777 & attrs.permissions;
|
||||||
if (scp_sftp_preserve &&
|
if (scp_sftp_preserve &&
|
||||||
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
|
(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->buf = dupstr(stripslashes(fname, 0));
|
||||||
act->name = act->buf;
|
act->name = act->buf;
|
||||||
if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
|
if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
|
||||||
if (uint64_compare(attrs.size,
|
act->size = attrs.size;
|
||||||
uint64_make(0, ULONG_MAX)) > 0) {
|
|
||||||
act->size = ULONG_MAX; /* *boggle* */
|
|
||||||
} else
|
|
||||||
act->size = attrs.size.lo;
|
|
||||||
} else
|
} else
|
||||||
act->size = ULONG_MAX; /* no idea */
|
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
|
||||||
act->mode = 07777 & attrs.permissions;
|
act->mode = 07777 & attrs.permissions;
|
||||||
if (scp_sftp_preserve &&
|
if (scp_sftp_preserve &&
|
||||||
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
|
(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
|
* If we get here, we must have seen SCP_SINK_FILE or
|
||||||
* SCP_SINK_DIR.
|
* SCP_SINK_DIR.
|
||||||
*/
|
*/
|
||||||
if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2)
|
{
|
||||||
bump("Protocol error: Illegal file descriptor format");
|
char sizestr[40];
|
||||||
act->name = act->buf + i;
|
|
||||||
return 0;
|
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)
|
static void source(char *src)
|
||||||
{
|
{
|
||||||
unsigned long size;
|
uint64 size;
|
||||||
unsigned long mtime, atime;
|
unsigned long mtime, atime;
|
||||||
char *last;
|
char *last;
|
||||||
RFile *f;
|
RFile *f;
|
||||||
int attr;
|
int attr;
|
||||||
unsigned long i;
|
uint64 i;
|
||||||
unsigned long stat_bytes;
|
uint64 stat_bytes;
|
||||||
time_t stat_starttime, stat_lasttime;
|
time_t stat_starttime, stat_lasttime;
|
||||||
|
|
||||||
attr = file_type(src);
|
attr = file_type(src);
|
||||||
@ -1655,21 +1651,26 @@ static void source(char *src)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose) {
|
||||||
tell_user(stderr, "Sending file %s, size=%lu", last, size);
|
char sizestr[40];
|
||||||
|
uint64_decimal(size, sizestr);
|
||||||
|
tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
|
||||||
|
}
|
||||||
if (scp_send_filename(last, size, 0644))
|
if (scp_send_filename(last, size, 0644))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stat_bytes = 0;
|
stat_bytes = uint64_make(0,0);
|
||||||
stat_starttime = time(NULL);
|
stat_starttime = time(NULL);
|
||||||
stat_lasttime = 0;
|
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];
|
char transbuf[4096];
|
||||||
int j, k = 4096;
|
int j, k = 4096;
|
||||||
|
|
||||||
if (i + k > size)
|
if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */
|
||||||
k = size - i;
|
k = (uint64_subtract(size, i)).lo; /* k = size - i; */
|
||||||
if ((j = read_from_file(f, transbuf, k)) != k) {
|
if ((j = read_from_file(f, transbuf, k)) != k) {
|
||||||
if (statistics)
|
if (statistics)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -1679,8 +1680,9 @@ static void source(char *src)
|
|||||||
bump("%s: Network error occurred", src);
|
bump("%s: Network error occurred", src);
|
||||||
|
|
||||||
if (statistics) {
|
if (statistics) {
|
||||||
stat_bytes += k;
|
stat_bytes = uint64_add32(stat_bytes, k);
|
||||||
if (time(NULL) != stat_lasttime || i + k == size) {
|
if (time(NULL) != stat_lasttime ||
|
||||||
|
(uint64_compare(uint64_add32(i, k), size) == 0)) {
|
||||||
stat_lasttime = time(NULL);
|
stat_lasttime = time(NULL);
|
||||||
print_stats(last, size, stat_bytes,
|
print_stats(last, size, stat_bytes,
|
||||||
stat_starttime, stat_lasttime);
|
stat_starttime, stat_lasttime);
|
||||||
@ -1747,9 +1749,9 @@ static void sink(char *targ, char *src)
|
|||||||
int exists;
|
int exists;
|
||||||
int attr;
|
int attr;
|
||||||
WFile *f;
|
WFile *f;
|
||||||
unsigned long received;
|
uint64 received;
|
||||||
int wrerror = 0;
|
int wrerror = 0;
|
||||||
unsigned long stat_bytes;
|
uint64 stat_bytes;
|
||||||
time_t stat_starttime, stat_lasttime;
|
time_t stat_starttime, stat_lasttime;
|
||||||
char *stat_name;
|
char *stat_name;
|
||||||
|
|
||||||
@ -1880,20 +1882,20 @@ static void sink(char *targ, char *src)
|
|||||||
if (scp_accept_filexfer())
|
if (scp_accept_filexfer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stat_bytes = 0;
|
stat_bytes = uint64_make(0, 0);
|
||||||
stat_starttime = time(NULL);
|
stat_starttime = time(NULL);
|
||||||
stat_lasttime = 0;
|
stat_lasttime = 0;
|
||||||
stat_name = stripslashes(destfname, 1);
|
stat_name = stripslashes(destfname, 1);
|
||||||
|
|
||||||
received = 0;
|
received = uint64_make(0, 0);
|
||||||
while (received < act.size) {
|
while (uint64_compare(received,act.size) < 0) {
|
||||||
char transbuf[32768];
|
char transbuf[32768];
|
||||||
unsigned long blksize;
|
uint64 blksize;
|
||||||
int read;
|
int read;
|
||||||
blksize = 32768;
|
blksize = uint64_make(0, 32768);
|
||||||
if (blksize > (act.size - received))
|
if (uint64_compare(blksize,uint64_subtract(act.size,received)) > 0)
|
||||||
blksize = act.size - received;
|
blksize = uint64_subtract(act.size,received);
|
||||||
read = scp_recv_filedata(transbuf, (int)blksize);
|
read = scp_recv_filedata(transbuf, (int)blksize.lo);
|
||||||
if (read <= 0)
|
if (read <= 0)
|
||||||
bump("Lost connection");
|
bump("Lost connection");
|
||||||
if (wrerror)
|
if (wrerror)
|
||||||
@ -1908,15 +1910,15 @@ static void sink(char *targ, char *src)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (statistics) {
|
if (statistics) {
|
||||||
stat_bytes += read;
|
stat_bytes = uint64_add32(stat_bytes,read);
|
||||||
if (time(NULL) > stat_lasttime ||
|
if (time(NULL) > stat_lasttime ||
|
||||||
received + read == act.size) {
|
uint64_compare(uint64_add32(received, read), act.size) == 0) {
|
||||||
stat_lasttime = time(NULL);
|
stat_lasttime = time(NULL);
|
||||||
print_stats(stat_name, act.size, stat_bytes,
|
print_stats(stat_name, act.size, stat_bytes,
|
||||||
stat_starttime, stat_lasttime);
|
stat_starttime, stat_lasttime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
received += read;
|
received = uint64_add32(received, read);
|
||||||
}
|
}
|
||||||
if (act.settime) {
|
if (act.settime) {
|
||||||
set_file_times(f, act.mtime, act.atime);
|
set_file_times(f, act.mtime, act.atime);
|
||||||
@ -2244,10 +2246,6 @@ int psftp_main(int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
} else if (strcmp(argv[i], "-V") == 0) {
|
} else if (strcmp(argv[i], "-V") == 0) {
|
||||||
version();
|
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) {
|
} else if (strcmp(argv[i], "-ls") == 0) {
|
||||||
list = 1;
|
list = 1;
|
||||||
} else if (strcmp(argv[i], "-batch") == 0) {
|
} else if (strcmp(argv[i], "-batch") == 0) {
|
||||||
@ -2294,9 +2292,6 @@ int psftp_main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
random_save_seed();
|
random_save_seed();
|
||||||
|
|
||||||
if (gui_mode)
|
|
||||||
gui_send_errcount(list, errs);
|
|
||||||
|
|
||||||
cmdline_cleanup();
|
cmdline_cleanup();
|
||||||
console_provide_logctx(NULL);
|
console_provide_logctx(NULL);
|
||||||
back->free(backhandle);
|
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 sftp_request *req, *rreq;
|
||||||
struct fxp_xfer *xfer;
|
struct fxp_xfer *xfer;
|
||||||
uint64 offset;
|
uint64 offset;
|
||||||
FILE *fp;
|
WFile *file;
|
||||||
int ret, shown_err = FALSE;
|
int ret, shown_err = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -386,12 +386,12 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (restart) {
|
if (restart) {
|
||||||
fp = fopen(outfname, "rb+");
|
file = open_existing_wfile(outfname, NULL);
|
||||||
} else {
|
} else {
|
||||||
fp = fopen(outfname, "wb");
|
file = open_new_file(outfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp) {
|
if (!file) {
|
||||||
printf("local: unable to open %s\n", outfname);
|
printf("local: unable to open %s\n", outfname);
|
||||||
|
|
||||||
sftp_register(req = fxp_close_send(fh));
|
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) {
|
if (restart) {
|
||||||
long posn;
|
char decbuf[30];
|
||||||
fseek(fp, 0L, SEEK_END);
|
if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) {
|
||||||
posn = ftell(fp);
|
printf("reget: cannot restart %s - file too large\n",
|
||||||
printf("reget: restarting at file position %ld\n", posn);
|
outfname);
|
||||||
offset = uint64_make(0, posn);
|
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 {
|
} else {
|
||||||
offset = uint64_make(0, 0);
|
offset = uint64_make(0, 0);
|
||||||
}
|
}
|
||||||
@ -442,7 +452,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
|
|
||||||
wpos = 0;
|
wpos = 0;
|
||||||
while (wpos < len) {
|
while (wpos < len) {
|
||||||
wlen = fwrite(buf + wpos, 1, len - wpos, fp);
|
wlen = write_to_file(file, buf + wpos, len - wpos);
|
||||||
if (wlen <= 0) {
|
if (wlen <= 0) {
|
||||||
printf("error while writing local file\n");
|
printf("error while writing local file\n");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -461,7 +471,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
|
|
||||||
xfer_cleanup(xfer);
|
xfer_cleanup(xfer);
|
||||||
|
|
||||||
fclose(fp);
|
close_wfile(file);
|
||||||
|
|
||||||
sftp_register(req = fxp_close_send(fh));
|
sftp_register(req = fxp_close_send(fh));
|
||||||
rreq = sftp_find_request(pktin = sftp_recv());
|
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_packet *pktin;
|
||||||
struct sftp_request *req, *rreq;
|
struct sftp_request *req, *rreq;
|
||||||
uint64 offset;
|
uint64 offset;
|
||||||
FILE *fp;
|
RFile *file;
|
||||||
int ret, err, eof;
|
int ret, err, eof;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -608,8 +618,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(fname, "rb");
|
file = open_existing_file(fname, NULL, NULL, NULL);
|
||||||
if (!fp) {
|
if (!file) {
|
||||||
printf("local: unable to open %s\n", fname);
|
printf("local: unable to open %s\n", fname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -649,12 +659,9 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
offset = attrs.size;
|
offset = attrs.size;
|
||||||
uint64_decimal(offset, decbuf);
|
uint64_decimal(offset, decbuf);
|
||||||
printf("reput: restarting at file position %s\n", 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");
|
if (seek_file((WFile *)file, offset, FROM_START) != 0)
|
||||||
return 0;
|
seek_file((WFile *)file, uint64_make(0,0), FROM_END); /* *shrug* */
|
||||||
}
|
|
||||||
if (fseek(fp, offset.lo, SEEK_SET) != 0)
|
|
||||||
fseek(fp, 0, SEEK_END); /* *shrug* */
|
|
||||||
} else {
|
} else {
|
||||||
offset = uint64_make(0, 0);
|
offset = uint64_make(0, 0);
|
||||||
}
|
}
|
||||||
@ -673,7 +680,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
int len, ret;
|
int len, ret;
|
||||||
|
|
||||||
while (xfer_upload_ready(xfer) && !err && !eof) {
|
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) {
|
if (len == -1) {
|
||||||
printf("error while reading local file\n");
|
printf("error while reading local file\n");
|
||||||
err = 1;
|
err = 1;
|
||||||
@ -701,7 +708,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
|||||||
assert(rreq == req);
|
assert(rreq == req);
|
||||||
fxp_close_recv(pktin, rreq);
|
fxp_close_recv(pktin, rreq);
|
||||||
|
|
||||||
fclose(fp);
|
close_rfile(file);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
17
psftp.h
17
psftp.h
@ -3,6 +3,8 @@
|
|||||||
* platform-specific SFTP module.
|
* platform-specific SFTP module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "int64.h"
|
||||||
|
|
||||||
#ifndef PUTTY_PSFTP_H
|
#ifndef PUTTY_PSFTP_H
|
||||||
#define PUTTY_PSFTP_H
|
#define PUTTY_PSFTP_H
|
||||||
|
|
||||||
@ -78,16 +80,15 @@ void gui_enable(char *arg);
|
|||||||
* the times when saving a new file.
|
* the times when saving a new file.
|
||||||
*
|
*
|
||||||
* On the other hand, the abstraction is pretty simple: it supports
|
* On the other hand, the abstraction is pretty simple: it supports
|
||||||
* only opening a file and reading it, or creating a file and
|
* only opening a file and reading it, or creating a file and writing
|
||||||
* writing it. (FIXME: to use this in PSFTP it will also need to
|
* it. None of this read-and-write, seeking-back-and-forth stuff.
|
||||||
* support seeking to a starting point for restarted transfers.)
|
|
||||||
* None of this read-and-write, seeking-back-and-forth stuff.
|
|
||||||
*/
|
*/
|
||||||
typedef struct RFile RFile;
|
typedef struct RFile RFile;
|
||||||
typedef struct WFile WFile;
|
typedef struct WFile WFile;
|
||||||
/* Output params size, mtime and atime can all be NULL if desired */
|
/* 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);
|
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 */
|
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
|
||||||
int read_from_file(RFile *f, void *buffer, int length);
|
int read_from_file(RFile *f, void *buffer, int length);
|
||||||
/* Closes and frees the RFile */
|
/* 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);
|
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);
|
||||||
/* Closes and frees the WFile */
|
/* Closes and frees the WFile */
|
||||||
void close_wfile(WFile *f);
|
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
|
* Determine the type of a file: nonexistent, file, directory or
|
||||||
* weird. `weird' covers anything else - named pipes, Unix sockets,
|
* 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 "putty.h"
|
||||||
#include "psftp.h"
|
#include "psftp.h"
|
||||||
|
#include "int64.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In PSFTP our selects are synchronous, so these functions are
|
* 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;
|
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
|
* Set local current directory. Returns NULL on success, or else an
|
||||||
* error message which must be freed after printing.
|
* error message which must be freed after printing.
|
||||||
@ -134,7 +123,7 @@ struct RFile {
|
|||||||
int fd;
|
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)
|
unsigned long *mtime, unsigned long *atime)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
@ -154,9 +143,15 @@ RFile *open_existing_file(char *name, unsigned long *size,
|
|||||||
memset(&statbuf, 0, sizeof(statbuf));
|
memset(&statbuf, 0, sizeof(statbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size)
|
if (size) {
|
||||||
*size = statbuf.st_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)
|
if (mtime)
|
||||||
*mtime = statbuf.st_mtime;
|
*mtime = statbuf.st_mtime;
|
||||||
|
|
||||||
@ -199,6 +194,37 @@ WFile *open_new_file(char *name)
|
|||||||
return ret;
|
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)
|
int write_to_file(WFile *f, void *buffer, int length)
|
||||||
{
|
{
|
||||||
char *p = (char *)buffer;
|
char *p = (char *)buffer;
|
||||||
@ -240,6 +266,53 @@ void close_wfile(WFile *f)
|
|||||||
sfree(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)
|
int file_type(char *name)
|
||||||
{
|
{
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
@ -6,124 +6,7 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "psftp.h"
|
#include "psftp.h"
|
||||||
|
#include "int64.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *get_ttymode(void *frontend, const char *mode) { return NULL; }
|
char *get_ttymode(void *frontend, const char *mode) { return NULL; }
|
||||||
|
|
||||||
@ -188,7 +71,7 @@ struct RFile {
|
|||||||
HANDLE h;
|
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)
|
unsigned long *mtime, unsigned long *atime)
|
||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
@ -203,7 +86,7 @@ RFile *open_existing_file(char *name, unsigned long *size,
|
|||||||
ret->h = h;
|
ret->h = h;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
*size = GetFileSize(h, NULL);
|
size->lo=GetFileSize(h, &(size->hi));
|
||||||
|
|
||||||
if (mtime || atime) {
|
if (mtime || atime) {
|
||||||
FILETIME actime, wrtime;
|
FILETIME actime, wrtime;
|
||||||
@ -253,6 +136,25 @@ WFile *open_new_file(char *name)
|
|||||||
return ret;
|
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 write_to_file(WFile *f, void *buffer, int length)
|
||||||
{
|
{
|
||||||
int ret, written;
|
int ret, written;
|
||||||
@ -277,6 +179,44 @@ void close_wfile(WFile *f)
|
|||||||
sfree(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)
|
int file_type(char *name)
|
||||||
{
|
{
|
||||||
DWORD attr;
|
DWORD attr;
|
||||||
|
Loading…
Reference in New Issue
Block a user