PageRenderTime 1551ms CodeModel.GetById 101ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/Net/SFTP/Foreign.pm

https://github.com/gitpan/Net-SFTP-Foreign
Perl | 5539 lines | 5006 code | 464 blank | 69 comment | 381 complexity | 1e86b93b9d910ec891b45dadf0c17437 MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. package Net::SFTP::Foreign;
  2. our $VERSION = '1.78_03';
  3. use strict;
  4. use warnings;
  5. use warnings::register;
  6. use Carp qw(carp croak);
  7. use Symbol ();
  8. use Errno ();
  9. use Fcntl;
  10. use File::Spec ();
  11. BEGIN {
  12. if ($] >= 5.008) {
  13. require Encode;
  14. }
  15. else {
  16. # Work around for incomplete Unicode handling in perl 5.6.x
  17. require bytes;
  18. bytes->import();
  19. *Encode::encode = sub { $_[1] };
  20. *Encode::decode = sub { $_[1] };
  21. *utf8::downgrade = sub { 1 };
  22. }
  23. }
  24. # we make $Net::SFTP::Foreign::Helpers::debug an alias for
  25. # $Net::SFTP::Foreign::debug so that the user can set it without
  26. # knowing anything about the Helpers package!
  27. our $debug;
  28. BEGIN { *Net::SFTP::Foreign::Helpers::debug = \$debug };
  29. use Net::SFTP::Foreign::Helpers qw(_is_reg _is_lnk _is_dir _debug
  30. _sort_entries _gen_wanted
  31. _gen_converter _hexdump
  32. _ensure_list _catch_tainted_args
  33. _file_part _umask_save_and_set);
  34. use Net::SFTP::Foreign::Constants qw( :fxp :flags :att
  35. :status :error
  36. SSH2_FILEXFER_VERSION );
  37. use Net::SFTP::Foreign::Attributes;
  38. use Net::SFTP::Foreign::Buffer;
  39. require Net::SFTP::Foreign::Common;
  40. our @ISA = qw(Net::SFTP::Foreign::Common);
  41. our $dirty_cleanup;
  42. my $windows;
  43. BEGIN {
  44. $windows = $^O =~ /Win(?:32|64)/;
  45. if ($^O =~ /solaris/i) {
  46. $dirty_cleanup = 1 unless defined $dirty_cleanup;
  47. }
  48. }
  49. sub _deprecated {
  50. if (warnings::enabled('deprecated') and warnings::enabled(__PACKAGE__)) {
  51. Carp::carp(join('', @_));
  52. }
  53. }
  54. sub _next_msg_id { shift->{_msg_id}++ }
  55. use constant _empty_attributes => Net::SFTP::Foreign::Attributes->new;
  56. sub _queue_new_msg {
  57. my $sftp = shift;
  58. my $code = shift;
  59. my $id = $sftp->_next_msg_id;
  60. my $msg = Net::SFTP::Foreign::Buffer->new(int8 => $code, int32 => $id, @_);
  61. $sftp->_queue_msg($msg);
  62. return $id;
  63. }
  64. sub _queue_msg {
  65. my ($sftp, $buf) = @_;
  66. my $bytes = $buf->bytes;
  67. my $len = length $bytes;
  68. if ($debug and $debug & 1) {
  69. $sftp->{_queued}++;
  70. _debug(sprintf("queueing msg len: %i, code:%i, id:%i ... [$sftp->{_queued}]",
  71. $len, unpack(CN => $bytes)));
  72. $debug & 16 and _hexdump(pack('N', length($bytes)) . $bytes);
  73. }
  74. $sftp->{_bout} .= pack('N', length($bytes));
  75. $sftp->{_bout} .= $bytes;
  76. }
  77. sub _do_io { $_[0]->{_backend}->_do_io(@_) }
  78. sub _conn_lost {
  79. my ($sftp, $status, $err, @str) = @_;
  80. $debug and $debug & 32 and _debug("_conn_lost");
  81. $sftp->{_status} or
  82. $sftp->_set_status(defined $status ? $status : SSH2_FX_CONNECTION_LOST);
  83. $sftp->{_error} or
  84. $sftp->_set_error((defined $err ? $err : SFTP_ERR_CONNECTION_BROKEN),
  85. (@str ? @str : "Connection to remote server is broken"));
  86. undef $sftp->{_connected};
  87. }
  88. sub _conn_failed {
  89. my $sftp = shift;
  90. $sftp->_conn_lost(SSH2_FX_NO_CONNECTION,
  91. SFTP_ERR_CONNECTION_BROKEN,
  92. @_)
  93. unless $sftp->{_error};
  94. }
  95. sub _get_msg {
  96. my $sftp = shift;
  97. $debug and $debug & 1 and _debug("waiting for message... [$sftp->{_queued}]");
  98. unless ($sftp->_do_io($sftp->{_timeout})) {
  99. $sftp->_conn_lost(undef, undef, "Connection to remote server stalled");
  100. return undef;
  101. }
  102. my $bin = \$sftp->{_bin};
  103. my $len = unpack N => substr($$bin, 0, 4, '');
  104. my $msg = Net::SFTP::Foreign::Buffer->make(substr($$bin, 0, $len, ''));
  105. if ($debug and $debug & 1) {
  106. $sftp->{_queued}--;
  107. my ($code, $id, $status) = unpack( CNN => $$msg);
  108. $id = '-' if $code == SSH2_FXP_VERSION;
  109. $status = '-' unless $code == SSH2_FXP_STATUS;
  110. _debug(sprintf("got it!, len:%i, code:%i, id:%s, status: %s",
  111. $len, $code, $id, $status));
  112. $debug & 8 and _hexdump($$msg);
  113. }
  114. return $msg;
  115. }
  116. sub _croak_bad_options {
  117. if (@_) {
  118. my $s = (@_ > 1 ? 's' : '');
  119. croak "Invalid option$s '" . CORE::join("', '", @_) . "' or bad combination of options";
  120. }
  121. }
  122. sub _fs_encode {
  123. my ($sftp, $path) = @_;
  124. Encode::encode($sftp->{_fs_encoding}, $path);
  125. }
  126. sub _fs_decode {
  127. my ($sftp, $path) = @_;
  128. Encode::decode($sftp->{_fs_encoding}, $path);
  129. }
  130. sub new {
  131. ${^TAINT} and &_catch_tainted_args;
  132. my $class = shift;
  133. unshift @_, 'host' if @_ & 1;
  134. my %opts = @_;
  135. my $sftp = { _msg_id => 0,
  136. _bout => '',
  137. _bin => '',
  138. _connected => 1,
  139. _queued => 0,
  140. _error => 0,
  141. _status => 0 };
  142. bless $sftp, $class;
  143. if ($debug) {
  144. _debug "This is Net::SFTP::Foreign $Net::SFTP::Foreign::VERSION";
  145. _debug "Loaded from $INC{'Net/SFTP/Foreign.pm'}";
  146. _debug "Running on Perl $^V for $^O";
  147. _debug "debug set to $debug";
  148. _debug "~0 is " . ~0;
  149. }
  150. $sftp->_clear_error_and_status;
  151. my $backend = delete $opts{backend};
  152. unless (ref $backend) {
  153. $backend = ($windows ? 'Windows' : 'Unix')
  154. unless (defined $backend);
  155. $backend =~ /^\w+$/
  156. or croak "Bad backend name $backend";
  157. my $backend_class = "Net::SFTP::Foreign::Backend::$backend";
  158. eval "require $backend_class; 1"
  159. or croak "Unable to load backend $backend: $@";
  160. $backend = $backend_class->_new($sftp, \%opts);
  161. }
  162. $sftp->{_backend} = $backend;
  163. if ($debug) {
  164. my $class = ref($backend) || $backend;
  165. no strict 'refs';
  166. my $version = ${$class .'::VERSION'} || 0;
  167. _debug "Using backend $class $version";
  168. }
  169. my %defs = $backend->_defaults;
  170. $sftp->{_autodie} = delete $opts{autodie};
  171. $sftp->{_block_size} = delete $opts{block_size} || $defs{block_size} || 32*1024;
  172. $sftp->{_min_block_size} = delete $opts{min_block_size} || $defs{min_block_size} || 512;
  173. $sftp->{_queue_size} = delete $opts{queue_size} || $defs{queue_size} || 32;
  174. $sftp->{_read_ahead} = $defs{read_ahead} || $sftp->{_block_size} * 4;
  175. $sftp->{_write_delay} = $defs{write_delay} || $sftp->{_block_size} * 8;
  176. $sftp->{_autoflush} = delete $opts{autoflush};
  177. $sftp->{_late_set_perm} = delete $opts{late_set_perm};
  178. $sftp->{_dirty_cleanup} = delete $opts{dirty_cleanup};
  179. $sftp->{_timeout} = delete $opts{timeout};
  180. defined $sftp->{_timeout} and $sftp->{_timeout} <= 0 and croak "invalid timeout";
  181. $sftp->{_fs_encoding} = delete $opts{fs_encoding};
  182. if (defined $sftp->{_fs_encoding}) {
  183. $] < 5.008
  184. and carp "fs_encoding feature is not supported in this perl version $]";
  185. }
  186. else {
  187. $sftp->{_fs_encoding} = 'utf8';
  188. }
  189. $sftp->autodisconnect(delete $opts{autodisconnect});
  190. $backend->_init_transport($sftp, \%opts);
  191. %opts and _croak_bad_options(keys %opts);
  192. $sftp->_init unless $sftp->{_error};
  193. $backend->_after_init($sftp);
  194. $sftp
  195. }
  196. sub autodisconnect {
  197. my ($sftp, $ad) = @_;
  198. if (defined $ad and $ad != 1) {
  199. if ($ad == 0) {
  200. $sftp->{_disconnect_by_pid} = -1;
  201. }
  202. elsif ($ad == 2) {
  203. $sftp->{_disconnect_by_pid} = $$;
  204. }
  205. else {
  206. croak "bad value '$ad' for autodisconnect";
  207. }
  208. }
  209. 1;
  210. }
  211. sub disconnect {
  212. my $sftp = shift;
  213. my $pid = delete $sftp->{pid};
  214. $debug and $debug & 4 and _debug("$sftp->disconnect called (ssh pid: ".($pid||'').")");
  215. local $sftp->{_autodie};
  216. $sftp->_conn_lost;
  217. if (defined $pid) {
  218. close $sftp->{ssh_out} if (defined $sftp->{ssh_out} and not $sftp->{_ssh_out_is_not_dupped});
  219. close $sftp->{ssh_in} if defined $sftp->{ssh_in};
  220. if ($windows) {
  221. kill KILL => $pid
  222. and waitpid($pid, 0);
  223. $debug and $debug & 4 and _debug "process $pid reaped";
  224. }
  225. else {
  226. my $dirty = ( defined $sftp->{_dirty_cleanup}
  227. ? $sftp->{_dirty_cleanup}
  228. : $dirty_cleanup );
  229. if ($dirty or not defined $dirty) {
  230. $debug and $debug & 4 and _debug("starting dirty cleanup of process $pid");
  231. for my $sig (($dirty ? () : 0), qw(TERM TERM KILL KILL)) {
  232. $debug and $debug & 4 and _debug("killing process $pid with signal $sig");
  233. $sig and kill $sig, $pid;
  234. local ($@, $SIG{__DIE__}, $SIG{__WARN__});
  235. my $wpr;
  236. eval {
  237. local $SIG{ALRM} = sub { die "timeout\n" };
  238. alarm 8;
  239. $wpr = waitpid($pid, 0);
  240. alarm 0;
  241. };
  242. $debug and $debug & 4 and _debug("waitpid returned " . (defined $wpr ? $wpr : '<undef>'));
  243. if ($wpr) {
  244. # $wpr > 0 ==> the process has ben reaped
  245. # $wpr < 0 ==> some error happened, retry unless ECHILD
  246. last if $wpr > 0 or $! == Errno::ECHILD();
  247. }
  248. }
  249. }
  250. else {
  251. while (1) {
  252. last if waitpid($pid, 0) > 0;
  253. if ($! != Errno::EINTR) {
  254. warn "internal error: unexpected error in waitpid($pid): $!"
  255. if $! != Errno::ECHILD;
  256. last;
  257. }
  258. }
  259. }
  260. $debug and $debug & 4 and _debug "process $pid reaped";
  261. }
  262. }
  263. close $sftp->{_pty} if defined $sftp->{_pty};
  264. 1
  265. }
  266. sub DESTROY {
  267. local ($?, $!, $@);
  268. my $sftp = shift;
  269. my $dbpid = $sftp->{_disconnect_by_pid};
  270. $debug and $debug & 4 and _debug("$sftp->DESTROY called (current pid: $$, disconnect_by_pid: ".($dbpid||'').")");
  271. $sftp->disconnect if (!defined $dbpid or $dbpid == $$);
  272. }
  273. sub _init {
  274. my $sftp = shift;
  275. $sftp->_queue_msg( Net::SFTP::Foreign::Buffer->new(int8 => SSH2_FXP_INIT,
  276. int32 => SSH2_FILEXFER_VERSION));
  277. if (my $msg = $sftp->_get_msg) {
  278. my $type = $msg->get_int8;
  279. if ($type == SSH2_FXP_VERSION) {
  280. my $version = $msg->get_int32;
  281. $sftp->{server_version} = $version;
  282. $sftp->{server_extensions} = {};
  283. while (length $$msg) {
  284. my $key = $msg->get_str;
  285. my $value = $msg->get_str;
  286. $sftp->{server_extensions}{$key} = $value;
  287. if ($key eq 'vendor-id') {
  288. my $vid = Net::SFTP::Foreign::Buffer->make("$value");
  289. $sftp->{_ext__vendor_id} = [ Encode::decode(utf8 => $vid->get_str),
  290. Encode::decode(utf8 => $vid->get_str),
  291. Encode::decode(utf8 => $vid->get_str),
  292. $vid->get_int64 ];
  293. }
  294. elsif ($key eq 'supported2') {
  295. my $s2 = Net::SFTP::Foreign::Buffer->make("$value");
  296. $sftp->{_ext__supported2} = [ $s2->get_int32,
  297. $s2->get_int32,
  298. $s2->get_int32,
  299. $s2->get_int32,
  300. $s2->get_int32,
  301. $s2->get_int16,
  302. $s2->get_int16,
  303. [map Encode::decode(utf8 => $_), $s2->get_str_list],
  304. [map Encode::decode(utf8 => $_), $s2->get_str_list] ];
  305. }
  306. }
  307. return $version;
  308. }
  309. $sftp->_conn_lost(SSH2_FX_BAD_MESSAGE,
  310. SFTP_ERR_REMOTE_BAD_MESSAGE,
  311. "bad packet type, expecting SSH2_FXP_VERSION, got $type");
  312. }
  313. elsif ($sftp->{_status} == SSH2_FX_CONNECTION_LOST
  314. and $sftp->{_password_authentication}
  315. and $sftp->{_password_sent}) {
  316. $sftp->_set_error(SFTP_ERR_PASSWORD_AUTHENTICATION_FAILED,
  317. "Password authentication failed or connection lost");
  318. }
  319. return undef;
  320. }
  321. sub server_extensions { %{shift->{server_extensions}} }
  322. sub _check_extension {
  323. my ($sftp, $name, $version, $error, $errstr) = @_;
  324. my $ext = $sftp->{server_extensions}{$name};
  325. return 1 if (defined $ext and $ext == $version);
  326. $sftp->_set_status(SSH2_FX_OP_UNSUPPORTED);
  327. $sftp->_set_error($error, "$errstr: extended operation not supported by server");
  328. return undef;
  329. }
  330. # helper methods:
  331. sub _get_msg_and_check {
  332. my ($sftp, $etype, $eid, $err, $errstr) = @_;
  333. my $msg = $sftp->_get_msg;
  334. if ($msg) {
  335. my $type = $msg->get_int8;
  336. my $id = $msg->get_int32;
  337. $sftp->_clear_error_and_status;
  338. if ($id != $eid) {
  339. $sftp->_conn_lost(SSH2_FX_BAD_MESSAGE,
  340. SFTP_ERR_REMOTE_BAD_MESSAGE,
  341. $errstr, "bad packet sequence, expected $eid, got $id");
  342. return undef;
  343. }
  344. if ($type != $etype) {
  345. if ($type == SSH2_FXP_STATUS) {
  346. my $code = $msg->get_int32;
  347. my $str = Encode::decode(utf8 => $msg->get_str);
  348. my $status = $sftp->_set_status($code, (defined $str ? $str : ()));
  349. $sftp->_set_error($err, $errstr, $status);
  350. }
  351. else {
  352. $sftp->_conn_lost(SSH2_FX_BAD_MESSAGE,
  353. SFTP_ERR_REMOTE_BAD_MESSAGE,
  354. $errstr, "bad packet type, expected $etype packet, got $type");
  355. }
  356. return undef;
  357. }
  358. }
  359. $msg;
  360. }
  361. # reads SSH2_FXP_HANDLE packet and returns handle, or undef on failure
  362. sub _get_handle {
  363. my ($sftp, $eid, $error, $errstr) = @_;
  364. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_HANDLE, $eid,
  365. $error, $errstr)) {
  366. return $msg->get_str;
  367. }
  368. return undef;
  369. }
  370. sub _rid {
  371. my ($sftp, $rfh) = @_;
  372. my $rid = $rfh->_rid;
  373. unless (defined $rid) {
  374. $sftp->_set_error(SFTP_ERR_REMOTE_ACCESING_CLOSED_FILE,
  375. "Couldn't access a file that has been previosly closed");
  376. }
  377. $rid
  378. }
  379. sub _rfid {
  380. $_[1]->_check_is_file;
  381. &_rid;
  382. }
  383. sub _rdid {
  384. $_[1]->_check_is_dir;
  385. &_rid;
  386. }
  387. sub _queue_rid_request {
  388. my ($sftp, $code, $fh, $attrs) = @_;
  389. my $rid = $sftp->_rid($fh);
  390. return undef unless defined $rid;
  391. $sftp->_queue_new_msg($code, str => $rid,
  392. (defined $attrs ? (attr => $attrs) : ()));
  393. }
  394. sub _queue_rfid_request {
  395. $_[2]->_check_is_file;
  396. &_queue_rid_request;
  397. }
  398. sub _queue_rdid_request {
  399. $_[2]->_check_is_dir;
  400. &_queue_rid_request;
  401. }
  402. sub _queue_str_request {
  403. my($sftp, $code, $str, $attrs) = @_;
  404. $sftp->_queue_new_msg($code, str => $str,
  405. (defined $attrs ? (attr => $attrs) : ()));
  406. }
  407. sub _check_status_ok {
  408. my ($sftp, $eid, $error, $errstr) = @_;
  409. if (defined $eid) {
  410. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_STATUS, $eid,
  411. $error, $errstr)) {
  412. my $status = $sftp->_set_status($msg->get_int32, $msg->get_str);
  413. return 1 if $status == SSH2_FX_OK;
  414. $sftp->_set_error($error, $errstr, $status);
  415. }
  416. }
  417. return undef;
  418. }
  419. sub setcwd {
  420. ${^TAINT} and &_catch_tainted_args;
  421. my ($sftp, $cwd, %opts) = @_;
  422. $sftp->_clear_error_and_status;
  423. my $check = delete $opts{check};
  424. $check = 1 unless defined $check;
  425. %opts and _croak_bad_options(keys %opts);
  426. if (defined $cwd) {
  427. if ($check) {
  428. $cwd = $sftp->realpath($cwd);
  429. return undef unless defined $cwd;
  430. my $a = $sftp->stat($cwd)
  431. or return undef;
  432. unless (_is_dir($a->perm)) {
  433. $sftp->_set_error(SFTP_ERR_REMOTE_BAD_OBJECT,
  434. "Remote object '$cwd' is not a directory");
  435. return undef;
  436. }
  437. }
  438. else {
  439. $cwd = $sftp->_rel2abs($cwd);
  440. }
  441. return $sftp->{cwd} = $cwd;
  442. }
  443. else {
  444. delete $sftp->{cwd};
  445. return $sftp->cwd if defined wantarray;
  446. }
  447. }
  448. sub cwd {
  449. @_ == 1 or croak 'Usage: $sftp->cwd()';
  450. my $sftp = shift;
  451. return defined $sftp->{cwd} ? $sftp->{cwd} : $sftp->realpath('');
  452. }
  453. ## SSH2_FXP_OPEN (3)
  454. # returns handle on success, undef on failure
  455. sub open {
  456. (@_ >= 2 and @_ <= 4)
  457. or croak 'Usage: $sftp->open($path [, $flags [, $attrs]])';
  458. ${^TAINT} and &_catch_tainted_args;
  459. my ($sftp, $path, $flags, $a) = @_;
  460. $path = $sftp->_rel2abs($path);
  461. defined $flags or $flags = SSH2_FXF_READ;
  462. defined $a or $a = Net::SFTP::Foreign::Attributes->new;
  463. my $id = $sftp->_queue_new_msg(SSH2_FXP_OPEN,
  464. str => $sftp->_fs_encode($path),
  465. int32 => $flags, attr => $a);
  466. my $rid = $sftp->_get_handle($id,
  467. SFTP_ERR_REMOTE_OPEN_FAILED,
  468. "Couldn't open remote file '$path'");
  469. if ($debug and $debug & 2) {
  470. if (defined $rid) {
  471. _debug("new remote file '$path' open, rid:");
  472. _hexdump($rid);
  473. }
  474. else {
  475. _debug("open failed: $sftp->{_status}");
  476. }
  477. }
  478. defined $rid or return undef;
  479. my $fh = Net::SFTP::Foreign::FileHandle->_new_from_rid($sftp, $rid);
  480. $fh->_flag(append => 1) if ($flags & SSH2_FXF_APPEND);
  481. $fh;
  482. }
  483. sub _open_mkpath {
  484. my ($sftp, $filename, $mkpath, $flags, $attrs) = @_;
  485. $flags = ($flags || 0) | SSH2_FXF_WRITE|SSH2_FXF_CREAT;
  486. my $fh = do {
  487. local $sftp->{_autodie};
  488. $sftp->open($filename, $flags, $attrs);
  489. };
  490. unless ($fh) {
  491. if ($mkpath and $sftp->status == SSH2_FX_NO_SUCH_FILE) {
  492. my $da = $attrs->clone;
  493. $da->set_perm(($da->perm || 0) | 0700);
  494. $sftp->mkpath($filename, $da, 1) or return;
  495. $fh = $sftp->open($filename, $flags, $attrs);
  496. }
  497. else {
  498. $sftp->_ok_or_autodie;
  499. }
  500. }
  501. $fh;
  502. }
  503. ## SSH2_FXP_OPENDIR (11)
  504. sub opendir {
  505. @_ == 2 or croak 'Usage: $sftp->opendir($path)';
  506. ${^TAINT} and &_catch_tainted_args;
  507. my $sftp = shift;
  508. my $path = shift;
  509. $path = $sftp->_rel2abs($path);
  510. my $id = $sftp->_queue_str_request(SSH2_FXP_OPENDIR, $sftp->_fs_encode($path), @_);
  511. my $rid = $sftp->_get_handle($id, SFTP_ERR_REMOTE_OPENDIR_FAILED,
  512. "Couldn't open remote dir '$path'");
  513. if ($debug and $debug & 2) {
  514. _debug("new remote dir '$path' open, rid:");
  515. _hexdump($rid);
  516. }
  517. defined $rid
  518. or return undef;
  519. Net::SFTP::Foreign::DirHandle->_new_from_rid($sftp, $rid, 0)
  520. }
  521. ## SSH2_FXP_READ (4)
  522. # returns data on success undef on failure
  523. sub sftpread {
  524. (@_ >= 3 and @_ <= 4)
  525. or croak 'Usage: $sftp->sftpread($fh, $offset [, $size])';
  526. my ($sftp, $rfh, $offset, $size) = @_;
  527. unless ($size) {
  528. return '' if defined $size;
  529. $size = $sftp->{_block_size};
  530. }
  531. my $rfid = $sftp->_rfid($rfh);
  532. defined $rfid or return undef;
  533. my $id = $sftp->_queue_new_msg(SSH2_FXP_READ, str=> $rfid,
  534. int64 => $offset, int32 => $size);
  535. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_DATA, $id,
  536. SFTP_ERR_REMOTE_READ_FAILED,
  537. "Couldn't read from remote file")) {
  538. return $msg->get_str;
  539. }
  540. return undef;
  541. }
  542. ## SSH2_FXP_WRITE (6)
  543. # returns true on success, undef on failure
  544. sub sftpwrite {
  545. @_ == 4 or croak 'Usage: $sftp->sftpwrite($fh, $offset, $data)';
  546. my ($sftp, $rfh, $offset) = @_;
  547. my $rfid = $sftp->_rfid($rfh);
  548. defined $rfid or return undef;
  549. utf8::downgrade($_[3], 1) or croak "wide characters found in data";
  550. my $id = $sftp->_queue_new_msg(SSH2_FXP_WRITE, str => $rfid,
  551. int64 => $offset, str => $_[3]);
  552. if ($sftp->_check_status_ok($id,
  553. SFTP_ERR_REMOTE_WRITE_FAILED,
  554. "Couldn't write to remote file")) {
  555. return 1;
  556. }
  557. return undef;
  558. }
  559. sub seek {
  560. (@_ >= 3 and @_ <= 4)
  561. or croak 'Usage: $sftp->seek($fh, $pos [, $whence])';
  562. my ($sftp, $rfh, $pos, $whence) = @_;
  563. $sftp->flush($rfh) or return undef;
  564. if (!$whence) {
  565. $rfh->_pos($pos)
  566. }
  567. elsif ($whence == 1) {
  568. $rfh->_inc_pos($pos)
  569. }
  570. elsif ($whence == 2) {
  571. my $a = $sftp->stat($rfh) or return undef;
  572. $rfh->_pos($pos + $a->size);
  573. }
  574. else {
  575. croak "invalid value for whence argument ('$whence')";
  576. }
  577. 1;
  578. }
  579. sub tell {
  580. @_ == 2 or croak 'Usage: $sftp->tell($fh)';
  581. my ($sftp, $rfh) = @_;
  582. return $rfh->_pos + length ${$rfh->_bout};
  583. }
  584. sub eof {
  585. @_ == 2 or croak 'Usage: $sftp->eof($fh)';
  586. my ($sftp, $rfh) = @_;
  587. $sftp->_fill_read_cache($rfh, 1);
  588. return length(${$rfh->_bin}) == 0
  589. }
  590. sub _write {
  591. my ($sftp, $rfh, $off, $cb) = @_;
  592. $sftp->_clear_error_and_status;
  593. my $rfid = $sftp->_rfid($rfh);
  594. defined $rfid or return undef;
  595. my $qsize = $sftp->{_queue_size};
  596. my @msgid;
  597. my @written;
  598. my $written = 0;
  599. my $end;
  600. while (!$end or @msgid) {
  601. while (!$end and @msgid < $qsize) {
  602. my $data = $cb->();
  603. if (defined $data and length $data) {
  604. my $id = $sftp->_queue_new_msg(SSH2_FXP_WRITE, str => $rfid,
  605. int64 => $off + $written, str => $data);
  606. push @written, $written;
  607. $written += length $data;
  608. push @msgid, $id;
  609. }
  610. else {
  611. $end = 1;
  612. }
  613. }
  614. my $eid = shift @msgid;
  615. my $last = shift @written;
  616. unless ($sftp->_check_status_ok($eid,
  617. SFTP_ERR_REMOTE_WRITE_FAILED,
  618. "Couldn't write to remote file")) {
  619. # discard responses to queued requests:
  620. $sftp->_get_msg for @msgid;
  621. return $last;
  622. }
  623. }
  624. return $written;
  625. }
  626. sub write {
  627. @_ == 3 or croak 'Usage: $sftp->write($fh, $data)';
  628. my ($sftp, $rfh) = @_;
  629. $sftp->flush($rfh, 'in') or return undef;
  630. utf8::downgrade($_[2], 1) or croak "wide characters found in data";
  631. my $datalen = length $_[2];
  632. my $bout = $rfh->_bout;
  633. $$bout .= $_[2];
  634. my $len = length $$bout;
  635. $sftp->flush($rfh, 'out')
  636. if ($len >= $sftp->{_write_delay} or ($len and $sftp->{_autoflush} ));
  637. return $datalen;
  638. }
  639. sub flush {
  640. (@_ >= 2 and @_ <= 3)
  641. or croak 'Usage: $sftp->flush($fh [, $direction])';
  642. my ($sftp, $rfh, $dir) = @_;
  643. $dir ||= '';
  644. if ($dir ne 'out') { # flush in!
  645. ${$rfh->_bin} = '';
  646. }
  647. if ($dir ne 'in') { # flush out!
  648. my $bout = $rfh->_bout;
  649. my $len = length $$bout;
  650. if ($len) {
  651. my $start;
  652. my $append = $rfh->_flag('append');
  653. if ($append) {
  654. my $attr = $sftp->stat($rfh)
  655. or return undef;
  656. $start = $attr->size;
  657. }
  658. else {
  659. $start = $rfh->_pos;
  660. ${$rfh->_bin} = '';
  661. }
  662. my $off = 0;
  663. my $written = $sftp->_write($rfh, $start,
  664. sub {
  665. my $data = substr($$bout, $off, $sftp->{_block_size});
  666. $off += length $data;
  667. $data;
  668. } );
  669. $rfh->_inc_pos($written)
  670. unless $append;
  671. substr($$bout, 0, $written, '');
  672. $written == $len or return undef;
  673. }
  674. }
  675. 1;
  676. }
  677. sub _fill_read_cache {
  678. my ($sftp, $rfh, $len) = @_;
  679. $sftp->_clear_error_and_status;
  680. $sftp->flush($rfh, 'out')
  681. or return undef;
  682. my $rfid = $sftp->_rfid($rfh);
  683. defined $rfid or return undef;
  684. my $bin = $rfh->_bin;
  685. if (defined $len) {
  686. return 1 if ($len < length $$bin);
  687. my $read_ahead = $sftp->{_read_ahead};
  688. $len = length($$bin) + $read_ahead
  689. if $len - length($$bin) < $read_ahead;
  690. }
  691. my $pos = $rfh->_pos;
  692. my $qsize = $sftp->{_queue_size};
  693. my $bsize = $sftp->{_block_size};
  694. my @msgid;
  695. my $askoff = length $$bin;
  696. my $eof;
  697. while (!defined $len or length $$bin < $len) {
  698. while ((!defined $len or $askoff < $len) and @msgid < $qsize) {
  699. my $id = $sftp->_queue_new_msg(SSH2_FXP_READ, str=> $rfid,
  700. int64 => $pos + $askoff, int32 => $bsize);
  701. push @msgid, $id;
  702. $askoff += $bsize;
  703. }
  704. my $eid = shift @msgid;
  705. my $msg = $sftp->_get_msg_and_check(SSH2_FXP_DATA, $eid,
  706. SFTP_ERR_REMOTE_READ_FAILED,
  707. "Couldn't read from remote file")
  708. or last;
  709. my $data = $msg->get_str;
  710. $$bin .= $data;
  711. if (length $data < $bsize) {
  712. unless (defined $len) {
  713. $eof = $sftp->_queue_new_msg(SSH2_FXP_READ, str=> $rfid,
  714. int64 => $pos + length $$bin, int32 => 1);
  715. }
  716. last;
  717. }
  718. }
  719. $sftp->_get_msg for @msgid;
  720. if ($eof) {
  721. $sftp->_get_msg_and_check(SSH2_FXP_DATA, $eof,
  722. SFTP_ERR_REMOTE_BLOCK_TOO_SMALL,
  723. "received block was too small")
  724. }
  725. if ($sftp->{_status} == SSH2_FX_EOF and length $$bin) {
  726. $sftp->_clear_error_and_status;
  727. }
  728. return $sftp->{_error} ? undef : length $$bin;
  729. }
  730. sub read {
  731. @_ == 3 or croak 'Usage: $sftp->read($fh, $len)';
  732. my ($sftp, $rfh, $len) = @_;
  733. if ($sftp->_fill_read_cache($rfh, $len)) {
  734. my $bin = $rfh->_bin;
  735. my $data = substr($$bin, 0, $len, '');
  736. $rfh->_inc_pos(length $data);
  737. return $data;
  738. }
  739. return undef;
  740. }
  741. sub _readline {
  742. my ($sftp, $rfh, $sep) = @_;
  743. $sep = "\n" if @_ < 3;
  744. my $sl = length $sep;
  745. my $bin = $rfh->_bin;
  746. my $last = 0;
  747. while(1) {
  748. my $ix = index $$bin, $sep, $last + 1 - $sl ;
  749. if ($ix >= 0) {
  750. $ix += $sl;
  751. $rfh->_inc_pos($ix);
  752. return substr($$bin, 0, $ix, '');
  753. }
  754. $last = length $$bin;
  755. $sftp->_fill_read_cache($rfh, length($$bin) + 1);
  756. unless (length $$bin > $last) {
  757. $sftp->{_error}
  758. and return undef;
  759. my $line = $$bin;
  760. $rfh->_inc_pos(length $line);
  761. $$bin = '';
  762. return $line;
  763. }
  764. }
  765. }
  766. sub readline {
  767. (@_ >= 2 and @_ <= 3)
  768. or croak 'Usage: $sftp->readline($fh [, $sep])';
  769. my ($sftp, $rfh, $sep) = @_;
  770. $sep = "\n" if @_ < 3;
  771. if (!defined $sep or $sep eq '') {
  772. $sftp->_fill_read_cache($rfh);
  773. $sftp->{_error}
  774. and return undef;
  775. my $bin = $rfh->_bin;
  776. my $line = $$bin;
  777. $rfh->_inc_pos(length $line);
  778. $$bin = '';
  779. return $line;
  780. }
  781. if (wantarray) {
  782. my @lines;
  783. while (defined (my $line = $sftp->_readline($rfh, $sep))) {
  784. push @lines, $line;
  785. }
  786. return @lines;
  787. }
  788. return $sftp->_readline($rfh, $sep);
  789. }
  790. sub getc {
  791. @_ == 2 or croak 'Usage: $sftp->getc($fh)';
  792. my ($sftp, $rfh) = @_;
  793. $sftp->_fill_read_cache($rfh, 1);
  794. my $bin = $rfh->_bin;
  795. if (length $bin) {
  796. $rfh->_inc_pos(1);
  797. return substr $$bin, 0, 1, '';
  798. }
  799. return undef;
  800. }
  801. ## SSH2_FXP_LSTAT (7), SSH2_FXP_FSTAT (8), SSH2_FXP_STAT (17)
  802. # these all return a Net::SFTP::Foreign::Attributes object on success, undef on failure
  803. sub lstat {
  804. @_ <= 2 or croak 'Usage: $sftp->lstat($path)';
  805. ${^TAINT} and &_catch_tainted_args;
  806. my ($sftp, $path) = @_;
  807. $path = '.' unless defined $path;
  808. $path = $sftp->_rel2abs($path);
  809. my $id = $sftp->_queue_str_request(SSH2_FXP_LSTAT, $sftp->_fs_encode($path));
  810. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_ATTRS, $id,
  811. SFTP_ERR_REMOTE_LSTAT_FAILED, "Couldn't stat remote link")) {
  812. return $msg->get_attributes;
  813. }
  814. return undef;
  815. }
  816. sub stat {
  817. @_ <= 2 or croak 'Usage: $sftp->stat($path_or_fh)';
  818. ${^TAINT} and &_catch_tainted_args;
  819. my ($sftp, $pofh) = @_;
  820. $pofh = '.' unless defined $pofh;
  821. my $id = $sftp->_queue_new_msg( (ref $pofh and UNIVERSAL::isa($pofh, 'Net::SFTP::Foreign::FileHandle'))
  822. ? ( SSH2_FXP_FSTAT, str => $sftp->_rid($pofh))
  823. : ( SSH2_FXP_STAT, str => $sftp->_fs_encode($sftp->_rel2abs($pofh))) );
  824. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_ATTRS, $id,
  825. SFTP_ERR_REMOTE_STAT_FAILED, "Couldn't stat remote file")) {
  826. return $msg->get_attributes;
  827. }
  828. return undef;
  829. }
  830. sub fstat {
  831. _deprecated "fstat is deprecated and will be removed on the upcomming 2.xx series, "
  832. . "stat method accepts now both file handlers and paths";
  833. goto &stat;
  834. }
  835. ## SSH2_FXP_RMDIR (15), SSH2_FXP_REMOVE (13)
  836. # these return true on success, undef on failure
  837. sub _gen_remove_method {
  838. my($name, $code, $error, $errstr) = @_;
  839. my $sub = sub {
  840. @_ == 2 or croak "Usage: \$sftp->$name(\$path)";
  841. ${^TAINT} and &_catch_tainted_args;
  842. my ($sftp, $path) = @_;
  843. $path = $sftp->_rel2abs($path);
  844. my $id = $sftp->_queue_str_request($code, $sftp->_fs_encode($path));
  845. $sftp->_check_status_ok($id, $error, $errstr);
  846. };
  847. no strict 'refs';
  848. *$name = $sub;
  849. }
  850. _gen_remove_method(remove => SSH2_FXP_REMOVE,
  851. SFTP_ERR_REMOTE_REMOVE_FAILED, "Couldn't delete remote file");
  852. _gen_remove_method(rmdir => SSH2_FXP_RMDIR,
  853. SFTP_ERR_REMOTE_RMDIR_FAILED, "Couldn't remove remote directory");
  854. ## SSH2_FXP_MKDIR (14), SSH2_FXP_SETSTAT (9)
  855. # these return true on success, undef on failure
  856. sub mkdir {
  857. (@_ >= 2 and @_ <= 3)
  858. or croak 'Usage: $sftp->mkdir($path [, $attrs])';
  859. ${^TAINT} and &_catch_tainted_args;
  860. my ($sftp, $path, $attrs) = @_;
  861. $attrs = _empty_attributes unless defined $attrs;
  862. $path = $sftp->_rel2abs($path);
  863. my $id = $sftp->_queue_str_request(SSH2_FXP_MKDIR,
  864. $sftp->_fs_encode($path),
  865. $attrs);
  866. $sftp->_check_status_ok($id,
  867. SFTP_ERR_REMOTE_MKDIR_FAILED,
  868. "Couldn't create remote directory");
  869. }
  870. sub join {
  871. my $sftp = shift;
  872. my $a = '.';
  873. while (@_) {
  874. my $b = shift;
  875. if (defined $b) {
  876. $b =~ s|^(?:\./+)+||;
  877. if (length $b and $b ne '.') {
  878. if ($b !~ m|^/| and $a ne '.' ) {
  879. $a = ($a =~ m|/$| ? "$a$b" : "$a/$b");
  880. }
  881. else {
  882. $a = $b
  883. }
  884. $a =~ s|(?:/+\.)+/?$|/|;
  885. $a =~ s|(?<=[^/])/+$||;
  886. $a = '.' unless length $a;
  887. }
  888. }
  889. }
  890. $a;
  891. }
  892. sub _rel2abs {
  893. my ($sftp, $path) = @_;
  894. my $old = $path;
  895. my $cwd = $sftp->{cwd};
  896. $path = $sftp->join($sftp->{cwd}, $path);
  897. $debug and $debug & 4096 and _debug("'$old' --> '$path'");
  898. return $path
  899. }
  900. sub mkpath {
  901. (@_ >= 2 and @_ <= 4)
  902. or croak 'Usage: $sftp->mkpath($path [, $attrs [, $parent]])';
  903. ${^TAINT} and &_catch_tainted_args;
  904. my ($sftp, $path, $attrs, $parent) = @_;
  905. $sftp->_clear_error_and_status;
  906. my $first = !$parent; # skips file name
  907. $path =~ s{^(/*)}{};
  908. my $start = $1;
  909. $path =~ s{/+$}{};
  910. my @path;
  911. while (1) {
  912. if ($first) {
  913. $first = 0
  914. }
  915. else {
  916. $path =~ s{/*[^/]*$}{}
  917. }
  918. my $p = "$start$path";
  919. $debug and $debug & 8192 and _debug "checking $p";
  920. if ($sftp->test_d($p)) {
  921. $debug and $debug & 8192 and _debug "$p is a dir";
  922. last;
  923. }
  924. unless (length $path) {
  925. $sftp->_set_error(SFTP_ERR_REMOTE_MKDIR_FAILED,
  926. "Unable to make path, bad root");
  927. return undef;
  928. }
  929. unshift @path, $p;
  930. }
  931. for my $p (@path) {
  932. $debug and $debug & 8192 and _debug "mkdir $p";
  933. if ($p =~ m{^(?:.*/)?\.{1,2}$} or $p =~ m{/$}) {
  934. $debug and $debug & 8192 and _debug "$p is a symbolic dir, skipping";
  935. unless ($sftp->test_d($p)) {
  936. $debug and $debug & 8192 and _debug "symbolic dir $p can not be checked";
  937. $sftp->{_error} or
  938. $sftp->_set_error(SFTP_ERR_REMOTE_MKDIR_FAILED,
  939. "Unable to make path, bad name");
  940. return undef;
  941. }
  942. }
  943. else {
  944. $sftp->mkdir($p, $attrs)
  945. or return undef;
  946. }
  947. }
  948. 1;
  949. }
  950. sub _mkpath_local {
  951. my ($sftp, $path, $perm, $parent) = @_;
  952. my @parts = File::Spec->splitdir($path);
  953. my @tail;
  954. if ($debug and $debug & 32768) {
  955. my $target = File::Spec->join(@parts);
  956. _debug "_mkpath_local('$target')";
  957. }
  958. if ($parent) {
  959. pop @parts while @parts and not length $parts[-1];
  960. @parts or goto top_dir_reached;
  961. pop @parts;
  962. }
  963. while (1) {
  964. my $target = File::Spec->join(@parts);
  965. $target = '' unless defined $target;
  966. if (-e $target) {
  967. if (-d $target) {
  968. while (@tail) {
  969. $target = File::Spec->join($target, shift(@tail));
  970. $debug and $debug and 32768 and _debug "creating local directory $target";
  971. unless (CORE::mkdir $target, $perm) {
  972. unless (do { local $!; -d $target}) {
  973. $sftp->_set_error(SFTP_ERR_LOCAL_MKDIR_FAILED,
  974. "mkdir '$target' failed", $!);
  975. return;
  976. }
  977. }
  978. }
  979. return 1;
  980. }
  981. else {
  982. $sftp->_set_error(SFTP_ERR_LOCAL_BAD_OBJECT,
  983. "Local file '$target' is not a directory");
  984. return;
  985. }
  986. }
  987. @parts or last;
  988. unshift @tail, pop @parts;
  989. }
  990. top_dir_reached:
  991. $sftp->_set_error(SFTP_ERR_LOCAL_MKDIR_FAILED,
  992. "mkpath failed, top dir reached");
  993. return;
  994. }
  995. sub setstat {
  996. @_ == 3 or croak 'Usage: $sftp->setstat($path_or_fh, $attrs)';
  997. ${^TAINT} and &_catch_tainted_args;
  998. my ($sftp, $pofh, $attrs) = @_;
  999. my $id = $sftp->_queue_new_msg( ( (ref $pofh and UNIVERSAL::isa($pofh, 'Net::SFTP::Foreign::FileHandle') )
  1000. ? ( SSH2_FXP_FSETSTAT, str => $sftp->_rid($pofh) )
  1001. : ( SSH2_FXP_SETSTAT, str => $sftp->_fs_encode($sftp->_rel2abs($pofh)) ) ),
  1002. attr => $attrs );
  1003. return $sftp->_check_status_ok($id,
  1004. SFTP_ERR_REMOTE_SETSTAT_FAILED,
  1005. "Couldn't setstat remote file");
  1006. }
  1007. ## SSH2_FXP_CLOSE (4), SSH2_FXP_FSETSTAT (10)
  1008. # these return true on success, undef on failure
  1009. sub fsetstat {
  1010. _deprecated "fsetstat is deprecated and will be removed on the upcomming 2.xx series, "
  1011. . "setstat method accepts now both file handlers and paths";
  1012. goto &setstat;
  1013. }
  1014. sub _gen_setstat_shortcut {
  1015. my ($name, $rid_type, $attrs_flag, @arg_types) = @_;
  1016. my $nargs = 2 + @arg_types;
  1017. my $usage = ("\$sftp->$name("
  1018. . CORE::join(', ', '$path_or_fh', map "arg$_", 1..@arg_types)
  1019. . ')');
  1020. my $rid_method = ($rid_type eq 'file' ? '_rfid' :
  1021. $rid_type eq 'dir' ? '_rdid' :
  1022. $rid_type eq 'any' ? '_rid' :
  1023. croak "bad rid type $rid_type");
  1024. my $sub = sub {
  1025. @_ == $nargs or croak $usage;
  1026. my $sftp = shift;
  1027. my $pofh = shift;
  1028. my $id = $sftp->_queue_new_msg( ( (ref $pofh and UNIVERSAL::isa($pofh, 'Net::SFTP::Foreign::FileHandle') )
  1029. ? ( SSH2_FXP_FSETSTAT, str => $sftp->$rid_method($pofh) )
  1030. : ( SSH2_FXP_SETSTAT, str => $sftp->_fs_encode($sftp->_rel2abs($pofh)) ) ),
  1031. int32 => $attrs_flag,
  1032. map { $arg_types[$_] => $_[$_] } 0..$#arg_types );
  1033. $sftp->_check_status_ok($id,
  1034. SFTP_ERR_REMOTE_SETSTAT_FAILED,
  1035. "Couldn't setstat remote file ($name)");
  1036. };
  1037. no strict 'refs';
  1038. *$name = $sub;
  1039. }
  1040. _gen_setstat_shortcut(truncate => 'file', SSH2_FILEXFER_ATTR_SIZE, 'int64');
  1041. _gen_setstat_shortcut(chown => 'any' , SSH2_FILEXFER_ATTR_UIDGID, 'int32', 'int32');
  1042. _gen_setstat_shortcut(chmod => 'any' , SSH2_FILEXFER_ATTR_PERMISSIONS, 'int32');
  1043. _gen_setstat_shortcut(utime => 'any' , SSH2_FILEXFER_ATTR_ACMODTIME, 'int32', 'int32');
  1044. sub _close {
  1045. @_ == 2 or croak 'Usage: $sftp->close($fh, $attrs)';
  1046. my $sftp = shift;
  1047. my $id = $sftp->_queue_rid_request(SSH2_FXP_CLOSE, @_);
  1048. defined $id or return undef;
  1049. my $ok = $sftp->_check_status_ok($id,
  1050. SFTP_ERR_REMOTE_CLOSE_FAILED,
  1051. "Couldn't close remote file");
  1052. if ($debug and $debug & 2) {
  1053. _debug sprintf("closing file handle, return: %s, rid:", (defined $ok ? $ok : '-'));
  1054. _hexdump($sftp->_rid($_[0]));
  1055. }
  1056. return $ok;
  1057. }
  1058. sub close {
  1059. @_ == 2 or croak 'Usage: $sftp->close($fh)';
  1060. my ($sftp, $rfh) = @_;
  1061. $rfh->_check_is_file;
  1062. $sftp->flush($rfh)
  1063. or return undef;
  1064. if ($sftp->_close($rfh)) {
  1065. $rfh->_close;
  1066. return 1
  1067. }
  1068. undef
  1069. }
  1070. sub closedir {
  1071. @_ == 2 or croak 'Usage: $sftp->closedir($dh)';
  1072. ${^TAINT} and &_catch_tainted_args;
  1073. my ($sftp, $rdh) = @_;
  1074. $rdh->_check_is_dir;
  1075. if ($sftp->_close($rdh)) {
  1076. $rdh->_close;
  1077. return 1;
  1078. }
  1079. undef
  1080. }
  1081. sub readdir {
  1082. @_ == 2 or croak 'Usage: $sftp->readdir($dh)';
  1083. ${^TAINT} and &_catch_tainted_args;
  1084. my ($sftp, $rdh) = @_;
  1085. my $rdid = $sftp->_rdid($rdh);
  1086. defined $rdid or return undef;
  1087. my $cache = $rdh->_cache;
  1088. while (!@$cache or wantarray) {
  1089. my $id = $sftp->_queue_str_request(SSH2_FXP_READDIR, $rdid);
  1090. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_NAME, $id,
  1091. SFTP_ERR_REMOTE_READDIR_FAILED,
  1092. "Couldn't read remote directory" )) {
  1093. my $count = $msg->get_int32 or last;
  1094. for (1..$count) {
  1095. push @$cache, { filename => $sftp->_fs_decode($msg->get_str),
  1096. longname => $sftp->_fs_decode($msg->get_str),
  1097. a => $msg->get_attributes };
  1098. }
  1099. }
  1100. else {
  1101. $sftp->_set_error if $sftp->{_status} == SSH2_FX_EOF;
  1102. last;
  1103. }
  1104. }
  1105. if (wantarray) {
  1106. my $old = $cache;
  1107. $cache = [];
  1108. return @$old;
  1109. }
  1110. shift @$cache;
  1111. }
  1112. sub _readdir {
  1113. my ($sftp, $rdh);
  1114. if (wantarray) {
  1115. my $line = $sftp->readdir($rdh);
  1116. if (defined $line) {
  1117. return $line->{filename};
  1118. }
  1119. }
  1120. else {
  1121. return map { $_->{filename} } $sftp->readdir($rdh);
  1122. }
  1123. }
  1124. sub _gen_getpath_method {
  1125. my ($code, $error, $name) = @_;
  1126. return sub {
  1127. @_ == 2 or croak 'Usage: $sftp->some_method($path)';
  1128. ${^TAINT} and &_catch_tainted_args;
  1129. my ($sftp, $path) = @_;
  1130. $path = $sftp->_rel2abs($path);
  1131. my $id = $sftp->_queue_str_request($code, $sftp->_fs_encode($path));
  1132. if (my $msg = $sftp->_get_msg_and_check(SSH2_FXP_NAME, $id,
  1133. $error,
  1134. "Couldn't get $name for remote '$path'")) {
  1135. $msg->get_int32 > 0
  1136. and return $sftp->_fs_decode($msg->get_str);
  1137. $sftp->_set_error($error,
  1138. "Couldn't get $name for remote '$path', no names on reply")
  1139. }
  1140. return undef;
  1141. };
  1142. }
  1143. ## SSH2_FXP_REALPATH (16)
  1144. ## SSH2_FXP_READLINK (19)
  1145. # return path on success, undef on failure
  1146. *realpath = _gen_getpath_method(SSH2_FXP_REALPATH,
  1147. SFTP_ERR_REMOTE_REALPATH_FAILED,
  1148. "realpath");
  1149. *readlink = _gen_getpath_method(SSH2_FXP_READLINK,
  1150. SFTP_ERR_REMOTE_READLINK_FAILED,
  1151. "link target");
  1152. ## SSH2_FXP_RENAME (18)
  1153. # true on success, undef on failure
  1154. sub _rename {
  1155. my ($sftp, $old, $new) = @_;
  1156. $old = $sftp->_rel2abs($old);
  1157. $new = $sftp->_rel2abs($new);
  1158. my $id = $sftp->_queue_new_msg(SSH2_FXP_RENAME,
  1159. str => $sftp->_fs_encode($old),
  1160. str => $sftp->_fs_encode($new));
  1161. $sftp->_check_status_ok($id, SFTP_ERR_REMOTE_RENAME_FAILED,
  1162. "Couldn't rename remote file '$old' to '$new'");
  1163. }
  1164. sub rename {
  1165. (@_ & 1) or croak 'Usage: $sftp->rename($old, $new, %opts)';
  1166. ${^TAINT} and &_catch_tainted_args;
  1167. my ($sftp, $old, $new, %opts) = @_;
  1168. my $overwrite = delete $opts{overwrite};
  1169. my $numbered = delete $opts{numbered};
  1170. croak "'overwrite' and 'numbered' options can not be used together"
  1171. if ($overwrite and $numbered);
  1172. %opts and _croak_bad_options(keys %opts);
  1173. if ($overwrite) {
  1174. $sftp->atomic_rename($old, $new) and return 1;
  1175. $sftp->{_status} != SSH2_FX_OP_UNSUPPORTED and return undef;
  1176. }
  1177. for (1) {
  1178. local $sftp->{_autodie};
  1179. # we are optimistic here and try to rename it without testing
  1180. # if a file of the same name already exists first
  1181. if (!$sftp->_rename($old, $new) and
  1182. $sftp->{_status} == SSH2_FX_FAILURE) {
  1183. if ($numbered and $sftp->test_e($new)) {
  1184. _inc_numbered($new);
  1185. redo;
  1186. }
  1187. elsif ($overwrite) {
  1188. my $rp_old = $sftp->realpath($old);
  1189. my $rp_new = $sftp->realpath($new);
  1190. if (defined $rp_old and defined $rp_new and $rp_old eq $rp_new) {
  1191. $sftp->_clear_error_and_status;
  1192. }
  1193. elsif ($sftp->remove($new)) {
  1194. $overwrite = 0;
  1195. redo;
  1196. }
  1197. }
  1198. }
  1199. }
  1200. $sftp->_ok_or_autodie;
  1201. }
  1202. sub atomic_rename {
  1203. @_ == 3 or croak 'Usage: $sftp->atomic_rename($old, $new)';
  1204. ${^TAINT} and &_catch_tainted_args;
  1205. my ($sftp, $old, $new) = @_;
  1206. $sftp->_check_extension('posix-rename@openssh.com' => 1,
  1207. SFTP_ERR_REMOTE_RENAME_FAILED,
  1208. "atomic rename failed")
  1209. or return undef;
  1210. $old = $sftp->_rel2abs($old);
  1211. $new = $sftp->_rel2abs($new);
  1212. my $id = $sftp->_queue_new_msg(SSH2_FXP_EXTENDED,
  1213. str => 'posix-rename@openssh.com',
  1214. str => $sftp->_fs_encode($old),
  1215. str => $sftp->_fs_encode($new));
  1216. $sftp->_check_status_ok($id, SFTP_ERR_REMOTE_RENAME_FAILED,
  1217. "Couldn't rename remote file '$old' to '$new'");
  1218. }
  1219. ## SSH2_FXP_SYMLINK (20)
  1220. # true on success, undef on failure
  1221. sub symlink {
  1222. @_ == 3 or croak 'Usage: $sftp->symlink($sl, $target)';
  1223. ${^TAINT} and &_catch_tainted_args;
  1224. my ($sftp, $sl, $target) = @_;
  1225. $sl = $sftp->_rel2abs($sl);
  1226. my $id = $sftp->_queue_new_msg(SSH2_FXP_SYMLINK,
  1227. str => $sftp->_fs_encode($target),
  1228. str => $sftp->_fs_encode($sl));
  1229. $sftp->_check_status_ok($id, SFTP_ERR_REMOTE_SYMLINK_FAILED,
  1230. "Couldn't create symlink '$sl' pointing to '$target'");
  1231. }
  1232. sub hardlink {
  1233. @_ == 3 or croak 'Usage: $sftp->hardlink($hl, $target)';
  1234. ${^TAINT} and &_catch_tainted_args;
  1235. my ($sftp, $hl, $target) = @_;
  1236. $sftp->_check_extension('hardlink@openssh.com' => 1,
  1237. SFTP_ERR_REMOTE_HARDLINK_FAILED,
  1238. "hardlink failed")
  1239. or return undef;
  1240. $hl = $sftp->_rel2abs($hl);
  1241. $target = $sftp->_rel2abs($target);
  1242. my $id = $sftp->_queue_new_msg(SSH2_FXP_EXTENDED,
  1243. str => 'hardlink@openssh.com',
  1244. str => $sftp->_fs_encode($target),
  1245. str => $sftp->_fs_encode($hl));
  1246. $sftp->_check_status_ok($id, SFTP_ERR_REMOTE_HARDLINK_FAILED,
  1247. "Couldn't create hardlink '$hl' pointing to '$target'");
  1248. }
  1249. sub _gen_save_status_method {
  1250. my $method = shift;
  1251. sub {
  1252. my $sftp = shift;
  1253. local ($sftp->{_error}, $sftp->{_status}) if $sftp->{_error};
  1254. $sftp->$method(@_);
  1255. }
  1256. }
  1257. *_close_save_status = _gen_save_status_method('close');
  1258. *_closedir_save_status = _gen_save_status_method('closedir');
  1259. *_remove_save_status = _gen_save_status_method('remove');
  1260. sub _inc_numbered {
  1261. $_[0] =~ s{^(.*)\((\d+)\)((?:\.[^\.]*)?)$}{"$1(" . ($2+1) . ")$3"}e or
  1262. $_[0] =~ s{((?:\.[^\.]*)?)$}{(1)$1};
  1263. $debug and $debug & 128 and _debug("numbering to: $_[0]");
  1264. }
  1265. ## High-level client -> server methods.
  1266. sub abort {
  1267. my $sftp = shift;
  1268. $sftp->_set_error(SFTP_ERR_ABORTED, ($@ ? $_[0] : "Aborted"));
  1269. }
  1270. # returns true on success, undef on failure
  1271. sub get {
  1272. @_ >= 2 or croak 'Usage: $sftp->get($remote, $local, %opts)';
  1273. ${^TAINT} and &_catch_tainted_args;
  1274. my ($sftp, $remote, $local, %opts) = @_;
  1275. defined $remote or croak "remote file path is undefined";
  1276. $sftp->_clear_error_and_status;
  1277. $remote = $sftp->_rel2abs($remote);
  1278. $local = _file_part($remote) unless defined $local;
  1279. my $local_is_fh = (ref $local and $local->isa('GLOB'));
  1280. my $cb = delete $opts{callback};
  1281. my $umask = delete $opts{umask};
  1282. my $perm = delete $opts{perm};
  1283. my $copy_perm = delete $opts{exists $opts{copy_perm} ? 'copy_perm' : 'copy_perms'};
  1284. my $copy_time = delete $opts{copy_time};
  1285. my $overwrite = delete $opts{overwrite};
  1286. my $resume = delete $opts{resume};
  1287. my $append = delete $opts{append};
  1288. my $block_size = delete $opts{block_size} || $sftp->{_block_size};
  1289. my $queue_size = delete $opts{queue_size} || $sftp->{_queue_size};
  1290. my $dont_save = delete $opts{dont_save};
  1291. my $conversion = delete $opts{conversion};
  1292. my $numbered = delete $opts{numbered};
  1293. my $cleanup = delete $opts{cleanup};
  1294. my $atomic = delete $opts{atomic};
  1295. my $best_effort = delete $opts{best_effort};
  1296. my $mkpath = delete $opts{mkpath};
  1297. croak "'perm' and 'copy_perm' options can not be used simultaneously"
  1298. if (defined $perm and defined $copy_perm);
  1299. croak "'resume' and 'append' options can not be used simultaneously"
  1300. if ($resume and $append);
  1301. croak "'numbered' can not be used with 'overwrite', 'resume' or 'append'"
  1302. if ($numbered and ($overwrite or $resume or $append));
  1303. croak "'atomic' can not be used with 'resume' or 'append'"
  1304. if ($atomic and ($resume or $append));
  1305. if ($local_is_fh) {
  1306. my $append = 'option can not be used when target is a file handle';
  1307. $resume and croak "'resume' $append";
  1308. $overwrite and croak "'overwrite' $append";
  1309. $numbered and croak "'numbered' $append";
  1310. $dont_save and croak "'dont_save' $append";
  1311. $atomic and croak "'croak' $append";
  1312. }
  1313. %opts and _croak_bad_options(keys %opts);
  1314. if ($resume and $conversion) {
  1315. carp "resume option is useless when data conversion has also been requested";
  1316. undef $resume;
  1317. }
  1318. $overwrite = 1 unless (defined $overwrite or $local_is_fh or $numbered);
  1319. $copy_perm = 1 unless (defined $perm or defined $copy_perm or $local_is_fh);
  1320. $copy_time = 1 unless (defined $copy_time or $local_is_fh);
  1321. $mkpath = 1 unless defined $mkpath;
  1322. $cleanup = ($atomic || $numbered) unless defined $cleanup;
  1323. my $a = do {
  1324. local $sftp->{_autodie};
  1325. $sftp->stat($remote);
  1326. };
  1327. my ($rperm, $size, $atime, $mtime) = ($a ? ($a->perm, $a->size, $a->atime, $a->mtime) : ());
  1328. $size = -1 unless defined $size;
  1329. if ($copy_time and not defined $atime) {
  1330. if ($best_effort) {
  1331. undef $copy_time;
  1332. }
  1333. else {
  1334. $sftp->_ok_or_autodie and $sftp->_set_error(SFTP_ERR_REMOTE_STAT_FAILED,
  1335. "Not enough information on stat, amtime not included");
  1336. return undef;
  1337. }
  1338. }
  1339. $umask = (defined $perm ? 0 : umask) unless defined $umask;
  1340. if ($copy_perm) {
  1341. if (defined $rperm) {
  1342. $perm = $rperm;
  1343. }
  1344. elsif ($best_effort) {
  1345. undef $copy_perm
  1346. }
  1347. else {
  1348. $sftp->_ok_or_autodie and $sftp->_set_error(SFTP_ERR_REMOTE_STAT_FAILED,
  1349. "Not enough information on stat, mode not included");
  1350. return undef
  1351. }
  1352. }
  1353. $perm &= ~$umask if defined $perm;
  1354. $sftp->_clear_error_and_status;
  1355. if ($resume and $resume eq 'auto') {
  1356. undef $resume;
  1357. if (defined $mtime) {
  1358. if (my @lstat = CORE::stat $local) {
  1359. $resume = ($mtime <= $lstat[9]);
  1360. }
  1361. }
  1362. }
  1363. my ($atomic_numbered, $atomic_local, $atomic_cleanup);
  1364. my ($rfh, $fh);
  1365. my $askoff = 0;
  1366. my $lstart = 0;
  1367. if ($dont_save) {
  1368. $rfh = $sftp->open($remote, SSH2_FXF_READ);
  1369. defined $rfh or return undef;
  1370. }
  1371. else {
  1372. unless ($local_is_fh or $overwrite or $append or $resume or $numbered) {
  1373. if (-e $local) {
  1374. $sftp->_set_error(SFTP_ERR_LOCAL_ALREADY_EXISTS,
  1375. "local file $local already exists");
  1376. return undef
  1377. }
  1378. }
  1379. if ($atomic) {
  1380. $atomic_local = $local;
  1381. $local .= sprintf("(%d).tmp", rand(10000));
  1382. $atomic_numbered = $numbered;
  1383. $numbered = 1;
  1384. $debug and $debug & 128 and _debug("temporal local file name: $local");
  1385. }
  1386. if ($resume) {
  1387. if (CORE::open $fh, '+<', $local) {
  1388. binmode $fh;
  1389. CORE::seek($fh, 0, 2);
  1390. $askoff = CORE::tell $fh;
  1391. if ($askoff < 0) {
  1392. # something is going really wrong here, fall
  1393. # back to non-resuming mode...
  1394. $askoff = 0;
  1395. undef $fh;
  1396. }
  1397. else {
  1398. if ($size >=0 and $askoff > $size) {
  1399. $sftp->_set_error(SFTP_ERR_LOCAL_BIGGER_THAN_REMOTE,
  1400. "Couldn't resume transfer, local file is bigger than remote");
  1401. return undef;
  1402. }
  1403. $size == $askoff and return 1;
  1404. }
  1405. }
  1406. }
  1407. # we open the remote file so late in order to skip it when
  1408. # resuming an already completed transfer:
  1409. $rfh = $sftp->open($remote, SSH2_FXF_READ);
  1410. defined $rfh or return undef;
  1411. unless (defined $fh) {
  1412. if ($local_is_fh) {
  1413. $fh = $local;
  1414. local ($@, $SIG{__DIE__}, $SIG{__WARN__});
  1415. eval { $lstart = CORE::tell($fh) };
  1416. $lstart = 0 unless ($lstart and $lstart > 0);
  1417. }
  1418. else {
  1419. my $flags = Fcntl::O_CREAT|Fcntl::O_WRONLY;
  1420. $flags |= Fcntl::O_APPEND if $append;
  1421. $flags |= Fcntl::O_EXCL if ($numbered or (!$overwrite and !$append));
  1422. unlink $local if $overwrite;
  1423. my $open_perm = (defined $perm ? $perm : 0666);
  1424. my $save = _umask_save_and_set($umask);
  1425. $sftp->_mkpath_local($local, $perm|0700, 1) if $mkpath;
  1426. while (1) {
  1427. sysopen ($fh, $local, $flags, $open_perm) and last;
  1428. unless ($numbered and -e $local) {
  1429. $sftp->_set_error(SFTP_ERR_LOCAL_OPEN_FAILED,
  1430. "Can't open $local", $!);
  1431. return undef;
  1432. }
  1433. _inc_numbered($local);
  1434. }
  1435. $$numbered = $local if ref $numbered;
  1436. binmode $fh;
  1437. $lstart = sysseek($fh, 0,

Large files files are truncated, but you can click here to view the full file