Skip to content
79 changes: 79 additions & 0 deletions scp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,14 @@ source(int argc, char **argv)
off_t i, statbytes;
size_t amt, nr;
int fd = -1, haderr, indx;
#ifdef WINDOWS
/* PATH_MAX is too large on Windows.*/
/* Allocate memory dynamically for encname and buf to avoid stack overflow on recursive calls.*/
char *last, *name, *buf = NULL, *encname = NULL;
size_t encname_len, buf_len, tmp_len;
#else
char *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX];
#endif
int len;

for (indx = 0; indx < argc; ++indx) {
Expand All @@ -1274,7 +1281,20 @@ source(int argc, char **argv)
if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) == -1)
goto syserr;
if (strchr(name, '\n') != NULL) {
#ifdef WINDOWS
if (!encname) {
encname_len = ((2 * len) < PATH_MAX) ? 2 * len : PATH_MAX;
encname = xmalloc(encname_len);
}
while ((tmp_len = strnvis(encname, name, encname_len, VIS_NL)) >= encname_len) {
if (tmp_len >= PATH_MAX)
break;
encname_len = tmp_len + 1;
encname = xreallocarray(encname, encname_len, sizeof(char));
}
#else
strnvis(encname, name, sizeof(encname), VIS_NL);
#endif
name = encname;
}
if (fstat(fd, &stb) == -1) {
Expand Down Expand Up @@ -1309,9 +1329,27 @@ syserr: run_err("%s: %s", name, strerror(errno));
goto next;
}
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
#ifdef WINDOWS
if (!buf)
{
/*Set the initial size of buf to "strlen(last) + 20" based on multiple tests that*/
/*inidicate that this is usually enough. If not enough, more space will be allocated below.*/
buf_len = ((strlen(last) + 20) < PATH_MAX) ? strlen(last) + 20 : PATH_MAX;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on what calculations, you are using 20 here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, not very precise calculations. Just by experience, "C%04o %lld", (u_int) (stb.st_mode & FILEMODEMASK), (long long)stb.st_size is less than 20 characters on all the tests I ran, I can't know for sure that this is always gonna be the case. I thought about just doing 2 * strlen(last), but I think it's more likely to have a filename with a very short name than the rest of the string to be more than 20 characters long.

buf = xmalloc(buf_len);
}
while ((tmp_len = snprintf(buf, buf_len, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last)) >= buf_len) {
if (tmp_len >= PATH_MAX)
break;
buf_len = tmp_len + 1;
buf = xreallocarray(buf, buf_len, sizeof(char));
}
#else
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
(long long)stb.st_size, last);
#endif
if (verbose_mode)
fmprintf(stderr, "Sending file modes: %s", buf);
(void) atomicio(vwrite, remout, buf, strlen(buf));
Expand Down Expand Up @@ -1363,14 +1401,29 @@ next: if (fd != -1) {
if (showprogress)
stop_progress_meter();
}
#ifdef WINDOWS
if (encname)
free(encname);
if (buf)
free(buf);
#endif
}

void
rsource(char *name, struct stat *statp)
{
DIR *dirp;
struct dirent *dp;
#ifndef WINDOWS
char *last, *vect[1], path[PATH_MAX];
#else
/* PATH_MAX is too large on Windows.*/
/* Allocate memory dynamically for path to avoid stack overflow on recursive calls.*/
char *last, *vect[1], *path;
size_t path_len = 260, len;

path = xmalloc(path_len);
#endif

if (!(dirp = opendir(name))) {
run_err("%s: %s", name, strerror(errno));
Expand All @@ -1387,8 +1440,19 @@ rsource(char *name, struct stat *statp)
return;
}
}
#ifdef WINDOWS
while ((len = snprintf(path, path_len, "D%04o %d %.1024s\n",
(u_int)(statp->st_mode & FILEMODEMASK), 0, last)) >= path_len)
{
if (len >= PATH_MAX)
break;
path_len = len + 1;
path = xreallocarray(path, path_len, sizeof(char));
}
#else
(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
(u_int) (statp->st_mode & FILEMODEMASK), 0, last);
#endif
if (verbose_mode)
fmprintf(stderr, "Entering directory: %s", path);
(void) atomicio(vwrite, remout, path, strlen(path));
Expand All @@ -1401,14 +1465,29 @@ rsource(char *name, struct stat *statp)
continue;
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
#ifdef WINDOWS
if (strlen(name) + 1 + strlen(dp->d_name) >= PATH_MAX - 1) {
#else
if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
#endif
run_err("%s/%s: name too long", name, dp->d_name);
continue;
}
#ifdef WINDOWS
while ((len = snprintf(path, path_len, "%s/%s", name, dp->d_name)) >= path_len) {
path_len = len + 1;
path = xreallocarray(path, path_len, sizeof(char));
}
#else
(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
#endif
vect[0] = path;
source(1, vect);
}
#ifdef WINDOWS
if (path)
free(path);
#endif
(void) closedir(dirp);
(void) atomicio(vwrite, remout, "E\n", 2);
(void) response();
Expand Down