/*
* scp.c - Scp (Secure Copy) client for PuTTY.
- * Joris van Rantwijk, Aug 1999, Nov 1999.
+ * Joris van Rantwijk, Simon Tatham
*
* This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
* They, in turn, used stuff from BSD rcp.
#define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
-int verbose = 0;
+static int verbose = 0;
static int recursive = 0;
static int preserve = 0;
static int targetshouldbedirectory = 0;
static void sink(char *targ);
/*
+ * This function is needed to link with ssh.c, but it never gets called.
+ */
+void term_out(void)
+{
+ abort();
+}
+
+/*
* Print an error message and perform a fatal exit.
*/
void fatalbox(char *fmt, ...)
va_end(ap);
if (connection_open) {
char ch;
- ssh_send_eof();
- ssh_recv(&ch, 1);
+ ssh_scp_send_eof();
+ ssh_scp_recv(&ch, 1);
}
exit(1);
}
-void ssh_get_password(char *prompt, char *str, int maxlen)
+static int get_password(const char *prompt, char *str, int maxlen)
{
HANDLE hin, hout;
DWORD savemode, i;
if (password) {
- strncpy(str, password, maxlen);
- str[maxlen-1] = '\0';
- password = NULL;
- return;
+ static int tried_once = 0;
+
+ if (tried_once) {
+ return 0;
+ } else {
+ strncpy(str, password, maxlen);
+ str[maxlen-1] = '\0';
+ tried_once = 1;
+ return 1;
+ }
}
hin = GetStdHandle(STD_INPUT_HANDLE);
str[i] = '\0';
WriteFile(hout, "\r\n", 2, &i, NULL);
+
+ return 1;
}
/*
cfg.port = 22;
}
- if (portnumber)
- cfg.port = portnumber;
-
/* Set username */
if (user != NULL && user[0] != '\0') {
strncpy(cfg.username, user, sizeof(cfg.username)-1);
cfg.username[sizeof(cfg.username)-1] = '\0';
- cfg.port = 22;
} else if (cfg.username[0] == '\0') {
bump("Empty user name");
}
if (cfg.protocol != PROT_SSH)
cfg.port = 22;
- err = ssh_init(cfg.host, cfg.port, cmd, &realhost);
+ if (portnumber)
+ cfg.port = portnumber;
+
+ err = ssh_scp_init(cfg.host, cfg.port, cmd, &realhost);
if (err != NULL)
bump("ssh_init: %s", err);
if (verbose && realhost != NULL)
/*
* Find a colon in str and return a pointer to the colon.
- * This is used to seperate hostname from filename.
+ * This is used to separate hostname from filename.
*/
static char * colon(char *str)
{
char ch, resp, rbuf[2048];
int p;
- if (ssh_recv(&resp, 1) <= 0)
+ if (ssh_scp_recv(&resp, 1) <= 0)
bump("Lost connection");
p = 0;
case 1: /* error */
case 2: /* fatal error */
do {
- if (ssh_recv(&ch, 1) <= 0)
+ if (ssh_scp_recv(&ch, 1) <= 0)
bump("Protocol error: Lost connection");
rbuf[p++] = ch;
} while (p < sizeof(rbuf) && ch != '\n');
strcpy(str, "\01scp: ");
vsprintf(str+strlen(str), fmt, ap);
strcat(str, "\n");
- ssh_send(str, strlen(str));
+ ssh_scp_send(str, strlen(str));
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
time_t stat_starttime, stat_lasttime;
attr = GetFileAttributes(src);
- if (attr == -1) {
+ if (attr == (DWORD)-1) {
run_err("%s: No such file or directory", src);
return;
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- if (recursive)
- rsource(src);
- else
+ if (recursive) {
+ /*
+ * Avoid . and .. directories.
+ */
+ char *p;
+ p = strrchr(src, '/');
+ if (!p)
+ p = strrchr(src, '\\');
+ if (!p)
+ p = src;
+ else
+ p++;
+ if (!strcmp(p, ".") || !strcmp(p, ".."))
+ /* skip . and .. */;
+ else
+ rsource(src);
+ } else {
run_err("%s: not a regular file", src);
+ }
return;
}
f = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, 0);
if (f == INVALID_HANDLE_VALUE) {
- run_err("%s: Cannot open file");
+ run_err("%s: Cannot open file", src);
return;
}
TIME_WIN_TO_POSIX(actime, atime);
TIME_WIN_TO_POSIX(wrtime, mtime);
sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
- ssh_send(buf, strlen(buf));
+ ssh_scp_send(buf, strlen(buf));
if (response())
return;
}
sprintf(buf, "C0644 %lu %s\n", size, last);
if (verbose)
fprintf(stderr, "Sending file modes: %s", buf);
- ssh_send(buf, strlen(buf));
+ ssh_scp_send(buf, strlen(buf));
if (response())
return;
if (statistics) printf("\n");
bump("%s: Read error", src);
}
- ssh_send(transbuf, k);
+ ssh_scp_send(transbuf, k);
if (statistics) {
stat_bytes += k;
if (time(NULL) != stat_lasttime ||
}
CloseHandle(f);
- ssh_send("", 1);
+ ssh_scp_send("", 1);
(void) response();
}
sprintf(buf, "D0755 0 %s\n", last);
if (verbose)
fprintf(stderr, "Entering directory: %s", buf);
- ssh_send(buf, strlen(buf));
+ ssh_scp_send(buf, strlen(buf));
if (response())
return;
FindClose(dir);
sprintf(buf, "E\n");
- ssh_send(buf, strlen(buf));
+ ssh_scp_send(buf, strlen(buf));
(void) response();
}
char namebuf[2048];
char ch;
int targisdir = 0;
- int settime = 0;
+ int settime;
int exists;
DWORD attr;
HANDLE f;
char *stat_name;
attr = GetFileAttributes(targ);
- if (attr != -1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
targisdir = 1;
if (targetshouldbedirectory && !targisdir)
bump("%s: Not a directory", targ);
- ssh_send("", 1);
+ ssh_scp_send("", 1);
while (1) {
settime = 0;
gottime:
- if (ssh_recv(&ch, 1) <= 0)
+ if (ssh_scp_recv(&ch, 1) <= 0)
return;
if (ch == '\n')
bump("Protocol error: Unexpected newline");
i = 0;
buf[i++] = ch;
do {
- if (ssh_recv(&ch, 1) <= 0)
+ if (ssh_scp_recv(&ch, 1) <= 0)
bump("Lost connection");
buf[i++] = ch;
} while (i < sizeof(buf) && ch != '\n');
case '\02': /* fatal error */
bump("%s", buf+1);
case 'E':
- ssh_send("", 1);
+ ssh_scp_send("", 1);
return;
case 'T':
if (sscanf(buf, "T%ld %*d %ld %*d",
&mtime, &atime) == 2) {
settime = 1;
- ssh_send("", 1);
+ ssh_scp_send("", 1);
goto gottime;
}
bump("Protocol error: Illegal time format");
strcpy(namebuf, targ);
}
attr = GetFileAttributes(namebuf);
- exists = (attr != -1);
+ exists = (attr != (DWORD)-1);
if (buf[0] == 'D') {
if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
continue;
}
- ssh_send("", 1);
+ ssh_scp_send("", 1);
if (statistics) {
stat_bytes = 0;
for (i = 0; i < size; i += 4096) {
char transbuf[4096];
- int j, k = 4096;
+ DWORD j, k = 4096;
if (i + k > size) k = size - i;
- if (ssh_recv(transbuf, k) == 0)
+ if (ssh_scp_recv(transbuf, k) == 0)
bump("Lost connection");
if (wrerror) continue;
if (! WriteFile(f, transbuf, k, &j, NULL) || j != k) {
run_err("%s: Write error", namebuf);
continue;
}
- ssh_send("", 1);
+ ssh_scp_send("", 1);
}
}
targ = argv[argc-1];
- /* Seperate host from filename */
+ /* Separate host from filename */
host = targ;
targ = colon(targ);
if (targ == NULL)
targ = ".";
/* Substitute "." for emtpy target */
- /* Seperate host and username */
+ /* Separate host and username */
user = host;
host = strrchr(host, '@');
if (host == NULL) {
src = argv[0];
targ = argv[1];
- /* Seperate host from filename */
+ /* Separate host from filename */
host = src;
src = colon(src);
if (src == NULL)
src = ".";
/* Substitute "." for empty filename */
- /* Seperate username and hostname */
+ /* Separate username and hostname */
user = host;
host = strrchr(host, '@');
if (host == NULL) {
}
/*
+ * We will issue a list command to get a remote directory.
+ */
+static void get_dir_list(int argc, char *argv[])
+{
+ char *src, *host, *user;
+ char *cmd, *p, *q;
+ char c;
+
+ src = argv[0];
+
+ /* Separate host from filename */
+ host = src;
+ src = colon(src);
+ if (src == NULL)
+ bump("Local to local copy not supported");
+ *src++ = '\0';
+ if (*src == '\0')
+ src = ".";
+ /* Substitute "." for empty filename */
+
+ /* Separate username and hostname */
+ user = host;
+ host = strrchr(host, '@');
+ if (host == NULL) {
+ host = user;
+ user = NULL;
+ } else {
+ *host++ = '\0';
+ if (*user == '\0')
+ user = NULL;
+ }
+
+ cmd = smalloc(4*strlen(src) + 100);
+ strcpy(cmd, "ls -la '");
+ p = cmd + strlen(cmd);
+ for (q = src; *q; q++) {
+ if (*q == '\'') {
+ *p++ = '\''; *p++ = '\\'; *p++ = '\''; *p++ = '\'';
+ } else {
+ *p++ = *q;
+ }
+ }
+ *p++ = '\'';
+ *p = '\0';
+
+ do_cmd(host, user, cmd);
+ sfree(cmd);
+
+ while (ssh_scp_recv(&c, 1) > 0)
+ fputc(c, stdout); /* thank heavens for buffered I/O */
+}
+
+/*
* Initialize the Win$ock driver.
*/
-static void init_winsock()
+static void init_winsock(void)
{
WORD winsock_ver;
WSADATA wsadata;
/*
* Short description of parameters.
*/
-static void usage()
+static void usage(void)
{
printf("PuTTY Secure Copy client\n");
printf("%s\n", ver);
- printf("Usage: scp [options] [user@]host:source target\n");
- printf(" scp [options] source [source...] [user@]host:target\n");
+ printf("Usage: pscp [options] [user@]host:source target\n");
+ printf(" pscp [options] source [source...] [user@]host:target\n");
+ printf(" pscp [options] -ls user@host:filespec\n");
printf("Options:\n");
printf(" -p preserve file attributes\n");
printf(" -q quiet, don't show statistics\n");
int main(int argc, char *argv[])
{
int i;
+ int list = 0;
+ default_protocol = PROT_TELNET;
+
+ scp_flags = SCP_FLAG;
+ ssh_get_password = &get_password;
init_winsock();
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-')
break;
if (strcmp(argv[i], "-v") == 0)
- verbose = 1;
+ verbose = 1, scp_flags |= SCP_VERBOSE;
else if (strcmp(argv[i], "-r") == 0)
recursive = 1;
else if (strcmp(argv[i], "-p") == 0)
portnumber = atoi(argv[++i]);
else if (strcmp(argv[i], "-pw") == 0 && i+1 < argc)
password = argv[++i];
+ else if (strcmp(argv[i], "-ls") == 0)
+ list = 1;
else if (strcmp(argv[i], "--") == 0)
{ i++; break; }
else
argc -= i;
argv += i;
- if (argc < 2)
- usage();
- if (argc > 2)
- targetshouldbedirectory = 1;
+ if (list) {
+ if (argc != 1)
+ usage();
+ get_dir_list(argc, argv);
- if (colon(argv[argc-1]) != NULL)
- toremote(argc, argv);
- else
- tolocal(argc, argv);
+ } else {
+
+ if (argc < 2)
+ usage();
+ if (argc > 2)
+ targetshouldbedirectory = 1;
+
+ if (colon(argv[argc-1]) != NULL)
+ toremote(argc, argv);
+ else
+ tolocal(argc, argv);
+ }
if (connection_open) {
char ch;
- ssh_send_eof();
- ssh_recv(&ch, 1);
+ ssh_scp_send_eof();
+ ssh_scp_recv(&ch, 1);
}
WSACleanup();
random_save_seed();
}
/* end */
+