|
|
07d5a6 |
diff --git a/src/clients/FtpGateway.cc b/src/clients/FtpGateway.cc
|
|
|
07d5a6 |
index 4f8319a..3a35784 100644
|
|
|
07d5a6 |
--- a/src/clients/FtpGateway.cc
|
|
|
07d5a6 |
+++ b/src/clients/FtpGateway.cc
|
|
|
07d5a6 |
@@ -543,8 +543,10 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
|
|
|
07d5a6 |
{
|
|
|
07d5a6 |
ftpListParts *p = NULL;
|
|
|
07d5a6 |
char *t = NULL;
|
|
|
07d5a6 |
- const char *ct = NULL;
|
|
|
07d5a6 |
- char *tokens[MAX_TOKENS];
|
|
|
07d5a6 |
+ struct FtpLineToken {
|
|
|
07d5a6 |
+ char *token = NULL; ///< token image copied from the received line
|
|
|
07d5a6 |
+ size_t pos = 0; ///< token offset on the received line
|
|
|
07d5a6 |
+ } tokens[MAX_TOKENS];
|
|
|
07d5a6 |
int i;
|
|
|
07d5a6 |
int n_tokens;
|
|
|
07d5a6 |
static char tbuf[128];
|
|
|
07d5a6 |
@@ -585,7 +587,8 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
for (t = strtok(xbuf, w_space); t && n_tokens < MAX_TOKENS; t = strtok(NULL, w_space)) {
|
|
|
07d5a6 |
- tokens[n_tokens] = xstrdup(t);
|
|
|
07d5a6 |
+ tokens[n_tokens].token = xstrdup(t);
|
|
|
07d5a6 |
+ tokens[n_tokens].pos = t - xbuf;
|
|
|
07d5a6 |
++n_tokens;
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
@@ -593,10 +596,10 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
|
|
|
07d5a6 |
|
|
|
07d5a6 |
/* locate the Month field */
|
|
|
07d5a6 |
for (i = 3; i < n_tokens - 2; ++i) {
|
|
|
07d5a6 |
- char *size = tokens[i - 1];
|
|
|
07d5a6 |
- char *month = tokens[i];
|
|
|
07d5a6 |
- char *day = tokens[i + 1];
|
|
|
07d5a6 |
- char *year = tokens[i + 2];
|
|
|
07d5a6 |
+ const char *size = tokens[i - 1].token;
|
|
|
07d5a6 |
+ char *month = tokens[i].token;
|
|
|
07d5a6 |
+ char *day = tokens[i + 1].token;
|
|
|
07d5a6 |
+ char *year = tokens[i + 2].token;
|
|
|
07d5a6 |
|
|
|
07d5a6 |
if (!is_month(month))
|
|
|
07d5a6 |
continue;
|
|
|
07d5a6 |
@@ -610,30 +613,35 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
|
|
|
07d5a6 |
if (regexec(&scan_ftp_time, year, 0, NULL, 0) != 0) /* Yr | hh:mm */
|
|
|
07d5a6 |
continue;
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- snprintf(tbuf, 128, "%s %2s %5s",
|
|
|
07d5a6 |
- month, day, year);
|
|
|
07d5a6 |
+ const char *copyFrom = buf + tokens[i].pos;
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- if (!strstr(buf, tbuf))
|
|
|
07d5a6 |
- snprintf(tbuf, 128, "%s %2s %-5s",
|
|
|
07d5a6 |
- month, day, year);
|
|
|
07d5a6 |
+ // "MMM DD [ YYYY|hh:mm]" with at most two spaces between DD and YYYY
|
|
|
07d5a6 |
+ int dateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %5s", month, day, year);
|
|
|
07d5a6 |
+ bool isTypeA = (dateSize == 12) && (strncmp(copyFrom, tbuf, dateSize) == 0);
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- char const *copyFrom = NULL;
|
|
|
07d5a6 |
+ // "MMM DD [YYYY|hh:mm]" with one space between DD and YYYY
|
|
|
07d5a6 |
+ dateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %-5s", month, day, year);
|
|
|
07d5a6 |
+ bool isTypeB = (dateSize == 12 || dateSize == 11) && (strncmp(copyFrom, tbuf, dateSize) == 0);
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- if ((copyFrom = strstr(buf, tbuf))) {
|
|
|
07d5a6 |
- p->type = *tokens[0];
|
|
|
07d5a6 |
+ // TODO: replace isTypeA and isTypeB with a regex.
|
|
|
07d5a6 |
+ if (isTypeA || isTypeB) {
|
|
|
07d5a6 |
+ p->type = *tokens[0].token;
|
|
|
07d5a6 |
p->size = strtoll(size, NULL, 10);
|
|
|
07d5a6 |
+ const int finalDateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %5s", month, day, year);
|
|
|
07d5a6 |
+ assert(finalDateSize >= 0);
|
|
|
07d5a6 |
p->date = xstrdup(tbuf);
|
|
|
07d5a6 |
|
|
|
07d5a6 |
+ // point after tokens[i+2] :
|
|
|
07d5a6 |
+ copyFrom = buf + tokens[i + 2].pos + strlen(tokens[i + 2].token);
|
|
|
07d5a6 |
if (flags.skip_whitespace) {
|
|
|
07d5a6 |
- copyFrom += strlen(tbuf);
|
|
|
07d5a6 |
-
|
|
|
07d5a6 |
while (strchr(w_space, *copyFrom))
|
|
|
07d5a6 |
++copyFrom;
|
|
|
07d5a6 |
} else {
|
|
|
07d5a6 |
/* XXX assumes a single space between date and filename
|
|
|
07d5a6 |
* suggested by: Nathan.Bailey@cc.monash.edu.au and
|
|
|
07d5a6 |
* Mike Battersby <mike@starbug.bofh.asn.au> */
|
|
|
07d5a6 |
- copyFrom += strlen(tbuf) + 1;
|
|
|
07d5a6 |
+ if (strchr(w_space, *copyFrom))
|
|
|
07d5a6 |
+ ++copyFrom;
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
p->name = xstrdup(copyFrom);
|
|
|
07d5a6 |
@@ -651,45 +659,36 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
|
|
|
07d5a6 |
|
|
|
07d5a6 |
/* try it as a DOS listing, 04-05-70 09:33PM ... */
|
|
|
07d5a6 |
if (n_tokens > 3 &&
|
|
|
07d5a6 |
- regexec(&scan_ftp_dosdate, tokens[0], 0, NULL, 0) == 0 &&
|
|
|
07d5a6 |
- regexec(&scan_ftp_dostime, tokens[1], 0, NULL, 0) == 0) {
|
|
|
07d5a6 |
- if (!strcasecmp(tokens[2], "<dir>")) {
|
|
|
07d5a6 |
+ regexec(&scan_ftp_dosdate, tokens[0].token, 0, NULL, 0) == 0 &&
|
|
|
07d5a6 |
+ regexec(&scan_ftp_dostime, tokens[1].token, 0, NULL, 0) == 0) {
|
|
|
07d5a6 |
+ if (!strcasecmp(tokens[2].token, "<dir>")) {
|
|
|
07d5a6 |
p->type = 'd';
|
|
|
07d5a6 |
} else {
|
|
|
07d5a6 |
p->type = '-';
|
|
|
07d5a6 |
- p->size = strtoll(tokens[2], NULL, 10);
|
|
|
07d5a6 |
+ p->size = strtoll(tokens[2].token, NULL, 10);
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- snprintf(tbuf, 128, "%s %s", tokens[0], tokens[1]);
|
|
|
07d5a6 |
+ snprintf(tbuf, sizeof(tbuf), "%s %s", tokens[0].token, tokens[1].token);
|
|
|
07d5a6 |
p->date = xstrdup(tbuf);
|
|
|
07d5a6 |
|
|
|
07d5a6 |
if (p->type == 'd') {
|
|
|
07d5a6 |
- /* Directory.. name begins with first printable after <dir> */
|
|
|
07d5a6 |
- ct = strstr(buf, tokens[2]);
|
|
|
07d5a6 |
- ct += strlen(tokens[2]);
|
|
|
07d5a6 |
-
|
|
|
07d5a6 |
- while (xisspace(*ct))
|
|
|
07d5a6 |
- ++ct;
|
|
|
07d5a6 |
-
|
|
|
07d5a6 |
- if (!*ct)
|
|
|
07d5a6 |
- ct = NULL;
|
|
|
07d5a6 |
+ // Directory.. name begins with first printable after <dir>
|
|
|
07d5a6 |
+ // Because of the "n_tokens > 3", the next printable after <dir>
|
|
|
07d5a6 |
+ // is stored at token[3]. No need for more checks here.
|
|
|
07d5a6 |
} else {
|
|
|
07d5a6 |
- /* A file. Name begins after size, with a space in between */
|
|
|
07d5a6 |
- snprintf(tbuf, 128, " %s %s", tokens[2], tokens[3]);
|
|
|
07d5a6 |
- ct = strstr(buf, tbuf);
|
|
|
07d5a6 |
-
|
|
|
07d5a6 |
- if (ct) {
|
|
|
07d5a6 |
- ct += strlen(tokens[2]) + 2;
|
|
|
07d5a6 |
- }
|
|
|
07d5a6 |
+ // A file. Name begins after size, with a space in between.
|
|
|
07d5a6 |
+ // Also a space should exist before size.
|
|
|
07d5a6 |
+ // But there is not needed to be very strict with spaces.
|
|
|
07d5a6 |
+ // The name is stored at token[3], take it from here.
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
- p->name = xstrdup(ct ? ct : tokens[3]);
|
|
|
07d5a6 |
+ p->name = xstrdup(tokens[3].token);
|
|
|
07d5a6 |
goto found;
|
|
|
07d5a6 |
}
|
|
|
07d5a6 |
|
|
|
07d5a6 |
/* Try EPLF format; carson@lehman.com */
|
|
|
07d5a6 |
if (buf[0] == '+') {
|
|
|
07d5a6 |
- ct = buf + 1;
|
|
|
07d5a6 |
+ const char *ct = buf + 1;
|
|
|
07d5a6 |
p->type = 0;
|
|
|
07d5a6 |
|
|
|
07d5a6 |
while (ct && *ct) {
|
|
|
07d5a6 |
@@ -760,7 +759,7 @@ blank:
|
|
|
07d5a6 |
found:
|
|
|
07d5a6 |
|
|
|
07d5a6 |
for (i = 0; i < n_tokens; ++i)
|
|
|
07d5a6 |
- xfree(tokens[i]);
|
|
|
07d5a6 |
+ xfree(tokens[i].token);
|
|
|
07d5a6 |
|
|
|
07d5a6 |
if (!p->name)
|
|
|
07d5a6 |
ftpListPartsFree(&p); /* cleanup */
|