+ }
+ CloseHandle(f);
+
+ (void) scp_send_finish();
+}
+
+/*
+ * Recursively send the contents of a directory.
+ */
+static void rsource(char *src)
+{
+ char *last, *findfile;
+ char *save_target;
+ HANDLE dir;
+ WIN32_FIND_DATA fdat;
+ int ok;
+
+ if ((last = strrchr(src, '/')) == NULL)
+ last = src;
+ else
+ last++;
+ if (strrchr(last, '\\') != NULL)
+ last = strrchr(last, '\\') + 1;
+ if (last == src && strchr(src, ':') != NULL)
+ last = strchr(src, ':') + 1;
+
+ /* maybe send filetime */
+
+ save_target = scp_save_remotepath();
+
+ if (verbose)
+ tell_user(stderr, "Entering directory: %s", last);
+ if (scp_send_dirname(last, 0755))
+ return;
+
+ findfile = dupcat(src, "/*", NULL);
+ dir = FindFirstFile(findfile, &fdat);
+ ok = (dir != INVALID_HANDLE_VALUE);
+ while (ok) {
+ if (strcmp(fdat.cFileName, ".") == 0 ||
+ strcmp(fdat.cFileName, "..") == 0) {
+ /* ignore . and .. */
+ } else {
+ char *foundfile = dupcat(src, "/", fdat.cFileName, NULL);
+ source(foundfile);
+ sfree(foundfile);
+ }
+ ok = FindNextFile(dir, &fdat);
+ }
+ FindClose(dir);
+ sfree(findfile);
+
+ (void) scp_send_enddir();
+
+ scp_restore_remotepath(save_target);
+}
+
+/*
+ * Execute the sink part of the SCP protocol.
+ */
+static void sink(char *targ, char *src)
+{
+ char *destfname;
+ int targisdir = 0;
+ int exists;
+ DWORD attr;
+ HANDLE f;
+ unsigned long received;
+ int wrerror = 0;
+ unsigned long stat_bytes;
+ time_t stat_starttime, stat_lasttime;
+ char *stat_name;
+
+ attr = GetFileAttributes(targ);
+ if (attr != (DWORD) - 1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ targisdir = 1;
+
+ if (targetshouldbedirectory && !targisdir)
+ bump("%s: Not a directory", targ);
+
+ scp_sink_init();
+ while (1) {
+ struct scp_sink_action act;
+ if (scp_get_sink_action(&act))
+ return;
+
+ if (act.action == SCP_SINK_ENDDIR)
+ return;
+
+ if (act.action == SCP_SINK_RETRY)
+ continue;
+
+ if (targisdir) {
+ /*
+ * Prevent the remote side from maliciously writing to
+ * files outside the target area by sending a filename
+ * containing `../'. In fact, it shouldn't be sending
+ * filenames with any slashes or colons in at all; so
+ * we'll find the last slash, backslash or colon in the
+ * filename and use only the part after that. (And
+ * warn!)
+ *
+ * In addition, we also ensure here that if we're
+ * copying a single file and the target is a directory
+ * (common usage: `pscp host:filename .') the remote
+ * can't send us a _different_ file name. We can
+ * distinguish this case because `src' will be non-NULL
+ * and the last component of that will fail to match
+ * (the last component of) the name sent.
+ *
+ * Well, not always; if `src' is a wildcard, we do
+ * expect to get back filenames that don't correspond
+ * exactly to it. Ideally in this case, we would like
+ * to ensure that the returned filename actually
+ * matches the wildcard pattern - but one of SCP's
+ * protocol infelicities is that wildcard matching is
+ * done at the server end _by the server's rules_ and
+ * so in general this is infeasible. Hence, we only
+ * accept filenames that don't correspond to `src' if
+ * unsafe mode is enabled or we are using SFTP (which
+ * resolves remote wildcards on the client side and can
+ * be trusted).
+ */
+ char *striptarget, *stripsrc;
+
+ striptarget = stripslashes(act.name, 1);
+ if (striptarget != act.name) {
+ tell_user(stderr, "warning: remote host sent a compound"
+ " pathname '%s'", act.name);
+ tell_user(stderr, " renaming local file to '%s'",
+ striptarget);
+ }
+
+ /*
+ * Also check to see if the target filename is '.' or
+ * '..', or indeed '...' and so on because Windows
+ * appears to interpret those like '..'.
+ */
+ if (is_dots(striptarget)) {
+ bump("security violation: remote host attempted to write to"
+ " a '.' or '..' path!");
+ }
+
+ if (src) {
+ stripsrc = stripslashes(src, 1);
+ if (strcmp(striptarget, stripsrc) &&
+ !using_sftp && !scp_unsafe_mode) {
+ tell_user(stderr, "warning: remote host tried to write "
+ "to a file called '%s'", striptarget);
+ tell_user(stderr, " when we requested a file "
+ "called '%s'.", stripsrc);
+ tell_user(stderr, " If this is a wildcard, "
+ "consider upgrading to SSH 2 or using");
+ tell_user(stderr, " the '-unsafe' option. Renaming"
+ " of this file has been disallowed.");
+ /* Override the name the server provided with our own. */
+ striptarget = stripsrc;