1 /* Virtual File System: SFTP file system.
4 Copyright (C) 2011-2017
5 Free Software Foundation, Inc.
8 Ilia Maslakov <il.smind@gmail.com>, 2011
9 Slava Zanko <slavazanko@gmail.com>, 2011, 2012
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "lib/global.h"
35 /*** global variables ****************************************************************************/
37 GString
*sftpfs_filename_buffer
= NULL
;
39 /*** file scope macro definitions ****************************************************************/
41 /*** file scope type declarations ****************************************************************/
43 /*** file scope variables ************************************************************************/
45 /* --------------------------------------------------------------------------------------------- */
46 /*** file scope functions ************************************************************************/
47 /* --------------------------------------------------------------------------------------------- */
50 sftpfs_is_sftp_error (LIBSSH2_SFTP
* sftp_session
, int sftp_res
, int sftp_error
)
52 return (sftp_res
== LIBSSH2_ERROR_SFTP_PROTOCOL
&&
53 libssh2_sftp_last_error (sftp_session
) == (unsigned long) sftp_error
);
56 /* --------------------------------------------------------------------------------------------- */
58 /* Adjust block size and number of blocks */
61 sftpfs_blksize (struct stat
*s
)
63 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
64 s
->st_blksize
= LIBSSH2_CHANNEL_WINDOW_DEFAULT
; /* FIXME */
65 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
69 /* --------------------------------------------------------------------------------------------- */
72 sftpfs_waitsocket_or_error (sftpfs_super_data_t
* super_data
, int res
, GError
** mcerror
,
75 if (res
!= LIBSSH2_ERROR_EAGAIN
)
77 sftpfs_ssherror_to_gliberror (super_data
, res
, mcerror
);
82 sftpfs_waitsocket (super_data
, mcerror
);
84 if (mcerror
!= NULL
&& *mcerror
!= NULL
)
93 /* --------------------------------------------------------------------------------------------- */
94 /*** public functions ****************************************************************************/
95 /* --------------------------------------------------------------------------------------------- */
97 * Convert libssh error to GError object.
99 * @param super_data extra data for SFTP connection
100 * @param libssh_errno errno from libssh
101 * @param mcerror pointer to the error object
105 sftpfs_ssherror_to_gliberror (sftpfs_super_data_t
* super_data
, int libssh_errno
, GError
** mcerror
)
110 mc_return_if_error (mcerror
);
112 libssh2_session_last_error (super_data
->session
, &err
, &err_len
, 1);
113 if (libssh_errno
== LIBSSH2_ERROR_SFTP_PROTOCOL
&& super_data
->sftp_session
!= NULL
)
114 mc_propagate_error (mcerror
, libssh_errno
, "%s %lu", err
,
115 libssh2_sftp_last_error (super_data
->sftp_session
));
117 mc_propagate_error (mcerror
, libssh_errno
, "%s", err
);
121 /* --------------------------------------------------------------------------------------------- */
123 * Fix filename for SFTP operations: add leading slash to file name.
125 * @param file_name file name
126 * @param length length of returned string
128 * @return pointer to string that contains the file name with leading slash
132 sftpfs_fix_filename (const char *file_name
, unsigned int *length
)
134 g_string_printf (sftpfs_filename_buffer
, "%c%s", PATH_SEP
, file_name
);
135 *length
= sftpfs_filename_buffer
->len
;
136 return sftpfs_filename_buffer
->str
;
139 /* --------------------------------------------------------------------------------------------- */
141 * Awaiting for any activity on socket.
143 * @param super_data extra data for SFTP connection
144 * @param mcerror pointer to the error object
145 * @return 0 if success, negative value otherwise
149 sftpfs_waitsocket (sftpfs_super_data_t
* super_data
, GError
** mcerror
)
151 struct timeval timeout
= { 10, 0 };
153 fd_set
*writefd
= NULL
;
154 fd_set
*readfd
= NULL
;
157 mc_return_val_if_error (mcerror
, -1);
160 FD_SET (super_data
->socket_handle
, &fd
);
162 /* now make sure we wait in the correct direction */
163 dir
= libssh2_session_block_directions (super_data
->session
);
165 if ((dir
& LIBSSH2_SESSION_BLOCK_INBOUND
) != 0)
168 if ((dir
& LIBSSH2_SESSION_BLOCK_OUTBOUND
) != 0)
171 return select (super_data
->socket_handle
+ 1, readfd
, writefd
, NULL
, &timeout
);
174 /* --------------------------------------------------------------------------------------------- */
177 sftpfs_attr_to_stat (const LIBSSH2_SFTP_ATTRIBUTES
* attrs
, struct stat
*s
)
179 if ((attrs
->flags
& LIBSSH2_SFTP_ATTR_UIDGID
) != 0)
181 s
->st_uid
= attrs
->uid
;
182 s
->st_gid
= attrs
->gid
;
185 if ((attrs
->flags
& LIBSSH2_SFTP_ATTR_ACMODTIME
) != 0)
187 s
->st_atime
= attrs
->atime
;
188 s
->st_mtime
= attrs
->mtime
;
189 s
->st_ctime
= attrs
->mtime
;
190 #ifdef HAVE_STRUCT_STAT_ST_MTIM
191 s
->st_atim
.tv_nsec
= s
->st_mtim
.tv_nsec
= s
->st_ctim
.tv_nsec
= 0;
195 if ((attrs
->flags
& LIBSSH2_SFTP_ATTR_SIZE
) != 0)
197 s
->st_size
= attrs
->filesize
;
201 if ((attrs
->flags
& LIBSSH2_SFTP_ATTR_PERMISSIONS
) != 0)
202 s
->st_mode
= attrs
->permissions
;
205 /* --------------------------------------------------------------------------------------------- */
207 * Getting information about a symbolic link.
209 * @param vpath path to file, directory or symbolic link
210 * @param buf buffer for store stat-info
211 * @param mcerror pointer to error object
212 * @return 0 if success, negative value otherwise
216 sftpfs_lstat (const vfs_path_t
* vpath
, struct stat
*buf
, GError
** mcerror
)
218 struct vfs_s_super
*super
;
219 sftpfs_super_data_t
*super_data
;
220 LIBSSH2_SFTP_ATTRIBUTES attrs
;
222 const vfs_path_element_t
*path_element
;
224 mc_return_val_if_error (mcerror
, -1);
226 path_element
= vfs_path_get_by_index (vpath
, -1);
228 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
234 super_data
= (sftpfs_super_data_t
*) super
->data
;
235 if (super_data
->sftp_session
== NULL
)
240 const char *fixfname
;
241 unsigned int fixfname_len
= 0;
243 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
246 libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
, fixfname_len
,
247 LIBSSH2_SFTP_LSTAT
, &attrs
);
251 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_PERMISSION_DENIED
))
254 /* perhaps the copy function tries to stat destination file
255 to make sure it's not overwriting anything */
256 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_NO_SUCH_FILE
))
259 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
262 while (res
== LIBSSH2_ERROR_EAGAIN
);
264 sftpfs_attr_to_stat (&attrs
, buf
);
269 /* --------------------------------------------------------------------------------------------- */
271 * Getting information about a file or directory.
273 * @param vpath path to file or directory
274 * @param buf buffer for store stat-info
275 * @param mcerror pointer to error object
276 * @return 0 if success, negative value otherwise
280 sftpfs_stat (const vfs_path_t
* vpath
, struct stat
*buf
, GError
** mcerror
)
282 struct vfs_s_super
*super
;
283 sftpfs_super_data_t
*super_data
;
284 LIBSSH2_SFTP_ATTRIBUTES attrs
;
286 const vfs_path_element_t
*path_element
;
288 mc_return_val_if_error (mcerror
, -1);
290 path_element
= vfs_path_get_by_index (vpath
, -1);
292 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
298 super_data
= (sftpfs_super_data_t
*) super
->data
;
299 if (super_data
->sftp_session
== NULL
)
304 const char *fixfname
;
305 unsigned int fixfname_len
= 0;
307 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
310 libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
, fixfname_len
,
311 LIBSSH2_SFTP_STAT
, &attrs
);
315 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_PERMISSION_DENIED
))
318 /* perhaps the copy function tries to stat destination file
319 to make sure it's not overwriting anything */
320 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_NO_SUCH_FILE
))
323 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
326 while (res
== LIBSSH2_ERROR_EAGAIN
);
330 sftpfs_attr_to_stat (&attrs
, buf
);
335 /* --------------------------------------------------------------------------------------------- */
337 * Read value of a symbolic link.
339 * @param vpath path to file or directory
340 * @param buf buffer for store stat-info
341 * @param size buffer size
342 * @param mcerror pointer to error object
343 * @return 0 if success, negative value otherwise
347 sftpfs_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
, GError
** mcerror
)
349 struct vfs_s_super
*super
;
350 sftpfs_super_data_t
*super_data
;
352 const vfs_path_element_t
*path_element
;
354 mc_return_val_if_error (mcerror
, -1);
356 path_element
= vfs_path_get_by_index (vpath
, -1);
358 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
364 super_data
= (sftpfs_super_data_t
*) super
->data
;
365 if (super_data
->sftp_session
== NULL
)
370 const char *fixfname
;
371 unsigned int fixfname_len
= 0;
373 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
376 libssh2_sftp_symlink_ex (super_data
->sftp_session
, fixfname
, fixfname_len
, buf
, size
,
377 LIBSSH2_SFTP_READLINK
);
381 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
384 while (res
== LIBSSH2_ERROR_EAGAIN
);
389 /* --------------------------------------------------------------------------------------------- */
391 * Create symlink to file or directory
393 * @param vpath1 path to file or directory
394 * @param vpath2 path to symlink
395 * @param mcerror pointer to error object
396 * @return 0 if success, negative value otherwise
400 sftpfs_symlink (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
, GError
** mcerror
)
402 struct vfs_s_super
*super
;
403 sftpfs_super_data_t
*super_data
;
404 const vfs_path_element_t
*path_element1
;
405 const vfs_path_element_t
*path_element2
;
407 unsigned int tmp_path_len
;
410 mc_return_val_if_error (mcerror
, -1);
412 path_element2
= vfs_path_get_by_index (vpath2
, -1);
414 if (vfs_s_get_path (vpath2
, &super
, 0) == NULL
)
420 super_data
= (sftpfs_super_data_t
*) super
->data
;
421 if (super_data
->sftp_session
== NULL
)
424 tmp_path
= (char *) sftpfs_fix_filename (path_element2
->path
, &tmp_path_len
);
425 tmp_path
= g_strndup (tmp_path
, tmp_path_len
);
427 path_element1
= vfs_path_get_by_index (vpath1
, -1);
431 const char *fixfname
;
432 unsigned int fixfname_len
= 0;
434 fixfname
= sftpfs_fix_filename (path_element1
->path
, &fixfname_len
);
437 libssh2_sftp_symlink_ex (super_data
->sftp_session
, fixfname
, fixfname_len
, tmp_path
,
438 tmp_path_len
, LIBSSH2_SFTP_SYMLINK
);
442 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, tmp_path
))
445 while (res
== LIBSSH2_ERROR_EAGAIN
);
451 /* --------------------------------------------------------------------------------------------- */
453 * Changes the permissions of the file.
455 * @param vpath path to file or directory
456 * @param mode mode (see man 2 open)
457 * @param mcerror pointer to error object
458 * @return 0 if success, negative value otherwise
462 sftpfs_chmod (const vfs_path_t
* vpath
, mode_t mode
, GError
** mcerror
)
464 struct vfs_s_super
*super
;
465 sftpfs_super_data_t
*super_data
;
466 LIBSSH2_SFTP_ATTRIBUTES attrs
;
468 const vfs_path_element_t
*path_element
;
470 mc_return_val_if_error (mcerror
, -1);
472 path_element
= vfs_path_get_by_index (vpath
, -1);
474 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
480 super_data
= (sftpfs_super_data_t
*) super
->data
;
481 if (super_data
->sftp_session
== NULL
)
486 const char *fixfname
;
487 unsigned int fixfname_len
= 0;
489 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
492 libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
, fixfname_len
,
493 LIBSSH2_SFTP_LSTAT
, &attrs
);
497 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_PERMISSION_DENIED
))
500 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_FAILURE
))
502 res
= 0; /* need something like ftpfs_ignore_chattr_errors */
506 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
509 while (res
== LIBSSH2_ERROR_EAGAIN
);
511 attrs
.permissions
= mode
;
515 const char *fixfname
;
516 unsigned int fixfname_len
= 0;
518 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
521 libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
, fixfname_len
,
522 LIBSSH2_SFTP_SETSTAT
, &attrs
);
526 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_NO_SUCH_FILE
))
529 if (sftpfs_is_sftp_error (super_data
->sftp_session
, res
, LIBSSH2_FX_FAILURE
))
531 res
= 0; /* need something like ftpfs_ignore_chattr_errors */
535 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
538 while (res
== LIBSSH2_ERROR_EAGAIN
);
543 /* --------------------------------------------------------------------------------------------- */
545 * Delete a name from the file system.
547 * @param vpath path to file or directory
548 * @param mcerror pointer to error object
549 * @return 0 if success, negative value otherwise
553 sftpfs_unlink (const vfs_path_t
* vpath
, GError
** mcerror
)
555 struct vfs_s_super
*super
;
556 sftpfs_super_data_t
*super_data
;
558 const vfs_path_element_t
*path_element
;
560 mc_return_val_if_error (mcerror
, -1);
562 path_element
= vfs_path_get_by_index (vpath
, -1);
564 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
570 super_data
= (sftpfs_super_data_t
*) super
->data
;
571 if (super_data
->sftp_session
== NULL
)
576 const char *fixfname
;
577 unsigned int fixfname_len
= 0;
579 fixfname
= sftpfs_fix_filename (path_element
->path
, &fixfname_len
);
581 res
= libssh2_sftp_unlink_ex (super_data
->sftp_session
, fixfname
, fixfname_len
);
585 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, NULL
))
588 while (res
== LIBSSH2_ERROR_EAGAIN
);
593 /* --------------------------------------------------------------------------------------------- */
595 * Rename a file, moving it between directories if required.
597 * @param vpath1 path to source file or directory
598 * @param vpath2 path to destination file or directory
599 * @param mcerror pointer to error object
600 * @return 0 if success, negative value otherwise
604 sftpfs_rename (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
, GError
** mcerror
)
606 struct vfs_s_super
*super
;
607 sftpfs_super_data_t
*super_data
;
608 const vfs_path_element_t
*path_element1
;
609 const vfs_path_element_t
*path_element2
;
611 unsigned int tmp_path_len
;
614 mc_return_val_if_error (mcerror
, -1);
615 path_element2
= vfs_path_get_by_index (vpath2
, -1);
617 if (vfs_s_get_path (vpath2
, &super
, 0) == NULL
)
623 super_data
= (sftpfs_super_data_t
*) super
->data
;
624 if (super_data
->sftp_session
== NULL
)
627 tmp_path
= (char *) sftpfs_fix_filename (path_element2
->path
, &tmp_path_len
);
628 tmp_path
= g_strndup (tmp_path
, tmp_path_len
);
630 path_element1
= vfs_path_get_by_index (vpath1
, -1);
634 const char *fixfname
;
635 unsigned int fixfname_len
= 0;
637 fixfname
= sftpfs_fix_filename (path_element1
->path
, &fixfname_len
);
640 libssh2_sftp_rename_ex (super_data
->sftp_session
, fixfname
, fixfname_len
, tmp_path
,
641 tmp_path_len
, LIBSSH2_SFTP_SYMLINK
);
645 if (!sftpfs_waitsocket_or_error (super_data
, res
, mcerror
, tmp_path
))
648 while (res
== LIBSSH2_ERROR_EAGAIN
);
654 /* --------------------------------------------------------------------------------------------- */