1 /* Virtual File System: SFTP file system.
2 The internal functions: files
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 <libssh2_sftp.h>
32 #include "lib/global.h"
36 /*** global variables ****************************************************************************/
38 /*** file scope macro definitions ****************************************************************/
40 /*** file scope type declarations ****************************************************************/
44 LIBSSH2_SFTP_HANDLE
*handle
;
47 } sftpfs_file_handler_data_t
;
49 /*** file scope variables ************************************************************************/
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
54 * Reopen file by file handle.
56 * @param file_handler the file handler data
57 * @param error pointer to the error handler
60 sftpfs_reopen (vfs_file_handler_t
* file_handler
, GError
** error
)
62 sftpfs_file_handler_data_t
*file_handler_data
;
64 file_handler_data
= (sftpfs_file_handler_data_t
*) file_handler
->data
;
66 sftpfs_close_file (file_handler
, error
);
67 if (error
== NULL
|| *error
== NULL
)
68 sftpfs_open_file (file_handler
, file_handler_data
->flags
, file_handler_data
->mode
, error
);
71 /* --------------------------------------------------------------------------------------------- */
72 /*** public functions ****************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
77 * @param file_handler the file handler data
78 * @param flags flags (see man 2 open)
79 * @param mode mode (see man 2 open)
80 * @param error pointer to the error handler
81 * @return TRUE if connection was created successfully, FALSE otherwise
85 sftpfs_open_file (vfs_file_handler_t
* file_handler
, int flags
, mode_t mode
, GError
** error
)
87 unsigned long sftp_open_flags
= 0;
88 int sftp_open_mode
= 0;
89 gboolean do_append
= FALSE
;
90 sftpfs_file_handler_data_t
*file_handler_data
;
91 sftpfs_super_data_t
*super_data
;
96 name
= vfs_s_fullpath (&sftpfs_class
, file_handler
->ino
);
100 super_data
= (sftpfs_super_data_t
*) file_handler
->ino
->super
->data
;
101 file_handler_data
= g_new0 (sftpfs_file_handler_data_t
, 1);
103 if ((flags
& O_CREAT
) != 0 || (flags
& O_WRONLY
) != 0)
105 sftp_open_flags
= (flags
& O_WRONLY
) != 0 ? LIBSSH2_FXF_WRITE
: 0;
106 sftp_open_flags
|= (flags
& O_CREAT
) != 0 ? LIBSSH2_FXF_CREAT
: 0;
107 if ((flags
& O_APPEND
) != 0)
109 sftp_open_flags
|= LIBSSH2_FXF_APPEND
;
112 sftp_open_flags
|= (flags
& O_TRUNC
) != 0 ? LIBSSH2_FXF_TRUNC
: 0;
114 sftp_open_mode
= LIBSSH2_SFTP_S_IRUSR
|
115 LIBSSH2_SFTP_S_IWUSR
| LIBSSH2_SFTP_S_IRGRP
| LIBSSH2_SFTP_S_IROTH
;
118 sftp_open_flags
= LIBSSH2_FXF_READ
;
124 file_handler_data
->handle
=
125 libssh2_sftp_open (super_data
->sftp_session
, sftpfs_fix_filename (name
),
126 sftp_open_flags
, sftp_open_mode
);
128 if (file_handler_data
->handle
!= NULL
)
131 libssh_errno
= libssh2_session_last_errno (super_data
->session
);
132 if (libssh_errno
!= LIBSSH2_ERROR_EAGAIN
)
134 sftpfs_ssherror_to_gliberror (super_data
, libssh_errno
, error
);
142 file_handler_data
->flags
= flags
;
143 file_handler_data
->mode
= mode
;
144 file_handler
->data
= file_handler_data
;
148 struct stat file_info
;
150 if (sftpfs_fstat (file_handler
, &file_info
, error
) == 0)
151 libssh2_sftp_seek64 (file_handler_data
->handle
, file_info
.st_size
);
156 /* --------------------------------------------------------------------------------------------- */
158 * Stats the file specified by the file descriptor.
160 * @param data file data handler
161 * @param buf buffer for store stat-info
162 * @param error pointer to the error handler
163 * @return 0 if sucess, negative value otherwise
167 sftpfs_fstat (void *data
, struct stat
*buf
, GError
** error
)
170 LIBSSH2_SFTP_ATTRIBUTES attrs
;
171 vfs_file_handler_t
*fh
= (vfs_file_handler_t
*) data
;
172 sftpfs_file_handler_data_t
*sftpfs_fh
= fh
->data
;
173 struct vfs_s_super
*super
= fh
->ino
->super
;
174 sftpfs_super_data_t
*super_data
= (sftpfs_super_data_t
*) super
->data
;
176 if (sftpfs_fh
->handle
== NULL
)
181 res
= libssh2_sftp_fstat_ex (sftpfs_fh
->handle
, &attrs
, 0);
185 if (res
!= LIBSSH2_ERROR_EAGAIN
)
187 sftpfs_ssherror_to_gliberror (super_data
, res
, error
);
191 sftpfs_waitsocket (super_data
, error
);
192 if (error
!= NULL
&& *error
!= NULL
)
195 while (res
== LIBSSH2_ERROR_EAGAIN
);
197 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_UIDGID
) != 0)
199 buf
->st_uid
= attrs
.uid
;
200 buf
->st_gid
= attrs
.gid
;
203 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_ACMODTIME
) != 0)
205 buf
->st_atime
= attrs
.atime
;
206 buf
->st_mtime
= attrs
.mtime
;
207 buf
->st_ctime
= attrs
.mtime
;
210 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_SIZE
) != 0)
211 buf
->st_size
= attrs
.filesize
;
213 if ((attrs
.flags
& LIBSSH2_SFTP_ATTR_PERMISSIONS
) != 0)
214 buf
->st_mode
= attrs
.permissions
;
219 /* --------------------------------------------------------------------------------------------- */
221 * Read up to 'count' bytes from the file descriptor 'file_handler' to the buffer starting at 'buffer'.
223 * @param file_handler file data handler
224 * @param buffer buffer for data
225 * @param count data size
226 * @param error pointer to the error handler
228 * @returns 0 on sucess, negative value otherwise
232 sftpfs_read_file (vfs_file_handler_t
* file_handler
, char *buffer
, size_t count
, GError
** error
)
235 sftpfs_file_handler_data_t
*file_handler_data
;
236 sftpfs_super_data_t
*super_data
;
238 if (file_handler
== NULL
|| file_handler
->data
== NULL
)
240 g_set_error (error
, MC_ERROR
, -1, _("sftp: No file handler data present for reading file"));
244 file_handler_data
= file_handler
->data
;
245 super_data
= (sftpfs_super_data_t
*) file_handler
->ino
->super
->data
;
249 rc
= libssh2_sftp_read (file_handler_data
->handle
, buffer
, count
);
253 if (rc
!= LIBSSH2_ERROR_EAGAIN
)
255 sftpfs_ssherror_to_gliberror (super_data
, rc
, error
);
259 sftpfs_waitsocket (super_data
, error
);
260 if (error
!= NULL
&& *error
!= NULL
)
263 while (rc
== LIBSSH2_ERROR_EAGAIN
);
265 file_handler
->pos
= (off_t
) libssh2_sftp_tell64 (file_handler_data
->handle
);
270 /* --------------------------------------------------------------------------------------------- */
273 * Write up to 'count' bytes from the buffer starting at 'buffer' to the descriptor 'file_handler'.
275 * @param file_handler file data handler
276 * @param buffer buffer for data
277 * @param count data size
278 * @param error pointer to the error handler
280 * @returns 0 on sucess, negative value otherwise
284 sftpfs_write_file (vfs_file_handler_t
* file_handler
, const char *buffer
, size_t count
,
288 sftpfs_file_handler_data_t
*file_handler_data
;
289 sftpfs_super_data_t
*super_data
;
291 file_handler_data
= (sftpfs_file_handler_data_t
*) file_handler
->data
;
292 super_data
= (sftpfs_super_data_t
*) file_handler
->ino
->super
->data
;
294 file_handler
->pos
= (off_t
) libssh2_sftp_tell64 (file_handler_data
->handle
);
298 rc
= libssh2_sftp_write (file_handler_data
->handle
, buffer
, count
);
302 if (rc
!= LIBSSH2_ERROR_EAGAIN
)
304 sftpfs_ssherror_to_gliberror (super_data
, rc
, error
);
308 sftpfs_waitsocket (super_data
, error
);
309 if (error
!= NULL
&& *error
!= NULL
)
312 while (rc
== LIBSSH2_ERROR_EAGAIN
);
317 /* --------------------------------------------------------------------------------------------- */
320 * Close a file descriptor.
322 * @param file_handler file data handler
323 * @param error pointer to the error handler
325 * @returns 0 on sucess, negative value otherwise
329 sftpfs_close_file (vfs_file_handler_t
* file_handler
, GError
** error
)
331 sftpfs_file_handler_data_t
*file_handler_data
;
335 file_handler_data
= (sftpfs_file_handler_data_t
*) file_handler
->data
;
336 if (file_handler_data
== NULL
)
339 libssh2_sftp_close (file_handler_data
->handle
);
341 g_free (file_handler_data
);
345 /* --------------------------------------------------------------------------------------------- */
348 * Reposition the offset of the open file associated with the file descriptor.
350 * @param file_handler file data handler
351 * @param offset file offset
352 * @param whence method of seek (at begin, at current, at end)
353 * @param error pointer to the error handler
355 * @returns 0 on sucess, negative value otherwise
359 sftpfs_lseek (vfs_file_handler_t
* file_handler
, off_t offset
, int whence
, GError
** error
)
361 sftpfs_file_handler_data_t
*file_handler_data
;
363 file_handler_data
= (sftpfs_file_handler_data_t
*) file_handler
->data
;
368 /* Need reopen file because:
369 "You MUST NOT seek during writing or reading a file with SFTP, as the internals use
370 outstanding packets and changing the "file position" during transit will results in
372 if (file_handler
->pos
> offset
|| offset
== 0)
374 sftpfs_reopen (file_handler
, error
);
375 if (error
!= NULL
&& *error
!= NULL
)
378 file_handler
->pos
= offset
;
381 file_handler
->pos
+= offset
;
384 if (file_handler
->pos
> file_handler
->ino
->st
.st_size
- offset
)
386 sftpfs_reopen (file_handler
, error
);
387 if (error
!= NULL
&& *error
!= NULL
)
390 file_handler
->pos
= file_handler
->ino
->st
.st_size
- offset
;
394 libssh2_sftp_seek64 (file_handler_data
->handle
, file_handler
->pos
);
395 file_handler
->pos
= (off_t
) libssh2_sftp_tell64 (file_handler_data
->handle
);
397 return file_handler
->pos
;
400 /* --------------------------------------------------------------------------------------------- */