PageRenderTime 91ms CodeModel.GetById 20ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 1ms

/php-pecl-ssh2-0.11.3/ssh2-0.11.3/ssh2_sftp.c

#
C | 856 lines | 573 code | 154 blank | 129 comment | 99 complexity | 18f51ab86b10a5761da04ec3711bbef6 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1/*
  2  +----------------------------------------------------------------------+
  3  | PHP Version 4                                                        |
  4  +----------------------------------------------------------------------+
  5  | Copyright (c) 1997-2006 The PHP Group                                |
  6  +----------------------------------------------------------------------+
  7  | This source file is subject to version 2.02 of the PHP license,      |
  8  | that is bundled with this package in the file LICENSE, and is        |
  9  | available at through the world-wide-web at                           |
 10  | http://www.php.net/license/2_02.txt.                                 |
 11  | If you did not receive a copy of the PHP license and are unable to   |
 12  | obtain it through the world-wide-web, please send a note to          |
 13  | license@php.net so we can mail you a copy immediately.               |
 14  +----------------------------------------------------------------------+
 15  | Author: Sara Golemon <pollita@php.net>                               |
 16  +----------------------------------------------------------------------+
 17
 18  $Id: ssh2_sftp.c 317118 2011-09-21 19:05:21Z bjori $
 19*/
 20
 21#ifdef HAVE_CONFIG_H
 22#include "config.h"
 23#endif
 24
 25#include "php.h"
 26#include "php_ssh2.h"
 27#include "ext/standard/php_string.h"
 28
 29/* *************************
 30   * Resource Housekeeping *
 31   ************************* */
 32
 33void php_ssh2_sftp_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 34{
 35	php_ssh2_sftp_data *data = (php_ssh2_sftp_data*)rsrc->ptr;
 36
 37	if (!data) {
 38		return;
 39	}
 40
 41	libssh2_sftp_shutdown(data->sftp);
 42
 43	zend_list_delete(data->session_rsrcid);
 44
 45	efree(data);
 46}
 47
 48/* *****************
 49   * SFTP File Ops *
 50   ***************** */
 51
 52inline unsigned long php_ssh2_parse_fopen_modes(char *openmode) {
 53	unsigned long flags = 0;
 54
 55	if (strchr(openmode, 'a')) {
 56		flags |= LIBSSH2_FXF_APPEND;
 57	}
 58
 59	if (strchr(openmode, 'w')) {
 60		flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_CREAT;
 61	}
 62
 63	if (strchr(openmode, 'r')) {
 64		flags |= LIBSSH2_FXF_READ;
 65	}
 66
 67	if (strchr(openmode, '+')) {
 68		flags |= LIBSSH2_FXF_READ | LIBSSH2_FXF_WRITE;
 69	}
 70
 71	if (strchr(openmode, 'x')) {
 72		flags |= LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC | LIBSSH2_FXF_EXCL | LIBSSH2_FXF_CREAT;
 73	}
 74
 75	return flags;
 76}
 77
 78inline int php_ssh2_sftp_attr2ssb(php_stream_statbuf *ssb, LIBSSH2_SFTP_ATTRIBUTES *attrs)
 79{
 80	memset(ssb, 0, sizeof(php_stream_statbuf));
 81	if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
 82		ssb->sb.st_size = attrs->filesize;
 83	}
 84	
 85	if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
 86		ssb->sb.st_uid = attrs->uid;
 87		ssb->sb.st_gid = attrs->gid;
 88	}
 89	if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
 90		ssb->sb.st_mode = attrs->permissions;
 91	}
 92	if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
 93		ssb->sb.st_atime = attrs->atime;
 94		ssb->sb.st_mtime = attrs->mtime;
 95	}
 96
 97	return 0;
 98}
 99
100typedef struct _php_ssh2_sftp_handle_data {
101	LIBSSH2_SFTP_HANDLE *handle;
102
103	long sftp_rsrcid;
104} php_ssh2_sftp_handle_data;
105
106/* {{{ php_ssh2_sftp_stream_write
107 */
108static size_t php_ssh2_sftp_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
109{
110	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
111	ssize_t bytes_written;
112
113	bytes_written = libssh2_sftp_write(data->handle, buf, count);
114
115	return (size_t)(bytes_written<0 ? 0 : bytes_written);
116}
117/* }}} */
118
119/* {{{ php_ssh2_sftp_stream_read
120 */
121static size_t php_ssh2_sftp_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
122{
123	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
124	ssize_t bytes_read;
125
126	bytes_read = libssh2_sftp_read(data->handle, buf, count);
127
128	stream->eof = (bytes_read <= 0 && bytes_read != LIBSSH2_ERROR_EAGAIN);
129
130	return (size_t)(bytes_read<0 ? 0 : bytes_read);
131}
132/* }}} */
133
134/* {{{ php_ssh2_sftp_stream_close
135 */
136static int php_ssh2_sftp_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
137{
138	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
139
140	libssh2_sftp_close(data->handle);
141	zend_list_delete(data->sftp_rsrcid);
142	efree(data);
143
144	return 0;
145}
146/* }}} */
147
148/* {{{ php_ssh2_sftp_stream_seek
149 */
150static int php_ssh2_sftp_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
151{
152	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
153
154	switch (whence) {
155		case SEEK_END:
156		{
157			LIBSSH2_SFTP_ATTRIBUTES attrs;
158
159			if (libssh2_sftp_fstat(data->handle, &attrs)) {
160				return -1;
161			}
162			if ((attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) == 0) {
163				return -1;
164			}
165			offset += attrs.filesize;
166		}
167		case SEEK_CUR:
168		{
169			off_t current_offset = libssh2_sftp_tell(data->handle);
170
171			if (current_offset < 0) {
172				return -1;
173			}
174
175			offset += current_offset;
176		}
177	}
178
179	libssh2_sftp_seek(data->handle, offset);
180
181	if (newoffset) {
182		*newoffset = offset;
183	}
184
185	return 0;
186}
187/* }}} */
188
189/* {{{ php_ssh2_sftp_stream_fstat
190 */
191static int php_ssh2_sftp_stream_fstat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
192{
193	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
194	LIBSSH2_SFTP_ATTRIBUTES attrs;
195
196	if (libssh2_sftp_fstat(data->handle, &attrs)) {
197		return -1;
198	}
199
200	return php_ssh2_sftp_attr2ssb(ssb, &attrs);
201}
202/* }}} */
203
204static php_stream_ops php_ssh2_sftp_stream_ops = {
205    php_ssh2_sftp_stream_write,
206    php_ssh2_sftp_stream_read,
207    php_ssh2_sftp_stream_close,
208    NULL, /* flush */
209    PHP_SSH2_SFTP_STREAM_NAME,
210    php_ssh2_sftp_stream_seek,
211    NULL, /* cast */
212    php_ssh2_sftp_stream_fstat,
213	NULL, /* set_option */
214};
215
216/* {{{ php_ssh2_sftp_stream_opener
217 */
218static php_stream *php_ssh2_sftp_stream_opener(	php_stream_wrapper *wrapper, char *filename, char *mode,
219												int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
220{
221	php_ssh2_sftp_handle_data *data;
222	LIBSSH2_SESSION *session = NULL;
223	LIBSSH2_SFTP *sftp = NULL;
224	LIBSSH2_SFTP_HANDLE *handle;
225	php_stream *stream;
226	int resource_id = 0, sftp_rsrcid = 0;
227	php_url *resource;
228	unsigned long flags;
229	long perms = 0644;
230
231	resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
232	if (!resource || !session || !sftp) {
233		return NULL;
234	}
235
236	flags = php_ssh2_parse_fopen_modes(mode);
237
238	handle = libssh2_sftp_open(sftp, resource->path, flags, perms);
239	if (!handle) {
240		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
241		php_url_free(resource);
242		zend_list_delete(sftp_rsrcid);
243		return NULL;
244	}
245
246	data = emalloc(sizeof(php_ssh2_sftp_handle_data));
247	data->handle = handle;
248	data->sftp_rsrcid = sftp_rsrcid;
249
250	stream = php_stream_alloc(&php_ssh2_sftp_stream_ops, data, 0, mode);
251	if (!stream) {
252		libssh2_sftp_close(handle);
253		zend_list_delete(sftp_rsrcid);
254		efree(data);
255	}
256	php_url_free(resource);
257
258	return stream;
259}
260/* }}} */
261
262/* **********************
263   * SFTP Directory Ops *
264   ********************** */
265
266/* {{{ php_ssh2_sftp_dirstream_read
267 */
268static size_t php_ssh2_sftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
269{
270	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
271	php_stream_dirent *ent = (php_stream_dirent*)buf;
272	size_t bytesread = libssh2_sftp_readdir(data->handle, ent->d_name, sizeof(ent->d_name) - 1, NULL);
273	char *basename = NULL;
274	size_t basename_len = 0;
275
276	if (bytesread <= 0) {
277		return 0;
278	}
279	ent->d_name[bytesread] = 0;
280
281#ifdef ZEND_ENGINE_2
282	php_basename(ent->d_name, bytesread, NULL, 0, &basename, &basename_len TSRMLS_CC);
283#else
284/* CURSE YOU BC BREAKS! */
285	basename = php_basename(ent->d_name, bytesread, NULL, 0);
286	if (basename) {
287		basename_len = strlen(basename);
288	}
289#endif
290	if (!basename) {
291		return 0;
292	}
293
294	if (!basename_len) {
295		efree(basename);
296		return 0;
297	}
298	bytesread = MIN(sizeof(ent->d_name) - 1, basename_len);
299	memcpy(ent->d_name, basename, bytesread);
300	ent->d_name[bytesread] = 0;
301	efree(basename);
302
303	return sizeof(php_stream_dirent);
304}
305/* }}} */
306
307/* {{{ php_ssh2_sftp_dirstream_close
308 */
309static int php_ssh2_sftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
310{
311	php_ssh2_sftp_handle_data *data = (php_ssh2_sftp_handle_data*)stream->abstract;
312
313	libssh2_sftp_close(data->handle);
314	zend_list_delete(data->sftp_rsrcid);
315	efree(data);
316
317	return 0;
318}
319/* }}} */
320
321static php_stream_ops php_ssh2_sftp_dirstream_ops = {
322	NULL, /* write */
323    php_ssh2_sftp_dirstream_read,
324    php_ssh2_sftp_dirstream_close,
325    NULL, /* flush */
326    PHP_SSH2_SFTP_DIRSTREAM_NAME,
327	NULL, /* seek */
328    NULL, /* cast */
329	NULL, /* fstat */
330	NULL, /* set_option */
331};
332
333/* {{{ php_ssh2_sftp_dirstream_opener
334 */
335static php_stream *php_ssh2_sftp_dirstream_opener(	php_stream_wrapper *wrapper, char *filename, char *mode,
336													int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
337{
338	php_ssh2_sftp_handle_data *data;
339	LIBSSH2_SESSION *session = NULL;
340	LIBSSH2_SFTP *sftp = NULL;
341	LIBSSH2_SFTP_HANDLE *handle;
342	php_stream *stream;
343	int resource_id = 0, sftp_rsrcid = 0;
344	php_url *resource;
345
346	resource = php_ssh2_fopen_wraper_parse_path(filename, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
347	if (!resource || !session || !sftp) {
348		return NULL;
349	}
350
351	handle = libssh2_sftp_opendir(sftp, resource->path);
352	if (!handle) {
353		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s on remote host", filename);
354		php_url_free(resource);
355		zend_list_delete(sftp_rsrcid);
356		return NULL;
357	}
358
359	data = emalloc(sizeof(php_ssh2_sftp_handle_data));
360	data->handle = handle;
361	data->sftp_rsrcid = sftp_rsrcid;
362
363	stream = php_stream_alloc(&php_ssh2_sftp_dirstream_ops, data, 0, mode);
364	if (!stream) {
365		libssh2_sftp_close(handle);
366		zend_list_delete(sftp_rsrcid);
367		efree(data);
368	}
369	php_url_free(resource);
370
371	return stream;
372}
373/* }}} */
374
375/* ****************
376   * SFTP Wrapper *
377   **************** */
378
379#ifdef ZEND_ENGINE_2
380/* {{{ php_ssh2_sftp_urlstat
381 */
382static int php_ssh2_sftp_urlstat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
383{
384	LIBSSH2_SFTP_ATTRIBUTES attrs;
385	LIBSSH2_SESSION *session = NULL;
386	LIBSSH2_SFTP *sftp = NULL;
387	int resource_id = 0, sftp_rsrcid = 0;
388	php_url *resource;
389
390	resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
391	if (!resource || !session || !sftp || !resource->path) {
392		return -1;
393	}
394
395	if (libssh2_sftp_stat_ex(sftp, resource->path, strlen(resource->path),
396		(flags & PHP_STREAM_URL_STAT_LINK) ? LIBSSH2_SFTP_LSTAT : LIBSSH2_SFTP_STAT, &attrs)) {
397		php_url_free(resource);
398		zend_list_delete(sftp_rsrcid);
399		return -1;
400	}
401	
402	php_url_free(resource);
403
404	/* parse_path addrefs the resource, but we're not holding on to it so we have to delref it before we leave */
405	zend_list_delete(sftp_rsrcid);
406
407	return php_ssh2_sftp_attr2ssb(ssb, &attrs);
408}
409/* }}} */
410
411/* {{{ php_ssh2_sftp_unlink
412 */
413static int php_ssh2_sftp_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
414{
415	LIBSSH2_SESSION *session = NULL;
416	LIBSSH2_SFTP *sftp = NULL;
417	int resource_id = 0, sftp_rsrcid = 0;
418	php_url *resource;
419	int result;
420
421	resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
422	if (!resource || !session || !sftp || !resource->path) {
423		if (resource) {
424			php_url_free(resource);
425		}
426		return 0;
427	}
428
429	result = libssh2_sftp_unlink(sftp, resource->path);
430	php_url_free(resource);
431
432	zend_list_delete(sftp_rsrcid);
433
434	/* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
435	return (result == 0) ? -1 : 0;
436}
437/* }}} */
438
439/* {{{ php_ssh2_sftp_rename
440 */
441static int php_ssh2_sftp_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
442{
443	LIBSSH2_SESSION *session = NULL;
444	LIBSSH2_SFTP *sftp = NULL;
445	int resource_id = 0, sftp_rsrcid = 0;
446	php_url *resource, *resource_to;
447	int result;
448
449	if (strncmp(url_from, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1) ||
450		strncmp(url_to, "ssh2.sftp://", sizeof("ssh2.sftp://") - 1)) {
451		return 0;
452	}
453
454	resource_to = php_url_parse(url_to);
455	if (!resource_to || !resource_to->path) {
456		if (resource_to) {
457			php_url_free(resource_to);
458		}
459		return 0;
460	}
461
462	resource = php_ssh2_fopen_wraper_parse_path(url_from, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
463	if (!resource || !session || !sftp || !resource->path) {
464		if (resource) {
465			php_url_free(resource);
466		}
467		php_url_free(resource_to);
468		return 0;
469	}
470
471	result = libssh2_sftp_rename(sftp, resource->path, resource_to->path);
472	php_url_free(resource);
473	php_url_free(resource_to);
474
475	zend_list_delete(sftp_rsrcid);
476
477	/* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
478	return (result == 0) ? -1 : 0;
479}
480/* }}} */
481
482/* {{{ php_ssh2_sftp_mkdir
483 */
484static int php_ssh2_sftp_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
485{
486	LIBSSH2_SESSION *session = NULL;
487	LIBSSH2_SFTP *sftp = NULL;
488	int resource_id = 0, sftp_rsrcid = 0;
489	php_url *resource;
490	int result;
491
492	resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
493	if (!resource || !session || !sftp || !resource->path) {
494		if (resource) {
495			php_url_free(resource);
496		}
497		return 0;
498	}
499
500	if (options & PHP_STREAM_MKDIR_RECURSIVE) {
501		/* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
502		char *p = resource->path;
503		while ((p = strchr(p + 1, '/'))) {
504			libssh2_sftp_mkdir_ex(sftp, resource->path, p - resource->path, mode);
505		}
506	}
507
508	result = libssh2_sftp_mkdir(sftp, resource->path, mode);
509	php_url_free(resource);
510
511	zend_list_delete(sftp_rsrcid);
512
513	/* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
514	return (result == 0) ? -1 : 0;
515}
516/* }}} */
517
518/* {{{ php_ssh2_sftp_rmdir
519 */
520static int php_ssh2_sftp_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
521{
522	LIBSSH2_SESSION *session = NULL;
523	LIBSSH2_SFTP *sftp = NULL;
524	int resource_id = 0, sftp_rsrcid = 0;
525	php_url *resource;
526	int result;
527
528	resource = php_ssh2_fopen_wraper_parse_path(url, "sftp", context, &session, &resource_id, &sftp, &sftp_rsrcid TSRMLS_CC);
529	if (!resource || !session || !sftp || !resource->path) {
530		if (resource) {
531			php_url_free(resource);
532		}
533		return 0;
534	}
535
536	result = libssh2_sftp_rmdir(sftp, resource->path);
537	php_url_free(resource);
538
539	zend_list_delete(sftp_rsrcid);
540
541	/* libssh2 uses 0 for success and the streams API uses 0 for failure, so invert */
542	return (result == 0) ? -1 : 0;
543}
544/* }}} */
545#endif
546
547static php_stream_wrapper_ops php_ssh2_sftp_wrapper_ops = {
548	php_ssh2_sftp_stream_opener,
549	NULL, /* close */
550	NULL, /* stat */
551#ifdef ZEND_ENGINE_2
552	php_ssh2_sftp_urlstat,
553#else
554	NULL, /* url_stat isn't actually functional prior to PHP5 */
555#endif
556	php_ssh2_sftp_dirstream_opener,
557	PHP_SSH2_SFTP_WRAPPER_NAME,
558#ifdef ZEND_ENGINE_2
559	php_ssh2_sftp_unlink,
560	php_ssh2_sftp_rename,
561	php_ssh2_sftp_mkdir,
562	php_ssh2_sftp_rmdir,
563#endif
564};
565
566php_stream_wrapper php_ssh2_sftp_wrapper = {
567	&php_ssh2_sftp_wrapper_ops,
568	NULL,
569	1,
570	0,
571	NULL,
572};
573
574/* *****************
575   * Userspace API *
576   ***************** */
577
578
579/* {{{ proto resource ssh2_sftp(resource session)
580 * Request the SFTP subsystem from an already connected SSH2 server
581 */
582PHP_FUNCTION(ssh2_sftp)
583{
584	LIBSSH2_SESSION *session;
585	LIBSSH2_SFTP *sftp;
586	php_ssh2_sftp_data *data;
587	zval *zsession;
588
589	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsession) == FAILURE) {
590		RETURN_FALSE;
591	}
592
593	ZEND_FETCH_RESOURCE(session, LIBSSH2_SESSION*, &zsession, -1, PHP_SSH2_SESSION_RES_NAME, le_ssh2_session);
594
595	sftp = libssh2_sftp_init(session);
596	if (!sftp) {
597		char *sess_err = "Unknown";
598
599		libssh2_session_last_error(session, &sess_err, NULL, 0);
600		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to startup SFTP subsystem: %s", sess_err);
601		RETURN_FALSE;
602	}
603
604	data = emalloc(sizeof(php_ssh2_sftp_data));
605	data->session = session;
606	data->sftp = sftp;
607	data->session_rsrcid = Z_LVAL_P(zsession);
608	zend_list_addref(Z_LVAL_P(zsession));
609
610	ZEND_REGISTER_RESOURCE(return_value, data, le_ssh2_sftp);
611}
612/* }}} */
613
614/* Much of the stuff below can be done via wrapper ops as of PHP5, but is included here for PHP 4.3 users */
615
616/* {{{ proto bool ssh2_sftp_rename(resource sftp, string from, string to)
617 */
618PHP_FUNCTION(ssh2_sftp_rename)
619{
620	php_ssh2_sftp_data *data;
621	zval *zsftp;
622	char *src, *dst;
623	int src_len, dst_len;
624
625	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &src, &src_len, &dst, &dst_len) == FAILURE) {
626		RETURN_FALSE;
627	}
628
629	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
630
631	RETURN_BOOL(!libssh2_sftp_rename_ex(data->sftp, src, src_len, dst, dst_len,
632				 LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE));
633}
634/* }}} */
635
636/* {{{ proto bool ssh2_sftp_unlink(resource sftp, string filename)
637 */
638PHP_FUNCTION(ssh2_sftp_unlink)
639{
640	php_ssh2_sftp_data *data;
641	zval *zsftp;
642	char *filename;
643	int filename_len;
644
645	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
646		RETURN_FALSE;
647	}
648
649	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
650
651	RETURN_BOOL(!libssh2_sftp_unlink_ex(data->sftp, filename, filename_len));
652}
653/* }}} */
654
655/* {{{ proto bool ssh2_sftp_mkdir(resource sftp, string filename[, int mode[, int recursive]])
656 */
657PHP_FUNCTION(ssh2_sftp_mkdir)
658{
659	php_ssh2_sftp_data *data;
660	zval *zsftp;
661	char *filename;
662	int filename_len;
663	long mode = 0777;
664	zend_bool recursive = 0;
665	char *p;
666
667	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lb", &zsftp, &filename, &filename_len, &mode, &recursive) == FAILURE) {
668		RETURN_FALSE;
669	}
670
671	if (filename_len < 1) {
672		RETURN_FALSE;
673	}
674
675	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
676
677	if (recursive) {
678		/* Just attempt to make every directory, some will fail, but we only care about the last success/failure */
679		p = filename;
680		while ((p = strchr(p + 1, '/'))) {
681			if ((p - filename) + 1 == filename_len) {
682				break;
683			}
684			libssh2_sftp_mkdir_ex(data->sftp, filename, p - filename, mode);
685		}
686	}
687
688
689	RETURN_BOOL(!libssh2_sftp_mkdir_ex(data->sftp, filename, filename_len, mode));
690}
691/* }}} */
692
693/* {{{ proto bool ssh2_sftp_rmdir(resource sftp, string filename)
694 */
695PHP_FUNCTION(ssh2_sftp_rmdir)
696{
697	php_ssh2_sftp_data *data;
698	zval *zsftp;
699	char *filename;
700	int filename_len;
701
702	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &filename, &filename_len) == FAILURE) {
703		RETURN_FALSE;
704	}
705
706	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
707
708	RETURN_BOOL(!libssh2_sftp_rmdir_ex(data->sftp, filename, filename_len));
709}
710/* }}} */
711
712/* {{{ php_ssh2_sftp_stat_func
713 * In PHP4.3 this is the only way to request stat into, in PHP >= 5 you can use the fopen wrapper approach
714 * Both methods will return identical structures
715 * (well, the other one will include other values set to 0 but they don't count)
716 */
717static void php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAMETERS, int stat_type)
718{
719	php_ssh2_sftp_data *data;
720	LIBSSH2_SFTP_ATTRIBUTES attrs;
721	zval *zsftp;
722	char *path;
723	int path_len;
724
725	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &path, &path_len) == FAILURE) {
726		RETURN_FALSE;
727	}
728
729	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
730
731	if (libssh2_sftp_stat_ex(data->sftp, path, path_len, stat_type, &attrs)) {
732		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to stat remote file");
733		RETURN_FALSE;
734	}
735
736	array_init(return_value);
737
738	if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
739		add_index_long(return_value, 7, attrs.filesize);
740		add_assoc_long(return_value, "size", attrs.filesize);
741	}
742	if (attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) {
743		add_index_long(return_value, 4, attrs.uid);
744		add_assoc_long(return_value, "uid", attrs.uid);
745
746		add_index_long(return_value, 5, attrs.gid);
747		add_assoc_long(return_value, "gid", attrs.gid);
748	}
749	if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
750		add_index_long(return_value, 2, attrs.permissions);
751		add_assoc_long(return_value, "mode", attrs.permissions);
752	}
753	if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
754		add_index_long(return_value, 8, attrs.atime);
755		add_assoc_long(return_value, "atime", attrs.atime);
756
757		add_index_long(return_value, 9, attrs.mtime);
758		add_assoc_long(return_value, "mtime", attrs.mtime);
759	}
760}
761/* }}} */
762
763/* {{{ proto array ssh2_sftp_stat(resource sftp, string path)
764 */
765PHP_FUNCTION(ssh2_sftp_stat)
766{
767	php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_STAT);
768}
769/* }}} */
770
771/* {{{ proto array ssh2_sftp_lstat(resource sftp, string path)
772 */
773PHP_FUNCTION(ssh2_sftp_lstat)
774{
775	php_ssh2_sftp_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, LIBSSH2_SFTP_LSTAT);
776}
777/* }}} */
778
779/* {{{ proto bool ssh2_sftp_symlink(resource sftp, string target, string link)
780 */
781PHP_FUNCTION(ssh2_sftp_symlink)
782{
783	php_ssh2_sftp_data *data;
784	zval *zsftp;
785	char *targ, *link;
786	int targ_len, link_len;
787
788	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &zsftp, &targ, &targ_len, &link, &link_len) == FAILURE) {
789		RETURN_FALSE;
790	}
791
792	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
793
794	RETURN_BOOL(!libssh2_sftp_symlink_ex(data->sftp, targ, targ_len, link, link_len, LIBSSH2_SFTP_SYMLINK));
795}
796/* }}} */
797
798/* {{{ proto string ssh2_sftp_readlink(resource sftp, string link)
799 */
800PHP_FUNCTION(ssh2_sftp_readlink)
801{
802	php_ssh2_sftp_data *data;
803	zval *zsftp;
804	char *link;
805	int targ_len = 0, link_len;
806	char targ[8192];
807
808	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
809		RETURN_FALSE;
810	}
811
812	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
813
814	if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_READLINK)) < 0) {
815		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to read link '%s'", link);
816		RETURN_FALSE;
817	}
818
819	RETURN_STRINGL(targ, targ_len, 1);
820}
821/* }}} */
822
823/* {{{ proto string ssh2_sftp_realpath(resource sftp, string filename)
824 */
825PHP_FUNCTION(ssh2_sftp_realpath)
826{
827	php_ssh2_sftp_data *data;
828	zval *zsftp;
829	char *link;
830	int targ_len = 0, link_len;
831	char targ[8192];
832
833	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zsftp, &link, &link_len) == FAILURE) {
834		RETURN_FALSE;
835	}
836
837	ZEND_FETCH_RESOURCE(data, php_ssh2_sftp_data*, &zsftp, -1, PHP_SSH2_SFTP_RES_NAME, le_ssh2_sftp);
838
839	if ((targ_len = libssh2_sftp_symlink_ex(data->sftp, link, link_len, targ, 8192, LIBSSH2_SFTP_REALPATH)) < 0) {
840		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to resolve realpath for '%s'", link);
841		RETURN_FALSE;
842	}
843
844	RETURN_STRINGL(targ, targ_len, 1);
845}
846/* }}} */
847
848
849/*
850 * Local variables:
851 * tab-width: 4
852 * c-basic-offset: 4
853 * indent-tabs-mode: t
854 * End:
855 */
856