1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45#define FOR_ftpget
46#include "toys.h"
47
48GLOBALS(
49 char *user;
50 char *port;
51 char *password;
52
53 int fd;
54)
55
56
57static int xread2line(int fd, char *buf, int len)
58{
59 int i, total = 0;
60
61 len--;
62 while (total<len && (i = xread(fd, buf, len-total))) {
63 total += i;
64 if (buf[total-1] == '\n') break;
65 }
66 if (total>=len) error_exit("overflow");
67 while (total--)
68 if (buf[total]=='\r' || buf[total]=='\n') buf[total] = 0;
69 else break;
70 if (toys.optflags & FLAG_v) fprintf(stderr, "%s\n", toybuf);
71
72 return total+1;
73}
74
75static int ftp_line(char *cmd, char *arg, int must)
76{
77 int rc = 0;
78
79 if (cmd) {
80 char *s = "%s %s\r\n"+3*(!arg);
81 if (toys.optflags & FLAG_v) fprintf(stderr, s, cmd, arg);
82 dprintf(TT.fd, s, cmd, arg);
83 }
84 if (must>=0) {
85 xread2line(TT.fd, toybuf, sizeof(toybuf));
86 if (!sscanf(toybuf, "%d", &rc) || (must && rc != must))
87 error_exit_raw(toybuf);
88 }
89
90 return rc;
91}
92
93void ftpget_main(void)
94{
95 struct sockaddr_in6 si6;
96 int rc, ii = 1, port;
97 socklen_t sl = sizeof(si6);
98 char *s, *remote = toys.optargs[2];
99 unsigned long long lenl = 0, lenr;
100
101 if (!(toys.optflags&(FLAG_v-1)))
102 toys.optflags |= (toys.which->name[3]=='g') ? FLAG_g : FLAG_s;
103
104 if (!TT.user) TT.user = "anonymous";
105 if (!TT.password) TT.password = "ftpget@";
106 if (!TT.port) TT.port = "21";
107 if (!remote) remote = toys.optargs[1];
108
109
110 TT.fd = xconnect(xgetaddrinfo(*toys.optargs, TT.port, 0, SOCK_STREAM, 0,
111 AI_ADDRCONFIG));
112 if (getpeername(TT.fd, (void *)&si6, &sl)) perror_exit("getpeername");
113
114
115 ftp_line(0, 0, 220);
116 rc = ftp_line("USER", TT.user, 0);
117 if (rc == 331) rc = ftp_line("PASS", TT.password, 0);
118 if (rc != 230) error_exit_raw(toybuf);
119
120 if (toys.optflags & FLAG_m) {
121 if (toys.optc != 3) error_exit("-m FROM TO");
122 ftp_line("RNFR", toys.optargs[1], 350);
123 ftp_line("RNTO", toys.optargs[2], 250);
124 } else if (toys.optflags & FLAG_M) ftp_line("MKD", toys.optargs[1], 257);
125 else if (toys.optflags & FLAG_d) ftp_line("DELE", toys.optargs[1], 250);
126 else if (toys.optflags & FLAG_D) ftp_line("RMD", toys.optargs[1], 250);
127 else {
128 int get = !(toys.optflags&FLAG_s), cnt = toys.optflags&FLAG_c;
129 char *cmd;
130
131
132 ftp_line("TYPE", "I", 0);
133 rc = ftp_line("PASV", 0, 0);
134
135
136
137
138
139
140 s = 0;
141 if (rc==227) for (s = toybuf; (s = strchr(s, ',')); s++) {
142 int p1, got = 0;
143
144 sscanf(s, ",%u,%u)%n", &p1, &port, &got);
145 if (!got) continue;
146 port += 256*p1;
147 break;
148 }
149 if (!s || port<1 || port>65535) error_exit_raw(toybuf);
150 si6.sin6_port = SWAP_BE16(port);
151 port = xsocket(si6.sin6_family, SOCK_STREAM, 0);
152 if (connect(port, (void *)&si6, sizeof(si6))) perror_exit("connect");
153
154
155
156 lenr = 0;
157 if (toys.optflags&(FLAG_s|FLAG_g)) {
158 if (ftp_line("SIZE", remote, 0) == 213)
159 sscanf(toybuf, "%*u %llu", &lenr);
160 else if (get) error_exit("no %s", remote);
161 }
162
163
164 if (toys.optflags & (FLAG_g|FLAG_s)) {
165 if (strcmp(toys.optargs[1], "-"))
166 ii = xcreate(toys.optargs[1],
167 get ? (cnt ? O_APPEND : O_TRUNC)|O_CREAT|O_WRONLY : O_RDONLY, 0666);
168 lenl = fdlength(ii);
169 }
170 if (get) {
171 cmd = "REST";
172 if (toys.optflags&FLAG_l) cmd = "LIST";
173 if (toys.optflags&FLAG_L) cmd = "NLST";
174 if (cnt) {
175 char buf[32];
176
177 if (lenl>=lenr) goto done;
178 sprintf(buf, "%llu", lenl);
179 ftp_line("REST", buf, 350);
180 } else lenl = 0;
181
182 ftp_line(cmd, remote, -1);
183 lenl += xsendfile(port, ii);
184 ftp_line(0, 0, (toys.optflags&FLAG_g) ? 226 : 150);
185 } else if (toys.optflags & FLAG_s) {
186 cmd = "STOR";
187 if (cnt && lenr) {
188 cmd = "APPE";
189 xlseek(ii, lenl, SEEK_SET);
190 } else lenr = 0;
191 ftp_line(cmd, remote, 150);
192 lenr += xsendfile(ii, port);
193 close(port);
194 }
195 if (toys.optflags&(FLAG_g|FLAG_s))
196 if (lenl != lenr) error_exit("short %lld/%lld", lenl, lenr);
197 }
198 ftp_line("QUIT", 0, 0);
199
200done:
201 if (CFG_TOYBOX_FREE) {
202 if (ii!=1) xclose(ii);
203 xclose(port);
204 xclose(TT.fd);
205 }
206}
207