This source file includes following definitions.
- ftp_open
- ftp_close
- ftp_gc
- ftp_quit
- ftp_login
- ftp_reinit
- ftp_syst
- ftp_pwd
- ftp_exec
- ftp_raw
- ftp_chdir
- ftp_cdup
- ftp_mkdir
- ftp_rmdir
- ftp_chmod
- ftp_alloc
- ftp_nlist
- ftp_list
- ftp_type
- ftp_pasv
- ftp_get
- ftp_put
- ftp_size
- ftp_mdtm
- ftp_delete
- ftp_rename
- ftp_site
- ftp_putcmd
- ftp_readline
- ftp_getresp
- my_send
- my_recv
- data_available
- data_writeable
- my_accept
- ftp_getdata
- data_accept
- data_close
- ftp_genlist
- ftp_nb_get
- ftp_nb_continue_read
- ftp_nb_put
- ftp_nb_continue_write
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "php.h"
27
28 #if HAVE_FTP
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <fcntl.h>
37 #include <string.h>
38 #include <time.h>
39 #ifdef PHP_WIN32
40 #include <winsock2.h>
41 #elif defined(NETWARE)
42 #ifdef USE_WINSOCK
43 #include <novsock2.h>
44 #else
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48 #endif
49 #else
50 #ifdef HAVE_SYS_TYPES_H
51 #include <sys/types.h>
52 #endif
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 #include <netdb.h>
57 #endif
58 #include <errno.h>
59
60 #if HAVE_SYS_TIME_H
61 #include <sys/time.h>
62 #endif
63
64 #ifdef HAVE_SYS_SELECT_H
65 #include <sys/select.h>
66 #endif
67
68 #if HAVE_OPENSSL_EXT
69 #include <openssl/ssl.h>
70 #endif
71
72 #include "ftp.h"
73 #include "ext/standard/fsock.h"
74
75
76 #if defined(NETWARE) && !defined(USE_WINSOCK)
77 #include <sys/select.h>
78 #endif
79
80
81
82
83
84 static int ftp_putcmd( ftpbuf_t *ftp,
85 const char *cmd,
86 const char *args);
87
88
89 static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
90 static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
91 static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen);
92
93
94 static int ftp_readline(ftpbuf_t *ftp);
95
96
97 static int ftp_getresp(ftpbuf_t *ftp);
98
99
100 static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
101
102
103 static databuf_t* ftp_getdata(ftpbuf_t *ftp TSRMLS_DC);
104
105
106 static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC);
107
108
109 static databuf_t* data_close(ftpbuf_t *ftp, databuf_t *data);
110
111
112 static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC);
113
114
115 union ipbox {
116 struct in_addr ia[2];
117 unsigned short s[4];
118 unsigned char c[8];
119 };
120
121
122
123 ftpbuf_t*
124 ftp_open(const char *host, short port, long timeout_sec TSRMLS_DC)
125 {
126 ftpbuf_t *ftp;
127 socklen_t size;
128 struct timeval tv;
129
130
131
132 ftp = ecalloc(1, sizeof(*ftp));
133
134 tv.tv_sec = timeout_sec;
135 tv.tv_usec = 0;
136
137 ftp->fd = php_network_connect_socket_to_host(host,
138 (unsigned short) (port ? port : 21), SOCK_STREAM,
139 0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
140 if (ftp->fd == -1) {
141 goto bail;
142 }
143
144
145 ftp->timeout_sec = timeout_sec;
146 ftp->nb = 0;
147
148 size = sizeof(ftp->localaddr);
149 memset(&ftp->localaddr, 0, size);
150 if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) != 0) {
151 php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname failed: %s (%d)", strerror(errno), errno);
152 goto bail;
153 }
154
155 if (!ftp_getresp(ftp) || ftp->resp != 220) {
156 goto bail;
157 }
158
159 return ftp;
160
161 bail:
162 if (ftp->fd != -1) {
163 closesocket(ftp->fd);
164 }
165 efree(ftp);
166 return NULL;
167 }
168
169
170
171
172 ftpbuf_t*
173 ftp_close(ftpbuf_t *ftp)
174 {
175 if (ftp == NULL) {
176 return NULL;
177 }
178 if (ftp->data) {
179 data_close(ftp, ftp->data);
180 }
181 if (ftp->stream && ftp->closestream) {
182 TSRMLS_FETCH();
183 php_stream_close(ftp->stream);
184 }
185 if (ftp->fd != -1) {
186 #if HAVE_OPENSSL_EXT
187 if (ftp->ssl_active) {
188 SSL_shutdown(ftp->ssl_handle);
189 SSL_free(ftp->ssl_handle);
190 }
191 #endif
192 closesocket(ftp->fd);
193 }
194 ftp_gc(ftp);
195 efree(ftp);
196 return NULL;
197 }
198
199
200
201
202 void
203 ftp_gc(ftpbuf_t *ftp)
204 {
205 if (ftp == NULL) {
206 return;
207 }
208 if (ftp->pwd) {
209 efree(ftp->pwd);
210 ftp->pwd = NULL;
211 }
212 if (ftp->syst) {
213 efree(ftp->syst);
214 ftp->syst = NULL;
215 }
216 }
217
218
219
220
221 int
222 ftp_quit(ftpbuf_t *ftp)
223 {
224 if (ftp == NULL) {
225 return 0;
226 }
227
228 if (!ftp_putcmd(ftp, "QUIT", NULL)) {
229 return 0;
230 }
231 if (!ftp_getresp(ftp) || ftp->resp != 221) {
232 return 0;
233 }
234
235 if (ftp->pwd) {
236 efree(ftp->pwd);
237 ftp->pwd = NULL;
238 }
239
240 return 1;
241 }
242
243
244
245
246 int
247 ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
248 {
249 #if HAVE_OPENSSL_EXT
250 SSL_CTX *ctx = NULL;
251 long ssl_ctx_options = SSL_OP_ALL;
252 #endif
253 if (ftp == NULL) {
254 return 0;
255 }
256
257 #if HAVE_OPENSSL_EXT
258 if (ftp->use_ssl && !ftp->ssl_active) {
259 if (!ftp_putcmd(ftp, "AUTH", "TLS")) {
260 return 0;
261 }
262 if (!ftp_getresp(ftp)) {
263 return 0;
264 }
265
266 if (ftp->resp != 234) {
267 if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
268 return 0;
269 }
270 if (!ftp_getresp(ftp)) {
271 return 0;
272 }
273
274 if (ftp->resp != 334) {
275 return 0;
276 } else {
277 ftp->old_ssl = 1;
278 ftp->use_ssl_for_data = 1;
279 }
280 }
281
282 ctx = SSL_CTX_new(SSLv23_client_method());
283 if (ctx == NULL) {
284 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL context");
285 return 0;
286 }
287
288 #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
289 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
290 #endif
291 SSL_CTX_set_options(ctx, ssl_ctx_options);
292
293 ftp->ssl_handle = SSL_new(ctx);
294 if (ftp->ssl_handle == NULL) {
295 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL handle");
296 SSL_CTX_free(ctx);
297 return 0;
298 }
299
300 SSL_set_fd(ftp->ssl_handle, ftp->fd);
301
302 if (SSL_connect(ftp->ssl_handle) <= 0) {
303 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
304 SSL_shutdown(ftp->ssl_handle);
305 SSL_free(ftp->ssl_handle);
306 return 0;
307 }
308
309 ftp->ssl_active = 1;
310
311 if (!ftp->old_ssl) {
312
313
314 if (!ftp_putcmd(ftp, "PBSZ", "0")) {
315 return 0;
316 }
317 if (!ftp_getresp(ftp)) {
318 return 0;
319 }
320
321
322 if (!ftp_putcmd(ftp, "PROT", "P")) {
323 return 0;
324 }
325 if (!ftp_getresp(ftp)) {
326 return 0;
327 }
328
329 ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
330 }
331 }
332 #endif
333
334 if (!ftp_putcmd(ftp, "USER", user)) {
335 return 0;
336 }
337 if (!ftp_getresp(ftp)) {
338 return 0;
339 }
340 if (ftp->resp == 230) {
341 return 1;
342 }
343 if (ftp->resp != 331) {
344 return 0;
345 }
346 if (!ftp_putcmd(ftp, "PASS", pass)) {
347 return 0;
348 }
349 if (!ftp_getresp(ftp)) {
350 return 0;
351 }
352 return (ftp->resp == 230);
353 }
354
355
356
357
358 int
359 ftp_reinit(ftpbuf_t *ftp)
360 {
361 if (ftp == NULL) {
362 return 0;
363 }
364
365 ftp_gc(ftp);
366
367 ftp->nb = 0;
368
369 if (!ftp_putcmd(ftp, "REIN", NULL)) {
370 return 0;
371 }
372 if (!ftp_getresp(ftp) || ftp->resp != 220) {
373 return 0;
374 }
375
376 return 1;
377 }
378
379
380
381
382 const char*
383 ftp_syst(ftpbuf_t *ftp)
384 {
385 char *syst, *end;
386
387 if (ftp == NULL) {
388 return NULL;
389 }
390
391
392 if (ftp->syst) {
393 return ftp->syst;
394 }
395 if (!ftp_putcmd(ftp, "SYST", NULL)) {
396 return NULL;
397 }
398 if (!ftp_getresp(ftp) || ftp->resp != 215) {
399 return NULL;
400 }
401 syst = ftp->inbuf;
402 while (*syst == ' ') {
403 syst++;
404 }
405 if ((end = strchr(syst, ' '))) {
406 *end = 0;
407 }
408 ftp->syst = estrdup(syst);
409 if (end) {
410 *end = ' ';
411 }
412 return ftp->syst;
413 }
414
415
416
417
418 const char*
419 ftp_pwd(ftpbuf_t *ftp)
420 {
421 char *pwd, *end;
422
423 if (ftp == NULL) {
424 return NULL;
425 }
426
427
428 if (ftp->pwd) {
429 return ftp->pwd;
430 }
431 if (!ftp_putcmd(ftp, "PWD", NULL)) {
432 return NULL;
433 }
434 if (!ftp_getresp(ftp) || ftp->resp != 257) {
435 return NULL;
436 }
437
438 if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
439 return NULL;
440 }
441 if ((end = strrchr(++pwd, '"')) == NULL) {
442 return NULL;
443 }
444 ftp->pwd = estrndup(pwd, end - pwd);
445
446 return ftp->pwd;
447 }
448
449
450
451
452 int
453 ftp_exec(ftpbuf_t *ftp, const char *cmd)
454 {
455 if (ftp == NULL) {
456 return 0;
457 }
458 if (!ftp_putcmd(ftp, "SITE EXEC", cmd)) {
459 return 0;
460 }
461 if (!ftp_getresp(ftp) || ftp->resp != 200) {
462 return 0;
463 }
464
465 return 1;
466 }
467
468
469
470
471 void
472 ftp_raw(ftpbuf_t *ftp, const char *cmd, zval *return_value)
473 {
474 if (ftp == NULL || cmd == NULL) {
475 RETURN_NULL();
476 }
477 if (!ftp_putcmd(ftp, cmd, NULL)) {
478 RETURN_NULL();
479 }
480 array_init(return_value);
481 while (ftp_readline(ftp)) {
482 add_next_index_string(return_value, ftp->inbuf, 1);
483 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
484 return;
485 }
486 }
487 }
488
489
490
491
492 int
493 ftp_chdir(ftpbuf_t *ftp, const char *dir)
494 {
495 if (ftp == NULL) {
496 return 0;
497 }
498
499 if (ftp->pwd) {
500 efree(ftp->pwd);
501 ftp->pwd = NULL;
502 }
503
504 if (!ftp_putcmd(ftp, "CWD", dir)) {
505 return 0;
506 }
507 if (!ftp_getresp(ftp) || ftp->resp != 250) {
508 return 0;
509 }
510 return 1;
511 }
512
513
514
515
516 int
517 ftp_cdup(ftpbuf_t *ftp)
518 {
519 if (ftp == NULL) {
520 return 0;
521 }
522
523 if (ftp->pwd) {
524 efree(ftp->pwd);
525 ftp->pwd = NULL;
526 }
527
528 if (!ftp_putcmd(ftp, "CDUP", NULL)) {
529 return 0;
530 }
531 if (!ftp_getresp(ftp) || ftp->resp != 250) {
532 return 0;
533 }
534 return 1;
535 }
536
537
538
539
540 char*
541 ftp_mkdir(ftpbuf_t *ftp, const char *dir)
542 {
543 char *mkd, *end;
544
545 if (ftp == NULL) {
546 return NULL;
547 }
548 if (!ftp_putcmd(ftp, "MKD", dir)) {
549 return NULL;
550 }
551 if (!ftp_getresp(ftp) || ftp->resp != 257) {
552 return NULL;
553 }
554
555 if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
556 mkd = estrdup(dir);
557 return mkd;
558 }
559 if ((end = strrchr(++mkd, '"')) == NULL) {
560 return NULL;
561 }
562 *end = 0;
563 mkd = estrdup(mkd);
564 *end = '"';
565
566 return mkd;
567 }
568
569
570
571
572 int
573 ftp_rmdir(ftpbuf_t *ftp, const char *dir)
574 {
575 if (ftp == NULL) {
576 return 0;
577 }
578 if (!ftp_putcmd(ftp, "RMD", dir)) {
579 return 0;
580 }
581 if (!ftp_getresp(ftp) || ftp->resp != 250) {
582 return 0;
583 }
584 return 1;
585 }
586
587
588
589
590 int
591 ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
592 {
593 char *buffer;
594
595 if (ftp == NULL || filename_len <= 0) {
596 return 0;
597 }
598
599 spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
600
601 if (!ftp_putcmd(ftp, "SITE", buffer)) {
602 efree(buffer);
603 return 0;
604 }
605
606 efree(buffer);
607
608 if (!ftp_getresp(ftp) || ftp->resp != 200) {
609 return 0;
610 }
611
612 return 1;
613 }
614
615
616
617
618 int
619 ftp_alloc(ftpbuf_t *ftp, const long size, char **response)
620 {
621 char buffer[64];
622
623 if (ftp == NULL || size <= 0) {
624 return 0;
625 }
626
627 snprintf(buffer, sizeof(buffer) - 1, "%ld", size);
628
629 if (!ftp_putcmd(ftp, "ALLO", buffer)) {
630 return 0;
631 }
632
633 if (!ftp_getresp(ftp)) {
634 return 0;
635 }
636
637 if (response) {
638 *response = estrdup(ftp->inbuf);
639 }
640
641 if (ftp->resp < 200 || ftp->resp >= 300) {
642 return 0;
643 }
644
645 return 1;
646 }
647
648
649
650
651 char**
652 ftp_nlist(ftpbuf_t *ftp, const char *path TSRMLS_DC)
653 {
654 return ftp_genlist(ftp, "NLST", path TSRMLS_CC);
655 }
656
657
658
659
660 char**
661 ftp_list(ftpbuf_t *ftp, const char *path, int recursive TSRMLS_DC)
662 {
663 return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), path TSRMLS_CC);
664 }
665
666
667
668
669 int
670 ftp_type(ftpbuf_t *ftp, ftptype_t type)
671 {
672 char typechar[2] = "?";
673
674 if (ftp == NULL) {
675 return 0;
676 }
677 if (type == ftp->type) {
678 return 1;
679 }
680 if (type == FTPTYPE_ASCII) {
681 typechar[0] = 'A';
682 } else if (type == FTPTYPE_IMAGE) {
683 typechar[0] = 'I';
684 } else {
685 return 0;
686 }
687 if (!ftp_putcmd(ftp, "TYPE", typechar)) {
688 return 0;
689 }
690 if (!ftp_getresp(ftp) || ftp->resp != 200) {
691 return 0;
692 }
693 ftp->type = type;
694
695 return 1;
696 }
697
698
699
700
701 int
702 ftp_pasv(ftpbuf_t *ftp, int pasv)
703 {
704 char *ptr;
705 union ipbox ipbox;
706 unsigned long b[6];
707 socklen_t n;
708 struct sockaddr *sa;
709 struct sockaddr_in *sin;
710
711 if (ftp == NULL) {
712 return 0;
713 }
714 if (pasv && ftp->pasv == 2) {
715 return 1;
716 }
717 ftp->pasv = 0;
718 if (!pasv) {
719 return 1;
720 }
721 n = sizeof(ftp->pasvaddr);
722 memset(&ftp->pasvaddr, 0, n);
723 sa = (struct sockaddr *) &ftp->pasvaddr;
724
725 if (getpeername(ftp->fd, sa, &n) < 0) {
726 return 0;
727 }
728
729 #if HAVE_IPV6
730 if (sa->sa_family == AF_INET6) {
731 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
732 char *endptr, delimiter;
733
734
735 if (!ftp_putcmd(ftp, "EPSV", NULL)) {
736 return 0;
737 }
738 if (!ftp_getresp(ftp)) {
739 return 0;
740 }
741 if (ftp->resp == 229) {
742
743 for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
744 if (!*ptr) {
745 return 0;
746 }
747 delimiter = *++ptr;
748 for (n = 0; *ptr && n < 3; ptr++) {
749 if (*ptr == delimiter) {
750 n++;
751 }
752 }
753
754 sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
755 if (ptr == endptr || *endptr != delimiter) {
756 return 0;
757 }
758 ftp->pasv = 2;
759 return 1;
760 }
761 }
762
763
764 #endif
765
766 if (!ftp_putcmd(ftp, "PASV", NULL)) {
767 return 0;
768 }
769 if (!ftp_getresp(ftp) || ftp->resp != 227) {
770 return 0;
771 }
772
773 for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
774 n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
775 if (n != 6) {
776 return 0;
777 }
778 for (n = 0; n < 6; n++) {
779 ipbox.c[n] = (unsigned char) b[n];
780 }
781 sin = (struct sockaddr_in *) sa;
782 if (ftp->usepasvaddress) {
783 sin->sin_addr = ipbox.ia[0];
784 }
785 sin->sin_port = ipbox.s[2];
786
787 ftp->pasv = 2;
788
789 return 1;
790 }
791
792
793
794
795 int
796 ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
797 {
798 databuf_t *data = NULL;
799 size_t rcvd;
800 char arg[11];
801
802 if (ftp == NULL) {
803 return 0;
804 }
805 if (!ftp_type(ftp, type)) {
806 goto bail;
807 }
808
809 if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
810 goto bail;
811 }
812
813 ftp->data = data;
814
815 if (resumepos > 0) {
816 snprintf(arg, sizeof(arg), "%ld", resumepos);
817 if (!ftp_putcmd(ftp, "REST", arg)) {
818 goto bail;
819 }
820 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
821 goto bail;
822 }
823 }
824
825 if (!ftp_putcmd(ftp, "RETR", path)) {
826 goto bail;
827 }
828 if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
829 goto bail;
830 }
831
832 if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
833 goto bail;
834 }
835
836 while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
837 if (rcvd == -1) {
838 goto bail;
839 }
840
841 if (type == FTPTYPE_ASCII) {
842 #ifndef PHP_WIN32
843 char *s;
844 #endif
845 char *ptr = data->buf;
846 char *e = ptr + rcvd;
847
848
849
850
851 #ifdef PHP_WIN32
852 php_stream_write(outstream, ptr, (e - ptr));
853 ptr = e;
854 #else
855 while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
856 php_stream_write(outstream, ptr, (s - ptr));
857 if (*(s + 1) == '\n') {
858 s++;
859 php_stream_putc(outstream, '\n');
860 }
861 ptr = s + 1;
862 }
863 #endif
864 if (ptr < e) {
865 php_stream_write(outstream, ptr, (e - ptr));
866 }
867 } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
868 goto bail;
869 }
870 }
871
872 ftp->data = data = data_close(ftp, data);
873
874 if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
875 goto bail;
876 }
877
878 return 1;
879 bail:
880 ftp->data = data_close(ftp, data);
881 return 0;
882 }
883
884
885
886
887 int
888 ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
889 {
890 databuf_t *data = NULL;
891 long size;
892 char *ptr;
893 int ch;
894 char arg[11];
895
896 if (ftp == NULL) {
897 return 0;
898 }
899 if (!ftp_type(ftp, type)) {
900 goto bail;
901 }
902 if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
903 goto bail;
904 }
905 ftp->data = data;
906
907 if (startpos > 0) {
908 snprintf(arg, sizeof(arg), "%ld", startpos);
909 if (!ftp_putcmd(ftp, "REST", arg)) {
910 goto bail;
911 }
912 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
913 goto bail;
914 }
915 }
916
917 if (!ftp_putcmd(ftp, "STOR", path)) {
918 goto bail;
919 }
920 if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
921 goto bail;
922 }
923 if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
924 goto bail;
925 }
926
927 size = 0;
928 ptr = data->buf;
929 while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
930
931 if (FTP_BUFSIZE - size < 2) {
932 if (my_send(ftp, data->fd, data->buf, size) != size) {
933 goto bail;
934 }
935 ptr = data->buf;
936 size = 0;
937 }
938
939 if (ch == '\n' && type == FTPTYPE_ASCII) {
940 *ptr++ = '\r';
941 size++;
942 }
943
944 *ptr++ = ch;
945 size++;
946 }
947
948 if (size && my_send(ftp, data->fd, data->buf, size) != size) {
949 goto bail;
950 }
951 ftp->data = data = data_close(ftp, data);
952
953 if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
954 goto bail;
955 }
956 return 1;
957 bail:
958 ftp->data = data_close(ftp, data);
959 return 0;
960 }
961
962
963
964
965 long
966 ftp_size(ftpbuf_t *ftp, const char *path)
967 {
968 if (ftp == NULL) {
969 return -1;
970 }
971 if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
972 return -1;
973 }
974 if (!ftp_putcmd(ftp, "SIZE", path)) {
975 return -1;
976 }
977 if (!ftp_getresp(ftp) || ftp->resp != 213) {
978 return -1;
979 }
980 return atol(ftp->inbuf);
981 }
982
983
984
985
986 time_t
987 ftp_mdtm(ftpbuf_t *ftp, const char *path)
988 {
989 time_t stamp;
990 struct tm *gmt, tmbuf;
991 struct tm tm;
992 char *ptr;
993 int n;
994
995 if (ftp == NULL) {
996 return -1;
997 }
998 if (!ftp_putcmd(ftp, "MDTM", path)) {
999 return -1;
1000 }
1001 if (!ftp_getresp(ftp) || ftp->resp != 213) {
1002 return -1;
1003 }
1004
1005 for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
1006 n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
1007 if (n != 6) {
1008 return -1;
1009 }
1010 tm.tm_year -= 1900;
1011 tm.tm_mon--;
1012 tm.tm_isdst = -1;
1013
1014
1015 stamp = time(NULL);
1016 gmt = php_gmtime_r(&stamp, &tmbuf);
1017 if (!gmt) {
1018 return -1;
1019 }
1020 gmt->tm_isdst = -1;
1021
1022
1023 tm.tm_sec += stamp - mktime(gmt);
1024 tm.tm_isdst = gmt->tm_isdst;
1025
1026 stamp = mktime(&tm);
1027
1028 return stamp;
1029 }
1030
1031
1032
1033
1034 int
1035 ftp_delete(ftpbuf_t *ftp, const char *path)
1036 {
1037 if (ftp == NULL) {
1038 return 0;
1039 }
1040 if (!ftp_putcmd(ftp, "DELE", path)) {
1041 return 0;
1042 }
1043 if (!ftp_getresp(ftp) || ftp->resp != 250) {
1044 return 0;
1045 }
1046
1047 return 1;
1048 }
1049
1050
1051
1052
1053 int
1054 ftp_rename(ftpbuf_t *ftp, const char *src, const char *dest)
1055 {
1056 if (ftp == NULL) {
1057 return 0;
1058 }
1059 if (!ftp_putcmd(ftp, "RNFR", src)) {
1060 return 0;
1061 }
1062 if (!ftp_getresp(ftp) || ftp->resp != 350) {
1063 return 0;
1064 }
1065 if (!ftp_putcmd(ftp, "RNTO", dest)) {
1066 return 0;
1067 }
1068 if (!ftp_getresp(ftp) || ftp->resp != 250) {
1069 return 0;
1070 }
1071 return 1;
1072 }
1073
1074
1075
1076
1077 int
1078 ftp_site(ftpbuf_t *ftp, const char *cmd)
1079 {
1080 if (ftp == NULL) {
1081 return 0;
1082 }
1083 if (!ftp_putcmd(ftp, "SITE", cmd)) {
1084 return 0;
1085 }
1086 if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
1087 return 0;
1088 }
1089
1090 return 1;
1091 }
1092
1093
1094
1095
1096
1097
1098 int
1099 ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
1100 {
1101 int size;
1102 char *data;
1103
1104 if (strpbrk(cmd, "\r\n")) {
1105 return 0;
1106 }
1107
1108 if (args && args[0]) {
1109
1110 if (strlen(cmd) + strlen(args) + 4 > FTP_BUFSIZE) {
1111 return 0;
1112 }
1113 if (strpbrk(args, "\r\n")) {
1114 return 0;
1115 }
1116 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
1117 } else {
1118
1119 if (strlen(cmd) + 3 > FTP_BUFSIZE) {
1120 return 0;
1121 }
1122 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
1123 }
1124
1125 data = ftp->outbuf;
1126
1127
1128 ftp->extra = NULL;
1129
1130 if (my_send(ftp, ftp->fd, data, size) != size) {
1131 return 0;
1132 }
1133 return 1;
1134 }
1135
1136
1137
1138
1139 int
1140 ftp_readline(ftpbuf_t *ftp)
1141 {
1142 long size, rcvd;
1143 char *data, *eol;
1144
1145
1146 size = FTP_BUFSIZE;
1147 rcvd = 0;
1148 if (ftp->extra) {
1149 memmove(ftp->inbuf, ftp->extra, ftp->extralen);
1150 rcvd = ftp->extralen;
1151 }
1152
1153 data = ftp->inbuf;
1154
1155 do {
1156 size -= rcvd;
1157 for (eol = data; rcvd; rcvd--, eol++) {
1158 if (*eol == '\r') {
1159 *eol = 0;
1160 ftp->extra = eol + 1;
1161 if (rcvd > 1 && *(eol + 1) == '\n') {
1162 ftp->extra++;
1163 rcvd--;
1164 }
1165 if ((ftp->extralen = --rcvd) == 0) {
1166 ftp->extra = NULL;
1167 }
1168 return 1;
1169 } else if (*eol == '\n') {
1170 *eol = 0;
1171 ftp->extra = eol + 1;
1172 if ((ftp->extralen = --rcvd) == 0) {
1173 ftp->extra = NULL;
1174 }
1175 return 1;
1176 }
1177 }
1178
1179 data = eol;
1180 if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
1181 return 0;
1182 }
1183 } while (size);
1184
1185 return 0;
1186 }
1187
1188
1189
1190
1191 int
1192 ftp_getresp(ftpbuf_t *ftp)
1193 {
1194 if (ftp == NULL) {
1195 return 0;
1196 }
1197 ftp->resp = 0;
1198
1199 while (1) {
1200
1201 if (!ftp_readline(ftp)) {
1202 return 0;
1203 }
1204
1205
1206 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
1207 break;
1208 }
1209 }
1210
1211
1212 if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
1213 return 0;
1214 }
1215
1216 ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
1217
1218 memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
1219
1220 if (ftp->extra) {
1221 ftp->extra -= 4;
1222 }
1223 return 1;
1224 }
1225
1226
1227
1228
1229 int
1230 my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
1231 {
1232 long size, sent;
1233 int n;
1234
1235 size = len;
1236 while (size) {
1237 n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
1238
1239 if (n < 1) {
1240
1241 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
1242 if (n == 0) {
1243 errno = ETIMEDOUT;
1244 }
1245 #endif
1246 return -1;
1247 }
1248
1249 #if HAVE_OPENSSL_EXT
1250 if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
1251 sent = SSL_write(ftp->ssl_handle, buf, size);
1252 } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
1253 sent = SSL_write(ftp->data->ssl_handle, buf, size);
1254 } else {
1255 #endif
1256 sent = send(s, buf, size, 0);
1257 #if HAVE_OPENSSL_EXT
1258 }
1259 #endif
1260 if (sent == -1) {
1261 return -1;
1262 }
1263
1264 buf = (char*) buf + sent;
1265 size -= sent;
1266 }
1267
1268 return len;
1269 }
1270
1271
1272
1273
1274 int
1275 my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
1276 {
1277 int n, nr_bytes;
1278
1279 n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
1280 if (n < 1) {
1281 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
1282 if (n == 0) {
1283 errno = ETIMEDOUT;
1284 }
1285 #endif
1286 return -1;
1287 }
1288
1289 #if HAVE_OPENSSL_EXT
1290 if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
1291 nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
1292 } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
1293 nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
1294 } else {
1295 #endif
1296 nr_bytes = recv(s, buf, len, 0);
1297 #if HAVE_OPENSSL_EXT
1298 }
1299 #endif
1300 return (nr_bytes);
1301 }
1302
1303
1304
1305
1306 int
1307 data_available(ftpbuf_t *ftp, php_socket_t s)
1308 {
1309 int n;
1310
1311 n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
1312 if (n < 1) {
1313 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
1314 if (n == 0) {
1315 errno = ETIMEDOUT;
1316 }
1317 #endif
1318 return 0;
1319 }
1320
1321 return 1;
1322 }
1323
1324
1325
1326 int
1327 data_writeable(ftpbuf_t *ftp, php_socket_t s)
1328 {
1329 int n;
1330
1331 n = php_pollfd_for_ms(s, POLLOUT, 1000);
1332 if (n < 1) {
1333 #ifndef PHP_WIN32
1334 if (n == 0) {
1335 errno = ETIMEDOUT;
1336 }
1337 #endif
1338 return 0;
1339 }
1340
1341 return 1;
1342 }
1343
1344
1345
1346
1347 int
1348 my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
1349 {
1350 int n;
1351
1352 n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
1353 if (n < 1) {
1354 #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
1355 if (n == 0) {
1356 errno = ETIMEDOUT;
1357 }
1358 #endif
1359 return -1;
1360 }
1361
1362 return accept(s, addr, addrlen);
1363 }
1364
1365
1366
1367
1368 databuf_t*
1369 ftp_getdata(ftpbuf_t *ftp TSRMLS_DC)
1370 {
1371 int fd = -1;
1372 databuf_t *data;
1373 php_sockaddr_storage addr;
1374 struct sockaddr *sa;
1375 socklen_t size;
1376 union ipbox ipbox;
1377 char arg[sizeof("255, 255, 255, 255, 255, 255")];
1378 struct timeval tv;
1379
1380
1381
1382 if (ftp->pasv && !ftp_pasv(ftp, 1)) {
1383 return NULL;
1384 }
1385
1386 data = ecalloc(1, sizeof(*data));
1387 data->listener = -1;
1388 data->fd = -1;
1389 data->type = ftp->type;
1390
1391 sa = (struct sockaddr *) &ftp->localaddr;
1392
1393 if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
1394 php_error_docref(NULL TSRMLS_CC, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
1395 goto bail;
1396 }
1397
1398
1399 if (ftp->pasv) {
1400
1401 ftp->pasv = 1;
1402
1403
1404
1405 size = php_sockaddr_size(&ftp->pasvaddr);
1406 tv.tv_sec = ftp->timeout_sec;
1407 tv.tv_usec = 0;
1408 if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
1409 php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
1410 goto bail;
1411 }
1412
1413 data->fd = fd;
1414
1415 ftp->data = data;
1416 return data;
1417 }
1418
1419
1420
1421
1422
1423 php_any_addr(sa->sa_family, &addr, 0);
1424 size = php_sockaddr_size(&addr);
1425
1426 if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
1427 php_error_docref(NULL TSRMLS_CC, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
1428 goto bail;
1429 }
1430
1431 if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
1432 php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
1433 goto bail;
1434 }
1435
1436 if (listen(fd, 5) != 0) {
1437 php_error_docref(NULL TSRMLS_CC, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
1438 goto bail;
1439 }
1440
1441 data->listener = fd;
1442
1443 #if HAVE_IPV6 && HAVE_INET_NTOP
1444 if (sa->sa_family == AF_INET6) {
1445
1446 char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
1447 char out[INET6_ADDRSTRLEN];
1448 inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
1449 snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
1450
1451 if (!ftp_putcmd(ftp, "EPRT", eprtarg)) {
1452 goto bail;
1453 }
1454
1455 if (!ftp_getresp(ftp) || ftp->resp != 200) {
1456 goto bail;
1457 }
1458
1459 ftp->data = data;
1460 return data;
1461 }
1462 #endif
1463
1464
1465 ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
1466 ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
1467 snprintf(arg, sizeof(arg), "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]);
1468
1469 if (!ftp_putcmd(ftp, "PORT", arg)) {
1470 goto bail;
1471 }
1472 if (!ftp_getresp(ftp) || ftp->resp != 200) {
1473 goto bail;
1474 }
1475
1476 ftp->data = data;
1477 return data;
1478
1479 bail:
1480 if (fd != -1) {
1481 closesocket(fd);
1482 }
1483 efree(data);
1484 return NULL;
1485 }
1486
1487
1488
1489
1490 databuf_t*
1491 data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC)
1492 {
1493 php_sockaddr_storage addr;
1494 socklen_t size;
1495
1496 #if HAVE_OPENSSL_EXT
1497 SSL_CTX *ctx;
1498 long ssl_ctx_options = SSL_OP_ALL;
1499 #endif
1500
1501 if (data->fd != -1) {
1502 goto data_accepted;
1503 }
1504 size = sizeof(addr);
1505 data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
1506 closesocket(data->listener);
1507 data->listener = -1;
1508
1509 if (data->fd == -1) {
1510 efree(data);
1511 return NULL;
1512 }
1513
1514 data_accepted:
1515 #if HAVE_OPENSSL_EXT
1516
1517
1518 if (ftp->use_ssl && ftp->use_ssl_for_data) {
1519 ctx = SSL_CTX_new(SSLv23_client_method());
1520 if (ctx == NULL) {
1521 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL context");
1522 return 0;
1523 }
1524
1525 #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
1526 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
1527 #endif
1528 SSL_CTX_set_options(ctx, ssl_ctx_options);
1529
1530 data->ssl_handle = SSL_new(ctx);
1531 if (data->ssl_handle == NULL) {
1532 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL handle");
1533 SSL_CTX_free(ctx);
1534 return 0;
1535 }
1536
1537
1538 SSL_set_fd(data->ssl_handle, data->fd);
1539
1540 if (ftp->old_ssl) {
1541 SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
1542 }
1543
1544 if (SSL_connect(data->ssl_handle) <= 0) {
1545 php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
1546 SSL_shutdown(data->ssl_handle);
1547 SSL_free(data->ssl_handle);
1548 return 0;
1549 }
1550
1551 data->ssl_active = 1;
1552 }
1553
1554 #endif
1555
1556 return data;
1557 }
1558
1559
1560
1561
1562 databuf_t*
1563 data_close(ftpbuf_t *ftp, databuf_t *data)
1564 {
1565 #if HAVE_OPENSSL_EXT
1566 SSL_CTX *ctx;
1567 #endif
1568 if (data == NULL) {
1569 return NULL;
1570 }
1571 if (data->listener != -1) {
1572 #if HAVE_OPENSSL_EXT
1573 if (data->ssl_active) {
1574
1575 ctx = SSL_get_SSL_CTX(data->ssl_handle);
1576 SSL_CTX_free(ctx);
1577
1578 SSL_shutdown(data->ssl_handle);
1579 SSL_free(data->ssl_handle);
1580 data->ssl_active = 0;
1581 }
1582 #endif
1583 closesocket(data->listener);
1584 }
1585 if (data->fd != -1) {
1586 #if HAVE_OPENSSL_EXT
1587 if (data->ssl_active) {
1588 ctx = SSL_get_SSL_CTX(data->ssl_handle);
1589 SSL_CTX_free(ctx);
1590
1591 SSL_shutdown(data->ssl_handle);
1592 SSL_free(data->ssl_handle);
1593 data->ssl_active = 0;
1594 }
1595 #endif
1596 closesocket(data->fd);
1597 }
1598 if (ftp) {
1599 ftp->data = NULL;
1600 }
1601 efree(data);
1602 return NULL;
1603 }
1604
1605
1606
1607
1608 char**
1609 ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
1610 {
1611 php_stream *tmpstream = NULL;
1612 databuf_t *data = NULL;
1613 char *ptr;
1614 int ch, lastch;
1615 size_t size, rcvd;
1616 size_t lines;
1617 char **ret = NULL;
1618 char **entry;
1619 char *text;
1620
1621
1622 if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
1623 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create temporary file. Check permissions in temporary files directory.");
1624 return NULL;
1625 }
1626
1627 if (!ftp_type(ftp, FTPTYPE_ASCII)) {
1628 goto bail;
1629 }
1630
1631 if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
1632 goto bail;
1633 }
1634 ftp->data = data;
1635
1636 if (!ftp_putcmd(ftp, cmd, path)) {
1637 goto bail;
1638 }
1639 if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
1640 goto bail;
1641 }
1642
1643
1644 if (ftp->resp == 226) {
1645 ftp->data = data_close(ftp, data);
1646 php_stream_close(tmpstream);
1647 return ecalloc(1, sizeof(char*));
1648 }
1649
1650
1651 if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
1652 goto bail;
1653 }
1654 size = 0;
1655 lines = 0;
1656 lastch = 0;
1657 while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
1658 if (rcvd == -1 || rcvd > ((size_t)(-1))-size) {
1659 goto bail;
1660 }
1661
1662 php_stream_write(tmpstream, data->buf, rcvd);
1663
1664 size += rcvd;
1665 for (ptr = data->buf; rcvd; rcvd--, ptr++) {
1666 if (*ptr == '\n' && lastch == '\r') {
1667 lines++;
1668 }
1669 lastch = *ptr;
1670 }
1671 }
1672
1673 ftp->data = data_close(ftp, data);
1674
1675 php_stream_rewind(tmpstream);
1676
1677 ret = safe_emalloc((lines + 1), sizeof(char*), size);
1678
1679 entry = ret;
1680 text = (char*) (ret + lines + 1);
1681 *entry = text;
1682 lastch = 0;
1683 while ((ch = php_stream_getc(tmpstream)) != EOF) {
1684 if (ch == '\n' && lastch == '\r') {
1685 *(text - 1) = 0;
1686 *++entry = text;
1687 } else {
1688 *text++ = ch;
1689 }
1690 lastch = ch;
1691 }
1692 *entry = NULL;
1693
1694 php_stream_close(tmpstream);
1695
1696 if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
1697 efree(ret);
1698 return NULL;
1699 }
1700
1701 return ret;
1702 bail:
1703 ftp->data = data_close(ftp, data);
1704 php_stream_close(tmpstream);
1705 if (ret)
1706 efree(ret);
1707 return NULL;
1708 }
1709
1710
1711
1712
1713 int
1714 ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
1715 {
1716 databuf_t *data = NULL;
1717 char arg[11];
1718
1719 if (ftp == NULL) {
1720 return PHP_FTP_FAILED;
1721 }
1722
1723 if (!ftp_type(ftp, type)) {
1724 goto bail;
1725 }
1726
1727 if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
1728 goto bail;
1729 }
1730
1731 if (resumepos>0) {
1732 snprintf(arg, sizeof(arg), "%ld", resumepos);
1733 if (!ftp_putcmd(ftp, "REST", arg)) {
1734 goto bail;
1735 }
1736 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
1737 goto bail;
1738 }
1739 }
1740
1741 if (!ftp_putcmd(ftp, "RETR", path)) {
1742 goto bail;
1743 }
1744 if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
1745 goto bail;
1746 }
1747
1748 if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
1749 goto bail;
1750 }
1751
1752 ftp->data = data;
1753 ftp->stream = outstream;
1754 ftp->lastch = 0;
1755 ftp->nb = 1;
1756
1757 return (ftp_nb_continue_read(ftp TSRMLS_CC));
1758
1759 bail:
1760 ftp->data = data_close(ftp, data);
1761 return PHP_FTP_FAILED;
1762 }
1763
1764
1765
1766
1767 int
1768 ftp_nb_continue_read(ftpbuf_t *ftp TSRMLS_DC)
1769 {
1770 databuf_t *data = NULL;
1771 char *ptr;
1772 int lastch;
1773 size_t rcvd;
1774 ftptype_t type;
1775
1776 data = ftp->data;
1777
1778
1779 if (!data_available(ftp, data->fd)) {
1780 return PHP_FTP_MOREDATA;
1781 }
1782
1783 type = ftp->type;
1784
1785 lastch = ftp->lastch;
1786 if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
1787 if (rcvd == -1) {
1788 goto bail;
1789 }
1790
1791 if (type == FTPTYPE_ASCII) {
1792 for (ptr = data->buf; rcvd; rcvd--, ptr++) {
1793 if (lastch == '\r' && *ptr != '\n') {
1794 php_stream_putc(ftp->stream, '\r');
1795 }
1796 if (*ptr != '\r') {
1797 php_stream_putc(ftp->stream, *ptr);
1798 }
1799 lastch = *ptr;
1800 }
1801 } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
1802 goto bail;
1803 }
1804
1805 ftp->lastch = lastch;
1806 return PHP_FTP_MOREDATA;
1807 }
1808
1809 if (type == FTPTYPE_ASCII && lastch == '\r') {
1810 php_stream_putc(ftp->stream, '\r');
1811 }
1812
1813 ftp->data = data = data_close(ftp, data);
1814
1815 if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
1816 goto bail;
1817 }
1818
1819 ftp->nb = 0;
1820 return PHP_FTP_FINISHED;
1821 bail:
1822 ftp->nb = 0;
1823 ftp->data = data_close(ftp, data);
1824 return PHP_FTP_FAILED;
1825 }
1826
1827
1828
1829
1830 int
1831 ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
1832 {
1833 databuf_t *data = NULL;
1834 char arg[11];
1835
1836 if (ftp == NULL) {
1837 return 0;
1838 }
1839 if (!ftp_type(ftp, type)) {
1840 goto bail;
1841 }
1842 if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
1843 goto bail;
1844 }
1845 if (startpos > 0) {
1846 snprintf(arg, sizeof(arg), "%ld", startpos);
1847 if (!ftp_putcmd(ftp, "REST", arg)) {
1848 goto bail;
1849 }
1850 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
1851 goto bail;
1852 }
1853 }
1854
1855 if (!ftp_putcmd(ftp, "STOR", path)) {
1856 goto bail;
1857 }
1858 if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
1859 goto bail;
1860 }
1861 if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
1862 goto bail;
1863 }
1864 ftp->data = data;
1865 ftp->stream = instream;
1866 ftp->lastch = 0;
1867 ftp->nb = 1;
1868
1869 return (ftp_nb_continue_write(ftp TSRMLS_CC));
1870
1871 bail:
1872 ftp->data = data_close(ftp, data);
1873 return PHP_FTP_FAILED;
1874 }
1875
1876
1877
1878
1879
1880 int
1881 ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC)
1882 {
1883 long size;
1884 char *ptr;
1885 int ch;
1886
1887
1888 if (!data_writeable(ftp, ftp->data->fd)) {
1889 return PHP_FTP_MOREDATA;
1890 }
1891
1892 size = 0;
1893 ptr = ftp->data->buf;
1894 while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
1895
1896 if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
1897 *ptr++ = '\r';
1898 size++;
1899 }
1900
1901 *ptr++ = ch;
1902 size++;
1903
1904
1905 if (FTP_BUFSIZE - size < 2) {
1906 if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
1907 goto bail;
1908 }
1909 return PHP_FTP_MOREDATA;
1910 }
1911 }
1912
1913 if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
1914 goto bail;
1915 }
1916 ftp->data = data_close(ftp, ftp->data);
1917
1918 if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
1919 goto bail;
1920 }
1921 ftp->nb = 0;
1922 return PHP_FTP_FINISHED;
1923 bail:
1924 ftp->data = data_close(ftp, ftp->data);
1925 ftp->nb = 0;
1926 return PHP_FTP_FAILED;
1927 }
1928
1929
1930 #endif
1931
1932
1933
1934
1935
1936
1937
1938
1939