+#define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
+ ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
+#define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
+ ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
+
+struct RFile {
+ HANDLE h;
+};
+
+RFile *open_existing_file(char *name, unsigned long *size,
+ unsigned long *mtime, unsigned long *atime)
+{
+ HANDLE h;
+ RFile *ret;
+
+ h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, 0, 0);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ ret = snew(RFile);
+ ret->h = h;
+
+ if (size)
+ *size = GetFileSize(h, NULL);
+
+ if (mtime || atime) {
+ FILETIME actime, wrtime;
+ GetFileTime(h, NULL, &actime, &wrtime);
+ if (atime)
+ TIME_WIN_TO_POSIX(actime, *atime);
+ if (mtime)
+ TIME_WIN_TO_POSIX(wrtime, *mtime);
+ }
+
+ return ret;
+}
+
+int read_from_file(RFile *f, void *buffer, int length)
+{
+ int ret, read;
+ ret = ReadFile(f->h, buffer, length, &read, NULL);
+ if (!ret)
+ return -1; /* error */
+ else
+ return read;
+}
+
+void close_rfile(RFile *f)
+{
+ CloseHandle(f->h);
+ sfree(f);
+}
+
+struct WFile {
+ HANDLE h;
+};
+
+WFile *open_new_file(char *name)
+{
+ HANDLE h;
+ WFile *ret;
+
+ h = CreateFile(name, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ ret = snew(WFile);
+ ret->h = h;
+
+ return ret;
+}
+
+int write_to_file(WFile *f, void *buffer, int length)
+{
+ int ret, written;
+ ret = WriteFile(f->h, buffer, length, &written, NULL);
+ if (!ret)
+ return -1; /* error */
+ else
+ return written;
+}
+
+void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
+{
+ FILETIME actime, wrtime;
+ TIME_POSIX_TO_WIN(atime, actime);
+ TIME_POSIX_TO_WIN(mtime, wrtime);
+ SetFileTime(f->h, NULL, &actime, &wrtime);
+}
+
+void close_wfile(WFile *f)
+{
+ CloseHandle(f->h);
+ sfree(f);
+}
+
+int file_type(char *name)
+{
+ DWORD attr;
+ attr = GetFileAttributes(name);
+ /* We know of no `weird' files under Windows. */
+ if (attr == (DWORD)-1)
+ return FILE_TYPE_NONEXISTENT;
+ else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+ return FILE_TYPE_DIRECTORY;
+ else
+ return FILE_TYPE_FILE;
+}
+
+struct DirHandle {
+ HANDLE h;
+ char *name;
+};
+
+DirHandle *open_directory(char *name)
+{
+ HANDLE h;
+ WIN32_FIND_DATA fdat;
+ char *findfile;
+ DirHandle *ret;
+
+ /* To enumerate files in dir `foo', we search for `foo/*'. */
+ findfile = dupcat(name, "/*", NULL);
+ h = FindFirstFile(findfile, &fdat);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ sfree(findfile);
+
+ ret = snew(DirHandle);
+ ret->h = h;
+ ret->name = dupstr(fdat.cFileName);
+ return ret;
+}
+
+char *read_filename(DirHandle *dir)
+{
+ while (!dir->name) {
+ WIN32_FIND_DATA fdat;
+ int ok = FindNextFile(dir->h, &fdat);
+
+ if (!ok)
+ return NULL;
+
+ if (fdat.cFileName[0] == '.' &&
+ (fdat.cFileName[1] == '\0' ||
+ (fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
+ dir->name = NULL;
+ else
+ dir->name = dupstr(fdat.cFileName);
+ }
+
+ if (dir->name) {
+ char *ret = dir->name;
+ dir->name = NULL;
+ return ret;
+ } else
+ return NULL;
+}
+
+void close_directory(DirHandle *dir)
+{
+ FindClose(dir->h);
+ if (dir->name)
+ sfree(dir->name);
+ sfree(dir);
+}
+
+int test_wildcard(char *name, int cmdline)
+{
+ HANDLE fh;
+ WIN32_FIND_DATA fdat;
+
+ /* First see if the exact name exists. */
+ if (GetFileAttributes(name) != (DWORD)-1)
+ return WCTYPE_FILENAME;
+
+ /* Otherwise see if a wildcard match finds anything. */
+ fh = FindFirstFile(name, &fdat);
+ if (fh == INVALID_HANDLE_VALUE)
+ return WCTYPE_NONEXISTENT;
+
+ FindClose(fh);
+ return WCTYPE_WILDCARD;
+}
+
+struct WildcardMatcher {
+ HANDLE h;
+ char *name;
+ char *srcpath;
+};
+
+/*
+ * Return a pointer to the portion of str that comes after the last
+ * slash (or backslash or colon, if `local' is TRUE).
+ */
+static char *stripslashes(char *str, int local)
+{
+ char *p;
+
+ if (local) {
+ p = strchr(str, ':');
+ if (p) str = p+1;
+ }
+
+ p = strrchr(str, '/');
+ if (p) str = p+1;
+
+ if (local) {
+ p = strrchr(str, '\\');
+ if (p) str = p+1;
+ }
+
+ return str;
+}
+
+WildcardMatcher *begin_wildcard_matching(char *name)
+{
+ HANDLE h;
+ WIN32_FIND_DATA fdat;
+ WildcardMatcher *ret;
+ char *last;
+
+ h = FindFirstFile(name, &fdat);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ ret = snew(WildcardMatcher);
+ ret->h = h;
+ ret->srcpath = dupstr(name);
+ last = stripslashes(ret->srcpath, 1);
+ *last = '\0';
+ if (fdat.cFileName[0] == '.' &&
+ (fdat.cFileName[1] == '\0' ||
+ (fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
+ ret->name = NULL;
+ else
+ ret->name = dupcat(ret->srcpath, fdat.cFileName, NULL);
+
+ return ret;
+}
+
+char *wildcard_get_filename(WildcardMatcher *dir)
+{
+ while (!dir->name) {
+ WIN32_FIND_DATA fdat;
+ int ok = FindNextFile(dir->h, &fdat);
+
+ if (!ok)
+ return NULL;
+
+ if (fdat.cFileName[0] == '.' &&
+ (fdat.cFileName[1] == '\0' ||
+ (fdat.cFileName[1] == '.' && fdat.cFileName[2] == '\0')))
+ dir->name = NULL;
+ else
+ dir->name = dupcat(dir->srcpath, fdat.cFileName, NULL);
+ }
+
+ if (dir->name) {
+ char *ret = dir->name;
+ dir->name = NULL;
+ return ret;
+ } else
+ return NULL;
+}
+
+void finish_wildcard_matching(WildcardMatcher *dir)
+{
+ FindClose(dir->h);
+ if (dir->name)
+ sfree(dir->name);
+ sfree(dir->srcpath);
+ sfree(dir);
+}
+
+int create_directory(char *name)
+{
+ return CreateDirectory(name, NULL) != 0;
+}
+
+char *dir_file_cat(char *dir, char *file)
+{
+ return dupcat(dir, "\\", file, NULL);
+}
+
+/* ----------------------------------------------------------------------
+ * Platform-specific network handling.
+ */
+
+/*
+ * Be told what socket we're supposed to be using.
+ */
+static SOCKET sftp_ssh_socket;
+char *do_select(SOCKET skt, int startup)
+{
+ if (startup)
+ sftp_ssh_socket = skt;
+ else
+ sftp_ssh_socket = INVALID_SOCKET;
+ return NULL;
+}
+extern int select_result(WPARAM, LPARAM);
+