/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