for (p = buf; (p = strchr(p, '%')) != NULL && p[1]; ) {
s = p++;
n = fmt + 1;
- while (isdigit(*(uchar*)p) && n - fmt < 16)
+ if (*p == '-')
*n++ = *p++;
+ while (isdigit(*(uchar*)p) && n - fmt < (int)(sizeof fmt) - 8)
+ *n++ = *p++;
+ if (!*p)
+ break;
*n = '\0';
n = NULL;
break;
case 'o': n = op; break;
case 'f':
- pathjoin(buf2, sizeof buf2,
- am_sender && file->dir.root ? file->dir.root : "",
- safe_fname(f_name(file)));
- clean_fname(buf2, 0);
- n = buf2;
- if (*n == '/') n++;
+ n = safe_fname(f_name(file));
+ if (am_sender && file->dir.root) {
+ pathjoin(buf2, sizeof buf2,
+ file->dir.root, n);
+ /* The buffer from safe_fname() has more
+ * room than MAXPATHLEN, so this is safe. */
+ if (fmt[1])
+ strcpy(n, buf2);
+ else
+ n = buf2;
+ }
+ clean_fname(n, 0);
+ if (*n == '/')
+ n++;
break;
case 'n':
- n = (char*)safe_fname(f_name(file));
+ n = safe_fname(f_name(file));
if (S_ISDIR(file->mode)) {
/* The buffer from safe_fname() has more
* room than MAXPATHLEN, so this is safe. */
n = "*deleting";
break;
}
- n = buf2;
+ n = buf2 + MAXPATHLEN - 32;
n[0] = iflags & ITEM_LOCAL_CHANGE
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
: !(iflags & ITEM_TRANSFER) ? '.'
break;
}
- /* Subtract the length of the escape from the string's size. */
- total -= p - s;
-
/* "n" is the string to be inserted in place of this % code. */
if (!n)
continue;
+ if (n != buf2 && fmt[1]) {
+ strlcat(fmt, "s", sizeof fmt);
+ snprintf(buf2, sizeof buf2, fmt, n);
+ n = buf2;
+ }
len = strlen(n);
+ /* Subtract the length of the escape from the string's size. */
+ total -= p - s;
+
if (len + total >= sizeof buf) {
rprintf(FERROR,
"buffer overflow expanding %%%c -- exiting\n",