"\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",
#include "ssh.h"
#include "sftp.h"
#include "storage.h"
+#include "int64.h"
static int list = 0;
static int verbose = 0;
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;
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)
sfree(str2);
errs++;
- if (gui_mode)
- gui_send_errcount(list, errs);
-
cleanup_exit(1);
}
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, ...)
sfree(str2);
errs++;
- if (gui_mode)
- gui_send_errcount(list, errs);
-
cleanup_exit(1);
}
ssh_scp_recv((unsigned char *) &ch, 1);
}
- if (gui_mode)
- gui_send_errcount(list, errs);
-
cleanup_exit(1);
}
/*
* 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;
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);
}
}
-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;
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);
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 */
};
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)) {
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)) {
* 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;
+ }
}
}
*/
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);
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");
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);
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;
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)
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);
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) {
}
random_save_seed();
- if (gui_mode)
- gui_send_errcount(list, errs);
-
cmdline_cleanup();
console_provide_logctx(NULL);
back->free(backhandle);
struct sftp_request *req, *rreq;
struct fxp_xfer *xfer;
uint64 offset;
- FILE *fp;
+ WFile *file;
int ret, shown_err = FALSE;
/*
}
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));
}
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);
}
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;
xfer_cleanup(xfer);
- fclose(fp);
+ close_wfile(file);
sftp_register(req = fxp_close_send(fh));
rreq = sftp_find_request(pktin = sftp_recv());
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
uint64 offset;
- FILE *fp;
+ RFile *file;
int ret, err, eof;
/*
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;
}
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);
}
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;
assert(rreq == req);
fxp_close_recv(pktin, rreq);
- fclose(fp);
+ close_rfile(file);
return ret;
}
* platform-specific SFTP module.
*/
+#include "int64.h"
+
#ifndef PUTTY_PSFTP_H
#define PUTTY_PSFTP_H
* 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 */
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,
#include "putty.h"
#include "psftp.h"
+#include "int64.h"
/*
* In PSFTP our selects are synchronous, so these functions are
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.
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;
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;
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;
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;
#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; }
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;
ret->h = h;
if (size)
- *size = GetFileSize(h, NULL);
+ size->lo=GetFileSize(h, &(size->hi));
if (mtime || atime) {
FILETIME actime, wrtime;
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;
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;