1 /* Virtual File System: SFTP file system.
5 The 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"
34 /*** global variables ****************************************************************************/
36 GString
*sftpfs_filename_buffer
= NULL
;
38 /*** file scope macro definitions ****************************************************************/
40 /*** file scope type declarations ****************************************************************/
42 /*** file scope variables ************************************************************************/
44 /*** file scope functions ************************************************************************/
45 /* --------------------------------------------------------------------------------------------- */
47 /* --------------------------------------------------------------------------------------------- */
48 /*** public functions ****************************************************************************/
49 /* --------------------------------------------------------------------------------------------- */
51 * Show error message (if error have raised) and cleanup GError object.
53 * @param error pointer to object contains error message
54 * @return TRUE if error message was printed, FALSE otherwise
58 sftpfs_show_error (GError
** error
)
60 if (error
== NULL
|| *error
== NULL
)
63 vfs_print_message ("(%d) %s", (*error
)->code
, (*error
)->message
);
64 g_error_free (*error
);
69 /* --------------------------------------------------------------------------------------------- */
71 * Convert libssh error to GError object.
73 * @param super_data extra data for SFTP connection
74 * @param libssh_errno errno from libssh
75 * @param error pointer to the error object
79 sftpfs_ssherror_to_gliberror (sftpfs_super_data_t
* super_data
, int libssh_errno
, GError
** error
)
84 g_return_if_fail (error
== NULL
|| *error
== NULL
);
86 libssh2_session_last_error (super_data
->session
, &err
, &err_len
, 1);
87 g_set_error (error
, MC_ERROR
, libssh_errno
, "%s", err
);
91 /* --------------------------------------------------------------------------------------------- */
93 * Fix filename for SFTP operations: add leading slash to file name.
95 * @param file_name file name
96 * @return newly allocated string contains the file name with leading slash
100 sftpfs_fix_filename (const char *file_name
)
102 g_string_printf (sftpfs_filename_buffer
, "%c%s", PATH_SEP
, file_name
);
103 return sftpfs_filename_buffer
->str
;
106 /* --------------------------------------------------------------------------------------------- */
108 * Awaiting for any activity on socket.
110 * @param super_data extra data for SFTP connection
111 * @param error unused
112 * @return 0 if sucess, negative value otherwise
116 sftpfs_waitsocket (sftpfs_super_data_t
* super_data
, GError
** error
)
118 struct timeval timeout
= { 10, 0 };
120 fd_set
*writefd
= NULL
;
121 fd_set
*readfd
= NULL
;
127 FD_SET (super_data
->socket_handle
, &fd
);
129 /* now make sure we wait in the correct direction */
130 dir
= libssh2_session_block_directions (super_data
->session
);
132 if ((dir
& LIBSSH2_SESSION_BLOCK_INBOUND
) != 0)
135 if ((dir
& LIBSSH2_SESSION_BLOCK_OUTBOUND
) != 0)
138 return select (super_data
->socket_handle
+ 1, readfd
, writefd
, NULL
, &timeout
);
141 /* --------------------------------------------------------------------------------------------- */
143 * Getting information about a symbolic link.
145 * @param vpath path to file, directory or symbolic link
146 * @param buf buffer for store stat-info
147 * @param error pointer to error object
148 * @return 0 if sucess, negative value otherwise
152 sftpfs_lstat (const vfs_path_t
* vpath
, struct stat
*buf
, GError
** error
)
154 struct vfs_s_super
*super
;
155 sftpfs_super_data_t
*super_data
;
156 LIBSSH2_SFTP_ATTRIBUTES attrs
;
158 const vfs_path_element_t
*path_element
;
160 path_element
= vfs_path_get_by_index (vpath
, -1);
162 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
168 super_data
= (sftpfs_super_data_t
*) super
->data
;
169 if (super_data
->sftp_session
== NULL
)
174 const char *fixfname
;
176 fixfname
= sftpfs_fix_filename (path_element
->path
);
178 res
= libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
,
179 sftpfs_filename_buffer
->len
, LIBSSH2_SFTP_LSTAT
, &attrs
);
183 if (res
!= LIBSSH2_ERROR_EAGAIN
)
185 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
189 sftpfs_waitsocket (super_data
, error
);
190 if (error
!= NULL
&& *error
!= NULL
)
193 while (res
== LIBSSH2_ERROR_EAGAIN
);
195 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_UIDGID
) != 0)
197 buf
->st_uid
= attrs
.uid
;
198 buf
->st_gid
= attrs
.gid
;
201 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_ACMODTIME
) != 0)
203 buf
->st_atime
= attrs
.atime
;
204 buf
->st_mtime
= attrs
.mtime
;
205 buf
->st_ctime
= attrs
.mtime
;
208 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_SIZE
) != 0)
209 buf
->st_size
= attrs
.filesize
;
211 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_PERMISSIONS
) != 0)
212 buf
->st_mode
= attrs
.permissions
;
217 /* --------------------------------------------------------------------------------------------- */
219 * Getting information about a file or directory.
221 * @param vpath path to file or directory
222 * @param buf buffer for store stat-info
223 * @param error pointer to error object
224 * @return 0 if sucess, negative value otherwise
228 sftpfs_stat (const vfs_path_t
* vpath
, struct stat
*buf
, GError
** error
)
230 struct vfs_s_super
*super
;
231 sftpfs_super_data_t
*super_data
;
232 LIBSSH2_SFTP_ATTRIBUTES attrs
;
234 const vfs_path_element_t
*path_element
;
236 path_element
= vfs_path_get_by_index (vpath
, -1);
238 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
244 super_data
= (sftpfs_super_data_t
*) super
->data
;
245 if (super_data
->sftp_session
== NULL
)
250 const char *fixfname
;
252 fixfname
= sftpfs_fix_filename (path_element
->path
);
255 libssh2_sftp_stat_ex (super_data
->sftp_session
,
256 fixfname
, sftpfs_filename_buffer
->len
, LIBSSH2_SFTP_STAT
, &attrs
);
260 if (res
!= LIBSSH2_ERROR_EAGAIN
)
262 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
266 sftpfs_waitsocket (super_data
, error
);
267 if (error
!= NULL
&& *error
!= NULL
)
270 while (res
== LIBSSH2_ERROR_EAGAIN
);
273 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_UIDGID
) != 0)
275 buf
->st_uid
= attrs
.uid
;
276 buf
->st_gid
= attrs
.gid
;
279 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_ACMODTIME
) != 0)
281 buf
->st_atime
= attrs
.atime
;
282 buf
->st_mtime
= attrs
.mtime
;
283 buf
->st_ctime
= attrs
.mtime
;
286 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_SIZE
) != 0)
287 buf
->st_size
= attrs
.filesize
;
289 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_PERMISSIONS
) != 0)
290 buf
->st_mode
= attrs
.permissions
;
295 /* --------------------------------------------------------------------------------------------- */
297 * Read value of a symbolic link.
299 * @param vpath path to file or directory
300 * @param buf buffer for store stat-info
301 * @param size buffer size
302 * @param error pointer to error object
303 * @return 0 if sucess, negative value otherwise
307 sftpfs_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
, GError
** error
)
309 struct vfs_s_super
*super
;
310 sftpfs_super_data_t
*super_data
;
312 const vfs_path_element_t
*path_element
;
314 path_element
= vfs_path_get_by_index (vpath
, -1);
316 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
322 super_data
= (sftpfs_super_data_t
*) super
->data
;
323 if (super_data
->sftp_session
== NULL
)
328 const char *fixfname
;
330 fixfname
= sftpfs_fix_filename (path_element
->path
);
332 res
= libssh2_sftp_readlink (super_data
->sftp_session
, fixfname
, buf
, size
);
336 if (res
!= LIBSSH2_ERROR_EAGAIN
)
338 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
342 sftpfs_waitsocket (super_data
, error
);
343 if (error
!= NULL
&& *error
!= NULL
)
346 while (res
== LIBSSH2_ERROR_EAGAIN
);
351 /* --------------------------------------------------------------------------------------------- */
353 * Create symlink to file or directory
355 * @param vpath1 path to file or directory
356 * @param vpath2 path to symlink
357 * @param error pointer to error object
358 * @return 0 if sucess, negative value otherwise
362 sftpfs_symlink (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
, GError
** error
)
364 struct vfs_s_super
*super
;
365 sftpfs_super_data_t
*super_data
;
366 const vfs_path_element_t
*path_element1
;
367 const vfs_path_element_t
*path_element2
;
371 path_element2
= vfs_path_get_by_index (vpath2
, -1);
373 if (vfs_s_get_path (vpath2
, &super
, 0) == NULL
)
379 super_data
= (sftpfs_super_data_t
*) super
->data
;
380 if (super_data
->sftp_session
== NULL
)
383 tmp_path
= g_strdup_printf ("%c%s", PATH_SEP
, path_element2
->path
);
384 path_element1
= vfs_path_get_by_index (vpath1
, -1);
388 const char *fixfname
;
390 fixfname
= sftpfs_fix_filename (path_element1
->path
);
393 libssh2_sftp_symlink_ex (super_data
->sftp_session
,
395 sftpfs_filename_buffer
->len
, tmp_path
, strlen (tmp_path
),
396 LIBSSH2_SFTP_SYMLINK
);
400 if (res
!= LIBSSH2_ERROR_EAGAIN
)
402 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
407 sftpfs_waitsocket (super_data
, error
);
408 if (error
!= NULL
&& *error
!= NULL
)
414 while (res
== LIBSSH2_ERROR_EAGAIN
);
420 /* --------------------------------------------------------------------------------------------- */
422 * Changes the permissions of the file.
424 * @param vpath path to file or directory
425 * @param mode mode (see man 2 open)
426 * @param error pointer to error object
427 * @return 0 if sucess, negative value otherwise
431 sftpfs_chmod (const vfs_path_t
* vpath
, mode_t mode
, GError
** error
)
433 struct vfs_s_super
*super
;
434 sftpfs_super_data_t
*super_data
;
435 LIBSSH2_SFTP_ATTRIBUTES attrs
;
437 const vfs_path_element_t
*path_element
;
439 path_element
= vfs_path_get_by_index (vpath
, -1);
441 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
447 super_data
= (sftpfs_super_data_t
*) super
->data
;
448 if (super_data
->sftp_session
== NULL
)
453 const char *fixfname
;
455 fixfname
= sftpfs_fix_filename (path_element
->path
);
457 res
= libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
,
458 sftpfs_filename_buffer
->len
, LIBSSH2_SFTP_LSTAT
, &attrs
);
462 if (res
!= LIBSSH2_ERROR_EAGAIN
)
464 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
468 sftpfs_waitsocket (super_data
, error
);
469 if (error
!= NULL
&& *error
!= NULL
)
472 while (res
== LIBSSH2_ERROR_EAGAIN
);
474 attrs
.permissions
= mode
;
478 const char *fixfname
;
480 fixfname
= sftpfs_fix_filename (path_element
->path
);
482 res
= libssh2_sftp_stat_ex (super_data
->sftp_session
, fixfname
,
483 sftpfs_filename_buffer
->len
, LIBSSH2_SFTP_SETSTAT
, &attrs
);
486 else if (res
!= LIBSSH2_ERROR_EAGAIN
)
488 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
492 sftpfs_waitsocket (super_data
, error
);
493 if (error
!= NULL
&& *error
!= NULL
)
496 while (res
== LIBSSH2_ERROR_EAGAIN
);
500 /* --------------------------------------------------------------------------------------------- */
502 * Delete a name from the file system.
504 * @param vpath path to file or directory
505 * @param error pointer to error object
506 * @return 0 if sucess, negative value otherwise
510 sftpfs_unlink (const vfs_path_t
* vpath
, GError
** error
)
512 struct vfs_s_super
*super
;
513 sftpfs_super_data_t
*super_data
;
515 const vfs_path_element_t
*path_element
;
517 path_element
= vfs_path_get_by_index (vpath
, -1);
519 if (vfs_s_get_path (vpath
, &super
, 0) == NULL
)
525 super_data
= (sftpfs_super_data_t
*) super
->data
;
526 if (super_data
->sftp_session
== NULL
)
531 const char *fixfname
;
533 fixfname
= sftpfs_fix_filename (path_element
->path
);
536 libssh2_sftp_unlink_ex (super_data
->sftp_session
, fixfname
,
537 sftpfs_filename_buffer
->len
);
541 if (res
!= LIBSSH2_ERROR_EAGAIN
)
543 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
547 sftpfs_waitsocket (super_data
, error
);
548 if (error
!= NULL
&& *error
!= NULL
)
551 while (res
== LIBSSH2_ERROR_EAGAIN
);
556 /* --------------------------------------------------------------------------------------------- */
558 * Rename a file, moving it between directories if required.
560 * @param vpath1 path to source file or directory
561 * @param vpath2 path to destination file or directory
562 * @param error pointer to error object
563 * @return 0 if sucess, negative value otherwise
567 sftpfs_rename (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
, GError
** error
)
569 struct vfs_s_super
*super
;
570 sftpfs_super_data_t
*super_data
;
571 const vfs_path_element_t
*path_element1
;
572 const vfs_path_element_t
*path_element2
;
576 path_element2
= vfs_path_get_by_index (vpath2
, -1);
578 if (vfs_s_get_path (vpath2
, &super
, 0) == NULL
)
584 super_data
= (sftpfs_super_data_t
*) super
->data
;
585 if (super_data
->sftp_session
== NULL
)
588 tmp_path
= g_strdup_printf ("%c%s", PATH_SEP
, path_element2
->path
);
589 path_element1
= vfs_path_get_by_index (vpath1
, -1);
593 const char *fixfname
;
595 fixfname
= sftpfs_fix_filename (path_element1
->path
);
597 res
= libssh2_sftp_rename_ex
598 (super_data
->sftp_session
,
600 sftpfs_filename_buffer
->len
, tmp_path
, strlen (tmp_path
), LIBSSH2_SFTP_SYMLINK
);
604 if (res
!= LIBSSH2_ERROR_EAGAIN
)
606 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
611 sftpfs_waitsocket (super_data
, error
);
612 if (error
!= NULL
&& *error
!= NULL
)
618 while (res
== LIBSSH2_ERROR_EAGAIN
);
624 /* --------------------------------------------------------------------------------------------- */