From: owen Date: Sat, 12 Aug 2006 15:20:19 +0000 (+0000) Subject: Large file support for psftp and pscp on both Windows and Unix. On Unix X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/commitdiff_plain/0ac1920cf35f15c8fd8dbfedb332bd79e5ecdd33 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. git-svn-id: svn://svn.tartarus.org/sgt/putty@6783 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/mkfiles.pl b/mkfiles.pl index b13c4eba..79a2f0a1 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -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", diff --git a/pscp.c b/pscp.c index 5792c3ed..a906303b 100644 --- a/pscp.c +++ b/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); diff --git a/psftp.c b/psftp.c index 2b0a1371..2a74bcd2 100644 --- a/psftp.c +++ b/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; } diff --git a/psftp.h b/psftp.h index 2f323c7b..8d9391c2 100644 --- a/psftp.h +++ b/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, diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 0779ff18..8db397ad 100644 --- a/unix/uxsftp.c +++ b/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 @@ -80,18 +81,6 @@ int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) } /* - * 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; diff --git a/windows/winsftp.c b/windows/winsftp.c index 47d3c437..d14e817e 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -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;