I'd prefer something like this using strtoll().  We can't easily
use strtonum() here since there can be anything past the digits.
The lexer is in charge of matching whitespace and space and newlines
are explicit in the yacc grammar.

For numbers larger than INT_MAX the lexer now returns BIGNUM instead
of NUMBER so only yacc rules that expect a BIGNUM (currently only
REST) will get it.  Using a number larger than INT_MAX when not
expected will result in a syntax error so we don't have to worry
about assigning the wrong thing.

I also changed some non-std %qd -> %lld while there.

 - todd

Index: libexec/ftpd/ftpcmd.y
===================================================================
RCS file: /home/cvs/openbsd/src/libexec/ftpd/ftpcmd.y,v
retrieving revision 1.55
diff -u -r1.55 ftpcmd.y
--- libexec/ftpd/ftpcmd.y       27 Nov 2013 21:25:25 -0000      1.55
+++ libexec/ftpd/ftpcmd.y       21 Jan 2014 15:18:05 -0000
@@ -59,6 +59,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <netdb.h>
+#include <limits.h>
 
 #include "monitor.h"
 #include "extern.h"
@@ -97,6 +98,7 @@
 
 %union {
        int     i;
+       off_t   o;
        char   *s;
 }
 
@@ -122,11 +124,13 @@
 
 %token <s> STRING
 %token <i> NUMBER
+%token <o> BIGNUM
 
 %type  <i> check_login check_login_epsvall octal_number byte_size
 %type  <i> struct_code mode_code type_code form_code
-%type  <s> pathstring pathname password username
 %type  <i> host_port host_long_port4 host_long_port6
+%type  <o> file_size
+%type  <s> pathstring pathname password username
 
 %start cmd_list
 
@@ -656,16 +660,16 @@
                        }
                }
 
-       | REST check_login SP byte_size CRLF
+       | REST check_login SP file_size CRLF
                {
                        if ($2) {
                                if (fromname) {
                                        free(fromname);
                                        fromname = NULL;
                                }
-                               restart_point = $4;     /* XXX $4 is only "int" 
*/
-                               reply(350, "Restarting at %qd. %s",
-                                   restart_point,
+                               restart_point = $4;
+                               reply(350, "Restarting at %lld. %s",
+                                   (long long)restart_point,
                                    "Send STORE or RETRIEVE to initiate 
transfer.");
                        }
                }
@@ -687,6 +691,17 @@
        : NUMBER
        ;
 
+file_size
+       : NUMBER
+               {
+                       $$ = $1;
+               }
+       | BIGNUM
+               {
+                       $$ = $1;
+               }
+       ;
+
 host_port
        : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
                NUMBER COMMA NUMBER
@@ -1328,14 +1343,23 @@
 
                case ARGS:
                        if (isdigit((unsigned char)cbuf[cpos])) {
+                               long long llval;
+
                                cp = &cbuf[cpos];
-                               while (isdigit((unsigned char)cbuf[++cpos]))
-                                       ;
-                               c = cbuf[cpos];
-                               cbuf[cpos] = '\0';
-                               yylval.i = atoi(cp);
-                               cbuf[cpos] = c;
-                               return (NUMBER);
+                               errno = 0;
+                               llval = strtoll(cp, &cp2, 10);
+                               if (llval < 0 ||
+                                   (errno == ERANGE && llval == LLONG_MAX))
+                                       break;
+
+                               cpos = (int)(cp2 - cbuf);
+                               if (llval > INT_MAX) {
+                                       yylval.o = llval;
+                                       return (BIGNUM);
+                               } else {
+                                       yylval.i = (int)llval;
+                                       return (NUMBER);
+                               }
                        }
                        if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 &&
                            !isalnum((unsigned char)cbuf[cpos + 3])) {
@@ -1501,7 +1525,7 @@
                if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
                        reply(550, "%s: not a plain file.", filename);
                else
-                       reply(213, "%qu", stbuf.st_size);
+                       reply(213, "%lld", (long long)stbuf.st_size);
                break; }
        case TYPE_A: {
                FILE *fin;
@@ -1532,7 +1556,7 @@
                }
                (void) fclose(fin);
 
-               reply(213, "%qd", count);
+               reply(213, "%lld", (long long)count);
                break; }
        default:
                reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);

Reply via email to