123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2016 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Andrew Skalski <askalski@chek.com> |
- | Stefan Esser <sesser@php.net> (resume functions) |
- +----------------------------------------------------------------------+
- */
- /* $Id$ */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #if HAVE_FTP
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <fcntl.h>
- #include <string.h>
- #include <time.h>
- #ifdef PHP_WIN32
- #include <winsock2.h>
- #elif defined(NETWARE)
- #ifdef USE_WINSOCK /* Modified to use Winsock (NOVSOCK2.H), at least for now */
- #include <novsock2.h>
- #else
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #endif
- #else
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #endif
- #include <errno.h>
- #if HAVE_SYS_TIME_H
- #include <sys/time.h>
- #endif
- #ifdef HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif
- #if HAVE_OPENSSL_EXT
- #include <openssl/ssl.h>
- #endif
- #include "ftp.h"
- #include "ext/standard/fsock.h"
- /* Additional headers for NetWare */
- #if defined(NETWARE) && !defined(USE_WINSOCK)
- #include <sys/select.h>
- #endif
- /* sends an ftp command, returns true on success, false on error.
- * it sends the string "cmd args\r\n" if args is non-null, or
- * "cmd\r\n" if args is null
- */
- static int ftp_putcmd( ftpbuf_t *ftp,
- const char *cmd,
- const char *args);
- /* wrapper around send/recv to handle timeouts */
- static int my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
- static int my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
- static int my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen);
- /* reads a line the socket , returns true on success, false on error */
- static int ftp_readline(ftpbuf_t *ftp);
- /* reads an ftp response, returns true on success, false on error */
- static int ftp_getresp(ftpbuf_t *ftp);
- /* sets the ftp transfer type */
- static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
- /* opens up a data stream */
- static databuf_t* ftp_getdata(ftpbuf_t *ftp TSRMLS_DC);
- /* accepts the data connection, returns updated data buffer */
- static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC);
- /* closes the data connection, returns NULL */
- static databuf_t* data_close(ftpbuf_t *ftp, databuf_t *data);
- /* generic file lister */
- static char** ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC);
- /* IP and port conversion box */
- union ipbox {
- struct in_addr ia[2];
- unsigned short s[4];
- unsigned char c[8];
- };
- /* {{{ ftp_open
- */
- ftpbuf_t*
- ftp_open(const char *host, short port, long timeout_sec TSRMLS_DC)
- {
- ftpbuf_t *ftp;
- socklen_t size;
- struct timeval tv;
- /* alloc the ftp structure */
- ftp = ecalloc(1, sizeof(*ftp));
- tv.tv_sec = timeout_sec;
- tv.tv_usec = 0;
- ftp->fd = php_network_connect_socket_to_host(host,
- (unsigned short) (port ? port : 21), SOCK_STREAM,
- 0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
- if (ftp->fd == -1) {
- goto bail;
- }
- /* Default Settings */
- ftp->timeout_sec = timeout_sec;
- ftp->nb = 0;
- size = sizeof(ftp->localaddr);
- memset(&ftp->localaddr, 0, size);
- if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) != 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 220) {
- goto bail;
- }
- return ftp;
- bail:
- if (ftp->fd != -1) {
- closesocket(ftp->fd);
- }
- efree(ftp);
- return NULL;
- }
- /* }}} */
- /* {{{ ftp_close
- */
- ftpbuf_t*
- ftp_close(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return NULL;
- }
- if (ftp->data) {
- data_close(ftp, ftp->data);
- }
- if (ftp->stream && ftp->closestream) {
- TSRMLS_FETCH();
- php_stream_close(ftp->stream);
- }
- if (ftp->fd != -1) {
- #if HAVE_OPENSSL_EXT
- if (ftp->ssl_active) {
- SSL_shutdown(ftp->ssl_handle);
- SSL_free(ftp->ssl_handle);
- }
- #endif
- closesocket(ftp->fd);
- }
- ftp_gc(ftp);
- efree(ftp);
- return NULL;
- }
- /* }}} */
- /* {{{ ftp_gc
- */
- void
- ftp_gc(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return;
- }
- if (ftp->pwd) {
- efree(ftp->pwd);
- ftp->pwd = NULL;
- }
- if (ftp->syst) {
- efree(ftp->syst);
- ftp->syst = NULL;
- }
- }
- /* }}} */
- /* {{{ ftp_quit
- */
- int
- ftp_quit(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "QUIT", NULL)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 221) {
- return 0;
- }
- if (ftp->pwd) {
- efree(ftp->pwd);
- ftp->pwd = NULL;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_login
- */
- int
- ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
- {
- #if HAVE_OPENSSL_EXT
- SSL_CTX *ctx = NULL;
- long ssl_ctx_options = SSL_OP_ALL;
- #endif
- if (ftp == NULL) {
- return 0;
- }
- #if HAVE_OPENSSL_EXT
- if (ftp->use_ssl && !ftp->ssl_active) {
- if (!ftp_putcmd(ftp, "AUTH", "TLS")) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- if (ftp->resp != 234) {
- if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- if (ftp->resp != 334) {
- return 0;
- } else {
- ftp->old_ssl = 1;
- ftp->use_ssl_for_data = 1;
- }
- }
- ctx = SSL_CTX_new(SSLv23_client_method());
- if (ctx == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL context");
- return 0;
- }
- #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
- ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
- #endif
- SSL_CTX_set_options(ctx, ssl_ctx_options);
- /* allow SSL to re-use sessions */
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
- ftp->ssl_handle = SSL_new(ctx);
- if (ftp->ssl_handle == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL handle");
- SSL_CTX_free(ctx);
- return 0;
- }
- SSL_set_fd(ftp->ssl_handle, ftp->fd);
- if (SSL_connect(ftp->ssl_handle) <= 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
- SSL_shutdown(ftp->ssl_handle);
- SSL_free(ftp->ssl_handle);
- return 0;
- }
- ftp->ssl_active = 1;
- if (!ftp->old_ssl) {
- /* set protection buffersize to zero */
- if (!ftp_putcmd(ftp, "PBSZ", "0")) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- /* enable data conn encryption */
- if (!ftp_putcmd(ftp, "PROT", "P")) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
- }
- }
- #endif
- if (!ftp_putcmd(ftp, "USER", user)) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- if (ftp->resp == 230) {
- return 1;
- }
- if (ftp->resp != 331) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "PASS", pass)) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- return (ftp->resp == 230);
- }
- /* }}} */
- /* {{{ ftp_reinit
- */
- int
- ftp_reinit(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return 0;
- }
- ftp_gc(ftp);
- ftp->nb = 0;
- if (!ftp_putcmd(ftp, "REIN", NULL)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 220) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_syst
- */
- const char*
- ftp_syst(ftpbuf_t *ftp)
- {
- char *syst, *end;
- if (ftp == NULL) {
- return NULL;
- }
- /* default to cached value */
- if (ftp->syst) {
- return ftp->syst;
- }
- if (!ftp_putcmd(ftp, "SYST", NULL)) {
- return NULL;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 215) {
- return NULL;
- }
- syst = ftp->inbuf;
- while (*syst == ' ') {
- syst++;
- }
- if ((end = strchr(syst, ' '))) {
- *end = 0;
- }
- ftp->syst = estrdup(syst);
- if (end) {
- *end = ' ';
- }
- return ftp->syst;
- }
- /* }}} */
- /* {{{ ftp_pwd
- */
- const char*
- ftp_pwd(ftpbuf_t *ftp)
- {
- char *pwd, *end;
- if (ftp == NULL) {
- return NULL;
- }
- /* default to cached value */
- if (ftp->pwd) {
- return ftp->pwd;
- }
- if (!ftp_putcmd(ftp, "PWD", NULL)) {
- return NULL;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 257) {
- return NULL;
- }
- /* copy out the pwd from response */
- if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
- return NULL;
- }
- if ((end = strrchr(++pwd, '"')) == NULL) {
- return NULL;
- }
- ftp->pwd = estrndup(pwd, end - pwd);
- return ftp->pwd;
- }
- /* }}} */
- /* {{{ ftp_exec
- */
- int
- ftp_exec(ftpbuf_t *ftp, const char *cmd)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "SITE EXEC", cmd)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 200) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_raw
- */
- void
- ftp_raw(ftpbuf_t *ftp, const char *cmd, zval *return_value)
- {
- if (ftp == NULL || cmd == NULL) {
- RETURN_NULL();
- }
- if (!ftp_putcmd(ftp, cmd, NULL)) {
- RETURN_NULL();
- }
- array_init(return_value);
- while (ftp_readline(ftp)) {
- add_next_index_string(return_value, ftp->inbuf, 1);
- if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
- return;
- }
- }
- }
- /* }}} */
- /* {{{ ftp_chdir
- */
- int
- ftp_chdir(ftpbuf_t *ftp, const char *dir)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (ftp->pwd) {
- efree(ftp->pwd);
- ftp->pwd = NULL;
- }
- if (!ftp_putcmd(ftp, "CWD", dir)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 250) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_cdup
- */
- int
- ftp_cdup(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (ftp->pwd) {
- efree(ftp->pwd);
- ftp->pwd = NULL;
- }
- if (!ftp_putcmd(ftp, "CDUP", NULL)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 250) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_mkdir
- */
- char*
- ftp_mkdir(ftpbuf_t *ftp, const char *dir)
- {
- char *mkd, *end;
- if (ftp == NULL) {
- return NULL;
- }
- if (!ftp_putcmd(ftp, "MKD", dir)) {
- return NULL;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 257) {
- return NULL;
- }
- /* copy out the dir from response */
- if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
- mkd = estrdup(dir);
- return mkd;
- }
- if ((end = strrchr(++mkd, '"')) == NULL) {
- return NULL;
- }
- *end = 0;
- mkd = estrdup(mkd);
- *end = '"';
- return mkd;
- }
- /* }}} */
- /* {{{ ftp_rmdir
- */
- int
- ftp_rmdir(ftpbuf_t *ftp, const char *dir)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "RMD", dir)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 250) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_chmod
- */
- int
- ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
- {
- char *buffer;
- if (ftp == NULL || filename_len <= 0) {
- return 0;
- }
- spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
- if (!ftp_putcmd(ftp, "SITE", buffer)) {
- efree(buffer);
- return 0;
- }
- efree(buffer);
- if (!ftp_getresp(ftp) || ftp->resp != 200) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_alloc
- */
- int
- ftp_alloc(ftpbuf_t *ftp, const long size, char **response)
- {
- char buffer[64];
- if (ftp == NULL || size <= 0) {
- return 0;
- }
- snprintf(buffer, sizeof(buffer) - 1, "%ld", size);
- if (!ftp_putcmd(ftp, "ALLO", buffer)) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- if (response) {
- *response = estrdup(ftp->inbuf);
- }
- if (ftp->resp < 200 || ftp->resp >= 300) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_nlist
- */
- char**
- ftp_nlist(ftpbuf_t *ftp, const char *path TSRMLS_DC)
- {
- return ftp_genlist(ftp, "NLST", path TSRMLS_CC);
- }
- /* }}} */
- /* {{{ ftp_list
- */
- char**
- ftp_list(ftpbuf_t *ftp, const char *path, int recursive TSRMLS_DC)
- {
- return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), path TSRMLS_CC);
- }
- /* }}} */
- /* {{{ ftp_type
- */
- int
- ftp_type(ftpbuf_t *ftp, ftptype_t type)
- {
- char typechar[2] = "?";
- if (ftp == NULL) {
- return 0;
- }
- if (type == ftp->type) {
- return 1;
- }
- if (type == FTPTYPE_ASCII) {
- typechar[0] = 'A';
- } else if (type == FTPTYPE_IMAGE) {
- typechar[0] = 'I';
- } else {
- return 0;
- }
- if (!ftp_putcmd(ftp, "TYPE", typechar)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 200) {
- return 0;
- }
- ftp->type = type;
- return 1;
- }
- /* }}} */
- /* {{{ ftp_pasv
- */
- int
- ftp_pasv(ftpbuf_t *ftp, int pasv)
- {
- char *ptr;
- union ipbox ipbox;
- unsigned long b[6];
- socklen_t n;
- struct sockaddr *sa;
- struct sockaddr_in *sin;
- if (ftp == NULL) {
- return 0;
- }
- if (pasv && ftp->pasv == 2) {
- return 1;
- }
- ftp->pasv = 0;
- if (!pasv) {
- return 1;
- }
- n = sizeof(ftp->pasvaddr);
- memset(&ftp->pasvaddr, 0, n);
- sa = (struct sockaddr *) &ftp->pasvaddr;
- if (getpeername(ftp->fd, sa, &n) < 0) {
- return 0;
- }
- #if HAVE_IPV6
- if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
- char *endptr, delimiter;
- /* try EPSV first */
- if (!ftp_putcmd(ftp, "EPSV", NULL)) {
- return 0;
- }
- if (!ftp_getresp(ftp)) {
- return 0;
- }
- if (ftp->resp == 229) {
- /* parse out the port */
- for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
- if (!*ptr) {
- return 0;
- }
- delimiter = *++ptr;
- for (n = 0; *ptr && n < 3; ptr++) {
- if (*ptr == delimiter) {
- n++;
- }
- }
- sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
- if (ptr == endptr || *endptr != delimiter) {
- return 0;
- }
- ftp->pasv = 2;
- return 1;
- }
- }
- /* fall back to PASV */
- #endif
- if (!ftp_putcmd(ftp, "PASV", NULL)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 227) {
- return 0;
- }
- /* parse out the IP and port */
- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
- n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
- if (n != 6) {
- return 0;
- }
- for (n = 0; n < 6; n++) {
- ipbox.c[n] = (unsigned char) b[n];
- }
- sin = (struct sockaddr_in *) sa;
- if (ftp->usepasvaddress) {
- sin->sin_addr = ipbox.ia[0];
- }
- sin->sin_port = ipbox.s[2];
- ftp->pasv = 2;
- return 1;
- }
- /* }}} */
- /* {{{ ftp_get
- */
- int
- ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
- {
- databuf_t *data = NULL;
- size_t rcvd;
- char arg[11];
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_type(ftp, type)) {
- goto bail;
- }
- if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- ftp->data = data;
- if (resumepos > 0) {
- snprintf(arg, sizeof(arg), "%ld", resumepos);
- if (!ftp_putcmd(ftp, "REST", arg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
- goto bail;
- }
- }
- if (!ftp_putcmd(ftp, "RETR", path)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
- goto bail;
- }
- if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
- if (rcvd == -1) {
- goto bail;
- }
- if (type == FTPTYPE_ASCII) {
- #ifndef PHP_WIN32
- char *s;
- #endif
- char *ptr = data->buf;
- char *e = ptr + rcvd;
- /* logic depends on the OS EOL
- * Win32 -> \r\n
- * Everything Else \n
- */
- #ifdef PHP_WIN32
- php_stream_write(outstream, ptr, (e - ptr));
- ptr = e;
- #else
- while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
- php_stream_write(outstream, ptr, (s - ptr));
- if (*(s + 1) == '\n') {
- s++;
- php_stream_putc(outstream, '\n');
- }
- ptr = s + 1;
- }
- #endif
- if (ptr < e) {
- php_stream_write(outstream, ptr, (e - ptr));
- }
- } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
- goto bail;
- }
- }
- ftp->data = data = data_close(ftp, data);
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
- goto bail;
- }
- return 1;
- bail:
- ftp->data = data_close(ftp, data);
- return 0;
- }
- /* }}} */
- /* {{{ ftp_put
- */
- int
- ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
- {
- databuf_t *data = NULL;
- long size;
- char *ptr;
- int ch;
- char arg[11];
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_type(ftp, type)) {
- goto bail;
- }
- if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- ftp->data = data;
- if (startpos > 0) {
- snprintf(arg, sizeof(arg), "%ld", startpos);
- if (!ftp_putcmd(ftp, "REST", arg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
- goto bail;
- }
- }
- if (!ftp_putcmd(ftp, "STOR", path)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
- goto bail;
- }
- if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- size = 0;
- ptr = data->buf;
- while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
- /* flush if necessary */
- if (FTP_BUFSIZE - size < 2) {
- if (my_send(ftp, data->fd, data->buf, size) != size) {
- goto bail;
- }
- ptr = data->buf;
- size = 0;
- }
- if (ch == '\n' && type == FTPTYPE_ASCII) {
- *ptr++ = '\r';
- size++;
- }
- *ptr++ = ch;
- size++;
- }
- if (size && my_send(ftp, data->fd, data->buf, size) != size) {
- goto bail;
- }
- ftp->data = data = data_close(ftp, data);
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
- goto bail;
- }
- return 1;
- bail:
- ftp->data = data_close(ftp, data);
- return 0;
- }
- /* }}} */
- /* {{{ ftp_size
- */
- long
- ftp_size(ftpbuf_t *ftp, const char *path)
- {
- if (ftp == NULL) {
- return -1;
- }
- if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
- return -1;
- }
- if (!ftp_putcmd(ftp, "SIZE", path)) {
- return -1;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 213) {
- return -1;
- }
- return atol(ftp->inbuf);
- }
- /* }}} */
- /* {{{ ftp_mdtm
- */
- time_t
- ftp_mdtm(ftpbuf_t *ftp, const char *path)
- {
- time_t stamp;
- struct tm *gmt, tmbuf;
- struct tm tm;
- char *ptr;
- int n;
- if (ftp == NULL) {
- return -1;
- }
- if (!ftp_putcmd(ftp, "MDTM", path)) {
- return -1;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 213) {
- return -1;
- }
- /* parse out the timestamp */
- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
- 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);
- if (n != 6) {
- return -1;
- }
- tm.tm_year -= 1900;
- tm.tm_mon--;
- tm.tm_isdst = -1;
- /* figure out the GMT offset */
- stamp = time(NULL);
- gmt = php_gmtime_r(&stamp, &tmbuf);
- if (!gmt) {
- return -1;
- }
- gmt->tm_isdst = -1;
- /* apply the GMT offset */
- tm.tm_sec += stamp - mktime(gmt);
- tm.tm_isdst = gmt->tm_isdst;
- stamp = mktime(&tm);
- return stamp;
- }
- /* }}} */
- /* {{{ ftp_delete
- */
- int
- ftp_delete(ftpbuf_t *ftp, const char *path)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "DELE", path)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 250) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_rename
- */
- int
- ftp_rename(ftpbuf_t *ftp, const char *src, const char *dest)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "RNFR", src)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 350) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "RNTO", dest)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 250) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_site
- */
- int
- ftp_site(ftpbuf_t *ftp, const char *cmd)
- {
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_putcmd(ftp, "SITE", cmd)) {
- return 0;
- }
- if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* static functions */
- /* {{{ ftp_putcmd
- */
- int
- ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
- {
- int size;
- char *data;
- if (strpbrk(cmd, "\r\n")) {
- return 0;
- }
- /* build the output buffer */
- if (args && args[0]) {
- /* "cmd args\r\n\0" */
- if (strlen(cmd) + strlen(args) + 4 > FTP_BUFSIZE) {
- return 0;
- }
- if (strpbrk(args, "\r\n")) {
- return 0;
- }
- size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
- } else {
- /* "cmd\r\n\0" */
- if (strlen(cmd) + 3 > FTP_BUFSIZE) {
- return 0;
- }
- size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
- }
- data = ftp->outbuf;
- /* Clear the extra-lines buffer */
- ftp->extra = NULL;
- if (my_send(ftp, ftp->fd, data, size) != size) {
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ ftp_readline
- */
- int
- ftp_readline(ftpbuf_t *ftp)
- {
- long size, rcvd;
- char *data, *eol;
- /* shift the extra to the front */
- size = FTP_BUFSIZE;
- rcvd = 0;
- if (ftp->extra) {
- memmove(ftp->inbuf, ftp->extra, ftp->extralen);
- rcvd = ftp->extralen;
- }
- data = ftp->inbuf;
- do {
- size -= rcvd;
- for (eol = data; rcvd; rcvd--, eol++) {
- if (*eol == '\r') {
- *eol = 0;
- ftp->extra = eol + 1;
- if (rcvd > 1 && *(eol + 1) == '\n') {
- ftp->extra++;
- rcvd--;
- }
- if ((ftp->extralen = --rcvd) == 0) {
- ftp->extra = NULL;
- }
- return 1;
- } else if (*eol == '\n') {
- *eol = 0;
- ftp->extra = eol + 1;
- if ((ftp->extralen = --rcvd) == 0) {
- ftp->extra = NULL;
- }
- return 1;
- }
- }
- data = eol;
- if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
- return 0;
- }
- } while (size);
- return 0;
- }
- /* }}} */
- /* {{{ ftp_getresp
- */
- int
- ftp_getresp(ftpbuf_t *ftp)
- {
- if (ftp == NULL) {
- return 0;
- }
- ftp->resp = 0;
- while (1) {
- if (!ftp_readline(ftp)) {
- return 0;
- }
- /* Break out when the end-tag is found */
- if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
- break;
- }
- }
- /* translate the tag */
- if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
- return 0;
- }
- ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
- memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
- if (ftp->extra) {
- ftp->extra -= 4;
- }
- return 1;
- }
- /* }}} */
- /* {{{ my_send
- */
- int
- my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
- {
- long size, sent;
- int n;
- size = len;
- while (size) {
- n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
- if (n < 1) {
- #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
- if (n == 0) {
- errno = ETIMEDOUT;
- }
- #endif
- return -1;
- }
- #if HAVE_OPENSSL_EXT
- if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
- sent = SSL_write(ftp->ssl_handle, buf, size);
- } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
- sent = SSL_write(ftp->data->ssl_handle, buf, size);
- } else {
- #endif
- sent = send(s, buf, size, 0);
- #if HAVE_OPENSSL_EXT
- }
- #endif
- if (sent == -1) {
- return -1;
- }
- buf = (char*) buf + sent;
- size -= sent;
- }
- return len;
- }
- /* }}} */
- /* {{{ my_recv
- */
- int
- my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
- {
- int n, nr_bytes;
- n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
- if (n < 1) {
- #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
- if (n == 0) {
- errno = ETIMEDOUT;
- }
- #endif
- return -1;
- }
- #if HAVE_OPENSSL_EXT
- if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
- nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
- } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
- nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
- } else {
- #endif
- nr_bytes = recv(s, buf, len, 0);
- #if HAVE_OPENSSL_EXT
- }
- #endif
- return (nr_bytes);
- }
- /* }}} */
- /* {{{ data_available
- */
- int
- data_available(ftpbuf_t *ftp, php_socket_t s)
- {
- int n;
- n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
- if (n < 1) {
- #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
- if (n == 0) {
- errno = ETIMEDOUT;
- }
- #endif
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ data_writeable
- */
- int
- data_writeable(ftpbuf_t *ftp, php_socket_t s)
- {
- int n;
- n = php_pollfd_for_ms(s, POLLOUT, 1000);
- if (n < 1) {
- #ifndef PHP_WIN32
- if (n == 0) {
- errno = ETIMEDOUT;
- }
- #endif
- return 0;
- }
- return 1;
- }
- /* }}} */
- /* {{{ my_accept
- */
- int
- my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
- {
- int n;
- n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
- if (n < 1) {
- #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
- if (n == 0) {
- errno = ETIMEDOUT;
- }
- #endif
- return -1;
- }
- return accept(s, addr, addrlen);
- }
- /* }}} */
- /* {{{ ftp_getdata
- */
- databuf_t*
- ftp_getdata(ftpbuf_t *ftp TSRMLS_DC)
- {
- int fd = -1;
- databuf_t *data;
- php_sockaddr_storage addr;
- struct sockaddr *sa;
- socklen_t size;
- union ipbox ipbox;
- char arg[sizeof("255, 255, 255, 255, 255, 255")];
- struct timeval tv;
- /* ask for a passive connection if we need one */
- if (ftp->pasv && !ftp_pasv(ftp, 1)) {
- return NULL;
- }
- /* alloc the data structure */
- data = ecalloc(1, sizeof(*data));
- data->listener = -1;
- data->fd = -1;
- data->type = ftp->type;
- sa = (struct sockaddr *) &ftp->localaddr;
- /* bind/listen */
- if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- /* passive connection handler */
- if (ftp->pasv) {
- /* clear the ready status */
- ftp->pasv = 1;
- /* connect */
- /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */
- size = php_sockaddr_size(&ftp->pasvaddr);
- tv.tv_sec = ftp->timeout_sec;
- tv.tv_usec = 0;
- if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- data->fd = fd;
- ftp->data = data;
- return data;
- }
- /* active (normal) connection */
- /* bind to a local address */
- php_any_addr(sa->sa_family, &addr, 0);
- size = php_sockaddr_size(&addr);
- if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- if (listen(fd, 5) != 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
- goto bail;
- }
- data->listener = fd;
- #if HAVE_IPV6 && HAVE_INET_NTOP
- if (sa->sa_family == AF_INET6) {
- /* need to use EPRT */
- char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
- char out[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
- snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
- if (!ftp_putcmd(ftp, "EPRT", eprtarg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 200) {
- goto bail;
- }
- ftp->data = data;
- return data;
- }
- #endif
- /* send the PORT */
- ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
- ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
- 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]);
- if (!ftp_putcmd(ftp, "PORT", arg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || ftp->resp != 200) {
- goto bail;
- }
- ftp->data = data;
- return data;
- bail:
- if (fd != -1) {
- closesocket(fd);
- }
- efree(data);
- return NULL;
- }
- /* }}} */
- /* {{{ data_accept
- */
- databuf_t*
- data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC)
- {
- php_sockaddr_storage addr;
- socklen_t size;
- #if HAVE_OPENSSL_EXT
- SSL_CTX *ctx;
- SSL_SESSION *session;
- int result;
- #endif
- if (data->fd != -1) {
- goto data_accepted;
- }
- size = sizeof(addr);
- data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
- closesocket(data->listener);
- data->listener = -1;
- if (data->fd == -1) {
- efree(data);
- return NULL;
- }
- data_accepted:
- #if HAVE_OPENSSL_EXT
- /* now enable ssl if we need to */
- if (ftp->use_ssl && ftp->use_ssl_for_data) {
- ctx = SSL_get_SSL_CTX(ftp->ssl_handle);
- if (ctx == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to retreive the existing SSL context");
- return 0;
- }
- data->ssl_handle = SSL_new(ctx);
- if (data->ssl_handle == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL handle");
- return 0;
- }
- SSL_set_fd(data->ssl_handle, data->fd);
- if (ftp->old_ssl) {
- SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
- }
- /* get the session from the control connection so we can re-use it */
- session = SSL_get_session(ftp->ssl_handle);
- if (session == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to retreive the existing SSL session");
- SSL_free(data->ssl_handle);
- return 0;
- }
- /* and set it on the data connection */
- result = SSL_set_session(data->ssl_handle, session);
- if (result == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to set the existing SSL session");
- SSL_free(data->ssl_handle);
- return 0;
- }
- if (SSL_connect(data->ssl_handle) <= 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
- SSL_shutdown(data->ssl_handle);
- SSL_free(data->ssl_handle);
- return 0;
- }
- data->ssl_active = 1;
- }
- #endif
- return data;
- }
- /* }}} */
- /* {{{ data_close
- */
- databuf_t*
- data_close(ftpbuf_t *ftp, databuf_t *data)
- {
- #if HAVE_OPENSSL_EXT
- SSL_CTX *ctx;
- #endif
- if (data == NULL) {
- return NULL;
- }
- if (data->listener != -1) {
- #if HAVE_OPENSSL_EXT
- if (data->ssl_active) {
- /* don't free the data context, it's the same as the control */
- SSL_shutdown(data->ssl_handle);
- SSL_free(data->ssl_handle);
- data->ssl_active = 0;
- }
- #endif
- closesocket(data->listener);
- }
- if (data->fd != -1) {
- #if HAVE_OPENSSL_EXT
- if (data->ssl_active) {
- /* don't free the data context, it's the same as the control */
- SSL_shutdown(data->ssl_handle);
- SSL_free(data->ssl_handle);
- data->ssl_active = 0;
- }
- #endif
- closesocket(data->fd);
- }
- if (ftp) {
- ftp->data = NULL;
- }
- efree(data);
- return NULL;
- }
- /* }}} */
- /* {{{ ftp_genlist
- */
- char**
- ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
- {
- php_stream *tmpstream = NULL;
- databuf_t *data = NULL;
- char *ptr;
- int ch, lastch;
- size_t size, rcvd;
- size_t lines;
- char **ret = NULL;
- char **entry;
- char *text;
- if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create temporary file. Check permissions in temporary files directory.");
- return NULL;
- }
- if (!ftp_type(ftp, FTPTYPE_ASCII)) {
- goto bail;
- }
- if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- ftp->data = data;
- if (!ftp_putcmd(ftp, cmd, path)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
- goto bail;
- }
- /* some servers don't open a ftp-data connection if the directory is empty */
- if (ftp->resp == 226) {
- ftp->data = data_close(ftp, data);
- php_stream_close(tmpstream);
- return ecalloc(1, sizeof(char*));
- }
- /* pull data buffer into tmpfile */
- if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- size = 0;
- lines = 0;
- lastch = 0;
- while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
- if (rcvd == -1 || rcvd > ((size_t)(-1))-size) {
- goto bail;
- }
- php_stream_write(tmpstream, data->buf, rcvd);
- size += rcvd;
- for (ptr = data->buf; rcvd; rcvd--, ptr++) {
- if (*ptr == '\n' && lastch == '\r') {
- lines++;
- }
- lastch = *ptr;
- }
- }
- ftp->data = data_close(ftp, data);
- php_stream_rewind(tmpstream);
- ret = safe_emalloc((lines + 1), sizeof(char*), size);
- entry = ret;
- text = (char*) (ret + lines + 1);
- *entry = text;
- lastch = 0;
- while ((ch = php_stream_getc(tmpstream)) != EOF) {
- if (ch == '\n' && lastch == '\r') {
- *(text - 1) = 0;
- *++entry = text;
- } else {
- *text++ = ch;
- }
- lastch = ch;
- }
- *entry = NULL;
- php_stream_close(tmpstream);
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
- efree(ret);
- return NULL;
- }
- return ret;
- bail:
- ftp->data = data_close(ftp, data);
- php_stream_close(tmpstream);
- if (ret)
- efree(ret);
- return NULL;
- }
- /* }}} */
- /* {{{ ftp_nb_get
- */
- int
- ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, long resumepos TSRMLS_DC)
- {
- databuf_t *data = NULL;
- char arg[11];
- if (ftp == NULL) {
- return PHP_FTP_FAILED;
- }
- if (!ftp_type(ftp, type)) {
- goto bail;
- }
- if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- if (resumepos>0) {
- snprintf(arg, sizeof(arg), "%ld", resumepos);
- if (!ftp_putcmd(ftp, "REST", arg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
- goto bail;
- }
- }
- if (!ftp_putcmd(ftp, "RETR", path)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
- goto bail;
- }
- if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- ftp->data = data;
- ftp->stream = outstream;
- ftp->lastch = 0;
- ftp->nb = 1;
- return (ftp_nb_continue_read(ftp TSRMLS_CC));
- bail:
- ftp->data = data_close(ftp, data);
- return PHP_FTP_FAILED;
- }
- /* }}} */
- /* {{{ ftp_nb_continue_read
- */
- int
- ftp_nb_continue_read(ftpbuf_t *ftp TSRMLS_DC)
- {
- databuf_t *data = NULL;
- char *ptr;
- int lastch;
- size_t rcvd;
- ftptype_t type;
- data = ftp->data;
- /* check if there is already more data */
- if (!data_available(ftp, data->fd)) {
- return PHP_FTP_MOREDATA;
- }
- type = ftp->type;
- lastch = ftp->lastch;
- if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
- if (rcvd == -1) {
- goto bail;
- }
- if (type == FTPTYPE_ASCII) {
- for (ptr = data->buf; rcvd; rcvd--, ptr++) {
- if (lastch == '\r' && *ptr != '\n') {
- php_stream_putc(ftp->stream, '\r');
- }
- if (*ptr != '\r') {
- php_stream_putc(ftp->stream, *ptr);
- }
- lastch = *ptr;
- }
- } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
- goto bail;
- }
- ftp->lastch = lastch;
- return PHP_FTP_MOREDATA;
- }
- if (type == FTPTYPE_ASCII && lastch == '\r') {
- php_stream_putc(ftp->stream, '\r');
- }
- ftp->data = data = data_close(ftp, data);
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
- goto bail;
- }
- ftp->nb = 0;
- return PHP_FTP_FINISHED;
- bail:
- ftp->nb = 0;
- ftp->data = data_close(ftp, data);
- return PHP_FTP_FAILED;
- }
- /* }}} */
- /* {{{ ftp_nb_put
- */
- int
- ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, long startpos TSRMLS_DC)
- {
- databuf_t *data = NULL;
- char arg[11];
- if (ftp == NULL) {
- return 0;
- }
- if (!ftp_type(ftp, type)) {
- goto bail;
- }
- if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- if (startpos > 0) {
- snprintf(arg, sizeof(arg), "%ld", startpos);
- if (!ftp_putcmd(ftp, "REST", arg)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
- goto bail;
- }
- }
- if (!ftp_putcmd(ftp, "STOR", path)) {
- goto bail;
- }
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
- goto bail;
- }
- if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
- goto bail;
- }
- ftp->data = data;
- ftp->stream = instream;
- ftp->lastch = 0;
- ftp->nb = 1;
- return (ftp_nb_continue_write(ftp TSRMLS_CC));
- bail:
- ftp->data = data_close(ftp, data);
- return PHP_FTP_FAILED;
- }
- /* }}} */
- /* {{{ ftp_nb_continue_write
- */
- int
- ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC)
- {
- long size;
- char *ptr;
- int ch;
- /* check if we can write more data */
- if (!data_writeable(ftp, ftp->data->fd)) {
- return PHP_FTP_MOREDATA;
- }
- size = 0;
- ptr = ftp->data->buf;
- while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
- if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
- *ptr++ = '\r';
- size++;
- }
- *ptr++ = ch;
- size++;
- /* flush if necessary */
- if (FTP_BUFSIZE - size < 2) {
- if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
- goto bail;
- }
- return PHP_FTP_MOREDATA;
- }
- }
- if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
- goto bail;
- }
- ftp->data = data_close(ftp, ftp->data);
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
- goto bail;
- }
- ftp->nb = 0;
- return PHP_FTP_FINISHED;
- bail:
- ftp->data = data_close(ftp, ftp->data);
- ftp->nb = 0;
- return PHP_FTP_FAILED;
- }
- /* }}} */
- #endif /* HAVE_FTP */
- /*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
|